① 基於單片機的數字時鍾設計方案
數字鍾〔★〕這里用了兩種編租肆寫方法(即匯編語言與C語言)
(1. 開機時,顯示12:00:00的時間開始計時;
(2. P0.0/AD0控制「秒」的調整,每按一次加1秒;
(3. P0.1/AD1控制「分」的調整,每按一次加1分;
(4. P0.2/AD2控制「時」的調整,每按一次加1個小時;
2. 電路原理圖
3. 系統板上硬體連線
(1. 把「單片機系統」區域中的P1.0-P1.7埠用8芯排線連接到「動態數碼顯示」區域中的A-H埠上;
(2. 把「單片機系統:區域中的P3.0-P3.7埠用8芯排線連接到「動態數碼顯示」區域中的S1-S8埠上;
(3. 把「單片陵型碧機系統」區域中的P0.0/AD0、P0.1/AD1、P0.2/AD2埠分別用導線連接到「獨立式鍵盤」區域中尺舉的SP3、SP2、SP1埠上;
4. 相關基本知識
(1. 動態數碼顯示的方法
(2. 獨立式按鍵識別過程
(3. 「時」,「分」,「秒」數據送出顯示處理方法
5. 程序框圖
6. 匯編源程序
SECOND EQU 30H
MINITE EQU 31H
HOUR EQU 32H
HOURK BIT P0.0
MINITEK BIT P0.1
SECONDK BIT P0.2
DISPBUF EQU 40H
DISPBIT EQU 48H
T2SCNTA EQU 49H
T2SCNTB EQU 4AH
TEMP EQU 4BH
ORG 00H
LJMP START
ORG 0BH
LJMP INT_T0
START: MOV SECOND,#00H
MOV MINITE,#00H
MOV HOUR,#12
MOV DISPBIT,#00H
MOV T2SCNTA,#00H
MOV T2SCNTB,#00H
MOV TEMP,#0FEH
LCALL DISP
MOV TMOD,#01H
MOV TH0,#(65536-2000) / 256
MOV TL0,#(65536-2000) MOD 256
SETB TR0
SETB ET0
SETB EA
WT: JB SECONDK,NK1
LCALL DELY10MS
JB SECONDK,NK1
INC SECOND
MOV A,SECOND
CJNE A,#60,NS60
MOV SECOND,#00H
NS60: LCALL DISP
JNB SECONDK,$
NK1: JB MINITEK,NK2
LCALL DELY10MS
JB MINITEK,NK2
INC MINITE
MOV A,MINITE
CJNE A,#60,NM60
MOV MINITE,#00H
NM60: LCALL DISP
JNB MINITEK,$
NK2: JB HOURK,NK3
LCALL DELY10MS
JB HOURK,NK3
INC HOUR
MOV A,HOUR
CJNE A,#24,NH24
MOV HOUR,#00H
NH24: LCALL DISP
JNB HOURK,$
NK3: LJMP WT
DELY10MS:
MOV R6,#10
D1: MOV R7,#248
DJNZ R7,$
DJNZ R6,D1
RET
DISP:
MOV A,#DISPBUF
ADD A,#8
DEC A
MOV R1,A
MOV A,HOUR
MOV B,#10
DIV AB
MOV @R1,A
DEC R1
MOV A,B
MOV @R1,A
DEC R1
MOV A,#10
MOV @R1,A
DEC R1
MOV A,MINITE
MOV B,#10
DIV AB
MOV @R1,A
DEC R1
MOV A,B
MOV @R1,A
DEC R1
MOV A,#10
MOV @R1,A
DEC R1
MOV A,SECOND
MOV B,#10
DIV AB
MOV @R1,A
DEC R1
MOV A,B
MOV @R1,A
DEC R1
RET
INT_T0:
MOV TH0,#(65536-2000) / 256
MOV TL0,#(65536-2000) MOD 256
MOV A,#DISPBUF
ADD A,DISPBIT
MOV R0,A
MOV A,@R0
MOV DPTR,#TABLE
MOVC A,@A+DPTR
MOV P1,A
MOV A,DISPBIT
MOV DPTR,#TAB
MOVC A,@A+DPTR
MOV P3,A
INC DISPBIT
MOV A,DISPBIT
CJNE A,#08H,KNA
MOV DISPBIT,#00H
KNA: INC T2SCNTA
MOV A,T2SCNTA
CJNE A,#100,DONE
MOV T2SCNTA,#00H
INC T2SCNTB
MOV A,T2SCNTB
CJNE A,#05H,DONE
MOV T2SCNTB,#00H
INC SECOND
MOV A,SECOND
CJNE A,#60,NEXT
MOV SECOND,#00H
INC MINITE
MOV A,MINITE
CJNE A,#60,NEXT
MOV MINITE,#00H
INC HOUR
MOV A,HOUR
CJNE A,#24,NEXT
MOV HOUR,#00H
NEXT: LCALL DISP
DONE: RETI
TABLE: DB 3FH,06H,5BH,4FH,66H,6DH,7DH,07H,7FH,6FH,40H
TAB: DB 0FEH,0FDH,0FBH,0F7H,0EFH,0DFH,0BFH,07FH
END
7. C語言源程序
#include <AT89X51.H>
unsigned char code dispcode[]={0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71,0x00};
unsigned char dispbitcode[]={0xfe,0xfd,0xfb,0xf7,
0xef,0xdf,0xbf,0x7f};
unsigned char dispbuf[8]={0,0,16,0,0,16,0,0};
unsigned char dispbitcnt;
unsigned char second;
unsigned char minite;
unsigned char hour;
unsigned int tcnt;
unsigned char mstcnt;
unsigned char i,j;
void main(void)
{
TMOD=0x02;
TH0=0x06;
TL0=0x06;
TR0=1;
ET0=1;
EA=1;
while(1)
{
if(P0_0==0)
{
for(i=5;i>0;i--)
for(j=248;j>0;j--);
if(P0_0==0)
{
second++;
if(second==60)
{
second=0;
}
dispbuf[0]=second%10;
dispbuf[1]=second/10;
while(P0_0==0);
}
}
if(P0_1==0)
{
for(i=5;i>0;i--)
for(j=248;j>0;j--);
if(P0_1==0)
{
minite++;
if(minite==60)
{
minite=0;
}
dispbuf[3]=minite%10;
dispbuf[4]=minite/10;
while(P0_1==0);
}
}
if(P0_2==0)
{
for(i=5;i>0;i--)
for(j=248;j>0;j--);
if(P0_2==0)
{
hour++;
if(hour==24)
{
hour=0;
}
dispbuf[6]=hour%10;
dispbuf[7]=hour/10;
while(P0_2==0);
}
}
}
}
void t0(void) interrupt 1 using 0
{
mstcnt++;
if(mstcnt==8)
{
mstcnt=0;
P1=dispcode[dispbuf[dispbitcnt]];
P3=dispbitcode[dispbitcnt];
dispbitcnt++;
if(dispbitcnt==8)
{
dispbitcnt=0;
}
}
tcnt++;
if(tcnt==4000)
{
tcnt=0;
second++;
if(second==60)
{
second=0;
minite++;
if(minite==60)
{
minite=0;
hour++;
if(hour==24)
{
hour=0;
}
}
}
dispbuf[0]=second%10;
dispbuf[1]=second/10;
dispbuf[3]=minite%10;
dispbuf[4]=minite/10;
dispbuf[6]=hour%10;
dispbuf[7]=hour/10;
}
② 急求一個用51單片機編的可按鍵調時的數字時鍾程序,數碼管顯示,C語言編寫,謝謝。
#include <reg51.h>
#include <intrins.h>
unsigned char code dis_week[]={"SUN,MON,TUE,WED,THU,FRI,SAT"};
unsigned char code para_month[13]={0,0,3,3,6,1,4,6,2,5,0,3,5};//星期月參變數
unsigned char data dis_buf1[16];//lcd上排顯示緩沖區
unsigned char data dis_buf2[16];//lcd下排顯示緩沖區
unsigned char data year,month,date,week;//年、月、日、星期
unsigned char data armhour,armmin,armsec;//鬧鍾時、分、秒
unsigned char data hour,min,sec,sec100;//時、分、秒、百分之一秒
unsigned char data flag,vkey,skey;//設置狀態計數標志、按鍵先前值、按鍵當前值
bitalarm;//標識是否啟用鬧鍾,1--啟用,0--關閉
sbit rs = P2^0;//LCD數據/命令選擇端(H/L)
sbit rw = P2^1;//LCD讀/寫選擇端(H/L)
sbit ep = P2^2;//LCD使能控制
sbitPRE = P3^3;//調整鍵(AN3)
sbitSET = P3^4;//調整鍵(AN4)
sbitSPK = P3^6;
void delayms(unsigned char ms);//延時程序
bit lcd_busy();//測試LCD忙碌狀態程序
void lcd_wcmd(char cmd);//寫入指令到LCD程序
void lcd_wdat(char dat);//寫入數據到LCD程序
void lcd_pos(char pos);//LCD數據指針位置程序
void lcd_init();//LCD初始化設定程序
void pro_timedate();//時間日期處理程序
void pro_display();//顯示處理程序
void pro_key();//按鍵處理程序
void time_alarm();//定時報警功能(鬧鍾)
unsigned char scan_key();//按鍵掃描程序
unsigned char week_proc();//星期自動計算與顯示函數
bit leap_year();//判斷是否為閏年
void lcd_sef_chr();//LCD自定義字元程序
void update_disbuf(unsigned char t1,unsigned char t2[],unsigned char dis_h,unsigned char dis_m,unsigned char dis_s);
//更新顯示緩沖區函數
// 延時程序
void delay(unsigned char ms)
{while(ms--)
{unsigned char i;
for(i = 0; i< 250; i++)
{
_nop_(); //執行一條_nop_()指令為一個機器周期
_nop_();
_nop_();
_nop_();
}
}
}
//測試LCD忙碌狀態
bit lcd_busy()
{
bit result;
rs = 0;
rw = 1;
ep = 1;
_nop_();
_nop_();
_nop_();
_nop_();
result =(bit)(P0&0x80);//LCD的D0--D7中,D7=1為忙碌,D7=0為空閑
ep = 0;
return result;
}
//寫入指令到LCD
void lcd_wcmd(char cmd)
{
while(lcd_busy());//當lcd_busy為1時,再次檢測LCD忙碌狀態,lcd-busy為0時,開始寫指令
rs = 0;
rw = 0;
ep = 0;
_nop_();
_nop_();
P0 = cmd;
_nop_();
_nop_();
_nop_();
_nop_();
ep = 1;
_nop_();
_nop_();
_nop_();
_nop_();
ep = 0;
}
//寫入數據到LCD
void lcd_wdat(char dat)
{
while(lcd_busy());//當lcd_busy為1時,再次檢測LCD忙碌狀態,lcd-busy為0時,開始寫數據
rs = 1;
rw = 0;
ep = 0;
P0 = dat;
_nop_();
_nop_();
_nop_();
_nop_();
ep = 1;
_nop_();
_nop_();
_nop_();
_nop_();
ep = 0;
}
//LCD數據指針位置程序
void lcd_pos(char pos)
{
lcd_wcmd(pos|0x80);//數據指針=80+地址碼(00H~27H,40H~67H)
}
//設定二個自定義字元,(注意:LCD1602中自定義字元的地址為0x00--0x07,即可定義8個字元)
//這里我們設定把一個自定義字元放在0x00位置(000),另一個放在0x01位子(001)
void lcd_sef_chr()
{//第一個自定義字元
lcd_wcmd(0x40);//"01 000 000" 第1行地址 (D7D6為地址設定命令形式D5D4D3為字元存放位置(0--7),D2D1D0為字元行地址(0--7))
lcd_wdat(0x1f);//"XXX 11111"第1行數據(D7D6D5為XXX,表示為任意數(一般用000),D4D3D2D1D0為字元行數據(1-點亮,0-熄滅)
lcd_wcmd(0x41);//"01 000 001" 第2行地址
lcd_wdat(0x11);//"XXX 10001"第2行數據
lcd_wcmd(0x42);//"01 000 010" 第3行地址
lcd_wdat(0x15);//"XXX 10101"第3行數據
lcd_wcmd(0x43);//"01 000 011" 第4行地址
lcd_wdat(0x11);//"XXX 10001"第4行數據
lcd_wcmd(0x44);//"01 000 100" 第5行地址
lcd_wdat(0x1f);//"XXX 11111"第5行數據
lcd_wcmd(0x45);//"01 000 101" 第6行地址
lcd_wdat(0x0a);//"XXX 01010"第6行數據
lcd_wcmd(0x46);//"01 000 110" 第7行地址
lcd_wdat(0x1f);//"XXX 11111"第7行數據
lcd_wcmd(0x47);//"01 000 111" 第8行地址
lcd_wdat(0x00);//"XXX 00000"第8行數據
//第二個自定義字元
lcd_wcmd(0x48);//"01 001 000" 第1行地址
lcd_wdat(0x01);//"XXX 00001"第1行數據
lcd_wcmd(0x49);//"01 001 001" 第2行地址
lcd_wdat(0x1b);//"XXX 11011"第2行數據
lcd_wcmd(0x4a);//"01 001 010" 第3行地址
lcd_wdat(0x1d);//"XXX 11101"第3行數據
lcd_wcmd(0x4b);//"01 001 011" 第4行地址
lcd_wdat(0x19);//"XXX 11001"第4行數據
lcd_wcmd(0x4c);//"01 001 100" 第5行地址
lcd_wdat(0x1d);//"XXX 11101"第5行數據
lcd_wcmd(0x4d);//"01 001 101" 第6行地址
lcd_wdat(0x1b);//"XXX 11011"第6行數據
lcd_wcmd(0x4e);//"01 001 110" 第7行地址
lcd_wdat(0x01);//"XXX 00001"第7行數據
lcd_wcmd(0x4f);//"01 001 111" 第8行地址
lcd_wdat(0x00);//"XXX 00000"第8行數據
}
//LCD初始化設定
void lcd_init()
{
lcd_wcmd(0x38);//設置LCD為16X2顯示,5X7點陣,八位數據借口
delay(1);
lcd_wcmd(0x0c);//LCD開顯示及游標設置(游標不閃爍,不顯示"-")
delay(1);
lcd_wcmd(0x06);//LCD顯示游標移動設置(游標地址指針加1,整屏顯示不移動)
delay(1);
lcd_wcmd(0x01);//清除LCD的顯示內容
delay(1);
}
//閏年的計算
bit leap_year()
{
bit leap;
if((year%4==0&&year%100!=0)||year%400==0)//閏年的條件
leap=1;
else
leap=0;
return leap;
}
//星期的自動運算和處理
unsigned char week_proc()
{unsigned char num_leap;
unsigned char c;
num_leap=year/4-year/100+year/400;//自00年起到year所經歷的閏年數
if( leap_year()&& month<=2 ) //既是閏年且是1月和2月
c=5;
else
c=6;
week=(year+para_month[month]+date+num_leap+c)%7;//計算對應的星期
return week;
}
//更新顯示緩沖區
void update_disbuf(unsigned char t1,unsigned char t2[],unsigned char dis_h,unsigned char dis_m,unsigned char dis_s)
{dis_buf1[0]=t1; //
dis_buf1[1]=0x20; //空格
dis_buf1[2]=50; //'2'
dis_buf1[3]=48; //'0'
dis_buf1[4]=year/10+48;
dis_buf1[5]=year%10+48;
dis_buf1[6]=0x2d;
dis_buf1[7]=month/10+48;
dis_buf1[8]=month%10+48;
dis_buf1[9]=0x2d; //'-'
dis_buf1[10]=date/10+48;
dis_buf1[11]=date%10+48;
dis_buf1[12]=0x20;
dis_buf1[13]=dis_week[4*week];
dis_buf1[14]=dis_week[4*week+1];
dis_buf1[15]=dis_week[4*week+2];
dis_buf2[0]=t2[0];
dis_buf2[1]=t2[1];
dis_buf2[2]=t2[2];
dis_buf2[3]=t2[3];
dis_buf2[4]=t2[4];
dis_buf2[5]=t2[5];
dis_buf2[6]=t2[6];//空格
if (alarm)
dis_buf2[7]=0x01;//alarm=1,顯示鬧鍾啟用標致(第二個自定義字元)
else
dis_buf2[7]=0x20;//alarm=0,不顯示鬧鍾啟用標致
dis_buf2[8]=dis_h/10+48;
dis_buf2[9]=dis_h%10+48;
dis_buf2[10]=0x3a;//':'
dis_buf2[11]=dis_m/10+48;
dis_buf2[12]=dis_m%10+48;
dis_buf2[13]=0x3a;
dis_buf2[14]=dis_s/10+48;
dis_buf2[15]=dis_s%10+48;
}
//時間和日期處理程序
void pro_timedate()
{
sec++;
if(sec > 59)
{sec = 0;
min++;
if(min>59)
{min=0;
hour++;
if(hour>23)
{hour=0;
date++;
if (month==1||month==3||month==5||month==7||month==8||month==10||month==12)
if (date>31) {date=1;month++;}//大月31天
if (month==4||month==6||month==9||month==11)
if (date>30) {date=1;month++;}//小月30天
if (month==2)
{if( leap_year())//閏年的條件
{if (date>29) {date=1;month++;}}//閏年2月為29天
else
{if (date>28) {date=1;month++;}}//平年2月為28天
}
if (month>12) {month=1;year++;}
if (year>99) year=0;
}
}
}
week_proc();
if (sec==armsec && min==armmin && hour==armhour)
{if (alarm)
TR1=1;//鬧鍾啟用時,報警時間到,啟動Timer1
}
}
//顯示處理程序
void pro_display()
{unsigned char i;
lcd_pos(0x00);
for (i=0;i<=15;i++)
{lcd_wdat(dis_buf1[i]);}
lcd_pos(0x40);
for (i=0;i<=15;i++)
{lcd_wdat(dis_buf2[i]);}
}
//Timer0中斷處理程序,秒的產生
void timer0() interrupt 1
{
TH0=0xD8;
TL0=0xF0;
sec100++;
if(sec100 >= 100)//1秒時間 (100*10ms=1000ms=1s)
{sec100 = 0;
pro_timedate();//調用時間和日期處理程序
}
if (sec&0x01)//"RICHMCU"閃一秒,停一秒
update_disbuf(0x00," ",hour,min,sec); //0x00表示顯示00位置的自定義字元
else
update_disbuf(0x00,"RICHMCU",hour,min,sec);
pro_display(); //調用顯示處理函數
}
//按鍵掃描程序
unsigned char scan_key()
{
skey=0x00;//給變數vkey置初值
skey|=PRE;//讀取PRE鍵的狀態
skey=skey<<1;//將PRE鍵的狀態存於skey的B1位
skey|=SET;//讀取SET鍵的狀態,並存於skey的B0位
return skey;//返回skey的鍵值(即PRE,SET的狀態)
}
//外部中斷INT0中斷處理程序
void int0() interrupt 0
{
TR0=0;//禁止Timer0
IE=0;//禁止中斷
lcd_wcmd(0x0e);//顯示游標"_",整個游標不閃爍
alarm=1;
update_disbuf(0x50,"alarm:",armhour,armmin,armsec);//更新顯示數據,0x50表示要顯示"P"
pro_display();//調用顯示處理程序
lcd_pos(0x47); //使游標位於第一個調整項下
flag=0;
vkey=0x03;
while(flag^0x0a)
{skey = scan_key();//掃描按鍵狀態
if (skey^vkey)//若skey與vkey相同,跳出循環,相異執行循環體
{delay(10);//去按鍵抖動
skey = scan_key();//轉回掃描按鍵狀態
if (skey^vkey)//若skey與vkey相同,跳出循環,相異執行循環體
{vkey=skey;//將skey的值付給vkey
if (skey==0x01)//PRE鍵按下
{ flag++;//調整標志位加1
switch (flag)//將游標置於相應調整位置
{
case 1: lcd_pos(0x49);break;//游標置小時報警設置位置
case 2:lcd_pos(0x4c);break;//游標置分鍾報警設置位置
case 3:lcd_pos(0x4f);break;//游標置秒時報警設置位置
case 4:update_disbuf(0x50,"time: ",hour,min,sec);
pro_display();
lcd_pos(0x05);break;//游標置年調整位置
case 5:lcd_pos(0x08);break;//游標置月調整位置
case 6:lcd_pos(0x0b);break;//游標置日調整位置
case 7: lcd_pos(0x49);break;//游標置時調整位置
case 8:lcd_pos(0x4c);break;//游標置分調整位置
case 9:lcd_pos(0x4f);break;//游標置秒調整位置
default:break;
}
}
if (skey==0x02) //SET鍵按下
{pro_key();//轉設置按鍵處理程序
}
}
}
}
lcd_wcmd(0x0c);//設置LCD開顯示及游標不閃爍,不顯示"-"
lcd_wcmd(0x01); //清除LCD的顯示內容
IE=0x8f; //CPU開中斷,INT0,INT1,開中斷
TR0=1;//Timer0啟動
}
//主程序,初始化及初值設定
void main()
{
lcd_init(); //初始化LCD
lcd_sef_chr();//寫入自定義字元號
hour=0;min=0;sec=0; //開機時的時,分,秒顯示
armhour=0;armmin=0;armsec=0;//開機時的時,分,秒報警初值
year= 5; month=1;date=1; //開機時的年,月,日,星期顯示
week_proc();
alarm=1;//初始開機,啟用鬧鍾
IE = 0x8f;//CPU開中斷,INT0,INT1,Timer0,Timer1開中斷
IP = 0x04;//設置INT0為中斷最高優先順序
IT0=0;IT1=0;//外部INT0,INT1設置為電平觸發方式(注意,觸發不要選邊沿方式,易誤動)
TMOD = 0x11;//Timer0,Timer1工作於模式1, 16位定時方式
TH0 = 0xdc;TL0 = 0x00;//Timer0置10ms定時初值
TH1 = 0xff;TL1 = 0x00;//Timer1置初值
TR0 = 1;//Timer0啟動
TR1 = 0;
while(1);
}
//設置按鍵處理程序
void pro_key()
{
switch (flag)
{
case 0:alarm=!alarm;//啟用或關閉鬧鍾(alarm=1:啟用,alarm=0:關閉)
update_disbuf(0x50,"alarm:",armhour,armmin,armsec); //更新顯示數據
pro_display();//調用顯示處理
lcd_pos(0x47);break;//游標回到原調整位置
case 1:armhour++;
if (armhour>23) armhour=0;
update_disbuf(0x50,"alarm:",armhour,armmin,armsec); //更新顯示數據
pro_display();//調用顯示處理
lcd_pos(0x49);break;//游標回到原調整位置
case 2:armmin++;
if (armmin>59) armmin=0;
update_disbuf(0x50,"alarm:",armhour,armmin,armsec);
pro_display();
lcd_pos(0x4c);break;
case 3:armsec++;
if (armsec>59) armsec=0;
update_disbuf(0x50,"alarm:",armhour,armmin,armsec);
pro_display();
lcd_pos(0x4f);break;
case 4:year++;
if(year> 99) year= 0;
week_proc(); //星期自動運算
update_disbuf(0x50,"time: ",hour,min,sec);
pro_display();
lcd_pos(0x05);break;
case 5:month++;
if (month>12) month=1;
week_proc();//星期自動運算
update_disbuf(0x50,"time: ",hour,min,sec);
pro_display();
lcd_pos(0x08);break;
case 6:date++;
if (month==1||month==3||month==5||month==7||month==8||month==10||month==12)
if (date>31) date=1;//大月31天
if (month==4||month==6||month==9||month==11)
if (date>30) date=1;//小月30天
if (month==2)
{if(leap_year())//閏年的條件
{if (date>29) date=1;}//閏年2月為29天
else
{if (date>28) date=1;}}//平年2月為28天
week_proc(); //星期自動運算
update_disbuf(0x50,"time: ",hour,min,sec);
pro_display();
lcd_pos(0x0b);break;
case 7:hour++;
if (hour>23) hour=0;
update_disbuf(0x50,"time: ",hour,min,sec);
pro_display();
lcd_pos(0x49);break;
case 8:min++;
if (min>59) min=0;
update_disbuf(0x50,"time: ",hour,min,sec);
pro_display();
lcd_pos(0x4c);break;
case 9:sec++;
if (sec>59) sec=0;
update_disbuf(0x50,"time: ",hour,min,sec);
pro_display();
lcd_pos(0x4f);break;
default: break ;
}
}
//Timer1中斷處理程序,產生報警的聲音
void timer1() interrupt 3
{
TH1=0xff;
TL1=0x00;
SPK=~SPK;
}
//外部中斷INT1中斷處理程序,停止報警聲音
void int1() interrupt 2
{
if(TR1)
TR1=0;
}
實驗說明:
按K1按鍵進入設定狀態
按K2,依次進入鬧鍾功能是否啟用,鬧鍾時,分秒,年,月,日及時間時,分,秒的設置,直到退出設置狀態
按K3,調整是否起用鬧鍾和調節鬧鍾時,分,秒,年,月,日,時間的時,分,秒的數字
LCD第二排中間顯示小喇叭,表示啟用鬧鍾功能,無則禁止鬧鍾功能(可在調整狀態進行設置)
正常狀態,LCD上排最前面顯示自定義字元,LCD下排最前面閃動"RICHMCU"
設置狀態,LCD上排最前面顯示"P",下排最前面在設置鬧鍾時間時顯示"alarm:",其它狀態顯示"time"
年代變化2000--2099,星期自動轉換
望採納,謝謝~~
③ 51單片機實現數字時鍾,用四位數碼管實現分計時,顯示分和秒,可以任意設置時間。
1、將分(秒)中的數字位分離
2、控制顯示在相應數碼管
3、數碼管如果採用動態掃描實現,要注意位選和段選
4.更多交流參考我空間文章。
④ 急救!!!各位兄弟姐妹們誰懂單片機編程啊,幫幫我啊!用單片機編輯一個數字鍾的程序啊,要求如下:
給你一個我用液晶屏12864寫的程序,一個是功能鍵,按照順序按一下是第一位跳動,接下再按就是第二位,一次類推。第二個按鍵是控制加,第三個按鍵是控制減,你的數碼管和這個很類似,比這個還簡單,在這你也沒有要求數碼管是怎麼接的。你可以參考的。
#include<reg52.h>
#include<chushihua.h> //12864的初始化函數;
char gwnian,nian,yue,ri,xq,shi,fen,miao;
sbit DQ =P3^5; //定義DS18B20通信埠
sbit led_en_port = P2^5; /*發光二極體寄存器LE引腳*/
sbit sled_en_port = P3^6; /*數碼管寄存器LE引腳*/
sbit key1=P1^0;
sbit key2=P1^1;
sbit key3=P1^2;
uchar code mun_to_char[] = {"0123456789"}; /*數字轉換為ASCII字元碼*/
uchar table[]={"製作人:"};
uchar table2[]={"2009年11月28日晚"};
uchar table1[]={"江向陽"};
uchar table31[]={"年"};
uchar table32[]={"月"};
uchar table33[]={"日"};
uchar table4[]={"星期"};
uchar table51[]={"時"};
uchar table52[]={"分"};
uchar table53[]={"秒"};
uchar table6[]={"當前溫度:20.3"};
//uchar table61[]={"??度"};
uchar xq1[]={"一"};
uchar xq2[]={"二"};
uchar xq3[]={"叄"};
uchar xq4[]={"四"};
uchar xq5[]={"五"};
uchar xq6[]={"六"};
uchar xq7[]={"日"};
/***************寫星期函數*******************/
write_xq(uchar z)
{
uchar num;
write_com(0x90+5);
switch(z)
{
case 1: for(num=0;num<2;num++)
{
write_date(xq1[num]);
delay(1);
}
break;
case 2: for(num=0;num<2;num++)
{
write_date(xq2[num]);
delay(1);
}
break;
case 3: for(num=0;num<2;num++)
{
write_date(xq3[num]);
delay(1);
}
break;
case 4: for(num=0;num<2;num++)
{
write_date(xq4[num]);
delay(1);
}
break;
case 5: for(num=0;num<2;num++)
{
write_date(xq5[num]);
delay(1);
}
break;
case 6: for(num=0;num<2;num++)
{
write_date(xq6[num]);
delay(1);
}
break;
case 7: for(num=0;num<2;num++)
{
write_date(xq7[num]);
delay(1);
}
break;
}
}
/*************寫年月日函數**************/
void write_nyr(uchar date,uchar add)
{
uchar shi,ge;
shi=date/10;
ge=date%10;
write_com(0x80+add);
write_date(0x30+shi);
write_date(0x30+ge);
}
/*************寫時分秒函數**************/
void write_sfm(uchar date,uchar add)
{
uchar shi,ge;
shi=date/10;
ge=date%10;
write_com(0x88+add);
write_date(0x30+shi);
write_date(0x30+ge);
}
/*****************鍵盤掃描*****************/
void keyscan()
{
uchar keynum;
if(key1==0)
{
delay(5);
if(key1==0)
{
while(!key1);
delay(5);
while(!key1);
keynum++;
TR0=0;
if(keynum==1)
{
//TR0=0;
write_com(0x8D);
write_com(0x0f);
}
if(keynum==2)
{
//TR0=0;
write_com(0x8B);
write_com(0x0f);
}
if(keynum==3)
{
//TR0=0;
write_com(0x89);
write_com(0x0f);
}
if(keynum==4)
{
//TR0=1;
write_com(0x95);
write_com(0x0f);
}
if(keynum==5)
{
//TR0=1;
write_com(0x85);
write_com(0x0f);
}
if(keynum==6)
{
//TR0=1;
write_com(0x83);
write_com(0x0f);
}
if(keynum==7)
{
//TR0=1;
write_com(0x81);
write_com(0x0f);
}
if(keynum==8)
{
//TR0=1;
write_com(0x80);
write_com(0x0f);
}
if(keynum==9)
{
TR0=1;
keynum=0;
//write_com(0x95);
write_com(0x0c);
}
}
}
if(keynum==1)
{
if(key2==0)
{
delay(5);
if(key2==0)
{
while(!key2);
delay(5);
while(!key2);
miao++;
if(miao==60)
miao=0;
write_sfm(miao,5);
write_com(0x8D);
}
}
if(key3==0)
{
delay(5);
if(key3==0)
{
while(!key3);
delay(5);
while(!key3);
miao--;
if(miao==-1)
miao=59;
write_sfm(miao,5);
write_com(0x8D);
}
}
}
if(keynum==2)
{
if(key2==0)
{
delay(5);
if(key2==0)
{
while(!key2);
delay(5);
while(!key2);
fen++;
if(fen==60)
fen=0;
write_sfm(fen,3);
write_com(0x8B);
}
}
if(key3==0)
{
delay(5);
if(key3==0)
{
while(!key3);
delay(5);
while(!key3);
fen--;
if(fen==-1)
fen=59;
write_sfm(fen,3);
write_com(0x8B);
}
}
}
if(keynum==3)
{
if(key2==0)
{
delay(5);
if(key2==0)
{
while(!key2);
delay(5);
while(!key2);
shi++;
if(shi==24)
shi=0;
write_sfm(shi,1);
write_com(0x89);
}
}
if(key3==0)
{
delay(5);
if(key3==0)
{
while(!key3);
delay(5);
while(!key3);
shi--;
if(shi==-1)
shi=23;
write_sfm(shi,1);
write_com(0x89);
}
}
}
if(keynum==4)
{
if(key2==0)
{
delay(5);
if(key2==0)
{
while(!key2);
delay(5);
while(!key2);
xq++;
if(xq==8)
xq=1;
write_xq(xq);
write_com(0x95);
}
}
if(key3==0)
{
delay(5);
if(key3==0)
{
while(!key3);
delay(5);
while(!key3);
xq--;
if(xq==0)
xq=7;
write_xq(xq);
write_com(0x95);
}
}
}
if(keynum==5)
{
if(key2==0)
{
delay(5);
if(key2==0)
{
while(!key2);
delay(5);
while(!key2);
ri++;
if(ri==31)
ri=1;
write_nyr(ri,5);
write_com(0x85);
}
}
if(key3==0)
{
delay(5);
if(key3==0)
{
while(!key3);
delay(5);
while(!key3);
ri--;
if(ri==0)
ri=30;
write_nyr(ri,5);
write_com(0x85);
}
}
}
if(keynum==6)
{
if(key2==0)
{
delay(5);
if(key2==0)
{
while(!key2);
delay(5);
while(!key2);
yue++;
if(yue==13)
yue=1;
write_nyr(yue,3);
write_com(0x83);
}
}
if(key3==0)
{
delay(5);
if(key3==0)
{
while(!key3);
delay(5);
while(!key3);
yue--;
if(yue==0)
yue=12;
write_nyr(yue,3);
write_com(0x83);
}
}
}
if(keynum==7)
{
if(key2==0)
{
delay(5);
if(key2==0)
{
while(!key2);
delay(5);
while(!key2);
nian++;
if(nian==100)
nian=0;;
write_nyr(nian,1);
write_com(0x81);
}
}
if(key3==0)
{
delay(5);
if(key3==0)
{
while(!key3);
delay(5);
while(!key3);
nian--;
if(nian==-1)
nian=99;
write_nyr(nian,1);
write_com(0x81);
}
}
}
if(keynum==8)
{
if(key2==0)
{
delay(5);
if(key2==0)
{
while(!key2);
delay(5);
while(!key2);
gwnian++;
if(gwnian==100)
gwnian=0;
write_nyr(gwnian,0);
write_com(0x80);
}
}
if(key3==0)
{
delay(5);
if(key3==0)
{
while(!key3);
delay(5);
while(!key3);
gwnian--;
if(gwnian==-1)
gwnian=99;
write_nyr(gwnian,0);
write_com(0x80);
}
}
}
}
/************主函數********************/
void main()
{
uint num;
led_en_port = 0;/*關閉發光二極體顯示*/
sled_en_port = 0;/*關閉數碼管顯示*/
gwnian=20;
nian=9;
yue=11;
ri=28;
xq=6;
shi=23;
fen=58;
miao=45;
init(); //12864液晶初始化;
write_com(0x80);//設置初始顯示的坐標;
for(num=0;num<8;num++) /******在第一行顯示製作人*******/
{
write_date(table[num]);
delay(100);
}
write_com(0x93); //第二行的初始坐標;
for(num=0;num<6;num++) /**********在第二行顯示江向陽*******/
{
write_date(table1[num]);
delay(100);
}
write_com(0x88);//第三行的初始坐標
for(num=0;num<16;num++) /******在第三行顯示製作時間*******/
{
write_date(table2[num]);
delay(100);
}
for(num=50;num>0;num--) ///延時,第一屏的顯示時間 ;
delay(50000);
TMOD=0x01; //定時器0工作方式1;
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
EA=0X01;
ET0=0X01;
TR0=0X01;
write_com(0x01);//清屏;
// delay(5);
// write_com(0x01);
write_com(0x80); //寫入初始的年月日數據(2009-11-28);
write_date('2');
write_date('0');
write_date('0');
write_date('9');
write_com(0x83);
write_date('1');
write_date('1');
write_com(0x85);
write_date('2');
write_date('8');
write_com(0x95);
for(num=0;num<2;num++) //寫入星期函數(周六);
{
write_date(xq6[num]);
}
write_com(0x89); //寫入初始的時分秒函數(23:58:45);
write_date('2');
write_date('3');
write_com(0x8B);
write_date('5');
write_date('8');
write_com(0x8D);
write_date('4');
write_date('5');
write_com(0x82);
for(num=0;num<2;num++) //固定顯示『年』
{
write_date(table31[num]);
delay(1);
}
write_com(0x84);
for(num=0;num<2;num++) //固定顯示『月』
{
write_date(table32[num]);
delay(1);
}
write_com(0x86); //固定顯示『日』
for(num=0;num<2;num++)
{
write_date(table33[num]);
delay(1);
}
write_com(0x92); //固定顯示『星期』
for(num=0;num<4;num++)
{
write_date(table4[num]);
delay(1);
}
write_com(0x8A); //固定顯示'時'
for(num=0;num<2;num++)
{
write_date(table51[num]);
delay(1);
}
write_com(0x8C); //固定顯示'分'
for(num=0;num<2;num++)
{
write_date(table52[num]);
delay(1);
}
write_com(0x8E); //固定顯示'秒'
for(num=0;num<2;num++)
{
write_date(table53[num]);
delay(1);
}
write_com(0x98); //固定顯示'當前溫度:20.3'
for(num=0;num<14;num++)
{
write_date(table6[num]);
delay(1);
}
/***************顯示溫度字元命令****************/
write_com(0x64); //開啟擴展指令顯示;
write_com(0x9f); //設置顯示地址 ;
write_date(0xA1); //顯示的字元編碼地址;
write_date(0xE6);
write_com(0x66); //關閉擴展功能;
while(1)
{
keyscan;
}
}
void timer0() interrupt 1
{
uchar count;
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
count++;
if(count==18)
{
count=0;
miao++;
if(miao==60)
{
miao=0;
fen++;
if(fen==60)
{
fen=0;
shi++;
if(shi==24)
{
shi=0;
ri++;
xq++;
if(xq==8)
{
xq=1;
}
if(ri==31)
{
ri=1;
yue++;
if(yue==13)
{
yue=1;
nian++;
if(nian==100)
{
nian=0;
gwnian++;
if(gwnian==100)
gwnian=0;
write_nyr(gwnian,0);
}
write_nyr(nian,1);
}
write_nyr(yue,3);
}
write_xq(xq);
write_nyr(ri,5);
}
write_sfm(shi,1);
}
write_sfm(fen,3);
}
write_sfm(miao,5);
}
}