电路原理图如下:
- #include <reg52.h>
- #define uchar unsigned char //为宏定义,把unsigned char用uchar表示,方便书写
- #define uint unsigned int //为宏定义,把unsigned int用uint表示,方便书写
- void display(); //显示函数声明
- uchar code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40}; //0~9,-共阴极段码表数码管段选编码
- char hour =23, min =59, sec=55; //定义全局变量时分秒并赋值
- sbit addr_A=P2^0; //定义addr_A为P2口的第一位
- sbit addr_B=P2^1; //定义addr_B为P2口的第二位
- sbit addr_C=P2^2; //定义addr_C为P2口的第三位
- sbit P10 = P1^0; //定义P10为P1口的第一位
- sbit P11 = P1^1; //定义P11为P1口的第二位
- sbit P12 = P1^2; //定义P12为P1口的第三位
- sbit P13 = P1^3; //定义P13为P1口的第四位
- uchar mode = 0; //0, 1, 2, 3分别表示正常计时、调时、调分、调秒模式
- uchar flash = 0xff; //定义全局变量flash并赋值
- void delay(uint i) { //延时函数的声明
- while(i--);
- }
- void initT0() { //初始化定时器函数声明
- TMOD = 0x01; //计数器工作在方式一,16位计数器
- TH0 = (65536-50000)/256; //给定时器0装初值,12MHZ晶振定时时间为50ms
- TL0 = (65536-50000)%256;
- EA =1; //开总中断
- ET0 =1; //开定时器0分开关
- TR0 =1; //启动定时器
- }
- void keyScan() { //键盘扫描函数
- static bit oldState = 1; //定义静态局部变量,保存按键的旧状态,1表示按键弹起,0表示按键已按下
- if(!(P10&P11&P12&P13)) { //判断是否可能有键按下
- delay(1000); //延时消抖
- if(!(P10&P11&P12&P13)) { //再次确认当前是否有键按下,且之前没有键按下
- if(oldState) {
- oldState = 0; //将旧键状态更新为已按下
- if(!P10) { //判断按键P10是否按下
- mode++; //按下,mode模式加一
- if(mode>3) mode = 0; //判断mode模式是否超出边界,超出清零
- }
- else if(!P11) //判断按键P11是否按下
- switch(mode) { //多分支选择语句
- case 1:hour++;if(hour>23) hour = 0;break; //1模式下,小时加一;判断小时是否超出边界,超出清零;退出switch语句
- case 2:min++;if(min>59) min = 0;break; //2模式下,分钟加一;判断分钟是否超出边界,超出清零;退出switch语句
- case 3:sec++;if(sec>59) sec = 0;break; //3模式下,秒加一;判断秒是否超出边界,超出清零;退出switch语句
- }
- else if(!P12){ //判断按键P12是否按下
- switch(mode) {
- case 1:hour--;if(hour<0) hour = 23;break; //1模式下,小时减一;判断小时是否小于零,小于零给小时赋值23;退出switch语句
- case 2:min--;if(min<0) min = 59;break; //2模式下,分钟减一;判断分钟是否小于零,小于零给分钟赋值59;退出switch语句
- case 3:sec--;if(sec<0) sec = 59;break; //3模式下,秒减一;判断秒是否小于零,小于零给秒赋值59;退出switch语句
- }
- //else //关闭闹钟
- }
- }
- }
- }
- else if(!oldState) oldState = 1; //检测按键是否弹起
- }
- void main() { //主函数
- initT0(); //定时函数
- while(1){ //死循环
- keyScan(); //键盘扫描函数
- display(); //显示函数
- }
- }
- void INT_T0() interrupt 1 //中断服务程序,其中1是定时器0入口序号
- {
- static uchar counter = 0, counter_1=0; //定义静态局部变量
- TR0 = 0; //关闭定时器
- TH0 = (65536-50000)/256; //给定时器0装初值,12MHZ晶振定时时间为50ms
- TL0 = (65536-50000)%256;
- TR0 = 1; //启动定时器
- counter++; //counter加一
- counter_1++; //counter_1加一
- if(counter_1==10) { //counter_1经过0.5秒
- counter_1 = 0; //counter_1清零
- flash = ~flash; //全局变量flash按位取反
- }
- if(counter==20) { //counter经过1秒
- counter = 0; //counter清零
- if(mode==0) sec++; //判断模式mode是否在0模式,是,秒加一
- }
- if(sec>=60) { //判断秒是否大于等于60
- sec = 0; //秒清零
- min++; //分加一
- }
- if(min>=60) { //判断分钟是否大于等于60
- min = 0; //分清零
- hour++; //小时加一
- }
- if(hour>=24) { //判断小时是否大于等于24
- hour = 0; //给小时赋0
- }
- }
- void display() { //显示函数
- uchar LED[8], i; //定义数组LED,局部变量i
- LED[0] = hour/10; //给数组的第一位赋值,为小时数值十位上的数
- LED[1] = hour%10; //给数组的第二位赋值,为小时数值个位上的数
- LED[2] = 10; //给数组的第三位赋值10
- LED[3] = min/10; //给数组的第四位赋值,为分钟数值十位上的数
- LED[4] = min%10; //给数组的第五位赋值,为分钟数值个位上的数
- LED[5] = 10; //给数组的第六位赋值10
- LED[6] = sec/10; //给数组的第七位赋值,为秒钟数值十位上的数
- LED[7] = sec%10; //给数组的第八位赋值,为秒钟数值个位上的数
-
- for(i=0;i<8;i++) { //FOR循环,数码管的位选
- addr_C = i/4; //最高位
- addr_B = i/2%2; //第二位
- addr_A = i%2; //最低位
- if(i==(mode-1)*3 || i==(mode-1)*3+1) P0=table[LED[i]] & flash;
- //mode 0 1 2 3 当模式mode和i满足关系
- //i 01 34 67 i == (mode-1)*3时
- //i == (mode-1)*3 数码管闪烁
- else P0 = table[LED[i]]; //不满足上述关系时,输出数码管的段选编码
- delay(200); //数码管延时
- P0 = 0X00; //数码管消隐
- }
- }
-
复制代码
|