利用中断与定时器来实现99秒的秒表
按键可以暂停
当然也可以清零 可以参照我上一个帖子自己再给按键加一些功能
仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
单片机源程序如下:
- #include <reg52.h>
- sbit p1=P1^0;
- sbit p2=P1^1;
- sbit k1=P1^7;
- 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 确保启动时都不亮
- 0xc0,0xc0
- };
- char scan[8]={0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe};
- unsigned char i = 0; //动态扫描的索引
- unsigned int cnt = 0;
- bit flag=0;//记录 T0 中断次数
- unsigned long sec = 0; //记录经过的秒数
- void debouncer();
- void main(){
-
- EA = 1; //使能总中断
- TMOD = 0x01; //设置 T0 为模式 1
- TH0 = 0xFC; //为 T0 赋初值 0xFC67,定时 1ms
- TL0 = 0x18;
- ET0 = 1; //使能 T0 中断
- TR0 = 0;
- ET1=1;
- TR1=0;
- TH1=0xfc;
- TL1=0x18;
- k1=1; //启动 T0
- while (1){
-
- if(k1==0&&flag==0){ //按键按下不放 开始计时 松开立即停止计时,示数定在当前计数数值
- debouncer();
- TR0=1; //打开定时器中断0
- TR1=1; //打开定时器中断1
- flag=1;
- while(k1==0); /*这两句防止在 按键按下的短时间内程序跑飞到下一个if语句*/
- debouncer();
-
- }
-
- if(k1==0&&flag==1){ //此时 k1==0,可以实现第二次功能 若k1==1即为按键松开产生动作
- debouncer();
- TR1=0; //关闭定时器中断1 使得程序停止在当前时刻
- flag=0;
- while(k1==0);
- debouncer();
- }
-
-
-
- }
- }
- /* 定时器 0 中断服务函数 控制位 并显示对应数值 */
- void InterruptTimer0() interrupt 1{
- TH0 = 0xFC; //重新加载初值
- TL0 = 0x18;
- cnt++; //中断次数计数值加 1
-
- //以下代码完成数码管动态扫描刷新
- P2 = 0xFF;
- //显示消隐
- switch (i){
- case 0: p2=1;p1=0; i++; P2=LedBuff[0]; break; //打开个位,关闭其他位,并给P2端口赋个位相应数值断码
- case 1: p1=1;p2=0; i=0; P2=LedBuff[1]; break; //打开十位,关闭其他位,并给P2端口赋十位相应数值断码
- default: break;
- }
- }
- void InterruptTimer1() interrupt 3{ /* 定时器 1 中断服务函数 控制段并 将要显示的数值断码 赋值到数组中等待调用 */
- TH1=0xc0;
- TL1=0x18;
- if (cnt >=800){ //判断 T0 溢出是否达到 1000 次 此处理论上写1000,但是实际写800是因为为了消除计时误差 800这个数
- cnt = 0; //达到 1000 次后计数值清零
- sec++; //秒计数自加 1
- if(sec>99)sec=0;
- //以下代码将 sec 按十进制位从低到高依次提取并转为数码管显示字符
- LedBuff[0] = LedChar[sec%10];
- LedBuff[1] = LedChar[sec/10];
-
- }
- }
- void debouncer(){ //延时20ms按键消抖
- int i;
- for(i=0;i<2400;i++);
- }
复制代码
所有资料51hei提供下载:
中断与数码管动态扫描.rar
(15.26 KB, 下载次数: 24)
|