今天給大家分享的是嵌入式里通用微秒(microseconds)計時函數框架設計與實現。
在嵌入式軟件開發里,計時可以說是非常基礎的功能模塊了,其應用也非常廣泛,比如可以輔助計算信號脈沖寬度時間,也可以直接用于常規延時等。相信很多人初次領略 MCU 的神奇,都是從計時功能相關小程序開始的。
在 MCU 里要想實現精確計時,往往都是利用其內部硬件定時器。不同廠商的 MCU,其定時器設計與使用都不太一樣。即使是同一 MCU 內,通常也會有好幾種不同類型的定時器共存。
基于此,今天分享一種非常簡單實用的通用計時函數框架。這個框架的目的是統一計時函數接口,并且在實現上將通用部分和硬件相關部分剝離開。這樣你的嵌入式項目在使用這個框架時,可以無縫快捷地切換底層定時器。
注:本框架主要適合定時器時鐘源不小于 1MHz 的 MCU,因為函數接口里延時最小單元是 1us。對于一些定時器時鐘源低于 1MHz 的 MCU,可將本框架簡單改成毫秒(milliseconds)計時函數。
一、微秒(microseconds)計時函數庫設計
1、函數接口定義
首先是設計通用計時函數框架頭文件:microseconds.h ,這個頭文件里直接定義如下 7 個接口函數原型。涵蓋必備的初始化流程init()、shutdown(),最核心的計時功能get_ticks()、convert_to_microseconds(),常用的延時功能delay()、set_delay()、is_timeout()。
//!@brief初始化計時 voidmicroseconds_init(void); //!@brief關閉計時 voidmicroseconds_shutdown(void); //!@brief獲取系統累計計數值 uint64_tmicroseconds_get_ticks(void); //!@brief將計數值轉換為時間值(微秒) uint32_tmicroseconds_convert_to_microseconds(uint64_tticks); //!@brief阻塞型延時(微秒級) voidmicroseconds_delay(uint32_tus); //!@brief設置超時時間(用于非阻塞型延時) voidmicroseconds_set_delay(uint32_tus); //!@brief判斷是否超時(用于非阻塞型延時) boolmicroseconds_is_timeout(void);
2、通用函數實現
然后是設計通用計時函數框架共用源文件:microseconds_common.c,這個文件里涉及三個靜態全局變量定義,四個私有函數聲明,以及除了 get_ticks() 之外的 6 個接口函數實現。
其中 s_tickPerMicrosecond 變量存的是每微秒對應計數值,其實這個變量不是一定要定義的,可以在函數需要時實時計算,但為了小小提升框架性能,就在 init() 里將這個值先算出來了,方便其他函數直接使用。
s_highCounter 變量存的是定時器中斷次數,即高位計數器,因為框架 get_ticks() 接口返回的是 64bit 的計數值,對于有些寬度小于 32bit 的定時器,我們常常需要開啟定時器中斷,否則無法保證系統長時間運行線性計時的正確性(比如 100MHz 時鐘源的 32bit 定時器,最長約 43 秒就會清零翻轉一次,需要 s_highCounter 變量記錄翻轉次數)。
當然,如果 MCU 里能級連出 64bit 的定時器,就可以不用開啟中斷(清零翻轉的時間特別長,可近似認為是永久),s_highCounter 此時就不需要了。
關于延時函數接口,delay() 用于阻塞型延時,即調用這個函數后一定是死等指定時間后才退出,系統會被強制掛起;set_delay()/is_timeout()用于非阻塞型延時,系統可以繼續干其他任務,在需要的時侯來查看一下超時時間是否到了即可。兩種延時各有各的用途。
//!
二、微秒(microseconds)計時函數庫實現
1、定時器相關實現(基于Cortex-M內核的SysTick)
最后是設計 MCU 相關的通用計時函數框架源文件:microseconds_xxTimer.c,這里我們以 Cortex-M 系列 MCU 的內核定時器 SysTick 為例。
SysTick 是 24bit 遞減定時器,時鐘源有兩種配置:一是內核主頻,二是外部時鐘(看廠商實現),最常用的時鐘源配置就是與內核同頻。
之前我們說過,用 SysTick 這類寬度小于 32bit 的定時器,是需要開啟定時器中斷的,所以 s_highCounter 會生效。get_ticks()是整個計時函數框架里最基礎也最核心的功能接口,這里面的實現有一個需要特別注意的地方,就是取系統當前計數值可能會有數值回退的風險,需要使用代碼中 do {} while();方式來確保正確性。
//!CTRL&=~(SysTick_CTRL_CLKSOURCE_Msk| SysTick_CTRL_TICKINT_Msk| SysTick_CTRL_ENABLE_Msk); SysTick->VAL=0; } uint32_tmicroseconds_get_clock(void) { returnSystemCoreClock; } uint64_tmicroseconds_get_ticks(void) { uint32_thigh; uint32_tlow; //這里的實現要注意確保中斷發生時獲取系統累計計數值的正確性 do { //先緩存高位計數器 high=s_highCounter; //再讀定時器實際計數值 low=~SysTick->VAL&SysTick_LOAD_RELOAD_Msk; }while(high!=s_highCounter);//保證緩存高位值與讀實際低位值間隙中沒有發生中斷 return((uint64_t)high<24)?+?low; } void?SysTick_Handler(void) { ????s_highCounter++; }
當然還有很多具體 MCU 平臺的各種定時器實現,因此這個項目會不斷更新,也歡迎大家來參與貢獻。
至此,嵌入式里通用微秒(microseconds)計時函數框架設計與實現便介紹完畢了。
審核編輯:湯梓紅
-
mcu
+關注
關注
146文章
17123瀏覽量
350983 -
嵌入式
+關注
關注
5082文章
19104瀏覽量
304802 -
定時器
+關注
關注
23文章
3246瀏覽量
114719 -
函數
+關注
關注
3文章
4327瀏覽量
62569
原文標題:MCU通用微秒計時函數框架設計
文章出處:【微信號:gh_c472c2199c88,微信公眾號:嵌入式微處理器】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論