在主程序中,先使能全局中断,然后使能74HC245来控制数码管。配置定时器0工作在模式1并设置定时初值1ms,清零TF位,使能定时器0并启动定时器0。按键动作函数keys进行按键消抖。进入中断后,不断扫描按键动作,并在中断中完成队伍比分、倒计时和蜂鸣器的显示。最后while(1)循环中调用按键扫描扫描函数Keys、 600s和24s倒计时, 检测一次按键状态,如果在连续的8次移位检测中按键状态保持不变,则判定为按键已动作,显示相应的数码管动态。主程序流程图如图6所示:
图6 主程序流程图
3.2蜂鸣器子程序设计
在中断子程序中,对蜂鸣器函数进行调用,并判断600s和24s函数中sec是否为0。当十分钟倒计未结束的时候,蜂鸣器不工作,当十分钟倒计时结束的时候,蜂鸣器发出响声。蜂鸣器电路流程图如图6所示:
图7 蜂鸣器电路
3.3按键动作子程序设计
在中断中完成按键扫描并消抖,主程序调用按键动作函数。如果检测到按键1按下,给k赋值1;如果检测到按键2按下,给k赋值2;如果检测到按键3按下,给k赋值3;如果检测到按键4按下,给k赋值4;如果检测到按键5按下,给k赋值5;如果检测到按键6按下,给k赋值6;如果检测到按键7按下,给k赋值7;如果检测到按键8按下,给k赋值8;如果检测到按键9按下,给k赋值9;如果检测到按键10按下,给k赋值10。按键动作函数流程图如图8所示:
图8 按键动作函数流程图
3.4中断子程序设计
中断子程序中,通过定时器T0调用数码管动态刷新函数、矩阵按键扫描函数以及蜂鸣器函数。中断1000次即一秒,当达到一秒时,清零计数值以重新开始下一个一秒计时,同时设置一秒定时器标志为1。定时器中断流程图如图9所示:
单片机源程序如下:
- #include<reg52.h>
-
- sbit ADDR0 = P1^0;
- sbit ADDR1 = P1^1;
- sbit ADDR2 = P1^2;
- sbit ADDR3 = P1^3;
- sbit KEY_OUT_1 = P2^3;
- sbit KEY_OUT_2 = P2^2;
- sbit KEY_OUT_3 = P2^1;
- sbit KEY_OUT_4 = P2^0;
- sbit KEY_IN_1 = P2^4;
- sbit KEY_IN_2 = P2^5;
- sbit KEY_IN_3 = P2^6;
- sbit KEY_IN_4 = P2^7;
- sbit BUZZ = P1^6;
- unsigned char code a[]={
- 0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
- 0x80, 0x90};
- unsigned char ledbuff[12] = {
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
- 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
- };
- unsigned char KeySta[4][4] = {
- {1,1,1,1,},
- {1,1,1,1,},
- {1,1,1,1,},
- {1,1,1,1,}};
- char x,z,k;
- char add1,add2;
- unsigned char flagls = 0;
- unsigned char rst24 = 24;
- int sec = 600;
- char cnt1 = 0;
- char cnt2 = 0;
- unsigned char b[4][4]={
- {1,3,0,9,},
- {2,4,0,0,},
- {5,6,0,10,},
- {7,8,0,0,}};
- //蜂鸣器部分
- void buzz()
- {
- if(sec == 0) BUZZ=0;
- }
-
- //矩阵按键消抖
- void keyx()
- {
- unsigned char i;
- static unsigned char keyout = 0; //矩阵按键扫描输出索引
- static unsigned char keybuf[4][4] = { //矩阵按键扫描缓冲区
- {0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF},
- {0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF}
- };
- //将一行的4个按键值移入缓冲区
- keybuf[keyout][0] = (keybuf[keyout][0] << 1) | KEY_IN_1;
- keybuf[keyout][1] = (keybuf[keyout][1] << 1) | KEY_IN_2;
- keybuf[keyout][2] = (keybuf[keyout][2] << 1) | KEY_IN_3;
- keybuf[keyout][3] = (keybuf[keyout][3] << 1) | KEY_IN_4;
- //消抖后更新按键状态
- for (i=0; i<4; i++) //每行4个按键,所以循环4次
- {
- if ((keybuf[keyout][i] & 0x0F) == 0x00)
- { //连续4次扫描值为0,即4*4ms内都是按下状态时,可认为按键已稳定的按下
- KeySta[keyout][i] = 0;
- }
- else if ((keybuf[keyout][i] & 0x0F) == 0x0F)
- { //连续4次扫描值为1,即4*4ms内都是弹起状态时,可认为按键已稳定的弹起
- KeySta[keyout][i] = 1;
- }
- }
- //执行下一次的扫描输出
- keyout++; //输出索引递增
- keyout = keyout & 0x03; //索引值加到4即归零
- switch (keyout) //根据索引,释放当前输出引脚,拉低下次的输出引脚
- {
- case 0: KEY_OUT_4 = 1; KEY_OUT_1 = 0; break;
- case 1: KEY_OUT_1 = 1; KEY_OUT_2 = 0; break;
- case 2: KEY_OUT_2 = 1; KEY_OUT_3 = 0; break;
- case 3: KEY_OUT_3 = 1; KEY_OUT_4 = 0; break;
- default: break;
- }
- }
- //600s and 24秒暂停
- void s600and24()
- {
-
- static char y;
- y = rst24;
-
- if(cnt2 != 0)
- {
- if(flagls == 1)
- {
- sec--;
- if(cnt1 % 2 == 1)
- {
- flagls = 0;
- }
-
- }
- }
- if(cnt1%2 == 0)
- {
- if(flagls == 1)
- {
- rst24--;
- flagls = 0;
- }
- }
- else
- {
- rst24 = y;
-
- }
- }
- //数码管扫描
- void LED()
- {
- static char n = 0;
- P0 =0XFF;
- ledbuff[0] = a[(sec%60)%10];
- ledbuff[1] = a[(sec%60)/10];
- ledbuff[2] = a[(sec/60)%10] & 0x7F;
- ledbuff[3] = a[(sec/60)/10];
- ledbuff[4] = a[rst24%10];
- ledbuff[5] = a[rst24/10];
- ledbuff[6] = a[add1%10];
- ledbuff[7] = a[add1/10%10];
- ledbuff[8] = a[add1/100%10];
- ledbuff[9] = a[add2%10];
- ledbuff[10] = a[add2/10%10];
- ledbuff[11] = a[add2/100%10];
- switch(n)
- {
- case 0: P3 = 0XFF;ADDR0 = 0;ADDR1 = 1;ADDR2 = 1;ADDR3 = 1; n++;P0 = ledbuff[0];break;
- case 1: P3 = 0XFF;ADDR0 = 1;ADDR1 = 0;ADDR2 = 1;ADDR3 = 1; n++;P0 = ledbuff[1];break;
- case 2: P3 = 0XFF;ADDR0 = 1;ADDR1 = 1;ADDR2 = 0;ADDR3 = 1; n++;P0 = ledbuff[2];break;
- case 3: P3 = 0XFF;ADDR0 = 1;ADDR1 = 1;ADDR2 = 1;ADDR3 = 0; n++;P0 = ledbuff[3];break;
- case 4: P3 = 0XFE;ADDR0 = 1;ADDR1 = 1;ADDR2 = 1;ADDR3 = 1; n++;P0 = ledbuff[4];break;
- case 5: P3 = 0XFD;ADDR0 = 1;ADDR1 = 1;ADDR2 = 1;ADDR3 = 1; n++;P0 = ledbuff[5];break;
- case 6: P3 = 0XFB;ADDR0 = 1;ADDR1 = 1;ADDR2 = 1;ADDR3 = 1; n++;P0 = ledbuff[6];break;
- case 7: P3 = 0XF7;ADDR0 = 1;ADDR1 = 1;ADDR2 = 1;ADDR3 = 1; n++;P0 = ledbuff[7];break;
- case 8: P3 = 0XEF;ADDR0 = 1;ADDR1 = 1;ADDR2 = 1;ADDR3 = 1; n++;P0 = ledbuff[8];break;
- case 9: P3 = 0XDF;ADDR0 = 1;ADDR1 = 1;ADDR2 = 1;ADDR3 = 1; n++;P0 = ledbuff[9];break;
- case 10: P3 = 0XBF;ADDR0 = 1;ADDR1 = 1;ADDR2 = 1;ADDR3 = 1; n++;P0 = ledbuff[10];break;
- case 11: P3 = 0X7F;ADDR0 = 1;ADDR1 = 1;ADDR2 = 1;ADDR3 = 1; n=0;P0 = ledbuff[11];break;
- default: break;
-
-
-
- }
- }
- //矩阵按键动作函数,根据键码进行相关操作
- void keys()
- {
- unsigned char i, j;
- static unsigned char backup [4][4] = {
- {1,1,1,1},{1,1,1,1},{1,1,1,1},{1,1,1,1}
- };
- for(i=0; i<4; i++)
- {
- for(j=0; j<4; j++)
- {
- if(backup[i][j] != KeySta[i][j])
- {
- if(backup[i][j] == 0)
- {
- k = b[i][j] ;
-
- switch(k)
- {
- case 1: add1++;break;
- case 2: add1--;break;
- case 3: add2++;break;
- case 4: add2--;break;
- case 5: rst24=24;break;
- case 6: cnt1++;break;
- case 7: x = add1; add1 = add2; add2 =x;break;
- case 8: cnt2++;break;
- case 9: sec = sec+60; break;
- case 10: sec = sec-60;break;
- default: break;
- }
-
- }
- backup[i][j] = KeySta[i][j];
- }
- }
- }
-
-
- }
- void main()
- {
- EA = 1;
- TMOD = 0X01;
- TH0 = 0XFC;
- TL0 = 0X67;
- ET0 = 1;
- TR0 = 1;
- add1 = add2 = 0;
- while(1)
- {
- keys();
- s600and24();
- }
- }
- //T0中断服务函数
- void InterruptTimer0()interrupt 1
- {
- static int cnt = 0;
- TH0 = 0XFC;
- TL0 = 0X67;
- cnt ++ ;
- keyx();
- LED() ;
- if(cnt >= 1000)
- {
- cnt = 0;
- flagls = 1;
- }
- buzz();
- }
复制代码
所有资料51hei提供下载:
篮球计分计时.rar
(2.34 MB, 下载次数: 35)
|