// 本实验采用c语言实现了数字钟实验,主要功能包括 用户设置时,分 // 考虑到键盘不多以及结构问题,本程序并没有实现一些复杂的功能。 // 采用模块化设计,用户要增加自己的功能也非常方便。 // 参见主程序的模块组织结构 // 在HJPC51-B上验证通过 #include "mcs51\8051.h" #define uchar unsigned char #define uint unsigned int #define key1 P3_3 //键盘定义 #define key2 P3_4 #define key3 P3_5 #define segdata P0 //数据 输出 #define sege P2_7 //显示 选中 #define segb P2_6 //位 选 #define segd P2_5 //段 选 uchar flag; //键盘模式,=1增加,=0减少 // 这里定义了一组显示码表。前面的code 关键字表示,这组码表定义 // 在程序存储器区域,而不是采用数据存储器来定义; // 在一般做这种固定数组时,都应该把他们放置在程序存储区。 uchar code disbuf_u[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8, 0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e, 0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78, 0x00,0x10,0x08,0x03,0x46,0x21,0x06,0x0e};
uchar led_buf[6]; //段 uchar timead,t_s,t_m,t_h; //基准时间,秒,分,时 void reset(); //上电复位模块 void delay(uint ysz);//模糊延时 void led_buf_flush(void);//缓冲 void disp(void);//显示 void off_led(void);//关显示 void display(unsigned char disseg,unsigned char disdata);//显示输出 uchar keyb(); //键盘程序 void settimer(); void main() { SP=0x50; //设置堆栈 reset(); while(1) { led_buf_flush(); disp(); off_led(); settimer(); } }
void reset() { TMOD = 0x1; //定时器T0模式1 TL0 = 0x0cf;//定时初值 TH0 = 0x3c; TR0 = 1; //开始运行 ET0 = 1; //允许定时器T0中断 EA = 1; //总的中断允许 t_m = 0; t_s = 0; t_h = 0; flag = 1; //键盘模式 P3_7 = 0; //关闭蜂鸣器 P0 = 0; //关闭数码管显示 P2 = 255; }
//中断 void time0() interrupt 1 using 1 { TR0 = 0; TL0=0x0cf; TH0=0x3c; timead+=1; if(timead==20) //12M==50ms延时,6M=100ms延时 { timead=0; t_s += 1; //1s到了,把秒单元加1
P1_0=!P1_0; //同时闪烁p1.0/1两个灯 P1_1=!P1_1;
if(t_s==60) //一些进位的判断 { t_s = 0,t_m ++; if(t_m ==60) t_m =0,t_h ++; if(t_h == 24) t_h = 0; }
} TR0 = 1; //开始计数,由于前面一些函数也需要占用时间 //因此,需要在定时初值中减去这段时间的延时常数 } //延时 void delay(uint ysz) { while(ysz--){}; } //设置时间 void settimer() { switch(keyb()) { case 3:{ if(flag) {if(t_h != 23) t_h ++;} //设置时 else {if(t_h !=0 ) t_h --;} break;}
case 2:{if(flag) {if(t_m != 59) t_m ++;} //设置分 else {if(t_m !=0 ) t_m --;} break;} case 1:{if(flag) flag = 0; //设置模式切换 else flag = 1; break;} } } //显示缓冲区 void led_buf_flush(void) { led_buf[0]=t_s%10; led_buf[1]=t_s/10; led_buf[2]=t_m%10; led_buf[3]=t_m/10; led_buf[4]=t_h%10; led_buf[5]=t_h/10; } //显示刷新子程序 void disp() { uchar i; for(i=0;i<6;i++) { display(i,led_buf); //调用输出显示
} } //显示 //这里是显示子程序,入口参数为 // disseg -> 位选 可选范围 0-7 一共8个数码管 // disdata -> 段选 可选范围 0-31 一个32个字符 // 段选 0-15 16个字符 为 "0"->"F" // 段选 16-31 16个字符 为 "0."->"F." void display(unsigned char disseg,unsigned char disdata) { unsigned char dataf; dataf = 1; while(disseg) { dataf <<= 1; disseg--; } sege = 0; segdata = dataf; //这里首先把要显示的数据放到数据总线 segb = 1; //这里给出一个脉冲,数据送往位选端 segb = 0;
segdata = disbuf_u[disdata]; segd = 1; //这里给出一个脉冲,数据送往段选端 segd = 0; delay(50); } //关显示 void off_led(void) { segdata = 255; segd = 1; //这里给出一个脉冲,数据送往段选端 segd = 0; } uchar keyb() { uchar key,keytmp; key1 = 1; //将输出线拉高 key2 = 1; key3 = 1; key = P3 ; //读回来 key = key & 0x38; //获得键盘结果 if(key == 56 ) return 0; //如果用户没有按键返回 0 else { keytmp = key; delay(1000); //判断是不是干扰 key = P3; key = key & 0x38; if (key != keytmp ) return 0; //是干扰,返回 0 else //不是干扰,等待用户释放按键 { do{ key1 = 1; //输出拉高 key2 = 1; key3 = 1; key = P3 & 0x38; //读回来 }while(key != 56 ); //等待用户释放 P1_2 = 1; //用户释放以后,清除p1.0指示灯 switch(keytmp) { case 24: return 3;//返回用户按键结果 case 40: return 2; case 48: return 1; }
}
}
return 0;
}
|