标题: 51单片机程序设计-时基 通过定时器中断计数的方式定时的实现 [打印本页]

作者: m5y2016    时间: 2023-6-26 14:45
标题: 51单片机程序设计-时基 通过定时器中断计数的方式定时的实现
在一个程序中的很多地方都需要定时,如LED闪烁、按键消抖和通讯等待等。通过阻塞CPU的方式定时,程序性能极差;通过硬件定时器定时,性能好,定时非常准确,但定时器资源有限;通过定时器中断计数的方式定时,性能好,定时较准确,使用非常灵活。本文主要描述通过定时器中断计数的方式定时的实现。


2.定时器中断计数
初始化?个定时器,1ms中断?次。定义?个uint32_t变量,每中断?次,变量加1,变量溢出后
变为0。
定时器初始化和中断服务程序
  1. uint32_t volatile time_base_ms;  //volatile关键字防?编译器优化
  2. void timer_init(void)
  3. {
  4.   //初始化定时器
  5.   time_base_ms = 0;
  6. }
  7. // 定时器中断服务程序
  8. void Timer_hander(void) interrupt 19
  9. {
  10.   ++time_base_ms;
  11. }
复制代码



3.获取当前时刻
定时器开启之后,变量time_base_ms开始计数,每加1表示时间过去1ms。在访问变量
time_base_ms的 过程中有可能发?了中断,必须特殊处理。?法是,先读?次,再读?次并?较?
次,如果相等说明两次读的过程都没有发?中断,数据可靠;如果不相等,说明两次读有?次发?了
中断,下?次中断没有那么快到来,再读?次数据?定不会发?中断(系统时钟不太慢的情况下)。
  1. uint32_t time_current(void)
  2. {
  3.   uint32_t ret;

  4.   ret = time_base_ms;     // 读取计数,该过程可能中断

  5.   if(ret != time_base_ms){  // 读取计数,该过程可能中断;如果不相等,说明两
  6. 个过程有?个发?过中断
  7.     ret = time_base_ms;   // 读取计数,该过程没有中断
  8.   }

  9.   return ret;
  10. }
复制代码

4.定时的计算
计算过去某个时刻据当前时刻的时间,或者说过去的某个时刻据现在有多久。需要考虑过去某个
时刻到当前时刻变量time_base_ms有没有溢出。
  1. uint32_t time_timing_ms(uint32_t moment)
  2. {
  3.   uint32_t current_moment;
  4.   uint32_t ret;

  5.   current_moment = time_current();

  6.   if(current_moment >= moment){
  7.     ret = current_moment - moment;
  8.   }else{
  9.     ret = (0xffffffff - moment) + current_moment + 1;
  10.   }

  11.   return ret;
  12. }
复制代码

应用
led1每秒闪烁1次,led2每秒闪烁5次。

  1. void main()
  2. {
  3.   uint32_t led1_moment;
  4.   uint32_t led2_moment;
  5.   //初始化定时器
  6.   timer_init();
  7.   //记录当前时刻
  8.   led1_moment = time_current();
  9.   led2_moment = time_current();
  10.   while(1){
  11.     //检查时间是否过去500ms
  12.     if(time_timing_ms(led1_moment) > 500){
  13.       led1 = ~led1;
  14.       led1_moment = time_current();  //记录当前时刻
  15.     }
  16.     //检查时间是否过去100ms
  17.     if(time_timing_ms(led2_moment) > 100){
  18.       led2 = ~led2;
  19.       led2_moment = time_current();  //记录当前时刻
  20.     }
  21.    
  22.   }
  23. }
复制代码

示例:




作者: 玲珑红豆    时间: 2023-6-26 21:25
void Timer_hander(void) interrupt 19
这个中断号是不是有问题,然后时间应该是时间差比较100 500ms,单片机的定时和晶振有关。
作者: m5y2016    时间: 2023-6-29 11:03
玲珑红豆 发表于 2023-6-26 21:25
void Timer_hander(void) interrupt 19
这个中断号是不是有问题,然后时间应该是时间差比较100 500ms,单 ...

代码不完全可用,只是用来说明思路
作者: KTTCO    时间: 2023-7-28 10:02
小白没看懂啊,点亮那个IO口了啊?
作者: 379887175    时间: 2023-8-5 14:35
小白没看懂啊,继续学习
作者: m5y2016    时间: 2023-8-9 18:32
KTTCO 发表于 2023-7-28 10:02
小白没看懂啊,点亮那个IO口了啊?

伪代码
作者: liqingyong    时间: 2023-10-3 14:54
KTTCO 发表于 2023-7-28 10:02
小白没看懂啊,点亮那个IO口了啊?

初始化把LED1定义到想要输出的口就行了,
作者: tthx13579    时间: 2024-2-4 18:53
不完全可用,只是用来说明思路
作者: 清水楼台    时间: 2024-2-17 22:02
这代码... AI生成的吧
作者: HHFIHHD    时间: 2024-6-20 12:57
讲的非常容易理解
作者: zyscxr    时间: 2024-9-22 18:01
新同学们慢慢来,逐步成长!多向大师学习
作者: 冬至是条狗    时间: 2025-1-12 18:15
新同学们慢慢来,逐步成长!多向大师学习




欢迎光临 (http://www.51hei.com/bbs/) Powered by Discuz! X3.1