手把手教你学51单片机-中断和数码管动态显示

中断是单片机系统重点中的重点,因为有了中断,单片机就具备了快速协调多模块工作 的能力,可以完成复杂的任务。

C 语言的数组

数组是具有相同数据类型的有序数据的组合,一般来讲,数组定义后满足 以下三个条件。

1、具有相同的数据类型;

2、具有相同的名字;

3、在存储器中是被连续存放的。

 

 

 在 C 语言程序中,是不能一次使用整个数组的,只能使用数组的单个元素。一个数组元 素相当于一个变量,使用数组元素的时候与使用相同数据类型的变量的方法是一样的。

数码管的动态显示

多个数码管显示数字的时候,我们实际上是轮流点亮数码管(一个时刻内只有一个数码 管是亮的),利用人眼的视觉暂留现象(也叫余辉效应),就可以做到看起来是所有数码管都 同时亮了,这就是动态显示,也叫做动态扫描。

#include <reg52.h>

sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;

unsigned char code LedChar[] = {  //数码管显示字符转换表
    0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
    0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};
unsigned char LedBuff[6] = {  //数码管显示缓冲区,初值0xFF确保启动时都不亮
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};

void main()
{
    unsigned char i = 0;    //动态扫描的索引
    unsigned int  cnt = 0;  //记录T0中断次数
    unsigned long sec = 0;  //记录经过的秒数

    ENLED = 0;    //使能U3,选择控制数码管
    ADDR3 = 1;    //因为需要动态改变ADDR0-2的值,所以不需要再初始化了
    TMOD = 0x01;  //设置T0为模式1
    TH0  = 0xFC;  //为T0赋初值0xFC67,定时1ms
    TL0  = 0x67;
    TR0  = 1;     //启动T0
    
    while (1)
    {
        if (TF0 == 1)         //判断T0是否溢出
        {
            TF0 = 0;          //T0溢出后,清零中断标志
            TH0 = 0xFC;       //并重新赋初值
            TL0 = 0x67;
            cnt++;            //计数值自加1
            if (cnt >= 1000)  //判断T0溢出是否达到1000次
            {
                cnt = 0;      //达到1000次后计数值清零
                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];
            }
            //以下代码完成数码管动态扫描刷新
            switch (i)
            {
                case 0: ADDR2=0; ADDR1=0; ADDR0=0; i++; P0=LedBuff[0]; break;
                case 1: ADDR2=0; ADDR1=0; ADDR0=1; i++; P0=LedBuff[1]; break;
                case 2: ADDR2=0; ADDR1=1; ADDR0=0; i++; P0=LedBuff[2]; break;
                case 3: ADDR2=0; ADDR1=1; ADDR0=1; i++; P0=LedBuff[3]; break;
                case 4: ADDR2=1; ADDR1=0; ADDR0=0; i++; P0=LedBuff[4]; break;
                case 5: ADDR2=1; ADDR1=0; ADDR0=1; i=0; P0=LedBuff[5]; break;
                default: break;
            }
        }
    }
}

单片机中断系统

 

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

#include <reg52.h>

sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;

unsigned char code LedChar[] = {  //数码管显示字符转换表
    0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
    0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};
unsigned char LedBuff[6] = {  //数码管显示缓冲区,初值0xFF确保启动时都不亮
    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
unsigned char i = 0;   //动态扫描的索引
unsigned int cnt = 0;  //记录T0中断次数
unsigned char flag1s = 0;  //1秒定时标志

void main()
{
    unsigned long sec = 0;  //记录经过的秒数

    EA = 1;       //使能总中断
    ENLED = 0;    //使能U3,选择控制数码管
    ADDR3 = 1;    //因为需要动态改变ADDR0-2的值,所以不需要再初始化了
    TMOD = 0x01;  //设置T0为模式1
    TH0  = 0xFC;  //为T0赋初值0xFC67,定时1ms
    TL0  = 0x67;
    ET0  = 1;     //使能T0中断
    TR0  = 1;     //启动T0
    
    while (1)
    {
        if (flag1s == 1)  //判断1秒定时标志
        {
            flag1s = 0;   //1秒定时标志清零
            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];
        }
    }
}
/* 定时器0中断服务函数 */
void InterruptTimer0() interrupt 1
{
    TH0 = 0xFC;  //重新加载初值
    TL0 = 0x67;
    cnt++;       //中断次数计数值加1
    if (cnt >= 1000)  //中断1000次即1秒
    {
        cnt = 0;      //清零计数值以重新开始下1秒计时
        flag1s = 1;   //设置1秒定时标志为1
    }
    //以下代码完成数码管动态扫描刷新
    P0 = 0xFF;   //显示消隐
    switch (i)
    {
        case 0: ADDR2=0; ADDR1=0; ADDR0=0; i++; P0=LedBuff[0]; break;
        case 1: ADDR2=0; ADDR1=0; ADDR0=1; i++; P0=LedBuff[1]; break;
        case 2: ADDR2=0; ADDR1=1; ADDR0=0; i++; P0=LedBuff[2]; break;
        case 3: ADDR2=0; ADDR1=1; ADDR0=1; i++; P0=LedBuff[3]; break;
        case 4: ADDR2=1; ADDR1=0; ADDR0=0; i++; P0=LedBuff[4]; break;
        case 5: ADDR2=1; ADDR1=0; ADDR0=1; i=0; P0=LedBuff[5]; break;
        default: break;
    }
}

 在这个程序中,有两个函数,一个是主函数,一个是中断服务函数。

中断服务函数,它的书写格式是固定的,首先中断函数前边 void 表示函数返回空,即中断函数不返回任何值,函数名是 InterruptTimer0()

 中断函数写好后,每当满足中断条件而触发中断后,系统就会自动来调用中断函数。

 

 

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一壶浊酒..

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值