日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

单片机裸机实用组件--软件定时器、时间戳

發布時間:2025/4/16 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 单片机裸机实用组件--软件定时器、时间戳 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

單片機裸機實用組件–軟件定時器、時間戳

之前寫過一篇關于單片機定時器延時計時功能的博客 ,剛工作的時候搞得現在看來還是比較糙的,是時候整一個新的了。

base_timer

單片機裸機適用的定時器小組件,通過一個定時器記錄系統運行時長,為用戶提供一個時間戳信息,當然也有軟件定時器功能。

移植教程

  • 將 base_timer.c base_timer.h base_timer_port.c 添加到工程中
  • 打開 base_timer_port.c 文件,自行實現里面的函數, 其中最重要的是 btimer_port_init(uint32_t clock, uint16_t ticks)函數和 uint32_t btimer_port_get_ticks(void)函數
  • /*!* @brief 初始化定時器** @param clock: 定時器時鐘* @param ticks: 定時器每s中斷ticks次** @return 無** @note 移植時需要根據使用的定時器實現該函數** @see btimer_port_init(72000000, 1000); ** @date 2019/07/15*/ void btimer_port_init(uint32_t clock, uint16_t ticks) {}/*!* @brief 獲取定時器的tick值** @param 無** @return ticks** @note 移植時需要根據使用的定時器實現該函數** @see ** @date 2019/07/15*/ uint32_t btimer_port_get_ticks(void) {return ; }
  • 將 btimer_ticks();函數添加到定時器中斷服務函數中,周期性的執行。
  • 使用說明

  • 初始化定時器
  • void btimer_init(uint32_t clock, uint16_t ticks);
  • 定時器初始化后,系統內就存在了一個時基,可以獲取系統從定時器初始化到現在的運行 ticks,通過這個時間戳信息,就可以實現各種各樣的功能了。
    需要注意的是,us和ms相關的函數都是在調用 uint64_t btimer_get_ticks(void); 函數的基礎上使用除法實現的,但是沒有double FPU的單片機對 uint64_t 的除法運算比較耗時,實測STM32F103 72MHz時, 一次uint64_t 需要50us左右
  • uint64_t btimer_get_ticks(void); uint32_t btimer_get_us(void); uint32_t btimer_get_ms(void); void btimer_delay_ticks(uint32_t ticks); void btimer_delay_us(uint32_t us); void btimer_delay_ms(uint32_t ms);
  • 組件內同樣也有實現軟件定時器,在 base_timer.h 中使能
  • /*! 是否使能軟件定時器 */ #define SOFT_TIMER_ENABLE 1
    • 調用軟件定時器初始化函數初始化一個軟件定時器
    void stimer_init(Stimer_t * stimer, uint16_t ticks, uint8_t count, stimerCallback_t cb);
    • 開啟關閉定時器
    void stimer_start(Stimer_t * stimer); void stimer_stop(Stimer_t * stimer);

    使用例子

    /* 定時器超時回調函數 */ void stimerLed1Callback(void) {//do something }void stimerLed2Callback(void) {//do something }void stimerLed3Callback(void) {//do something }Stimer_t g_stimerLed1, g_stimerLed2, g_stimerLed3;int main(void) {/* 初始化定時器 定時器時鐘 72MHz 每秒中斷1000次 */btimer_init(72000000, 1000);/* 獲取時間戳 */uint64_t ticks1 = btimer_get_ticks();/* 延時 10000us */btimer_delay_us(10000);/* 獲取時間戳 通過 ticks2 - ticks1 可以獲得 btimer_delay_us(10000); 運行時長 */uint64_t ticks2 = btimer_get_ticks();/* 延時 10ms */btimer_delay_ms(10);stimer_init(&g_stimerLed1, 100, COUNTER_MAX, stimerLed1Callback);stimer_init(&g_stimerLed2, 1000, 1, stimerLed2Callback);stimer_init(&g_stimerLed3, 1000, COUNTER_MAX, stimerLed3Callback);stimer_start(&g_stimerLed1);stimer_start(&g_stimerLed2);stimer_start(&g_stimerLed3);while (1){if(stimer_is_timeout(&g_stimerLed2)){stimer_init(&g_stimerLed2, 1000, 1, stimerLed2Callback);stimer_start(&g_stimerLed2);}} }

    base_timer.c

    /*!* @file base_timer.c** @brief 系統計時器** @company ** @author 不咸不要錢** @note ** @version V1.2** @Software ** @par URL * ** @date 2019/07/15*/ #include "base_timer.h"/** * @brief 一個時間結構體* @note 內部調用*/ typedef struct{uint32_t ulTickPerMicrosecond; /*!<每us tick計數值 */uint32_t ulTickPerMillisecond; /*!<每ms tick計數值 */uint32_t ulTickPerHandler; /*!<每?ticks 定時器中斷一次*/volatile uint64_t ullTicks; /*!<當前ticks */uint32_t ulDelayOffSet; /*!<函數零偏 */ }BaseTimerParame_t;/** 保存定時器參數 */ static BaseTimerParame_t s_tTimer;#if defined(SOFT_TIMER_ENABLE) && (SOFT_TIMER_ENABLE == 1) static void stimer_ticks(void); #endif/*!* @brief 定時器tick自增** @param 無** @return 無** @note 需要在定時器中斷服務函數中調用 btimer_ticks(); ** @see 無** @date 2019/07/15*/ void btimer_ticks(void) {s_tTimer.ullTicks += s_tTimer.ulTickPerHandler;#if defined(SOFT_TIMER_ENABLE) && (SOFT_TIMER_ENABLE == 1)stimer_ticks(); #endif }/*!* @brief 初始化定時器** @param clock: 定時器時鐘 clock要大于等于 1M* @param ticks: 定時器每s中斷ticks次 ** @return 無** @note ** @see btimer_init(72000000, 1000); ** @date 2019/07/15*/ void btimer_init(uint32_t clock, uint16_t ticks) {if(clock < 1000000ul){/* 定時器頻率 小于1MHz 每us tick計數值 固定為1 注意:定時器頻率過低,使用us相關函數時會不準確 */s_tTimer.ulTickPerMicrosecond = 1;}else{s_tTimer.ulTickPerMicrosecond = clock / 1000000ul;}if(clock < 1000){/* 定時器頻率 小于1KHz 注意:定時器頻率過低 */while(1);}else{s_tTimer.ulTickPerMillisecond = clock / 1000;}s_tTimer.ullTicks = 0;s_tTimer.ulTickPerHandler = clock / ticks;s_tTimer.ulDelayOffSet = 0;btimer_port_init(clock, ticks);/* 去零偏 */uint32_t currentTicks1 = 0, currentTicks2 = 0;for(int i = 0; i < 1000; i++){currentTicks1 = btimer_get_ticks();btimer_delay_us(1);currentTicks2 = btimer_get_ticks();s_tTimer.ulDelayOffSet += (currentTicks2 - currentTicks1 - s_tTimer.ulTickPerMicrosecond);}s_tTimer.ulDelayOffSet = (s_tTimer.ulDelayOffSet + 500)/1000; }/*!* @brief 關閉定時器** @param 無** @return 無** @note ** @see BaseTimerDeInit(); ** @date 2019/07/15*/ void btimer_deinit(void) {btimer_port_deinit(); }/*!* @brief 獲取當前tick值** @param 無** @return 從定時器初始化到當前的ticks** @note ** @see ** @date 2019/07/15*/ uint64_t btimer_get_ticks(void) {uint64_t ticks = 0;uint32_t timerValue = 0;do{ticks = s_tTimer.ullTicks;timerValue = btimer_port_get_ticks();}while(ticks != s_tTimer.ullTicks);return ticks + timerValue; }/*!* @brief 獲取當前us值** @param 無** @return 從定時器初始化到當前的us** @note uint64 除法非常耗時 stm32F1xx 做一次 uint64除法大概需要50us** @see ** @date 2019/07/15*/ uint32_t btimer_get_us(void) {return btimer_get_ticks()/s_tTimer.ulTickPerMicrosecond; }/*!* @brief 獲取當前ms值** @param 無** @return 從定時器初始化到當前的ms** @note uint64 除法非常耗時 stm32F1xx 做一次 uint64除法大概需要50us** @see ** @date 2019/07/15*/ uint32_t btimer_get_ms(void) {return btimer_get_ticks()/s_tTimer.ulTickPerMillisecond; }/*!* @brief 延時** @param ticks : 要延時的ticks** @return 無** @note ** @see ** @date 2019/07/15*/ void btimer_delay_ticks(uint32_t ticks) {uint64_t end = btimer_get_ticks() + ticks - s_tTimer.ulDelayOffSet;while(btimer_get_ticks() <= end); }/*!* @brief 延時** @param us : 要延時的us** @return 無** @note ** @see ** @date 2019/07/15*/ void btimer_delay_us(uint32_t us) {uint64_t end = btimer_get_ticks() + us * s_tTimer.ulTickPerMicrosecond - s_tTimer.ulDelayOffSet;while(btimer_get_ticks() <= end); }/*!* @brief 延時** @param ms : 要延時的ms** @return 無** @note ** @see ** @date 2019/07/15*/ void btimer_delay_ms(uint32_t ms) {uint64_t end = btimer_get_ticks() + ms * s_tTimer.ulTickPerMillisecond - s_tTimer.ulDelayOffSet;while(btimer_get_ticks() <= end); }#if defined(SOFT_TIMER_ENABLE) && (SOFT_TIMER_ENABLE == 1)/** 指向軟件定時器驅動鏈表頭節點 */ static Stimer_t * s_stimer_head = 0;/*!* @brief 軟件定時器節拍處理** @param 無** @return 無** @note 需要周期性調用該函數 軟件定時器ticks均以該周期為單位 ** @see ** @date 2019/07/15*/ static void stimer_ticks(void) {Stimer_t * node = s_stimer_head;while(node){if(node->ucCounter > 0){ if(-- node->ulTicks == 0){if(node->ucCounter != COUNTER_MAX){node->ucCounter--;}node->ulTicks = node->ulPerLoad;node->ucFlag = 1;if(node->stimerCallback != 0){node->stimerCallback((void *)node);}if(node->ucCounter == 0){stimer_stop(node);}}}else{stimer_stop(node);} node = node->ptNextTimer;} } /*!* @brief 軟件定時器初始化** @param stimer:軟件定時器* @param ticks :軟件定時器定時時間* @param count :軟件定時器定時次數 如果為0xFF 則為永久* @param cb :軟件定時器溢出回調函數** @return 無** @note cb 回調函數會在 btimer_ticks() 中執行,而 btimer_ticks() 一般在中斷服務函數中,因此定時器溢出回調函數盡量快進快出** @see ** @date 2019/07/15*/ void stimer_init(Stimer_t * stimer, uint16_t ticks, uint8_t count, stimerCallback_t cb) {stimer_port_lock();stimer->ulTicks = ticks;stimer->ulPerLoad = ticks;stimer->ucCounter = count;stimer->ucFlag = 0;stimer->stimerCallback = cb;stimer_port_unlock(); }/*!* @brief 開啟軟件定時器** @param stimer:軟件定時器** @return 無** @note 將軟件定時器添加到鏈表上** @see ** @date 2019/07/15*/ void stimer_start(Stimer_t * stimer) {stimer_port_lock();/* 防止重復 */Stimer_t * node = s_stimer_head;while(node){if(node == stimer){stimer_port_unlock();return;}else{node = node->ptNextTimer;} }stimer->ptNextTimer = s_stimer_head;s_stimer_head = stimer;stimer_port_unlock(); }/*!* @brief 停止軟件定時器** @param stimer:軟件定時器** @return 無** @note 將軟件定時器從定時器鏈表上移除** @see ** @date 2019/07/15*/ void stimer_stop(Stimer_t * stimer) {Stimer_t** curr;for(curr = &s_stimer_head; *curr; ) {Stimer_t* entry = *curr;if (entry == stimer) {stimer_port_lock();*curr = entry->ptNextTimer;stimer_port_unlock();return;} else{curr = &entry->ptNextTimer;} } }/*!* @brief 停止軟件定時器超時** @param stimer:軟件定時器** @return 無** @note 調用后會自動清除超時標志位** @see ** @date 2019/07/15*/ uint8_t stimer_is_timeout(Stimer_t * stimer) {uint8_t flag = stimer->ucFlag;stimer_port_lock();stimer->ucFlag = 0;stimer_port_unlock();return flag; } #endif

    base_timer.h

    /*!* @file base_timer.h** @brief 系統計時器** @company ** @author 不咸不要錢** @note ** @version V1.2** @Software C99** @par URL * ** @date 2019/07/15*/ #ifndef __BASE_TIMER_H #define __BASE_TIMER_H#ifdef __cplusplus extern "C" { #endif#include <stdint.h>/* 用戶函數 */ void btimer_init(uint32_t clock, uint16_t ticks); void btimer_deinit(void); uint64_t btimer_get_ticks(void); uint32_t btimer_get_us(void); uint32_t btimer_get_ms(void); void btimer_delay_ticks(uint32_t ticks); void btimer_delay_us(uint32_t us); void btimer_delay_ms(uint32_t ms); void btimer_ticks(void);/*! 是否使能軟件定時器 */ #define SOFT_TIMER_ENABLE 1#if defined(SOFT_TIMER_ENABLE) && (SOFT_TIMER_ENABLE == 1)/*! 定時器重復最大次數 */ #define COUNTER_MAX (0xFF)/*! 函數指針 指向軟件定時器超時回調函數 */ typedef void (*stimerCallback_t)(void *);/** * @brief stimer 軟件定時器結構體* @note 無*/ typedef struct Stimer {volatile uint8_t ucCounter;volatile uint8_t ucFlag;volatile uint32_t ulTicks;uint32_t ulPerLoad;stimerCallback_t stimerCallback;struct Stimer * ptNextTimer; }Stimer_t;void stimer_init(Stimer_t * stimer, uint16_t ticks, uint8_t count, stimerCallback_t cb); void stimer_start(Stimer_t * stimer); void stimer_stop(Stimer_t * stimer); uint8_t stimer_is_timeout(Stimer_t * stimer);void stimer_port_lock(void); void stimer_port_unlock(void); #endif/* 移植時需用戶實現 */ void btimer_port_init(uint32_t clock, uint16_t ticks); void btimer_port_deinit(void); uint32_t btimer_port_get_ticks(void);#ifdef __cplusplus } #endif#endif

    base_timer_port.c

    /*!* @file base_timer_port.c** @brief 系統計時器用戶接口** @company ** @author 不咸不要錢** @note ** @version V1.2** @Software C99** @par URL * ** @date 2019/07/15*/ #include "base_timer.h"/*!* @brief 初始化定時器** @param clock: 定時器時鐘* @param ticks: 定時器每s中斷ticks次** @return 無** @note 移植時需要根據使用的定時器實現該函數** @see btimer_port_init(72000000, 1000); ** @date 2019/07/15*/ void btimer_port_init(uint32_t clock, uint16_t ticks) {}/*!* @brief 關閉定時器** @param 無** @return 無** @note ** @see btimer_port_deinit(); ** @date 2019/07/15*/ void btimer_port_deinit(void) {}/*!* @brief 獲取定時器的tick值** @param 無** @return ticks** @note 移植時需要根據使用的定時器實現該函數** @see ** @date 2019/07/15*/ uint32_t btimer_port_get_ticks(void) {return ; }#if defined(SOFT_TIMER_ENABLE) && (SOFT_TIMER_ENABLE == 1) /*!* @brief 加鎖** @param ** @return 無** @note ** @see */ void stimer_port_lock(void) {}/*!* @brief 開鎖** @param 無** @return 無** @note ** @see */ void stimer_port_unlock(void) {}#endif 《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀

    總結

    以上是生活随笔為你收集整理的单片机裸机实用组件--软件定时器、时间戳的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 欧美韩日国产 | 国产精品一区在线播放 | 欧美大片免费看 | 黄网站免费在线观看 | 日韩香蕉网 | 日韩av一区在线观看 | 国产成人无码一区二区在线播放 | 日韩精品国产一区二区 | 女生扒开尿口让男生桶 | av高清免费 | 在线中出 | www国产精品 | 天堂视频在线免费观看 | 蜜桃av鲁一鲁一鲁一鲁俄罗斯的 | 在线视频日本 | 香蕉视频网站在线观看 | 免费a级片视频 | 青青草精品视频 | 亚洲第一中文字幕 | 日韩一区在线免费观看 | 日韩不卡免费视频 | 色校园| 动漫3d精品一区二区三区乱码 | 精品中文视频 | 动漫精品一区二区三区 | 夜夜欢视频| 国产一区视频在线播放 | 交专区videossex | 伊人网色| 亚洲天堂2024 | 日韩精品一线二线三线 | 美国性生活大片 | 欧美性猛交ⅹxx乱大交 | 久操网在线 | а√中文在线资源库 | 婷婷在线免费视频 | 国产精品一区一区三区 | 清清草在线视频 | 午夜私人影院 | 精品亚洲中文字幕 | 蜜臀一区二区三区精品免费视频 | 男人操女人逼逼视频 | 亚洲一二三不卡 | 蜜桃av色偷偷av老熟女 | 特级西西www444人体聚色 | 青草青青视频 | 国产精品美乳在线观看 | 欧美亚洲在线播放 | 欧美午夜一区二区三区 | 天堂网中文| 51人人看 | 天天影视插插插 | 久久成人动漫 | 欧美色啪| 夜色视频在线观看 | 精品亚洲成人 | 1024亚洲天堂 | 在线观看黄色片 | 天堂中文字幕av | 在线亚洲人成电影网站色www | 日韩黄色在线 | 国产又粗又大又黄 | 韩国短剧在线观看 | 国产天堂资源 | 男人用嘴添女人下身免费视频 | 黄色小说在线观看视频 | 日本高清免费视频 | 国产有码在线 | 在线免费看mv的网站入口 | 秋霞福利视频 | 国外成人免费视频 | 色欧美综合 | 亚洲视频大全 | 欧美日韩精品中文字幕 | 午夜视频久久 | 小蝌蚪av | 五月天色婷婷丁香 | jiz亚洲 | 熟女毛毛多熟妇人妻aⅴ在线毛片 | 婷婷av在线 | 久久久久久久久影院 | 男人的天堂手机在线 | 麻豆成人在线观看 | 女同动漫免费观看高清完整版在线观看 | www在线观看免费视频 | 国产精品videossex久久发布 | 精品一级少妇久久久久久久 | 国产一级淫片免费 | 高潮毛片7777777毛片 | a在线看 | 777久久| 黑森林av | 欧美日韩一区三区 | 日韩在线第一 | 欧美高清视频一区 | 成人免费高清 | 精品一卡二卡 | 96超碰在线 | 日本乱子伦 |