电子时钟程序代码
- 格式:doc
- 大小:42.50 KB
- 文档页数:10
实验名称:SUMA & BUZZER实验描述:一个带有闹钟的数码时钟,加三个键,一个调小时键一个调分钟键,一个设置闹钟时间键实验方法:TIMER0中断用来计时,控制数码时钟的时间显示还可设置半秒或四分之一秒,用来控制音调TIMER1用来控制音普,,timer0用MODE2自动加载模式*/# include<reg52.h>sbit speaker=P2^3 ;sbit AA=P2^2 ; //调时用sbit BB=P2^1 ; //调分用sbit CC=P2^0 ; // 设置闹钟用sbit P1_7=P1^7; //小数点// int code seven_reg[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90};//0123456789int code seven_reg[]={0x40,0x79,0x24,0x30,0x19,0x12,0x2,0x78,0x00,0x10};// int code scan[]={0x1F,0x2F,0x4F,0x8F}; //1110,1101,1011,0111int code scan[]={0x1,0x2,0x4,0x8}; //0001,0010,0100,1000unsigned int timer0_times;unsigned int timer1_times;unsigned int timer0_times_AA; //按纽AA用unsigned int timer0_times_BB; //按纽BB用unsigned int timer0_times_CC; // 半秒计时用unsigned int timer0_times_DD; //四分之一秒用unsigned int timer0_times_EE; // 闹钟用typedef struct{unsigned char second;unsigned char minute;unsigned char hour;unsigned char half_second;unsigned char alarm_hour;unsigned char alarm_minute;unsigned char quarter_second ;} time; //此处是固定格式,不能改time now;char mode=0;int i=0,j=0,k=0;int code tone[]={1012,956,852,759,716,638,568,506,478,426,379};//7()低音)1234567(中音)123(高音)int code song[22][2]={ {6,2},{6,2},{7,4},{6,2},{6,2}, {7,4},{6,2},{7,2},{8,2},{7,2},{6,2},{7,1},{6,1},{4,4},{3,2},{1,2},{3,2},{4,2},{3,2},{3,1},{1,1},{0,4}} ;/********************************************************************/void timer1_isr() interrupt TF1_VECTOR using 2{ TR1=0;TL1=(65536-tone[(song[j][0])])%256;TH1=(65536-tone[(song[j][0])])/256;TR1=1;speaker=~speaker;}/*******************************************************************/void timer0_isr() interrupt TF0_VECTOR using 1{/***************************************************/if(CC!=0) timer0_times_EE=0;else{ timer0_times_EE++;if(CC==0&&timer0_times_EE==4000) //按1S进入设置闹钟模式{mode++;//500 ~0.125sif(mode==2) mode=0;}}/**=调时键设置=*/if(AA!=0) timer0_times_AA=0;else{ timer0_times_AA++;if(AA==0&&timer0_times_AA==500&&mode==0)//500*0.25ms=0.125s{ now.hour++;// timer0_times_AA=0;if (now.hour==24) now.hour=0;//后边代码不会达到此效果}if(AA==0&timer0_times_AA==500&&mode==1) //设置闹钟时间HOUR{ now.alarm_hour++;if(now.alarm_hour==24) now.alarm_hour=0;}}/***=调分键设置=***/if (BB!=0) timer0_times_BB=0;else{ timer0_times_BB++;if(BB==0&&timer0_times_BB==500&&mode==0) //0.125s{ //timer0_times_BB=0;now.minute++;if(now.minute==60) now.minute=0;}if(BB==0&&mode==0){ if(timer0_times_BB==2000) //0.5s{ now.minute++;timer0_times_BB=1000;if(now.minute==60) now.minute=0;}}if(BB==0&&timer0_times_BB==500&&mode==1) //设置闹钟时间MINUTE { now.alarm_minute++;if(now.alarm_minute==60) now.alarm_minute=0;}if(BB==0&&mode==1){ if(timer0_times_BB==2000) //0.5s{ now.alarm_minute++;timer0_times_BB=1000;if(now.minute==60) now.minute=0;}}}/*=自然时间设置=*/timer0_times_DD++; //四分之一秒if(timer0_times_DD==1000){ now.quarter_second++;timer0_times_DD=0;if(now.quarter_second==60) now.quarter_second=0;} //二分之timer0_times_CC++;if(timer0_times_CC==2000){now.half_second++;timer0_times_CC=0;if(now.half_second==60) now.half_second=0;}timer0_times++; //一秒一分一时if (timer0_times==4000){ now.second++;timer0_times=0;if(now.second==60){ now.minute++;now.second=0;if(now.minute==60){ now.hour++;now.minute=0;if(now.hour==24) now.hour=0;} } }/******************扫描显示******************************/switch(mode){case 0 :{switch(i){ /*0.005秒选一次*/ case 0:P1=seven_reg[now.minute%10] ;if(now.half_second%2==0)P1_7=1; /*实现让它0.5秒闪一次*/break;case 1:P1=seven_reg[now.minute/10];//小数点不亮同,P1_7=1if(now.half_second%2==0)P1_7=1; /*为什么不能放在上一句前面昵????*/ break;case 2:P1=seven_reg[now.hour %10];break;case 3:P1=seven_reg[now.hour /10];break;}} break;case 1:{switch(i){case 0:P1=seven_reg[now.alarm_minute%10] ;break;case 1:P1=seven_reg[now.alarm_minute/10];break;case 2: P1=seven_reg[now.alarm_hour %10];break;case 3: P1=seven_reg[now.alarm_hour /10];break; }} break;}P3=scan[i];i++;if (i==4) i=0;if(now.quarter_second%2==0){ k++;if(k==(song[j][1]*4)){ j++;k=0;if(j==22) j=0;} } }/****************************************************************/void timer0_initialize(){ EA=0;TR0=0;TMOD=0X12;TL0=(256-250); //0.025ms 自动加载模式0.025*4000=1sTH0=(256-250);ET0=1;TR0=1;EA=1;}void timer1_initialize(){TR1=0;TL1=(65536-tone[song[j][0]])%256;TH1=(65536-tone[song[j][0]])/256;TMOD=0X12;ET1=1;}main(){ unsigned char m1=0;speaker=0;now.alarm_minute=1;timer0_initialize();timer1_initialize();while(1){if(now.alarm_minute!=0)//将闹钟设置为0时,相当于取消闹钟,不会响{ if(now.hour==now.alarm_hour&&now.minute==now.alarm_minute) { if(CC==0&&timer0_times_EE==500) m1=1;switch (m1){ case 0:TR1=1 ;break;case 1 :TR1=0;speaker=0;break;}}else{TR1=0;speaker=0;m1=0;} } } }#include<reg52.h>sbit P10=P1^0; //第0位数码管sbit P11=P1^1;sbit P12=P1^2;sbit P13=P1^3;#define THCO 0xee#define THLO 0x00unsigned char miao=0,fen=0,shi=0;unsigned char code duan[]={0x3F, 0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F}; main(void){TMOD=0x11;TH0=THCO;TL0=THLO;EA=1;ET0=1;TR0=1;while(1);}void timw0() interrupt 1{static unsigned char c=0,k=0;TH0=THCO;TL0=THLO;P1|=0xff;c++;if(c>200) {miao++;if(miao>=60){miao=0;fen++;}if(fen>=60){shi++;fen=0;}c=0;}if(k>3){k=0;}k++;switch(k-1){case(0):P10=0;P0=duan[shi/10];break;case(1):P11=0;P0=duan[shi%10];break;case(2):P12=0;P0=duan[fen/10];break;case(3):P13=0;P0=duan[fen%10];break;}}这是时钟程序,可以运行,无小数点,显示时分,小数点断码是0x80,其余的只有靠你自己了。
单片机时钟程序设计代码好的,由于你没有给出具体的单片机型号,下面是一个基于 51 单片机的时钟程序设计示例:```c#include <reg52.h>#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>// 定义变量char str[20];int i=0;int j=0;int k=0;int time=0;int flag=0;int h=0,m=0,s=0;void delay(int xms){int i,j;for(i=xms;i>0;i--)for(j=110;j>0;j--);}void time0() interrupt 1{TH0=(65536-50000)/256;TL0=(65536-50000)%256;time++;if(time==20){time=0;s++;if(s==60){s=0;m++;if(m==60){m=0;h++;}}}// 将时间数据转换为字符串sprintf(str," %02d:%02d:%02d",h,m,s);// 输出时间字符串for(i=0;i<16;i++){P0=str[i];delay(1000);}}void main(){// 初始化定时器 0 为 16 位定时器模式,计数初值为 50000 TMOD=0x01;TH0=(65536-50000)/256;TL0=(65536-50000)%256;EA=1;ET0=1;TR0=1;while(1);}```该程序利用 51 单片机的定时器 0 来产生定时中断,每 20 次中断为 1 秒,通过对秒、分、时的累计来实现时钟功能。
在中断服务函数中,将当前时间转换为字符串,并通过循环输出到 P0 口。
// 本程序实现功能:显示小时和分钟,并以最后一位的小数点闪烁一次表示一秒。
按下INT0键后显示日期。
并在所设定的时间蜂铃器响5次以此为闹钟;// 第二:按下INT1键后,可对时间,日期,闹钟进行设置,再次按下INT1推出设置//// 显示说明:前两位显示小时和月份,后两位显示分钟和日期//#include <reg52.h>/*==========================================宏定义uchar和uint===========================================*/#define uchar unsigned char#define uint unsigned intsbit alarm=P1^4;/*==============================================变量的定义==============================================*/int year=2010;/*初始年份为2010年*/uchar alarm_hour=0,alarm_min=0; /*初始闹钟时间为00:00*/uchar qian=0,bai=0,shi=0,ge=0,key_flag=0,Key=0,num=0,Flag=0; /*定义输出函数变量和按键号*/uchar x,dis_flag=0; /*显示变换标志位*/uchar Key_control=0; /*按键被按下的标志位*/uchar mounth=7,day=25; /*初始日期设为7月25号*/uchar hour=0,t=0,min=0,sec=0,ring=0;/*初始时间为00:00:00*//*=============================================子函数的定义=============================================*/void Init(); /*此函数用于初始化所有需要使用的中断*/void delay(uint z); /*用于数码管显示*/uchar Key_num(void); /*此函数为确定按下的按键输出编号*/void Led_display();void display(uchar cc, uchar dd); /*显示时间的函数,中间的点表示:*/void display_nian(uchar cc, uchar dd); /*显示年份的显示函数,即没有中间的点*/void display_date(uchar cc, uchar dd); /*显示日期的函数,即四个小数点全亮*/void display_alarm(uchar cc, uchar dd); /*显示闹钟的函数,第二个和第四个点*/void Leap_Nonleap(int aa); /*判断是闰年还是平年,并将二月的最大天数赋给Mounth_array[1]*/void Judge_Setting(uchar Key_set); /*所得出的按键号进行对应的设置*//*==========================================所使用数组的定义============================================*/uchar Mounth_array[12]={31,29,31,30,31,30,31,31,30,31,30,31}; /*每个月的最大天数数组*/uchar code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,/*数码管显示编码*/};uchar code table1[]={0xbf,0x86,0xdb,0xcf,0xe6,0xed,0xfd,0x87,0xff,0xef};/*百位及其小数点的段码*//*==============================================主函数部分==============================================*/void main(){Init();while(1){Leap_Nonleap(year); /*进入大循环后首先对年份进行判断*/while(Key_control)/*当P3.3被按下后Key_control=1进入函数进行设置,直到第二次Key_control=0推出循环*/{Flag=Key_num(); /*将按键函数里面是否有按键被按下的标志位赋给Flag*/if(Flag) /*当有按键被按下时,进入设置函数*/{Judge_Setting(num); /*将num值传入函数,并进行设置*/}Led_display(); /*保证在设置的循环时有显示*/}Led_display();/*循环式动态显示*/}}/*===========================================系统初始化函数=============================================*/void Init() /*初始化系统,启动计时器0,1,外部中断0,1*/{TMOD=0x01; /*将计时器0定位工作方式1,将计时器1定为工作方式2*/TH0=(65536-50000)/256;TL0=(65536-50000)%256;ET0=1;TR0=1;// ET1=1;// TR1=1;IE0=1;EX0=1; /*使用外部中断0和1,分别作为显示变换,设置的前戏*/IT0=1;/*为下降沿突发*/IE1=1;EX1=1;IT1=1;/*为下降沿突发*/EA=1;}void Display_flag() interrupt 0 /*使用外部中断0,进行显示时间和日期的转换P3.2口切换显示*/{dis_flag++;if(dis_flag==4) /*当dis_flag=0时,输出时间,当dis_flag=1时,输出日期,当dis_flag=2时,输出闹钟*/dis_flag=0; /*当dis_flag=3时,输出年份。
LED数字显示电子时钟源程序代码程序:(注已完全经过调试,达到预期目的)#include<reg51.h>#define uchar unsigned char#define uint unsigned intuchar count=0;sbit LED=P1^0;uchar tab[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; //显示数码管0,1,3,4,5,6,7,8,9 uchar miao=0,fen=0,hour=0;void delay(uint i) //延迟函数{uint j;for(;i>0;i--)for(j=124;j>0;j--);}void init(){ET0=1;TMOD=0x51; //选定定时器0,1和中断0,1TH0=(65536-25000)/256;TL0=(65536-25000)%256; //设定时器0时间为250ms一次ET1=1;TH1=0xff;TL1=0xff; //定时器1为中断EX0=1;IT0=1; //中断0开EX1=1;IT1=1; //中断1开TR0=1; //定时器0开TR1=1; //定时器1开EA=1; //总中断开}void display() //时钟显示函数{P0=tab[hour/10%10];P2=0xfe;delay(1);P0=tab[hour%10];P2=0xfd;delay(1);P0=tab[fen/10%10];P2=0xfb;delay(1);P0=tab[fen%10];P2=0xf7;delay(1);P0=tab[miao/10%10];P2=0xef;delay(1);P0=tab[miao%10];P2=0xdf;delay(1);}void main() //主函数{init();LED=0;while(1){display();}}void T0_int() interrupt 1 //定时器0函数{TH0=(65536-25000)/256;TL0=(65536-25000)%256;count++;if(count==20){count=0;miao= miao +1;LED=~LED;if(sec==60){miao=0;fen= fen +1;if(fen ==60){fen =0;hour=hour+1;if(hour==24)hour=0;}}}}void T1_int() interrupt 3 //定时器1函数控制秒针加1 {TH1=0xff;TL1=0xff;miao=miao+1;if(miao ==60)miao =0;}void I1_int() interrupt 2 //中断1函数控制按键分针加1 {EX0=0;fen= fen +1;if(fen ==60)fen =0;EX0=1;}void I0_int() interrupt 0 //中断函数0控制按键时针加1 {EX1=0;hour=hour+1;if(hour==24)hour=0;EX1=1;}。
实验目的:实现时钟显示,1——12——1——11——0——1循环,时钟调时,闹铃,闹铃定时等功能。
程序和注释:<code1.vhd>LIBRARY ieee;USE ieee.std_logic_1164.ALL;USE ieee.std_logic_unsigned.ALL;entity code1 isport (clk : in std_logic;reset : in std_logic;shi_key : in std_logic;fen_key : in std_logic;set_mode_key:in std_logic;en:out std_logic_vector(7 downto 0);y :out std_logic_vector(7 downto 0);beep_s:out std_logic);end code1 ;ARCHITECTURE code2 of code1 issignal a:integer:=0; --ji shisignal d:integer:=0; --xian shisignal b,b0,b1,b3,b4,b5,b6:std_logic:='1';signal e:std_logic:='0';--xian shisignal c:integer:=9; --miao geweisignal ch:integer:=5; --miao shiweisignal eight,eight1:integer:=0; --8 ge shu ma guansignal fg:integer:=9; --fen ge weisignal fs:integer:=5; --fen shi weisignal sg:integer:=1; --shi ge weisignal ss:integer:=1; --shi shi weisignal p:std_logic:='0';--zantingsignal set_mode :std_logic_vector(1 downto 0);signal beep_m1,beep_m2,beep_h1,beep_h2:integer:=1;signal AM_PM:std_logic:='0';signal beep_count:integer:=0;signal beep_clk: std_logic:='1';signal c1,c2,c3,c4,c5,c6:integer:=0;component set0port ( set_clk:in std_logic;m_key:in std_logic;h_key:in std_logic;mode_key:in std_logic;mode:out std_logic_vector(1 downto 0);set_out_m:out std_logic;set_out_h:out std_logic;beep_key_m:out std_logic;beep_key_h:out std_logic);end component;beginprocess(clk)beginif clk'event and clk='1' thend<=d+1;beep_count<=beep_count+1;if set_mode="01" thenb0<=b3;b1<=b4;elsea<=a+1;if a=30000000 then b<=not b;b1<=not b1;b0<=not b0;a<=0;end if;end if;if beep_count=15000000 thenbeep_clk<=not beep_clk;beep_count<=0;-- if beep_count=35000000 then beep_clk<=not beep_clk;beep_count<=0;end if;end if;if d=5000 then e<=not e;d<=0;end if;end if;end process;process(e)--variable c1,c2,c3,c4,c5,c6:integer:=0;beginif e'event and e='1' thenif set_mode="00"or set_mode="01" thenc1<=c;c2<=ch;c3<=fg;c4<=fs;c5<=sg;c6<=ss;end if;if set_mode="10" thenc1<=0;c2<=0;c3<=beep_m1;c4<=beep_m2;c5<=beep_h1;c6<=beep_h2;--c3<=3;--c4<=2;--c5<=5;--c6<=0;end if;case eight iswhen 0 =>en<="11111110";case c1 iswhen 0 => y<="11000000"; when 1 => y<="11111001"; when 2 => y<="10100100"; when 3 => y<="10110000"; when 4 => y<="10011001"; when 5 => y<="10010010"; when 6 => y<="10000010"; when 7 => y<="11111000"; when 8 => y<="10000000"; when 9 => y<="10010000"; when others =>y<="11000000"; end case;eight<=1;when 1 =>en<="11111101";case c2 iswhen 0 => y<="11000000"; when 1 => y<="11111001"; when 2 => y<="10100100";when 3 => y<="10110000"; when 4 => y<="10011001"; when 5 => y<="10010010"; when others =>y<="11000000"; end case;eight<=2;when 2 =>en<="11111011";y<="10111111";eight<=3;when 3 =>en<="11110111";case c3 iswhen 0 => y<="11000000"; when 1 => y<="11111001"; when 2 => y<="10100100"; when 3 => y<="10110000"; when 4 => y<="10011001"; when 5 => y<="10010010"; when 6 => y<="10000010"; when 7 => y<="11111000"; when 8 => y<="10000000"; when 9 => y<="10010000"; when others =>y<="11000000"; end case;eight<=4;when 4 =>en<="11101111";case c4 iswhen 0 => y<="11000000"; when 1 => y<="11111001"; when 2 => y<="10100100"; when 3 => y<="10110000"; when 4 => y<="10011001"; when 5 => y<="10010010"; when others =>y<="11000000"; end case;eight<=5;when 5 =>en<="11011111";y<="10111111";eight<=6;when 6 =>en<="10111111";case c5 iswhen 0 => y<="11000000"; when 1 => y<="11111001"; when 2 => y<="10100100"; when 3 => y<="10110000"; when 4 => y<="10011001"; when 5 => y<="10010010"; when 6 => y<="10000010"; when 7 => y<="11111000"; when 8 => y<="10000000"; when 9 => y<="10010000"; when others =>y<="11000000"; end case;eight<=7;when 7 =>en<="01111111";case c6 iswhen 0 => y<="11000000"; when 1 => y<="11111001"; when others =>y<="11000000"; end case;eight<=0;when others => eight<=0;end case;end if ;end process;miao:process(b,reset)beginif reset='0' thenc<=0;ch<=0;elseif b'event and b='0' thenif c=9 thenc<=0;elsec<=c+1;end if;if ch=5 and c=9 thench<=0;elseif c=9 thench<=ch+1;end if;end if;end if;end if;end process;fen:process(b0,reset,ch,c,b3)beginif reset='0' thenfg<=0;fs<=0;elseif b0'event and b0='0' thenif (((ch=5)and(c=9)) or (set_mode="01" and b3='0'))then if fg=9 thenfg<=0;elsefg<=fg+1;end if;if fs=5 and fg=9 thenfs<=0;elseif fg=9 thenfs<=fs+1;end if;end if;end if;end if;end if;end process;shi:process(b1,reset,fg,fs,ch,c,b4)beginif reset='0' thensg<=0;ss<=0;elseif b1'event and b1='0' thenif ((c=9) and (ch=5) and (fg=9) and (fs=5))or (set_mode="01" and b4='0') then--if ((ss=1 and sg=1) or sg=9) then-- sg<=0;--else-- sg<=sg+1;--end if;if sg=9 thensg<=0;elsesg<=sg+1;end if;if (ss=1 and sg=1 and AM_PM='0')thenss<=0;sg<=0;AM_PM<=not AM_PM;elseif sg=9 thenss<=ss+1;end if;end if;if (ss=1 and sg=2 and AM_PM='1')thenss<=0;sg<=1;AM_PM<=not AM_PM;elseif sg=9 thenss<=ss+1;end if;end if;end if;end if;end if;end process;set_time:set0 port map( set_clk=>clk,m_key=>fen_key,h_key=>shi_key,mode_key=>set_mode_key,mode=>set_mode,set_out_m=>b3,set_out_h=>b4,beep_key_m=>b5,beep_key_h=>b6);beep_set_fen:process(set_mode_key,b5)beginif b5'event and b5='0' thenif set_mode="10" thenif b5='0' thenif beep_m1=9 thenbeep_m1<=0;elsebeep_m1<=beep_m1+1;end if;if beep_m2=5 and beep_m1=9 thenbeep_m2<=0;elseif beep_m1=9 thenbeep_m2<=beep_m2+1;end if;end if;end if;end if;end if;end process;beep_set_shi:process(set_mode_key,b6)beginif b6'event and b6='0' thenif set_mode="10" thenif b6='0' thenif ((beep_h2=1 and beep_h1=1) or beep_h1=9) thenbeep_h1<=0;elsebeep_h1<=beep_h1+1;end if;if beep_h2=1 and beep_h1=1 thenbeep_h2<=0;elseif beep_h1=9 thenbeep_h2<=beep_h2+1;end if;end if;end if;end if;end if;end process;beep:process(e)beginif e'event and e='1' thenif beep_m1=fg thenif beep_m2=fs thenif beep_h1=sg thenif beep_h2=ss thenbeep_s<=beep_clk;end if;end if;end if;elsebeep_s<='1';end if;end if;end process;end code2;<set0.vhd>LIBRARY ieee;USE ieee.std_logic_1164.ALL;USE ieee.std_logic_unsigned.ALL;entity set0 isport ( set_clk:in std_logic;m_key:in std_logic;h_key:in std_logic;mode_key:in std_logic;mode:out std_logic_vector(1 downto 0);set_out_m:out std_logic;set_out_h:out std_logic;beep_key_m:out std_logic;beep_key_h:out std_logic);end set0;ARCHITECTURE set1 of set0 issignal s1:std_logic_vector (1 downto 0);beginprocess(mode_key) --模式设定beginif mode_key'event and mode_key='1' thens1<=s1+'1';mode<=s1;if s1="10" thens1<="00";end if;end if;end process;process(m_key,set_clk) --传递调时按键信号beginif set_clk'event and set_clk='1' then-- if s1="01" thenset_out_m<=m_key;-- else-- set_out_m<='1';-- end if;-- if s1="10" thenbeep_key_m<=m_key;-- else-- set_out_m<='1';-- end if;end if;end process;process(h_key,set_clk) --传递调时按键信号beginif set_clk'event and set_clk='1' then-- if s1="01" thenset_out_h<=h_key;-- else-- set_out_h<='1';-- end if;-- if s1="10" thenbeep_key_h<=h_key; -- else-- beep_key_h<='1';-- end if;end if;end process;end set1;引脚:clk input PIN_31en[7] output PIN_226 en[6] output PIN_230 en[5] output PIN_231 en[4] output PIN_232 en[3] output PIN_221 en[2] output PIN_222 en[1] output PIN_223 en[0] output PIN_224y[7] output PIN_233 y[6] output PIN_234 y[5] output PIN_235 y[4] output PIN_236 y[3] output PIN_237 y[2] output PIN_238 y[1] output PIN_239 y[0] output PIN_240实验中的注意的问题:1、数码管动态显示时,要对时钟信号进行分频,而且,分频计数最好在5000个时钟信号以上,否则数码管显示的可能是模糊的数字8;2、时间计数进程中的if语句要进行嵌套,否则,计数的更新会有一秒的滞后。
#include<AT89X52.H>#define uint unsigned int#define uchar unsigned charunsigned char key2;bit ding=1;unsigned char Getkey(void);uchar a,n=0,shi,fen,miao;void delay01s(void);uchar LED[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};uchar LED1[]={0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10};//有小数点的void init(); //函数声明void Delay(unsigned char z);//函数声明void display(); //函数声明//函数声明void main() //函数声明{P1=0xfe;//对P1口赋初值init(); //函数调用while(1){//函数调用key2=Getkey();switch(key2){case 1:shi++;if(shi==24){shi=0;}break;case 2:fen++;if(fen==60){fen=0;}break;case 3:if(fen!=0)fen--;if(fen==24){fen=0;}break;case 4:ding=~ding;default:break;}display(); //函数调用}}void init(){TMOD=0x01; //定时器工作方式选择和赋初值TH0=(65536-50000)/256;TL0=(65536-50000)%256;EA=1; //开总中断ET0=1; //开定时器中断TR0=1; //启动定时器}void timer0() interrupt 1 //中断服务程序{if(ding==1){TH0=(65536-50000)/256;//中断时间50msTL0=(65536-50000)%256; //定时器重新赋初值a++;if(a==10){n=~n;}if(a==20){n=~n;a=0;P1=P1<<1|P1>>7;miao++;if(miao==60){miao=0;fen++;if(fen==60){fen=0;shi++;if(shi==24){shi=0;}}}}}}void display()//显示程序{P0=LED[shi/10];P2=((P2&0x0f)|0x70); Delay(4);if(n==0){P0=LED[shi%10];}else{P0=LED1[shi%10];}P2=((P2&0x0f)|0xb0);Delay(4);P0=LED[fen/10];P2=((P2&0x0f)|0xd0);Delay(4);P0=LED[fen%10];P2=((P2&0x0f)|0xe0);Delay(4);}/**********获得键值子程序**********************/ unsigned char bool;//bool 是否松键的标志unsigned char Getkey(void){unsigned char temp,key=0;P2=(P2&0xff)|0x0f;if((P2&0xff)!=((P2&0xff)|0x0f)) // 有键按下{//delay01s();if(((P2&0xff)!=((P2&0xff)|0x0f)) &&(bool==0)) // 有键按下{temp=~(P2|0xf0);if(temp==1) key=1;else if(temp==2) key=2;else if(temp==4) key=3;else if(temp==8) key=4;bool=1;}}if(((P2&0xff)==((P2&0xff)|0x0f)) &&(bool==1)){bool=0;}return key; //返回1~16键值}/********延时程序******/void delay01s(void){unsigned char j,k;for(j=5;j>0;j--) //198{for(k=15;k>0;k--)//248{;}}}void Delay(unsigned char z){unsigned char i,j,k; //定义变量for(i=z;i>0;i--)for(j=25;j>0;j--)for(k=20;k>0;k--);}#include<reg52.h>//头文件#define uchar unsigned char//宏定义#define uint unsigned intsbit P31=P3^1;//位声明sbit P32=P3^2;sbit P33=P3^3;uchar code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//共阴段码表uint hou1,hou2,min1,min2,sec1,sec2,numhou,nummin,numsec,yue1,yue2,ri1,ri2,numyue,numri; uint num,m,n;void delayms(uint xms)//延时函数{uint i,j;for(i=xms;i>0;i--)for(j=110;j>0;j--);}void p31xd()//按键P31消抖{ delayms(2);while(P31!=1);delayms(2);}void p32xd()//按键P32消抖{ delayms(1);while(P32!=1);delayms(1);}void p33xd()//按键P33消抖{ delayms(1);while(P33!=1);delayms(1);}void displaysj()//显示时间{P2=0x00;P0=table[hou1];//显示时的第一位P2=0X20;delayms(1);P2=0xff;P0=table[hou2]&0x7f;//显示时的第二位与小数点P2=0X10;delayms(1);P2=0xff;P0=table[min1];//显示分的第一位P2=0X08;delayms(1);P2=0xff;P0=table[min2]&0x7f;//显示时的第二位与小数点P2=0X04;delayms(1);P2=0xff;P0=table[sec1];//显示秒的第一位P2=0X02;delayms(1);P2=0xff;P0=table[sec2];//显示秒的第二位P2=0X01;delayms(1);}void displayrq()//显示日期{ P2=0x00;P0=table[yue1];//显示月的第一位P2=0X20;delayms(1);P2=0x00;P0=table[yue2]&0x7f;//显示月的第二位P2=0X10;delayms(1);P2=0x00;P0=table[ri1];//显示日的第一位P2=0X08;delayms(1);P2=0x00;P0=table[ri2];//显示日的第二位P2=0X04;delayms(1);}void houqh()//时针切换函数{hou1=numhou/10;hou2=numhou%10;}void minqh()//分针切换函数{min1=nummin/10;min2=nummin%10;}void secqh()//秒针切换函数{sec1=numsec/10;sec2=numsec%10;}void yueqh()//月切换函数{yue1=numyue/10;yue2=numyue%10;}void riqh()//日切换函数{ri1=numri/10;ri2=numri%10;}void start()//初始化函数{num=0;TMOD=0x01;TH0=(65532-45872)/256;TL0=(65532-45872)%256;EA=1;IT0=0;//电平触发(低电平有效)EX0=1;ET0=1;TR0=1;yueqh(),riqh();//初始化日月切换}void ritiao()//日期的调节函数{ if(P32==0)//日期加一调节键{p32xd();if((numyue==1)||(numyue==3)||(numyue==5)||(numyue==7)||(numyue==8)||(numyue==10)||( numyue==12)){numri+=1;if(numri>=31)//如果是大月,日期有31号,等于符号是防止日期大于31号而乱码{numri=1;}}if((numyue==4)||(numyue==6)||(numyue==9)||(numyue==11)){numri+=1;if(numri>=30)//如果是小月,日期有30号{numri=1;}}if(numyue==2){numri+=1;if(numri>=28)//如果是小月,日期有28号{numri=1;}}riqh();//日期调节后切换一下}if(P33==0)//日期减一调节键{p33xd();if((numyue==1)||(numyue==3)||(numyue==5)||(numyue==7)||(numyue==8)||(numyue==10)||( numyue==12)){numri-=1;if(numri==0){numri=31;}}if((numyue==4)||(numyue==6)||(numyue==9)||(numyue==11)){numri-=1;if(numri==0){numri=30;}}if(numyue==2){numri-=1;if(numri==0){numri=28;}}riqh();}}void yuetiao()//月份的调节函数{if(P32==0){p32xd();numyue+=1;if(numyue==13)//月份为12时再加一马上为一月{numyue=1;}yueqh();}if(P33==0){p33xd();numyue-=1;if(numyue==0){numyue=12;}yueqh();}}void int0() interrupt 0{p31xd();while(P31!=0)//第一次按下p31时,进行秒调时{for(m=0;m<40;m++)//此for循环不显示秒,为的是使秒闪烁{P2=0x00;P0=table[hou1];P2=0X20;delayms(1);P2=0x00;P0=table[hou2]&0x7f;P2=0X10;delayms(1);P2=0x00;P0=table[min1];P2=0X08;delayms(1);P2=0x00;P0=table[min2]&0x7f;P2=0X04;delayms(1);if(P32==0)//如果按一下P32,则秒加一{p32xd();numsec+=1;if(numsec==60){numsec=0;}secqh();}if(P33==0)//如果按一下P33,则秒减一{p33xd();numsec-=1;if(numsec==-1){numsec=59;}secqh();}};for(n=0;n<40;n++)//此循环时分秒全显示,也为的是使秒闪烁{ displaysj();if(P32==0){p32xd();numsec+=1;if(numsec==60){numsec=0;}secqh();}if(P33==0){p33xd();numsec-=1;if(numsec==-1){numsec=59;}secqh();}}};p31xd();while(P31!=0)//第二次按下p31时,进行分调时{for(m=0;m<40;m++){P2=0x00;P0=table[hou1];P2=0X20;delayms(1);P2=0x00;P0=table[hou2]&0x7f;P2=0X10;delayms(1);P2=0x00;P0=table[sec1];P2=0X02;delayms(1);P2=0x00;P0=table[sec2];P2=0X01;delayms(1);if(P32==0){p32xd();nummin+=1;if(nummin==60){nummin=0;}minqh();}if(P33==0){p33xd();nummin-=1;if(nummin==-1){nummin=59;}minqh();}}for(n=0;n<40;n++){ displaysj();if(P32==0){p32xd();nummin+=1;if(nummin==60){nummin=0;}minqh();}if(P33==0){nummin-=1;if(nummin==-1){nummin=59;}minqh();}}};p31xd();while(P31!=0)//第三次按下p31时,进行时调时{for(m=0;m<40;m++){P2=0x00;P0=table[min1];P2=0X08;delayms(1);P2=0x00;P0=table[min2]&0x7f;P2=0X04;delayms(1);P2=0x00;P0=table[sec1];P2=0X02;delayms(1);P2=0x00;P0=table[sec2];P2=0X01;delayms(1);if(P32==0){p32xd();numhou+=1;if(numhou==24){numhou=0;}}if(P33==0){p33xd();numhou-=1;if(numhou==-1){numhou=23;}houqh();}}for(n=0;n<40;n++){ displaysj();if(P32==0){p32xd();numhou+=1;if(numhou==24){numhou=0;}houqh();}if(P33==0){p33xd();numhou-=1;if(numhou==-1){numhou=23;}houqh();}}}p31xd();while(P31!=0)//第四次按下p31时,进行日期调节{for(m=0;m<50;m++){ P2=0x00;P0=table[yue1];P2=0x20;delayms(1);P2=0x00;P0=table[yue2]&0x7f;P2=0x10;delayms(1);ritiao();}for(n=0;n<50;n++){ displayrq();ritiao();}}p31xd();while(P31!=0)//第五次按下p31时,进行月调节{for(m=0;m<50;m++){P2=0xff;P0=table[ri1];P2=0xf7;delayms(1);P2=0xff;P0=table[ri2];P2=0xfb;delayms(1);yuetiao();}for(n=0;n<50;n++){ displayrq();yuetiao();}}p31xd();}void yuejia(){ numri=1;numyue+=1;if(numyue==13){numyue=1;}}void timer0() interrupt 1{TH0=(65532-46100)/256;TL0=(65532-46100)%256;num++;if(num==20){num=0;TH0=(65532-46100)/256;TL0=(65532-46100)%256;numsec=numsec+1;if(numsec==60){numsec=0;nummin=nummin+1;if(nummin==60){nummin=0;numhou=numhou+1;if(numhou==24){numhou=0;numri+=1;if((numyue==1)||(numyue==3)||(numyue==5)||(numyue==7)||(numyue==8)||(numyue==10)||( numyue==12)){numri+=1;if(numri>=31){numri=1;numyue+=1;if(numyue==13){numyue=1;}}}if((numyue==4)||(numyue==6)||(numyue==9)||(numyue==11)){numri+=1;if(numri>=31){numri=1;numyue+=1;if(numyue==13){numyue=1;}}}if(numyue==2){numri+=1;if(numri>=29){numri=1;numyue+=1;if(numyue==13){numyue=1;}}}}}}}}void main(){numhou=12;//初始化时间设为12点,日期设为1月1日nummin=0;numsec=0;numyue=1;numri=1;start();while(1){if(P32==1)//默认(没有按下p32时)显示时间{houqh(),minqh(),secqh();displaysj();}if(P32==0)//当按下p32键时显示日期{yueqh(),riqh();displayrq();}}}。
单片机电子时钟设计程序
1.引用头文件和定义全局变量
首先需要引用相应的头文件,例如`reg52.h`,并定义全局变量用于
存储时间、闹钟时间以及其他相关参数。
2.初始化时钟
在主函数中,首先进行时钟的初始化。
这包括设置定时器和中断相关
的寄存器,以及初始化显示屏和按钮等外设。
3.时间更新
编写一个中断服务函数,用于根据定时器的中断来更新时间。
在该中
断服务函数中,需要将全局变量中的时间进行递增,并考虑到分钟、小时、日期和星期等的进位和换算。
4.按钮输入
设置一个子函数用于读取按钮输入,并根据按钮的状态来进行相应的
操作,比如切换时钟显示模式、设置闹钟等。
5.显示时间
编写一个子函数用于将时间信息显示在数码管上。
这需要先将时间信
息转换为数码管的显示格式,然后通过IO口输出控制数码管的显示。
6.闹钟设置
使用按钮输入的功能,可以设置闹钟时间和开关闹钟功能。
当闹钟时
间到达时,可以通过控制蜂鸣器发声或点亮LED等方式来进行提醒。
7.主函数
在主函数中,循环执行按钮输入的检测和相应操作,以及时间的更新和显示等功能。
可以通过一个状态机来控制整个程序的流程。
以上是一个简要的单片机电子时钟设计程序的概述。
实际的程序设计过程中,还需要考虑到各个模块之间的交互、错误处理、电源管理以及代码的优化等细节问题。
具体的程序实现可以根据具体需求和硬件平台的差异进行适当的修改和扩展。
//DS3231,经测试,日期,时间,星期,温度可以用1602显示#in elude <reg51.h>#in elude vintrin s.h>#defi ne uchar un sig ned char#defi ne uint un sig ned int#define yh 0x80 //第一行的初始位置#defi ne er 0x80+0x40 // 第二行初始位置sbit wr=P1A1;sbit rs=P1A。
;sbit en=卩2人5;sbit SDA=P3A6; //模拟I2C数据传送位 SDAsbit SCL=P3A7; //模拟I2C时钟控制位 SCL sbit INT=P3A2;sbit key1=P1A7; // 功能键,修改键sbitkey2=P3A4;// 上调键sbitkey3=P3A5;// 下调键sbit RESET=P3A3;bit ack;// 应答标志位#define DS3231 _WriteAddress 0xD0 // 器件写地址#define DS3231 _ReadAddress 0xD1// 器件读地址#define DS3231_SECOND 0x00 // 秒#define DS3231 _MINUTE 0x01 // 分#define DS3231 _HOUR 0x02 // 时#define DS3231 _WEEK 0x03 // 星期#define DS3231 _DAY 0x04 // 日#define DS3231_MONTH 0x05 // 月#define DS3231 _YEAR 0x06 // 年// 闹铃 1#define DS3231 _SALARM1ECOND 0x07 // 秒#define DS3231 _ALARM1MINUTE 0x08 // 分#define DS3231 _ALARM1HOUR 0x09 // 时#define DS3231 _ALARM1WEEK 0x0A// 星期 / 日// 闹铃 2#define DS3231 _ALARM2MINUTE 0x0b // 分#define DS3231 _ALARM2HOUR0x0c // 时可编辑#define DS3231_TEMPERATUREH 0x11#define DS3231_TEMPERATUREL 0x12 uchara,miao,shi,fen,ri,yue,nian,week,temp1,temp2,key1n,temp; uchar code tab1[]={"2017- - FRI"}; uchar code tab2[]={" : : ."};uchar HEX2BCD(uchar val) //B 码转换为 BCD 码{uchar k;k=(val)/10*16+(val)%10; return k;}uchar BCD_Decimal(uchar bcd){uchar Decimal; Decimal=bcd>>4;return(Decimal=Decimal*10+(bcd&=0x0F));#define DS3231_ALARM2WEEK #define DS3231_CONTROL #define DS3231_STATUS #define BSY #define OSF0x0d // 星期 / 日0x0e // 控制寄存器 0x0f // 状态寄存器2 // 忙7// 振荡器停止标志#define DS3231_XTAL0x10 // 晶体老化寄存器// 温度寄存器高字节 // 温度寄存器低字节 (8 位 ) (高 2 位 )}void delayus(uint us){while (us--);}void Start_I2C(){SDA=1; // 发送起始条件的数据信号 delayus(1);SCL=1;delayus(5); // 起始条件建立时间大于 4.7us, 延时SDA=0; // 发送起始信号delayus(5); //起始条件锁定时间大于4阳SCL=0; //钳住 I2C 总线,准备发送或接收数据delayus(2);}void Stop_I2C(){SDA=0; // 发送结束条件的数据信号delayus(1); // 发送结束条件的时钟信号SCL=1; // 结束条件建立时间大于 4us delayus(5);SDA=1; // 发送 I2C 总线结束信号delayus(4);}void SendByte(uchar c){uchar BitCnt;for(BitCnt=0;BitCnt<8;BitCnt ++){if((c<<BitCnt)&0x80)SDA=1;elseSDA=0;delayus(1);SCL=1;数据位delayus(5);SCL=0;// 要传送的数据长度为 8 位// 判断发送位// 置时钟线为高,通知被控器开始接收//保证时钟咼电平周期大于 4阳delayus(2);SDA=1; //8 位发送完后释放数据线,准备接收应答位delayus(2);SCL=1;delayus(3);if(SDA==1)ack=0;elseack=1; // 判断是否接收到应答信号SCL=0;delayus(2);}uchar RcvByte(){uchar retc;uchar BitCnt;retc=0;SDA=1; // 置数据线为输入方式for(BitCnt=0;BitCnt<8;BitCnt++)SCL=0;delayus(5);SCL=1;delayus(3);retc=retc<<1;if(SDA==1)retc=retc+1;delayus(2);}SCL=0;delayus(2);return(retc);}// 置时钟线为低,准备接收数据位//时钟低电平周期大于 4.7 Q//置时钟线为高使数据线上数据有效// 读数据位 ,接收的数据位放入 retc 中void Ack_I2C(bit a){if(a==0)SDA=0; else // 在此发出应答或非应答信号SDA=1;SCL=1;delayus(5); //时钟低电平周期大于4阴SCL=0; // 清时钟线,钳住 I2C 总线以便继续接收delayus(2);}uchar write_byte(uchar addr, uchar write_data) {Start_I2C();SendByte(DS3231_WriteAddress);if (ack == 0)return 0;SendByte(addr);if (ack == 0)return 0;SendByte(write_data);if (ack == 0)return 0;Stop_I2C();return 1;}uchar read_current(){uchar read_data;Start_I2C();SendByte(DS3231_ReadAddress);if(ack==0)return(0);read_data = RcvByte();Ack_I2C(1);Stop_I2C();return read_data;}uchar read_random(uchar random_addr) {Start_I2C();SendByte(DS3231_WriteAddress);if(ack==0)SendByte(random_addr);if(ack==0)return(0);return(read_current()); }void ModifyTime(uchar yea,uchar sec,uchar week){uchar temp=0;temp=HEX2BCD(yea);write_byte(DS3231_YEAR,temp);temp=HEX2BCD(mon);write_byte(DS3231_MONTH,temp);temp=HEX2BCD(da);write_byte(DS3231_DAY,temp);temp=HEX2BCD(hou);write_byte(DS3231_HOUR,temp); mon,uchar da,uchar hou,uchar// 修改年// 修改月// 修改日// 修改时min,uchartemp=HEX2BCD(min);write_byte(DS3231_MINUTE,temp); // 修改分temp=HEX2BCD(sec);write_byte(DS3231_SECOND,temp); // 修改秒temp=HEX2BCD(week);write_byte(DS3231_WEEK,temp); // 修改星期}**************** 液晶写入********************** write_1602com(uchar com)// 液晶写入指令函数{ rs=0;// 置为写入命令P0=com;// 送入数据delayus(1000);en=1;// 拉高使能端delayus(1000);en=0;// 完成高脉冲}write_1602dat(uchar dat){rs=1;// 置为写入数据P0=dat;// 送入数据delayus(1000);en=1;delayus(1000);en=0;}*******************over*********************lcd_init()// 液晶初始化函数{ wr=0;write_1602com(0x38);// 设置液晶工作模式write_1602com(0x0c);// 开显示不显示光标write_1602com(0x06);// 整屏不移动,指针加一write_1602com(0x01);write_1602com(yh+1);// 字符写入的位置for(a=0;a<14;a++){write_1602dat(tab1[a]);//delay(3);}write_1602com(er);for(a=0;a<12;a++){//delay(3);}write_1602com(er+14); // 写温度符号write_1602dat(0xdf);write_1602dat(0x43);void write_sfm(uchar add,uchar dat)// 写时分秒及温度{ uchar gw,sw;gw=dat%10;sw=dat/10;write_1602com(er+add);write_1602dat(0x30+sw);write_1602dat(0x30+gw);}void write_nyr(uchar add,uchar dat) // 写日期{ uchar gw,sw;gw=dat%10;sw=dat/10;write_1602com(yh+add);write_1602dat(0x30+sw);write_1602dat(0x30+gw);}void write_week(uchar week)// 写星期函数{write_1602com(yh+0x0c);switch(week){case 1:write_1602dat('M');//delay(5);write_1602dat('O');//delay(5);write_1602dat('N');break;case 2:write_1602dat('T');//delay(5);write_1602dat('U');//delay(5);write_1602dat('E');break;case 3:write_1602dat('W');//delay(5);break;case 4:write_1602dat('T');//delay(5);write_1602dat('H');//delay(5);write_1602dat('U');break;case 5:write_1602dat('F');//delay(5);write_1602dat('R');//delay(5);write_1602dat('I');break;case 6:write_1602dat('S');//delay(5);write_1602dat('T');//delay(5);write_1602dat('A');break;case 7:write_1602dat('S');//delay(5);write_1602dat('U');//delay(5);write_1602dat('N');break;}void keyscan(){if(key1==0)//key1 为功能键{delayus(5000);if(key1==0){while(!key1);key1n++;if(key1n==9)key1n=1;switch(key1n){case 1: TR0=0;// 关闭定时器//TR1=0;write_1602com(er+0x06);// 写入光标位置write_1602com(0x0f);// 设置光标为闪烁break;//write_1602com(0x0f);break;case 3: write_1602com(er+0);//shi//write_1602com(0x0f);break;case 4: write_1602com(yh+0x0d);//week//write_1602com(0x0f);break;case 5: write_1602com(yh+0x09);//ri//write_1602com(0x0f);break;case 6: write_1602com(yh+0x06);//yue//write_1602com(0x0f);break;case 7: write_1602com(yh+0x03);//nian//write_1602com(0x0f);break;case 8: write_1602com(0x0c);// 设置光标不闪烁write_sfm(6,miao);// 写入新的秒数temp=(miao)/10*16+(miao)%10;write_byte(DS3231_SECOND,temp); // 退出时修改秒write_1602com(er+6);temp=(fen)/10*16+(fen)%10;write_byte(DS3231_MINUTE,temp); // 修改分write_1602com(er+3);TR0=1;// 打开定时器break;}}}if(key1n!=0)// 当 key1 按下以下。
//DS3231,经测试,日期,时间,星期,温度可以用1602显示#in elude <reg51.h>#in elude vintrin s.h>#defi ne uchar un sig ned char#defi ne uint un sig ned int#define yh 0x80 //第一行的初始位置#defi ne er 0x80+0x40 // 第二行初始位置sbit wr=P1A1;sbit rs=P1A。
;sbit en=卩2人5;sbit SDA=P3A6; //模拟I2C数据传送位 SDAsbit SCL=P3A7; //模拟I2C时钟控制位 SCL sbit INT=P3A2;sbit key1=P1A7; // 功能键,修改键sbitkey2=P3A4;// 上调键sbitkey3=P3A5;// 下调键sbit RESET=P3A3;bit ack;// 应答标志位#define DS3231 _WriteAddress 0xD0 // 器件写地址#define DS3231 _ReadAddress 0xD1// 器件读地址#define DS3231_SECOND 0x00 // 秒#define DS3231 _MINUTE 0x01 // 分#define DS3231 _HOUR 0x02 // 时#define DS3231 _WEEK 0x03 // 星期#define DS3231 _DAY 0x04 // 日#define DS3231_MONTH 0x05 // 月#define DS3231 _YEAR 0x06 // 年// 闹铃 1#define DS3231 _SALARM1ECOND 0x07 // 秒#define DS3231 _ALARM1MINUTE 0x08 // 分#define DS3231 _ALARM1HOUR 0x09 // 时#define DS3231 _ALARM1WEEK 0x0A// 星期 / 日// 闹铃 2#define DS3231 _ALARM2MINUTE 0x0b // 分#define DS3231 _ALARM2HOUR0x0c // 时可编辑#define DS3231_TEMPERATUREH 0x11#define DS3231_TEMPERATUREL 0x12 uchara,miao,shi,fen,ri,yue,nian,week,temp1,temp2,key1n,temp; uchar code tab1[]={"2017- - FRI"}; uchar code tab2[]={" : : ."};uchar HEX2BCD(uchar val) //B 码转换为 BCD 码{uchar k;k=(val)/10*16+(val)%10; return k;}uchar BCD_Decimal(uchar bcd){uchar Decimal; Decimal=bcd>>4;return(Decimal=Decimal*10+(bcd&=0x0F));#define DS3231_ALARM2WEEK #define DS3231_CONTROL #define DS3231_STATUS #define BSY #define OSF0x0d // 星期 / 日0x0e // 控制寄存器 0x0f // 状态寄存器2 // 忙7// 振荡器停止标志#define DS3231_XTAL0x10 // 晶体老化寄存器// 温度寄存器高字节 // 温度寄存器低字节 (8 位 ) (高 2 位 )}void delayus(uint us){while (us--);}void Start_I2C(){SDA=1; // 发送起始条件的数据信号 delayus(1);SCL=1;delayus(5); // 起始条件建立时间大于 4.7us, 延时SDA=0; // 发送起始信号delayus(5); //起始条件锁定时间大于4阳SCL=0; //钳住 I2C 总线,准备发送或接收数据delayus(2);}void Stop_I2C(){SDA=0; // 发送结束条件的数据信号delayus(1); // 发送结束条件的时钟信号SCL=1; // 结束条件建立时间大于 4us delayus(5);SDA=1; // 发送 I2C 总线结束信号delayus(4);}void SendByte(uchar c){uchar BitCnt;for(BitCnt=0;BitCnt<8;BitCnt ++){if((c<<BitCnt)&0x80)SDA=1;elseSDA=0;delayus(1);SCL=1;数据位delayus(5);SCL=0;// 要传送的数据长度为 8 位// 判断发送位// 置时钟线为高,通知被控器开始接收//保证时钟咼电平周期大于 4阳delayus(2);SDA=1; //8 位发送完后释放数据线,准备接收应答位delayus(2);SCL=1;delayus(3);if(SDA==1)ack=0;elseack=1; // 判断是否接收到应答信号SCL=0;delayus(2);}uchar RcvByte(){uchar retc;uchar BitCnt;retc=0;SDA=1; // 置数据线为输入方式for(BitCnt=0;BitCnt<8;BitCnt++)SCL=0;delayus(5);SCL=1;delayus(3);retc=retc<<1;if(SDA==1)retc=retc+1;delayus(2);}SCL=0;delayus(2);return(retc);}// 置时钟线为低,准备接收数据位//时钟低电平周期大于 4.7 Q//置时钟线为高使数据线上数据有效// 读数据位 ,接收的数据位放入 retc 中void Ack_I2C(bit a){if(a==0)SDA=0; else // 在此发出应答或非应答信号SDA=1;SCL=1;delayus(5); //时钟低电平周期大于4阴SCL=0; // 清时钟线,钳住 I2C 总线以便继续接收delayus(2);}uchar write_byte(uchar addr, uchar write_data) {Start_I2C();SendByte(DS3231_WriteAddress);if (ack == 0)return 0;SendByte(addr);if (ack == 0)return 0;SendByte(write_data);if (ack == 0)return 0;Stop_I2C();return 1;}uchar read_current(){uchar read_data;Start_I2C();SendByte(DS3231_ReadAddress);if(ack==0)return(0);read_data = RcvByte();Ack_I2C(1);Stop_I2C();return read_data;}uchar read_random(uchar random_addr) {Start_I2C();SendByte(DS3231_WriteAddress);if(ack==0)SendByte(random_addr);if(ack==0)return(0);return(read_current()); }void ModifyTime(uchar yea,uchar sec,uchar week){uchar temp=0;temp=HEX2BCD(yea);write_byte(DS3231_YEAR,temp);temp=HEX2BCD(mon);write_byte(DS3231_MONTH,temp);temp=HEX2BCD(da);write_byte(DS3231_DAY,temp);temp=HEX2BCD(hou);write_byte(DS3231_HOUR,temp); mon,uchar da,uchar hou,uchar// 修改年// 修改月// 修改日// 修改时min,uchartemp=HEX2BCD(min);write_byte(DS3231_MINUTE,temp); // 修改分temp=HEX2BCD(sec);write_byte(DS3231_SECOND,temp); // 修改秒temp=HEX2BCD(week);write_byte(DS3231_WEEK,temp); // 修改星期}**************** 液晶写入********************** write_1602com(uchar com)// 液晶写入指令函数{ rs=0;// 置为写入命令P0=com;// 送入数据delayus(1000);en=1;// 拉高使能端delayus(1000);en=0;// 完成高脉冲}write_1602dat(uchar dat){rs=1;// 置为写入数据P0=dat;// 送入数据delayus(1000);en=1;delayus(1000);en=0;}*******************over*********************lcd_init()// 液晶初始化函数{ wr=0;write_1602com(0x38);// 设置液晶工作模式write_1602com(0x0c);// 开显示不显示光标write_1602com(0x06);// 整屏不移动,指针加一write_1602com(0x01);write_1602com(yh+1);// 字符写入的位置for(a=0;a<14;a++){write_1602dat(tab1[a]);//delay(3);}write_1602com(er);for(a=0;a<12;a++){//delay(3);}write_1602com(er+14); // 写温度符号write_1602dat(0xdf);write_1602dat(0x43);void write_sfm(uchar add,uchar dat)// 写时分秒及温度{ uchar gw,sw;gw=dat%10;sw=dat/10;write_1602com(er+add);write_1602dat(0x30+sw);write_1602dat(0x30+gw);}void write_nyr(uchar add,uchar dat) // 写日期{ uchar gw,sw;gw=dat%10;sw=dat/10;write_1602com(yh+add);write_1602dat(0x30+sw);write_1602dat(0x30+gw);}void write_week(uchar week)// 写星期函数{write_1602com(yh+0x0c);switch(week){case 1:write_1602dat('M');//delay(5);write_1602dat('O');//delay(5);write_1602dat('N');break;case 2:write_1602dat('T');//delay(5);write_1602dat('U');//delay(5);write_1602dat('E');break;case 3:write_1602dat('W');//delay(5);break;case 4:write_1602dat('T');//delay(5);write_1602dat('H');//delay(5);write_1602dat('U');break;case 5:write_1602dat('F');//delay(5);write_1602dat('R');//delay(5);write_1602dat('I');break;case 6:write_1602dat('S');//delay(5);write_1602dat('T');//delay(5);write_1602dat('A');break;case 7:write_1602dat('S');//delay(5);write_1602dat('U');//delay(5);write_1602dat('N');break;}void keyscan(){if(key1==0)//key1 为功能键{delayus(5000);if(key1==0){while(!key1);key1n++;if(key1n==9)key1n=1;switch(key1n){case 1: TR0=0;// 关闭定时器//TR1=0;write_1602com(er+0x06);// 写入光标位置write_1602com(0x0f);// 设置光标为闪烁break;//write_1602com(0x0f);break;case 3: write_1602com(er+0);//shi//write_1602com(0x0f);break;case 4: write_1602com(yh+0x0d);//week//write_1602com(0x0f);break;case 5: write_1602com(yh+0x09);//ri//write_1602com(0x0f);break;case 6: write_1602com(yh+0x06);//yue//write_1602com(0x0f);break;case 7: write_1602com(yh+0x03);//nian//write_1602com(0x0f);break;case 8: write_1602com(0x0c);// 设置光标不闪烁write_sfm(6,miao);// 写入新的秒数temp=(miao)/10*16+(miao)%10;write_byte(DS3231_SECOND,temp); // 退出时修改秒write_1602com(er+6);temp=(fen)/10*16+(fen)%10;write_byte(DS3231_MINUTE,temp); // 修改分write_1602com(er+3);TR0=1;// 打开定时器break;}}}if(key1n!=0)// 当 key1 按下以下。
《单片机技术》课程设计说明书数字电子钟系、部:电气与信息工程学院学生姓名:指导教师:职称专业:班级:完成时间:2013-06-07摘要电子钟在生活中应用非常广泛,而一种简单方便的数字电子钟则更能受到人们的欢迎。
所以设计一个简易数字电子钟很有必要。
本电子钟采用ATMEL公司的AT89S52单片机为核心,使用12MHz 晶振与单片机AT89S52 相连接,通过软件编程的方法实现以24小时为一个周期,同时8位7段LED数码管(两个四位一体数码管)显示小时、分钟和秒的要求,并在计时过程中具有定时功能,当时间到达提前定好的时间进行蜂鸣报时。
该电子钟设有四个按键KEY1、KEY2、KEY3、KEY4和KEU5键,进行相应的操作就可实现校时、定时、复位功能。
具有时间显示、整点报时、校正等功能。
走时准确、显示直观、运行稳定等优点。
具有极高的推广应用价值。
关键词电子钟;AT89S52;硬件设计;软件设计ABSTRACTClock is widely used in life, and a simple digital clock is more welcomed by people. So to design a simple digital electronic clock is necessary.The system use a single chip AT89S52 of ATMEL’s as its core to control The crystal oscillator clock,using of E-12MHZ is connected with the microcontroller AT89S52, through the software programming method to achieve a 24-hour cycle, and eight 7-segment LED digital tube (two four in one digital tube) displays hours, minutes and seconds requirements, and in the time course of a timing function, when the time arrived ahead of scheduled time to buzz a good timekeeping. The clock has four buttons KEY1, KEY2, KEY3,KEY4 and KEY5 key, and make the appropriate action can be achieved when the school, timing, reset. With a time display, alarm clock settings, timer function, corrective action. Accurate travel time, display and intuitive, precision, stability, and so on. With a high application value.Key words Electronic clock;;AT89S52;Hardware Design;Software Design目录1设计课题任务、功能要求说明及方案介绍 (1)1.1设计课题任务 (1)1.2功能要求说明 (1)1.3设计总体方案介绍及原理说明 (1)2设计课题硬件系统的设计 (2)2.1设计课题硬件系统各模块功能简要介绍 (2)2.2设计课题电路原理图、PCB图、元器件布局图 (2)2.3设计课题元器件清单 (5)3设计课题软件系统的设计 (6)3.1设计课题使用单片机资源的情况 (6)3.2设计课题软件系统各模块功能简要介绍 (6)3.3设计课题软件系统程序流程框图 (6)3.4设计课题软件系统程序清单 (10)4设计结论、仿真结果、误差分析、教学建议 (21)4.1设计课题的设计结论及使用说明 (21)4.2设计课题的仿真结果 (21)4.3设计课题的误差分析 (22)4.4设计体会 (22)4.5教学建议 (22)结束语 (23)参考文献 (24)致谢 (25)附录 (26)1 设计课题任务、功能要求说明及方案介绍1.1 设计课题任务设计一个具有特定功能的电子钟。
下面附有实物图和引脚接法图及程序时钟实物图LCD1602引脚连接P1.0 P1.1 P1.2P0.0~P0.7DS12C887引脚连接(打叉的表示不接)蜂鸣器引脚连接按键引脚连接P1.3P3.4P3.5P3.6P3.7源程序#include<reg52.h>#include<intrins.h>#define uint unsigned int#define uchar unsigned charsbit lcdrs=P1^0;sbit rw=P1^1;sbit lcden=P1^2;sbit s1=P3^4; //功能键sbit s2=P3^5; //增大键sbit s3=P3^6; //减小键sbit s4=P3^7; //闹铃查看键sbit beep=P1^3;//蜂鸣器sbit dscs=P1^7;sbit dsas=P1^6;sbit dsrw=P1^5;sbit dsds=P1^4;sbit dsirq=P3^3; //中断bit flag1,flag_ri;//定义标志位flag1设置闹铃uchar count,s1num,flag,t0_num;char miao,shi,fen,year,month,day,week,amiao,afen,ashi;char code table[]=" 20 - - "; // 20 - -uchar code table1[]=" : : "; // : :void write_ds(uchar,uchar); uchar read_ds(uchar);void set_time(); void read_alarm();void set_alarm(uchar,uchar,uchar);void delayms(uint z) //延时毫秒的程序{uint x,y;for(x=z;x>0;x--)for(y=112;y>0;y--);}void di(){beep=0;delayms(100);beep=1;}void write_cmd(uchar cmd){lcden=0;lcdrs=0;P0=cmd;_nop_();lcden=1;delayms(1);lcden=0;_nop_();}void write_dat(uchar dat){lcden=0;lcdrs=1;P0=dat;_nop_();lcden=1;delayms(1);lcden=0;_nop_();}void lcdint(){lcden=0;write_cmd(0x38); // 显示模式设置write_cmd(0x0c); //开显示,不显示光标,不闪烁write_cmd(0x06); //写一个字符后地址加1,屏幕不移write_cmd(0x01); //清屏delayms(1);}void init(){uchar num;rw=0;EA=1;//开总中断EX1=1;//开外部中断1IT1=1;//外部中断下降沿触发flag1=0; t0_num=0;s1num=0;week=1;/* write_ds(0x0A,0x20);//打开振荡器write_ds(0x0B,0x26);//设置24小时模式,数据二进制格式,开启闹铃中断set_time();//设置上电默认时间,调试的时候用*/lcdint();write_cmd(0x80);for(num=0;num<15;num++){write_dat(table[num]);}write_cmd(0xc0);for(num=0;num<11;num++){write_dat(table1[num]);}}void write_sfm(uchar add,char date) //写时间,2位一起写{char shi,ge;shi=date/10;ge=date%10;write_cmd(0xc0+add);write_dat(0x30+shi);write_dat(0x30+ge);}void write_nyr(uchar add,char date)//年月日{char shi,ge;shi=date/10;ge=date%10;write_cmd(0x80+add);write_dat(0x30+shi);write_dat(0x30+ge);}void write_week(char we)//星期{write_cmd(0x80+12);switch(we){case 1: write_dat('M');write_dat('O');write_dat('N');break;case 2: write_dat('T');write_dat('U');write_dat('E');break;case 3: write_dat('W');write_dat('E');write_dat('D');break;case 4: write_dat('T');write_dat('H');write_dat('U');break;case 5: write_dat('F');write_dat('R');write_dat('I');break;case 6: write_dat('S');write_dat('A');write_dat('T');break;case 7: write_dat('S');write_dat('U');write_dat('N');break;}}void keyscan(){if(flag_ri==1){if((s1==0)||(s2==0)||(s3==0)||(s4==0))//按任意键取消闹钟报警{delayms(5);if((s1==0)||(s2==0)||(s3==0)||(s4==0)){while(!(s1&&s2&&s3&&s4));di();flag_ri=0;}}}if(s1==0) //如果功能按键1按下{delayms(5); //去抖动if(s1==0){while(!s1); //等待松手s1num++; //记下次数di(); //蜂鸣器响if(flag1==1) //设置闹铃为1时才对s1num调整,只调秒,分,时{if(s1num>3){s1num=1;}}flag=1; //在调整时间时标志位flag为1,不进行正常操作switch(s1num){case 1:write_cmd(0xc0+10); write_cmd(0x0f); break; //按一下秒钟指针显示闪烁case 2:write_cmd(0xc0+7); break;case 3:write_cmd(0xc0+4); break;case 4:write_cmd(0x80+12); break;case 5:write_cmd(0x80+9); break;case 6:write_cmd(0x80+6); break;case 7:write_cmd(0x80+3); break;default: //用default可以解决s1num跑飞s1num=0;write_cmd(0x0c); //按了8次关闪烁,flag=0,退出调整,显示时间flag=0;write_ds(0,miao); //将调整后的时间写入ds12c887write_ds(2,fen);write_ds(4,shi);write_ds(6,week);write_ds(7,day);write_ds(8,month);write_ds(9,year);break;. . . .}}}if(s1num!=0) //S1有按下过,检测S2,S3{if(s2==0) //如果按键2按下执行加{delayms(5);if(s2==0){while(!s2);di();switch(s1num){case 1:miao++;if(miao>59){miao=0;}write_sfm(10,miao);write_cmd(0x80+0x40+10);break;. . . . case 2:fen++;if(fen>59){fen=0;}write_sfm(7,fen);write_cmd(0x80+0x40+7);break;case 3:shi++;if(shi>23){shi=0;}write_sfm(4,shi);write_cmd(0x80+0x40+4);break;case 4:week++;if(week>7){. . . .week=1;}write_week(week);write_cmd(0x80+12);break;case 5:day++;if(day>31){day=1;}write_nyr(9,day);write_cmd(0x80+9);break;case 6:month++;if(month>12){month=1;}write_nyr(6,month);write_cmd(0x80+6);. . . .break;case 7:year++;if(year>99){year=0;}write_nyr(3,year);write_cmd(0x80+3);break;}}}if(s3==0){delayms(5);if(s3==0){while(!s3);di();switch(s1num){case 1:. . . .miao--;if(miao<0){miao=59;}write_sfm(10,miao);write_cmd(0x80+0x40+10);break;case 2:fen--;if(fen<0){fen=59;}write_sfm(7,fen);write_cmd(0x80+0x40+7);break;case 3:shi--;if(shi<0){shi=23;write_sfm(4,shi);write_cmd(0x80+0x40+4);break;case 4:week--;if(week<1){week=7;}write_week(week);write_cmd(0x80+12);break;case 5:day--;if(day<1){day=31;}write_nyr(9,day);write_cmd(0x80+9);break;month--;if(month<1){month=12;}write_nyr(6,month);write_cmd(0x80+6);break;case 7:year--;if(year<0){year=99;}write_nyr(3,year);write_cmd(0x80+3);break;}}}}if(s4==0){delayms(5);if(s4==0){while(!s4);di(); flag1=~flag1; //闹铃调好后再按一次键返回if(flag1==0) //退出闹钟设置保存数值{flag=0; //启动时间显示write_cmd(0x80+0x40);write_dat(' ');write_dat(' ');write_cmd(0x0c); //清屏下,否则光标乱跳(闹铃调时间时)write_ds(1,miao);write_ds(3,fen);write_ds(5,shi);}else //设置闹钟{read_alarm(); //读原始数据miao=amiao;fen=afen;shi=ashi;write_cmd(0xc0);write_dat('R');write_dat('i');write_cmd(0x80+0x40);write_sfm(4,ashi);write_sfm(7,afen);write_sfm(10,amiao);}}}}void write_ds(uchar add,uchar date)//写12c887函数{dscs=0;dsas=1;dsds=1;dsrw=1;P0=add; //写地址dsas=0;dsrw=0;P0=date; //写数据dsrw=1;dsas=1;dscs=1;}uchar read_ds(uchar add) //读12c887 {uchar ds_date;dsas=1;dsds=1;dsrw=1;dscs=0;P0=add;dsas=0;dsds=0;P0=0xff;ds_date=P0;dsds=1;dsas=1;dscs=1;return ds_date;}/*void set_time() //初始化{write_ds(0,0); //秒write_ds(1,10); //秒闹铃write_ds(2,34); //分钟write_ds(3,34); //分钟闹铃write_ds(4,15); //小时write_ds(5,15); //小时闹铃write_ds(6,5); //星期write_ds(7,20); //日write_ds(8,5); //月write_ds(9,11); //年}*/void read_alarm(){amiao=read_ds(1);afen=read_ds(3);ashi=read_ds(5);}void main(){init();while(1){keyscan(); //键盘不断扫描if(flag_ri==1) //如果闹铃时间到{di();delayms(100);di();delayms(500);}if(flag==0&&flag1==0){keyscan();year=read_ds(9);month=read_ds(8);day=read_ds(7);week=read_ds(6);shi=read_ds(4);fen=read_ds(2);miao=read_ds(0);write_sfm(10,miao);write_sfm(7,fen);write_sfm(4,shi);write_week(week);write_nyr(3,year);write_nyr(6,month);write_nyr(9,day);}}}void exter()interrupt 2 //闹铃外部中断1{uchar c; //闹铃时间到flag_ri=1;c=read_ds(0x0c); //读C寄存器表示响应中断}。
多功能电子钟设计说明
书
一.作品硬件原理图
三、程序流程图
Go_dianzhen();
dz_ms=0;
TR1 =1;
}
//TR1=1;
}
五.作品实物图
六.作品演示效果图
七.作品创新性描述
1我们将作品分成两大部分,即单片机基础系统与单片机应用系统,并将其制作成两块板,这样我们可以用这个单片机基础系统来做其他方面的开发。
2.我们采用的是液晶显示,这样比数码管看起来效果会更好。
3.我们通过程序将几大部分功能的器件整合在一起,可以同时运行。
4.采用串口来与计算机通信,因此我们程序可以通过串口下载在线烧写程序,另外还可以与计算机进行其他方面的通信,如将单片机中的容显示在计算机上。
#include <reg51.h>#include <intrins.h>#define uchar unsigned char //宏定义#define uint unsigned intuchar sec,min,hour,sec50,jishu,dtp2; //sec、min、hour、为显示单元,sec50为60秒计数单元,jishu为扫描数码管计数单元uchar sec1,min1,hour1; //时间中介单元uchar nzmin,nzhour,nzjishu=0,dispjishu=0; //闹钟分、时定义uchar data nzbit=0; //闹钟标志位,闹钟默认为开启uchar data dispbit=0; //显示标志位,默认显示当前时间uchar data disp[8]; //秒、分、时个位与十位存放数组及‘—’uchar code table[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; //数字0-9sbit KEYmin=P3^2; //分加1按钮sbit KEYhour=P3^3; //时加1按钮sbit LABA=P1^0; //闹钟输出I/O口sbit NZdisplay=P3^4; //闹钟显示按钮,按住不放显示闹钟时间,放开则显示当前时间sbit KEYnzmin=P3^5; //闹钟分加1按钮sbit KEYnzhour=P3^6; //闹钟时加1按钮sbit KEYoff=P3^7; //关闭闹钟按钮,按第一次为关闭,第二次为开启void display(); //显示函数声明void keyscan(); //按键扫描函数声明void naozhong(); //闹钟判别函数声明void keynz(); //闹钟按键函数声明void main(){sec=0; //时间初始化为00—00—00min=0;hour=0;sec1=0; //显示单元初始化为00—00—00min1=0;hour1=0;nzmin=01; //闹钟初始时间为01:01nzhour=01;jishu=0;dtp2=0xfe;P0=0xff;TMOD=0x11; //设T0、T1为模式1IE=0x8a;TH0=0xb8; //T0定时20msTL0=0x0;TH1=0xfc; //T1定时1msTL1=0x66;TR0=1;TR1=1;while(1){display(); //调用显示子程序keyscan(); //调用按键子程序keynz(); //调用闹钟按键子程序}}void t0int() interrupt 1 //T0定时中断程序{TH0=0xb8;TL0=0x0;sec50++;if(sec50==50) //对20ms计数50次即1s{sec50=0; //清秒计数器,为下次做准备naozhong(); //调用闹钟判别子程序sec1++; //秒加1}if(sec1==60) //对秒计数60次即1min{sec1=0;min1++; //分加1}if(min1==60) //对分计数60次即1hour{min1=0;hour1++; //时加1}if(hour1==24){hour1=0;}if(dispbit==0) //判断显示标志位是否为0,为0显示当前时间{sec=sec1;min=min1;hour=hour1;}else //显示标志位为1,显示闹钟时间{min=nzmin; //将闹钟时间给显示单元hour=nzhour;}}void t1int() interrupt 3 //T1中断程序{TH1=0xfc;TL1=0x66;P2=0xff; //关闭所有数码管P2=dtp2;dtp2=_crol_(dtp2,1);P0=disp[jishu];jishu++;if(jishu==8) //扫描完8位数码管清0,重新从第一位开始扫描{jishu=0;}}void delay(uint x) //延时函数uchar i;while(x--){for(i=0;i<120;i++);}}void display() //显示子程序{disp[7]=table[sec%10]; //秒个位显示disp[6]=table[sec/10]; //秒十位显示disp[4]=table[min%10]; //分个位显示disp[3]=table[min/10]; //分十位显示disp[1]=table[hour%10]; //时个位显示disp[0]=table[hour/10]; //时十位显示disp[2]=0xbf; //显示‘_’disp[5]=0xbf;}void keyscan() //按键子程序{delay(20); //延时消抖if(KEYmin==0)//时间分加1按钮{min1++; //时间分加1if(min1==60){min1=0;hour1++; //分加到60对时加1}if(hour1==24){hour1=0;}while(!KEYmin); //等待按键放开}delay(20); //延时消抖if(KEYhour==0) //时间时加1按钮{hour1++; //时间时加1if(hour1==24){hour1=0;}while(!KEYhour); //等待按键放开}void naozhong() //闹钟判断{if(nzbit==0) //判断闹钟标志位,0为开启闹钟判断,1为关闭闹钟{if(min1==nzmin) //闹钟与时间分的判别if(hour1==nzhour) //闹钟与时间时的判别LABA=0; //时间分、时与闹钟分、时相等就打开蜂鸣器}elseLABA=1;}void keynz() //闹钟加、减及闹钟关闭、开启按键处理子程序{delay(20); //延时消抖if(KEYnzmin==0) //判别闹钟分加1按键{nzmin++; //闹钟分加1if(nzmin==60){nzmin=0;nzhour++; //闹钟分加到60对闹钟时加1if(nzhour==24)nzhour=0;}while(!KEYnzmin); //等待按键放开}delay(20); //延时消抖if(KEYnzhour==0) //判别闹钟时加1按键{nzhour++; //闹钟时加1if(nzhour==24)nzhour=0;while(!KEYnzhour); //等待按键放开}if(KEYoff==0)//判断关闭闹钟按键是否按下{delay(20); // 延时消抖nzjishu++;if(nzjishu==1) //判断是否为第一次按下{nzbit=1; //第一次按下关闭闹钟if(nzjishu==2) //判断是否为第二次按下{nzjishu=0; //第二次按下清计数单元nzbit=0; // 第二次按下开启闹钟判别}while(!KEYoff); //等待按键放开}if(NZdisplay==0) //判别显示切换闹钟按键是否按下{dispjishu++;if(dispjishu==1) //第一次按下显示闹钟时间{dispbit=1; //第一次按下,把标志位置1,显示切换为闹钟时间}if(dispjishu==2) //第二次按下显示为当前时间{dispjishu=0; //清零,重新计数dispbit=0; //第二次按下清零显示标志位,显示切换为当前时间}while(!NZdisplay); //等待按键放开}}。
//**单片机stc89c52, 8位共阴数码管12M晶振//*******P0 位选,P2 段选❖******//#include 〃reg52・ h〃#define uchar unsigned char#define uint unsigned intuchar code tab[] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x40, Oxff}; uchar n;uchar hh, mm, ss;uchar nhh, nmm, nss;uint year;uchar day, mon, week;uchar hhs, hhg, mms, mmg, sss, ssg;uchar days,dayg, mons, mong;uchar nhhs, nhhg, nmms, nmmg, nsss, nssg;uchar setl=l, set2=l;sbit dula=P3 3;sbit fm=P3 2;sbit kl二P3"4;sbit k2二P3"5;sbit k3二P3飞;sbit k4二P3"7;uchar tablel[] = {31, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; 〃闰年uchar table2[] = {31, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; //非闰年void jishi ();void baoshi ();void alarm();void set_time();void set_alarm();void set_mdw();void key_change():void key_set ();void delay (int m) 〃延时程序,延时m*0. 5msuint i;uint j;for (i=0;i<m;i++){for(j=0;j<500;j++){}}}void timerO() interrupt 1 {TMOD二0x01;TH0=0x3c;TLO=Oxbl;n++;JishiO;}main()TMOD二0x01;TH0=0x3c;TLO二Oxbl;TRO二1;EA二1;ETO二1;hh=12;mm=00;ss=00;nhh二7;nmm=30;nss=0;year=2012;mon=01;day=01;week=7; while(1){hhs=hh/10%10; // 时分秒hhg=hh%10;mms=mm/10%10;mmg=mm%10;sss=ss/10%10;ssg=ss%10;nhhs=nhh/10%10; 〃闹钟nhhg=nhh%10; nmms=nmm/10%10;nmmg=nmm%10; nsss=nss/10%10;nssg=nss%10; days=day/10%10;//月Hday萨day%10; mons=mon/10%10;mong=mon%10;key_change () ; //kl 按键扫描key_set (); //k2 按键扫描set_time() ; //设置时间set.mdwO ; //设置月日星期set_alarm() ; //设置闹钟辻(setl-1) //正常走时显示dula=l: P2=tab [hhs] ; dula=O: P2=0xff; PO=Oxef; delay (1) ;P0二Oxff; //时十位dula二1;P2二tab[hhg]; dula=0;P2=0xff;PO=Oxdf;delay(1) ; PO二Oxff;//时个位dula=l;P2=tab[10]:dula=0;P2=0xff; PO=Oxbf;delay(1); PO二Oxffdula=l: P2=tab [mms] : dula=0: P2 二Oxff ;P0 二0x7f; delay (1) ;P0 二Oxff; //分十位dula=l; P2=tab [mmg] ; dula=0; P2=0xf f; P0=0xfe; delay (1) ; PO 二Oxff;//分个位dula=l;P2=tab[10]; dula=0:P2=0xff;PO=Oxfd:delay(1); PO二Oxffdula二1;P2二tab[sss]; dula=0;P2=0xff;PO=Oxfb:delay(1) ; PO二Oxff;//秒十位dula二1;P2二tablssg]; dula=0:P2=0xff;P0=0xf7; delay(1) ;P0二Oxff; //秒个位}辻(set 1=2) //设置时间dula=l; P2=tab [hhs] ; dula=0; P2=Oxff; PO=Oxef; delay (1) ;P0二Oxff; //时十位dula二1;P2二tablhhg]; dula=0:P2=0xff;PO=Oxdf;delay(1) ; PO二Oxff;//时个位dula=l:P2=tab[10]:dula=0;P2=0xff; PO=Oxbf;delay(1); PO二Oxffdula=l: P2=tab [mms] : dula=0: P2 二Oxff ;P0 二0x7f; delay (1) ;P0 二Oxff; //分十位dula=l; P2=tab [mmg] ; dula=0: P2=0xf f: P0=0xfe; delay (1) ; PO 二Oxff;//分个位dula=l;P2=tab[10]; dula=0:P2=0xff;PO=Oxfd:delay(1); PO二Oxffdula二1;P2二tab[sss]; dula=0;P2=0xff;PO=Oxfb:delay(1) ; PO二Oxff;//秒十位dula二1;P2二tablssg]; dula=0:P2=0xff;P0=0xf7; delay(1) ;P0二Oxff; //秒个位}辻(set 1-3) //正常显示月日-星期(肆匕诂S )M心T P 鏗\m x o u o 匕(DAPWZJXOUOddxouzdoudnp 二席*〕qpf Zd二 H d n p 创+忌、、d x o u o d - (I )A p w q J x o u o d d x o u z d o H £n p =s 〕q p f z d =%-n p 、、—、、、、QJXOUOd - (I)xp^p&Jxouod2Jxouzdo%w 〔OI 〕qeTzd=%-np 心T p g 'm x o u o d - u)APW*xouoddxouzd oUPTnp 二"App 〕qpfzd二%-np^+、、dxouocr(DAP^PQZXOUOmxouzdou d n p 二 SAPP 〕qpfzd 二%-np 、、—、、、、QJXOUOdJI) A32P cu q x o u o d 世o %I n p 二2〕q e F CN d 二%H T P 鏗\m x o u o 匕(DAPWZJXOUOddxouzdoudnp 二席*〕qpf Zd二 H d n p 创+忌、、d x o u o d - (I )A p w q J x o u o d d x o u z d o H £n p =s 〕q p f z d =%-n p 、、—、、、、心 J x o u o d - (I)xp^p&Jxouod2Jxouzdo%w 〔OI 〕qeTzd=%-np 心T p g 'm x o u o d - u)APW*xouoddxouzd oUPTnp 二"App 〕qpfzd 二%-np ^+0、、d x ouocr(DAP^PQZXOUOmxouzdoudnp二SAPP〕qpfzd二%-np 、、—、、、、QJXOUOd J I ) A32Pcu q x o u o d £0 世dula=l; P2=tab [nhhs]; dula=O; P2二Oxff; PO二Oxef; delay (1) ; PO二Oxff; 〃时十位dula=l;P2=tab[nhhg]; dula=0;P2=0xff;PO=Oxdf; delay (1) ; PO二Oxff;//时个位dula=l;P2=tab[10];dula=0;P2=0xff; PO=Oxbf;delay(1); PO二Oxff dula=l:P2=tab [nmms] : dula=0; P2=0xff ;P0=0x7f; delay (1) ;PO=Oxff; //分十位dula=l;P2=tab[nmmg] :dula=0;P2=0xff;PO=Oxfe; delay (1) ; PO=Oxff;//分个位dula=l;P2=tab[10]; dula=0:P2=0xff;PO=Oxfd:delay(1) ; PO二Oxffdula=l ;P2=tab[nsss] : dula=0;P2=0xff ;PO=Oxfb; delay (1) ; PO二Oxff;//秒十位dula=l;P2=tab[nssg] ; dula=0: P2=0xff; PO=Oxf7; delay (1) ;PO=Oxff; //秒个位} if(setl—6) //设置闹钟定时dula=l; P2=tab [nhhs] ; dula=0; P2二Oxff; PO二Oxef; delay (1) ; PO二Oxff; 〃时十位dula=l;P2=tab[nhhg]; dula=0;P2=0xff;PO=Oxdf; delay (1) ; PO二Oxff;//时个位dula=l;P2=tab[10];dula=0;P2=0xff; PO=Oxbf;delay(1); PO二Oxff dula=l:P2=tab [nmms] : dula=0; P2=0xff ;P0=0x7f; delay (1) ;PO=Oxff; //分十位dula=l;P2=tab[nmmg] :dula=0;P2=0xff;PO=Oxfe;delay(1) ; PO二Oxff;//分个位dula=l;P2=tab[10]; dula=0;P2=0xff;PO=Oxfd:delay(1); PO二Oxff dula=l;P2=tab[nsss]; dula二0;P2二Oxff;P0二Oxfb;delay(l) ; PO二Oxff;//秒十位dula=l;P2=tab[nssg] ; dula=0: P2=0xff; PO=Oxf7; delay (1) ;P0二Oxff; //秒个位}baoshi () : //整点报时alarm () ; //闹钟}}void JishiO 〃计时函数辻(n二二20){n=0;ss++;辻(ss=60){ss二0;mm++;if(mm二二60){mm^O;hh++;辻(hh=24){hh二0;day++;week++;if(week==8){week二0;}if (year%4==0&&year%100! =0 year%400==0) //闰年if(day=二tablel[mon]+l){day=0;mon++;if(mon==13){mon二0;year++;}}else //非闰年{辻(day—table2 [mon]+l){day=0;mon++;辻(mon—13){mon二0;year++;}}}}}}}}uchar incone (uchar n) //加 1 函数{辻(k3=0){delay(20);if(k3==0){n++;while(!k3);}}return(n);}uchar decone(uchar m) //减 1 函数{ if (k4==0){delay(20);if(k4==0)辻(m<0){m 二0;}}}}void key_change() //kl 按键扫描{ if(kl==0){delay(20);if(kl==0){setl++;while(!kl);if(setl==7){setl二1;}}void key_set() //k2 按键扫描{if(k2==0){delay(20);{set2++;while(!k2);辻(set2=4){set2=l;}}}}void baoshi () //整点报时函数{ fm=O;}if(ss==l){fm=l;}}void alarm() //闹钟函数{uchar x;if(nhh==0){goto end;}if(hh==nhh&&mm二二nmm&&ss==nss)fm=O; delay(30); fm=l; delay(20); fm=0; delay(30); fm=l; delay(20); fm=0; delay(30); fm=l; delay(20); fm=0; delay(30); fm=l; delay (180);end:;}void set_time() //设置时间函数{辻(setl==2){辻(set2==l){hh=incone(hh);if(hh==24){hh=0;}if(hh==-l){hh二23;}hh二decone(hh);}mm=incone(mm); if(mm==60) {mm 二0;}if(mm==-l) {mm=59;}mm=decone(mm); }辻(set2=3){ss=incone(ss);辻(ss=60){ss=O;}if (ss—-1){ss=59;}ss二decone (ss);}void set_mdw() //设置月日星期函数{ 辻(setl==4) {辻(set2==l){mon=incone(mon);if(mon二二13){mon=l;}mon=decone(mon);if(mon==0){mon二12;}}if(set2==2)day=incone(day);if(day==32){day=l;} day=decone(day);if (day—0){day=31;}}辻(set2=3){week=incone(week);if(week==8){week二1;}week二decone(week);if(week==0){week=7;}}}void set_alarm() //设置闹钟函数{ if(setl二二6){辻(set2=l){nhh二incone(nhh);辻(nhh二二24) {nhh二0;}辻(nhh—-1){nhh二23;}nhh二decone(nhh); }if(set2==2){nmm二incone(nmm); if (nmm—60) {nmm二0;}nmm二decone(nmm); if (nmm 二二 T){nmm=59;}}辻(set2二二3) {nss=incone (nss); if (nss=60){nss=0;}nss二decone(nss); if(nss==-l){nss二59;}}}。
#include<reg52.h>
#define uchar unsigned char
#define uint unsigned int
uchar code weixuan[8]={0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01}; //位选,控制哪个数码管亮。
(从右到左)
uchar
code
duanxuan[12]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf, 0xff}; //0-9,'-','灭'
uchar data timedata[3]={0x00,0x00,0x00}; //时间缓冲区,分别为:秒、时、分。
uchar data datetime[8]={0xc0,0xc0,0xbf,0xc0,0xc0,0xbf,0xc0,0xc0}; //时间缓冲区,初始化显示00-00-00。
uchar tt1,tt2,tt,tt0,num=0;
uchar flag,flag1,flag2,flash;
sbit key1=P1^3;
sbit key2=P1^5;
sbit key3=P1^7;
//**************延时函数*********************************
void delay(uint del)
{
uchar i, j;
for(i=0; i<del; i++)
for(j=0; j<=148; j++);
}
//********************调用显示************************
void display()
{
datetime[0]=timedata[0]%10; datetime[1]=timedata[0]/10; //秒
datetime[3]=timedata[1]%10; datetime[4]=timedata[1]/10; //分 datetime[6]=timedata[2]%10; datetime[7]=timedata[2]/10; //时 if(!flag)
{
P2=0X80; //秒显示
P0=duanxuan[datetime[0]];
delay(2);
P2=0X40;
P0=duanxuan[datetime[1]];
delay(2);
}
else
{
P2=0X80; //秒显示
P0=duanxuan[datetime[0]]|flash;
delay(2);
P2=0X40;
P0=duanxuan[datetime[1]]|flash;
delay(2);
}
P2=0X20; //显示'-'
P0=duanxuan[10];
delay(2);
if(!flag1)
{
P2=0X10; //分显示
P0=duanxuan[datetime[3]];
delay(2);
P2=0X08;
P0=duanxuan[datetime[4]];
delay(2);
}
else
{
P2=0X10; //分显示
P0=duanxuan[datetime[3]]|flash;
delay(2);
P2=0X08;
P0=duanxuan[datetime[4]]|flash;
delay(2);
}
P2=0X04; //显示'-' P0=duanxuan[10];
delay(2);
if(!flag2)
{
P2=0X02; //小时
P0=duanxuan[datetime[6]];
delay(2);
P2=0X01;
P0=duanxuan[datetime[7]];
delay(2);
}
else
{
P2=0X02; //小时
P0=duanxuan[datetime[6]]|flash;
delay(2);
P2=0X01;
P0=duanxuan[datetime[7]]|flash;
delay(2);
}
}
/******************按键调节时间*****************************/ void keyscan()
{
if(key1==0)
{
delay(10);
if(key1==0)
{
num++;
while(!key1);
while(1)
{
if(num==1)
{
flag=1;
flag1=0;
flag2=0;
if(key2==0)
{
delay(10);
if(key2==0)
{
timedata[0]--;
if(timedata[0]==-1)
timedata[0]=60;
while(!key2);
}
}
if(key3==0)
{
delay(10);
if(key3==0)
{
timedata[0]++;
if(timedata[0]==60)
timedata[0]=0;
while(!key3);
}
}
}
if(key1==0)
{
delay(10);
if(key1==0)
num++;
while(!key1);
}
if(num==2)
{
flag=0;
flag1=1;
flag2=0;
if(key2==0)
{
delay(10);
if(key2==0)
{
timedata[1]--;
if(timedata[1]==-1)
timedata[1]=60;
while(!key2);
}
}
if(key3==0)
{
delay(10);
if(key3==0)
{
timedata[1]++;
if(timedata[1]==60)
timedata[1]=0;
while(!key3);
}
}
if(num==3)
{
flag=0;
flag1=0;
flag2=1;
if(key2==0)
{
delay(10);
if(key2==0)
{
timedata[2]--;
if(timedata[2]==-1)
timedata[2]=24;
while(!key2);
}
}
if(key3==0)
{
delay(10);
if(key3==0)
{
timedata[2]++;
if(timedata[2]==25)
timedata[2]=0;
while(!key3);
}
}
if(num==4)
{
num=0;
flag=0;
flag1=0;
flag2=0;
break;
}
}
}
}
}
//主函数
void main()
{
TMOD=0x01;
ET0=1;
TR0=1;
TH0=0x40;
TL0=0x00;
EA=1;
while(1)
{
keyscan();
}
}
//***************定时器函数*************************** void timer1() interrupt 1
{
TH0=0x40; //50ms自加一次。
TL0=0x00;
P3=100;
display();
if((flag||flag1||flag2))
{
tt0++;
if(tt0==10)
{
flash=~flash;
tt0=0;
}
}
//P3=11
else
{
tt++;
if(tt==20)
{
tt=0;
timedata[0]++; //秒加1
if(timedata[0]==60)
{
timedata[0]=0;
timedata[1]++; //分加1
if(timedata[1]==60)
{
timedata[1]=0;
timedata[2]++; //时加1
if(timedata[2]==24)
{
timedata[2]=0 ;
}
}
}
}
}
}。