在一个程序中的很多地方都需要定时,如LED闪烁、按键消抖和通讯等待等。通过阻塞CPU的方式定时,程序性能极差;通过硬件定时器定时,性能好,定时非常准确,但定时器资源有限;通过定时器中断计数的方式定时,性能好,定时较准确,使用非常灵活。本文主要描述通过定时器中断计数的方式定时的实现。
2.定时器中断计数
初始化?个定时器,1ms中断?次。定义?个uint32_t变量,每中断?次,变量加1,变量溢出后
变为0。
定时器初始化和中断服务程序
- uint32_t volatile time_base_ms; //volatile关键字防?编译器优化
- void timer_init(void)
- {
- //初始化定时器
- time_base_ms = 0;
- }
- // 定时器中断服务程序
- void Timer_hander(void) interrupt 19
- {
- ++time_base_ms;
- }
复制代码
3.获取当前时刻
定时器开启之后,变量time_base_ms开始计数,每加1表示时间过去1ms。在访问变量
time_base_ms的 过程中有可能发?了中断,必须特殊处理。?法是,先读?次,再读?次并?较?
次,如果相等说明两次读的过程都没有发?中断,数据可靠;如果不相等,说明两次读有?次发?了
中断,下?次中断没有那么快到来,再读?次数据?定不会发?中断(系统时钟不太慢的情况下)。
- uint32_t time_current(void)
- {
- uint32_t ret;
-
- ret = time_base_ms; // 读取计数,该过程可能中断
-
- if(ret != time_base_ms){ // 读取计数,该过程可能中断;如果不相等,说明两
- 个过程有?个发?过中断
- ret = time_base_ms; // 读取计数,该过程没有中断
- }
-
- return ret;
- }
复制代码
4.定时的计算
计算过去某个时刻据当前时刻的时间,或者说过去的某个时刻据现在有多久。需要考虑过去某个
时刻到当前时刻变量time_base_ms有没有溢出。
- uint32_t time_timing_ms(uint32_t moment)
- {
- uint32_t current_moment;
- uint32_t ret;
-
- current_moment = time_current();
-
- if(current_moment >= moment){
- ret = current_moment - moment;
- }else{
- ret = (0xffffffff - moment) + current_moment + 1;
- }
-
- return ret;
- }
复制代码
应用
led1每秒闪烁1次,led2每秒闪烁5次。
- void main()
- {
- uint32_t led1_moment;
- uint32_t led2_moment;
- //初始化定时器
- timer_init();
- //记录当前时刻
- led1_moment = time_current();
- led2_moment = time_current();
- while(1){
- //检查时间是否过去500ms
- if(time_timing_ms(led1_moment) > 500){
- led1 = ~led1;
- led1_moment = time_current(); //记录当前时刻
- }
- //检查时间是否过去100ms
- if(time_timing_ms(led2_moment) > 100){
- led2 = ~led2;
- led2_moment = time_current(); //记录当前时刻
- }
-
- }
- }
复制代码
示例:
|