首页 🥳 笔记

本文最后更新于 2021 年 02 月 08 日,已超过 135 天没更新!内容可能已失效,请自行测试 ~

定时器是单片机模块的一个资源,确确实实存在的一个模块,而中断,是单片机的一种运行机制。

标准51单片机中控制中断的寄存器有两个:一个是中断使能寄存器;另一个是中断优先级寄存器。

🟤中断使能寄存器

IE-中断使能寄存器的位分配(地址0xA8、可位寻址)

76543210
符号EA-ET2ESET1EX1ET0EX0
复位值0-000000

IE-中断使能寄存器的位描述

符号描述
7EA总中断使能位,相当于总开关
6--
5ET2定时器2中断使能
4ES串口中断使能
3ET1定时器1中断使能
2EX1外部中断1使能
1ET0定时器0中断使能
0EX0外部中断0使能

总开关相当于家里或者学生宿舍里的那个电源总闸门,而0~5位这6个位相当于每个分开关。也就是说,只要用到中断,就要写EA=1这一句,打开中断总开关,然后用到哪个分中断,再打开相对应的控制位就可以了。

🔸中断服务函数

书写格式:例如void InterruptTimer0() interrupt 1{},首先中断函数前边void表示函数返回空,即中断函数不返回任何值,函数名是InterruptTimer0(),这个函数名在符合函数命名规则的前提下可以随便取,而后是interrupt这个关键字,这是中断特有的关键字,紧跟在其后面的数字1为中断函数编号,是根据中断向量得出的,其计算方法是x*8+3=向量地址。

同时也解决了因为程序执行时间不一致而导致数码管显示抖动的视觉效果。

中断查询序列

中断函数编号中断名称中断标志位中断使能位中断向量地址默认优先级
0外部中断0IE0EX00x00031(最高)
1T0中断TF0ET00x000B2
2外部中断1IE1EX10x00133
3T1中断TF1ET10x001B4
4UART中断T1/R1ES0x00235
5T2中断TF2/EXF2ET20x002B6

🟣中断优先寄存器

中断优先级有两种:一种是抢占优先级,另一种是固有优先级

IP这个寄存器的每一位,表示对应中断的抢占优先级。

当进入低优先级中断中执行时,如又发生了高优先级的中断,则立刻进入高优先级中断执行,处理完高优先级中断后,再返回处理低优先级中断,这个过程就称为中断嵌套,也称为抢占

固有优先级又称非抢占优先级,其作用为多个中断同时存在时的仲裁。

IP-中断优先级寄存器的位分配(地址0xB8、可位寻址)

76543210
符号--PT2PSPT1PX1PT0PX0
复位值--000000

IP-中断优先级寄存器的位描述

符号描述
7-保留
6-保留
5PT2定时器2中断优先级控制位
4PS串口中断优先级控制位
3PT1定时器1中断优先级控制位
2PX1外部中断1中断优先级控制位
1PT0定时器0中断优先级控制位
0PX0外部中断0中断优先级控制位

#include "reg52.h"

sbit LSA=P2^3;
sbit LSB=P2^4;
sbit LSC=P2^5;

unsigned char code LedChar[]={            //数码管显示字符转换表
        0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
        0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71
};
unsigned char LedBuff[8]={                    //数码管显示缓冲区,初值0x00确保启动时都不亮
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
unsigned char i = 0;          //动态扫描的索引
unsigned int cnt = 0;            //记录T0中断次数
unsigned char flag1s=0;        //1秒定时标志

void main()
{
    unsigned long sec = 0;        //记录经过的秒数
    EA = 1;                                        //使能总中断
    TMOD = 0x01;                            //设置T0为模式1
    TH0 = 0xFC;                                //为T0赋初值0xFC67,定时1ms
    TL0 = 0x67;                                
    ET0 = 1;                                    //使能T0中断
    TR0 = 1;                                    //启动T0
    while(1)
    {
        if(flag1s == 1)                    //判断T0是否溢出
            {
                flag1s = 0;                    //T0溢出后,清0中断标志
                sec++;                            //秒计数自加1
                //以下代码将sec按十进制位从低到高依次提取并转为数码管显示字符
                LedBuff[0] = LedChar[sec%10];
                LedBuff[1] = LedChar[sec/10%10];
                LedBuff[2] = LedChar[sec/100%10];
                LedBuff[3] = LedChar[sec/1000%10];
                LedBuff[4] = LedChar[sec/10000%10];
                LedBuff[5] = LedChar[sec/100000%10];
                LedBuff[6] = LedChar[sec/1000000%10];
                LedBuff[7] = LedChar[sec/10000000%10];
            }
    }
}
/* 定时器0中断服务函数 */
void InterruptTimer0() interrupt 1
{
    TH0 = 0xFC;                    //重新加载初值
    TL0 = 0x67;
    cnt++;                            //中断次数计数值加1
    if(cnt >= 1000)            //中断1000次即1秒
    {
        cnt    = 0;                    //清0计数值以重新开始下1秒计时
        flag1s=1;                    //设置1秒定时标志为1
    }    
    //以下代码完成数码管动态扫描刷新
    P0 = 0x00;                    //显示消隐
    switch(i)
    {
        case 0:LSA=1;LSB=1;LSC=1;i++;P0=LedBuff[0];break;
        case 1:LSA=0;LSB=1;LSC=1;i++;P0=LedBuff[1];break;
        case 2:LSA=1;LSB=0;LSC=1;i++;P0=LedBuff[2];break;
        case 3:LSA=0;LSB=0;LSC=1;i++;P0=LedBuff[3];break;
        case 4:LSA=1;LSB=1;LSC=0;i++;P0=LedBuff[4];break;
        case 5:LSA=0;LSB=1;LSC=0;i++;P0=LedBuff[5];break;
        case 6:LSA=1;LSB=0;LSC=0;i++;P0=LedBuff[6];break;
        case 7:LSA=0;LSB=0;LSC=0;i=0;P0=LedBuff[7];break;
        default:break;
    }
}
#include "reg52.h"

sbit LSA=P2^3;
sbit LSB=P2^4;
sbit LSC=P2^5;

unsigned char code LedChar[]={            //数码管显示字符转换表
        0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
        0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71
};
unsigned char LedBuff[8]={                    //数码管显示缓冲区,初值0x00确保启动时都不亮
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
unsigned char water_led1[8]={
        0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f            //正向流动
};
unsigned char water_led2[8]={
        0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe            //反向流动
};

unsigned char flag1s=0;        //1秒定时标志

void main()
{
    unsigned long sec = 0;        //记录经过的秒数
    static unsigned char j=0;
    unsigned char buf[8];
    char k;
    EA = 1;                                        //使能总中断
    TMOD = 0x01;                            //设置T0为模式1
    TH0 = 0xFC;                                //为T0赋初值0xFC67,定时1ms
    TL0 = 0x67;                                
    ET0 = 1;                                    //使能T0中断
    TR0 = 1;                                    //启动T0

    while(1)
    {
        if(flag1s == 1)                    //判断T0是否溢出
        {
            flag1s = 0;                    //T0溢出后,清0中断标志
            sec++;                            //秒计数自加1
            //以下代码将sec按十进制位从低到高依次提取并转为数码管显示字符
            buf[0]=sec%10;
            buf[1]=sec/10%10;
            buf[2]=sec/100%10;
            buf[3]=sec/1000%10;
            buf[4]=sec/10000%10;
            buf[5]=sec/100000%10;
            buf[6]=sec/1000000%10;
            buf[7]=sec/10000000%10;
            for(k=7;k>=1;k--)
            {
                if(buf[k]==0)
                    LedBuff[k]=0x00;
                else
                    break;
            }
            for(;k>=0;k--)
            {
                LedBuff[k]=LedChar[buf[k]];
            }
            
            if(j<8)
                P1=water_led1[j];
            if(j>=8)
                P1=water_led2[j-8];
            j++;
            if(j==16)
                j=0;
        }
    }
}
/* 定时器0中断服务函数 */
void InterruptTimer0() interrupt 1
{
    static unsigned char i = 0;          //动态扫描的索引
    static unsigned int cnt = 0;            //记录T0中断次数
    TH0 = 0xFC;                    //重新加载初值
    TL0 = 0x67;
    cnt++;                            //中断次数计数值加1
    if(cnt >= 1000)            //中断1000次即1秒
    {
        cnt    = 0;                    //清0计数值以重新开始下1秒计时
        flag1s=1;                    //设置1秒定时标志为1
    }    
    //以下代码完成数码管动态扫描刷新
    P0 = 0x00;                    //显示消隐
    switch(i)
    {
        case 0:LSA=1;LSB=1;LSC=1;i++;P0=LedBuff[0];break;
        case 1:LSA=0;LSB=1;LSC=1;i++;P0=LedBuff[1];break;
        case 2:LSA=1;LSB=0;LSC=1;i++;P0=LedBuff[2];break;
        case 3:LSA=0;LSB=0;LSC=1;i++;P0=LedBuff[3];break;
        case 4:LSA=1;LSB=1;LSC=0;i++;P0=LedBuff[4];break;
        case 5:LSA=0;LSB=1;LSC=0;i++;P0=LedBuff[5];break;
        case 6:LSA=1;LSB=0;LSC=0;i++;P0=LedBuff[6];break;
        case 7:LSA=0;LSB=0;LSC=0;i=0;P0=LedBuff[7];break;
        default:break;
    }
}



文章评论