这是楼主学习单片机时做的,很适合新手学习定时器和外部中断时做参考。 左侧为单片机最小系统,左上按键为复位键,右侧P3口为两个外部中断,INT0为开始/暂停按键(用定时器控制),INT1为模式切换按键。
流水灯没有用循环函数写,其与定时器结合,可以用外部中断INT0实时控制。
keil所有文件和proteus仿真都已上传,程序注释标的很清楚,适合新手学习。
仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
正向秒表
逆向秒表
实时可控流水灯
proteus仿真
单片机正逆向秒表流水灯源程序如下:
- #include<reg51.h>
- #include"main.h"
- #include"delay.h"
- #define uchar unsigned char
- #define uint unsigned int
- unsigned long int g_unDisNum; //用于计数,从00000到99999
- unsigned long int g_unDisNum1; //用于计数,从99999到00000
- uchar i,K,m,g_ucNum;
- uint c=0;
- uchar code table[]={0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF,0x7F}; //流水灯显示模式一
- uchar code table1[]={0x55,0xAA}; //流水灯显示模式二
- uchar code table2[]={0x00,0xFF}; //流水灯显示模式三
- uchar code DIS_CODE[10]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F}; //共阴极数码管显示代码
- void disp_numu(unsigned long int num1) //数码管显示函数,显示5位数字
- {
- uchar sep_num1=0;
- uchar ten_num1=0;
- uchar hund_num1=0;
- uchar thou_num1=0;
- uchar tent_num1=0;
-
- sep_num1=num1%10; //数码管的个十百千万位
- ten_num1=(num1%100)/10;
- hund_num1=(num1%1000)/100;
- thou_num1=(num1%10000)/1000;
- tent_num1=(num1%100000)/10000;
-
- P2=0xFE; //通过扫描的方式显示
- P0=DIS_CODE[tent_num1];
- delay_ms(1);
- P2=0xFD;
- P0=DIS_CODE[thou_num1];
- delay_ms(1);
- P2=0xFB;
- P0=DIS_CODE[hund_num1];
- delay_ms(1);
- P2=0xF7;
- P0=DIS_CODE[ten_num1];
- delay_ms(1);
- P2=0xEF;
- P0=DIS_CODE[sep_num1];
- }
- void modea() //正序按秒从00000递增至99999
- {
- if(g_ucNum>=200) //g_ucNum增至200正好1秒,将g_ucNum清零,g_unDisNum增1
- {
- g_ucNum=0;
- g_unDisNum++;
- }
- disp_numu(g_unDisNum);
- P1=0x00;
- }
- void modeb() //倒序按秒从99999递减至00000
- {
- if(g_ucNum>=200) //g_ucNum增至200正好1秒,将g_ucNum清零,g_unDisNum1减1
- {
- g_ucNum=0;
- g_unDisNum1--;
- }
- disp_numu(g_unDisNum1);
- P1=0x00;
- }
- void mode1() //正序流水灯,为了实时暂停、开始流水灯,mode1mode2mode3mode4均采用定时器中断的方式控制
- {
- P1=table[i%8];
- if(g_ucNum>=20)
- {
- g_ucNum=0;
- i++;
- }
- P2=0xFF; //清除右侧数码管余辉
-
- }
- void mode2() //倒序流水灯
- {
- P1=table[i%8];
- if(g_ucNum>=20)
- {
- g_ucNum=0;
- i--;
- }
- }
- void mode3() //混合亮灭流水灯
- {
- P1=table1[i%2];
- if(g_ucNum>=20)
- {
- g_ucNum=0;
- i++;
- }
- }
- void mode4() //全亮全灭流水灯
- {
- P1=table2[i%2];
- if(g_ucNum>=20)
- {
- g_ucNum=0;
- i++;
- }
- }
- void mode5() //初始状态 数码管88888二极管1111 1111
- { uchar m;
- for(m=0;m<10;m++)
- {
- P2=0xFE;
- P0=0x7F;
- delay_ms(2);
- P2=0xFD;
- P0=0x7F;
- delay_ms(2);
- P2=0xFB;
- P0=0x7F;
- delay_ms(2);
- P2=0xF7;
- P0=0x7F;
- delay_ms(2);
- P2=0xEF;
- P0=0x7F;
- delay_ms(2);
- P1=0x00;
- delay_ms(2);
- }
- }
- void int0_inter()interrupt 0 //INT0外部中断,可暂停、开始所有的单片机状态
- { if(c%2==0)
- {
- g_ucNum=0;
- TL0=0x18; //定时器赋初值TL0=(8192-5000)%32
- TH0=0x63; //THO=(8192-5000)/32
- TR0=1; //T0定时器计数
- c++; //通过参数c,用一个外部中断按键开关定时器控制单片机的开始与暂停
- }
- else
- {
- TR0=0; //T0定时器计数停止计数
- c++; //通过参数c,用一个外部中断按键开关定时器控制单片机的开始与暂停
- }
- }
- void timer0_inter()interrupt 1 //定时器中断
- {
- g_ucNum++;
- TL0=0x18;
- TH0=0x63;
- }
- void int1_inter()interrupt 2 //INT1外部中断,切换单片机状态
- {
- if(!INT1)
- {
- delay_ms(2);
- if(!INT1)
- {
- K++;
- if(K==7)
- K=1;
- }
- while(!INT1);
- }
- }
- void main(void)
- {
- g_unDisNum=0; //正序秒表初值
- g_unDisNum1=99999; //逆序秒表初值
- g_ucNum=0; //定时计数初值
- P0=0xFF;
- P2=0xFF;
- P3=0xFF;
-
- IT0=1; //外部中断0下降沿触发
- IT1=1; //外部中断1下降沿触发
- EX0=1; //外部中断0打开
- EX1=1; //外部中断1打开
- TMOD=0; //定时器工作模式,工作方式0
- TL0=0x18; //定时器赋初值TL0=(8192-5000)%32
- TH0=0x63; //THO=(8192-5000)/32
- ET0=1; //打开T/C0溢出中断
- EA=1; //打开全局中断
- while(1)
- {
- switch(K)
- {
- case 1:modea();break;
- case 2:modeb();break;
- case 3:mode1();break;
- case 4:mode2();break;
- case 5:mode3();break;
- case 6:mode4();break;
- default:mode5();break;
- }
- }
- }
复制代码
所有资料51hei提供下载:
正逆向秒表流水灯.rar
(63.98 KB, 下载次数: 27)
|