定时器中断函数的使用

点击打开在线编译器,边学边练

1.定时器与延时的区别

大家可能会觉得我们用延时函数照样可以实现上一讲代码的实验现象,但是定时器与延时的概念不同,延时函数需要占用CPU的使用权,正在延时的时候其他任务没有CPU的使用权就会拖慢执行效率。

而定时器是不需要占用CPU的使用权的,它是独立自己运行的,就像我们在第一讲的时候提到调好5分钟的闹钟,在这5分钟里我们可以随意执行任务,也可以什么事都不做,但是5分钟过后闹钟响了就要执行相关的任务了。

所以上一讲的代码的实现原理就是每隔51微秒,有个变量会自加1,过了1000个51微秒的时候LED的状态才会改变,可以说CPU在51ms的时间里基本没什么事做,只是在51微秒到了的时候做了“cnt++;”这样简单的任务,然后又空闲地等下一个51微秒的到来再执行“cnt++;”。

 

2.定时器中断函数

与外部中断一样,定时器中断也有中断函数,同理,程序去执行中断函数就会把TF0的中断标志位自动清0,所以只要我们用了定时器中断函数,那么TF0就可以不用再出现在程序书写中了。

还记得外部中断这个图吗

定时器3

同样定时器0的中断函数使能如下

定时器4


至于“interrupt”后面的数字为什么是1,请再看我们以前给过大家的这个图的中断函数编号就明白了

定时器5

这些编号是为了区分哪些硬件资源的相关中断函数,如果我们同时使用两个定时器,那么只能用“interrupt 1”和“interrupt 3”来区分谁是谁的中断函数了。

使用“TIM0_IRQHandler”作为函数名也是模仿STM32定时器中断函数名的写法。

如果我们使用的是工作模式1,每次触发中断函数的执行内容首先就是再次给TH0和TL0赋初值保证下次的定时时间还是一样。

这里我们使用中断函数的执行方式来实现30ms的间隔流水灯,算出TH0和TL0合成的“16位的变量”要填充的值为37888=0x9400。

在中断函数里也是可以定义局部变量的,当然如果这个变量是用来辅助流水灯的,那么肯定是要定义成静态变量的。


3.代码

#include <reg52.h> 
#include <function.h>//详见第六章第8讲

void main()
{
    LED_Init();  //初始化LED硬件模块
    EA = 1;      //闭合总中断开关
    TMOD = 0x01; //设置定时器0为工作模式1
    TH0  = 0x94; //设置定时时间为30ms
    TL0  = 0x00;
    ET0  = 1;    //闭合定时器0中断的开关
    TR0  = 1;    //启动定时器0 
    while(1);
}
 
void TIM0_IRQHandler() interrupt 1
{
    static u8 i;
    TH0  = 0x94;  //重新设置定时时间为30ms
    TL0  = 0x00;
  
    P0=~(0x80>>i);//这一次让流水灯向右移
    i++;
    if(i>=8)i=0;
}

觉得30ms的流速太快,想改为300ms的话,修改一下中断函数即可,如下

void TIM0_IRQHandler() interrupt 1
{
    static u8 i,cnt;
    TH0  = 0x94;      //重新设置定时时间为30ms
    TL0  = 0x00;
    cnt++;
  
    if(cnt>=10)
    {
        cnt=0;
        P0=~(0x80>>i);//这一次让流水灯向右移
        i++;
        if(i>=8)i=0;
    }
}

本文固定URL:https://www.dotcpp.com/course/377

第一章 单片机入门
第二章 LED
第三章 蜂鸣器
第四章 数码管
第五章 独立按键
第六章 多文件编程
第七章 外部中断
第八章 定时器
第九章 舵机与超声波模块
第十章 串口通信
第十一章 1602液晶屏
第十二章 IIC通信
第十三章 红外遥控与温度传感器
第十四章 AD与DA
第十五章 混合例程
第十六章 完结
Dotcpp在线编译      (登录可减少运行等待时间)