今天给大家分享的是嵌入式里通用微秒(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 初始化计时void microseconds_init(void);//! @brief 关闭计时void microseconds_shutdown(void);//! @brief 获取系统累计计数值uint64_t microseconds_get_ticks(void);//! @brief 将计数值转换为时间值(微秒)uint32_t microseconds_convert_to_microseconds(uint64_t ticks);//! @brief 阻塞型延时(微秒级)void microseconds_delay(uint32_t us);//! @brief 设置超时时间(用于非阻塞型延时)void microseconds_set_delay(uint32_t us);//! @brief 判断是否超时(用于非阻塞型延时)bool microseconds_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()用于非阻塞型延时,系统可以继续干其他任务,在需要的时侯来查看一下超时时间是否到了即可。两种延时各有各的用途。
//!< 每微秒等效计数值static uint32_t s_tickpermicrosecond;//!< 超时时间点对应系统计数值(用于非阻塞型延时)static uint64_t s_timeoutticks;//!< 高位计数器,仅当使能定时器超时中断时有效,用于记录中断累计次数volatile uint32_t s_highcounter;//! @brief 打开硬件定时器extern void microseconds_timer_init(void);//! @brief 关闭硬件定时器extern void microseconds_timer_deinit(void);//! @brief 获取定时器时钟源数值extern uint32_t microseconds_get_clock(void);//! @brief 将时间值(微秒)转换为计数值static uint64_t microseconds_convert_to_ticks(uint32_t microseconds);void microseconds_init(void){ // 清零高位计数器 s_highcounter = 0; // 打开硬件定时器 microseconds_timer_init(); // 计算每微秒的等效计数值 s_tickpermicrosecond = microseconds_get_clock() / 1000000ul; // 假设定时器时钟源不小于 1mhz assert(s_tickpermicrosecond);}void microseconds_shutdown(void){ // 关闭硬件定时器 microseconds_timer_deinit();}uint32_t microseconds_convert_to_microseconds(uint64_t ticks){ return (ticks / s_tickpermicrosecond);}uint64_t microseconds_convert_to_ticks(uint32_t microseconds){ return ((uint64_t)microseconds * s_tickpermicrosecond);}void microseconds_delay(uint32_t us){ // 获取系统当前计数值 uint64_t currentticks = microseconds_get_ticks(); // 计算超时时间点系统计数值 uint64_t ticksneeded = ((uint64_t)us * s_tickpermicrosecond) + currentticks; // 等待系统计数值到达超时时间点系统计数值 while (microseconds_get_ticks() < ticksneeded);}void microseconds_set_delay(uint32_t us){ // 计算超时时间等效计数值 uint64_t ticks = microseconds_convert_to_ticks(us); // 设置超时时间点系统计数值 s_timeoutticks = microseconds_get_ticks() + ticks;}bool microseconds_is_timeout(void){ // 获取系统当前计数值 uint64_t currentticks = microseconds_get_ticks(); // 判断系统计数值是否大于超时时间点系统计数值 return (currentticks val = 0;}uint32_t microseconds_get_clock(void){ return systemcoreclock;}uint64_t microseconds_get_ticks(void){ uint32_t high; uint32_t low; // 这里的实现要注意确保中断发生时获取系统累计计数值的正确性 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)计时函数框架设计与实现便介绍完毕了。
萌新必看:嵌入式该怎么学
大陆为自动驾驶汽车提供了人机交互整体解决方案
区块链在各大行业中的应用介绍
上海电信5G建设“上海模式”取得突破,运营商积极推进5G共建共享
光纤链路的现场测试及故障点的定位
嵌入式里通用微秒计时函数框架设计与实现
iPhone 12的屏幕面板硬度大大超越了玻璃面板
基于ARM的嵌入式最小系统的架构研究
苹果CEO库克回应欧盟App Store新规:关注隐私安全,无法预估影响
到2030年将有8亿人的工作被机器所取代
赛普拉斯的新型低功耗蓝牙芯片获得蓝牙4.1认证
小米的九号平衡车怎么样?九号平衡车评测:电动出行的新解决方案
有多快?华为云刷新深度学习加速纪录
“云改”一年,中国移动1-9月份移动云收入同比增幅超过500%
苹果vr头显专利曝光 外观与三星Gear VR相似
近观三星新科技:迎合中国社会发展的大势
protel99se gerber文件的输出方法及步骤
智慧政府对于智慧城市的发展有没有推进作用
高通下一代移动处理器——骁龙855将加装NPU
数字货币普及以后会存在什么问题