『壹』 單片機做數字時鍾,求程序
1、解決驅動碼。得到顯示所有字元的七段碼。
2、解決動態掃描問題。在定時中斷中順序掃描其中一個數碼管。
3、解決內容——定時的計時表述。Hour,Minute,Second,mS;
4、解決時間的修改設置。
1、通用碼表
#define SEGA 1
#define SEGB 2
#define SEGC 4
#define SEGD 8
#define SEGE 0x10
#define SEGF 0x20
#define SEGG 0x40
#define SEGH 0x80
unsigned char code SegCode[11]=
{ ~(SEGA+SEGB+SEGC+SEGD+SEGE+SEGF),//0
~(SEGB+SEGC),//1
~(SEGA+SEGB+SEGD+SEGE+SEGG),//2
~(SEGA+SEGB+SEGC+SEGD+SEGG),//3
~(SEGB+SEGC+SEGF+SEGG),//4
~(SEGA+SEGC+SEGD+SEGF+SEGG),//5
~(SEGA+SEGC+SEGD+SEGE+SEGF+SEGG),//6
~(SEGA+SEGB+SEGC),//7
~(SEGA+SEGB+SEGC+SEGD+SEGE+SEGF+SEGG),//8
~(SEGA+SEGB+SEGC+SEGD+SEGF+SEGG),//9
~(SEGG),//—
};
2、動態掃描,內容放在
unsigned char i, Time[8]={0,0,0xa,0,0,0xa,0,0};
void Disp(unsigned char x)//顯示第x個數碼管的內容。
{
P0=0xff;
P1=SegCode[Time[x]];
P0=~(1<<x);
}
在定時中斷中調用。
3、定時管理並得到50mS時基。按12MHz,定時1方式,定時器0配置中斷。
定義unsigned char mS50,Sec,Min,Hour;
void InitialT0(void)//主程序調用一次
{
TMOD=0x1;
ET0=1;EA=1;TR0=1;
}
void ISRForT0(void) interrupt 1
{
TH0=(-50000)>>8;
TL0=(-50000)&0xff;
mS50++;
Disp(i++%8);
if(mS50>19)
{
mS50=0;
Sec++;
if(Sec>59){Sec=0;Min++;if(Min>59){Min=0;Hour++;Hour%=24;}}
Time[0]=Hour/10;
Time[1]=Hour%10;
Time[3]=Min/10;
Time[4]=Min%10;
Time[6]=Sec/10;
Time[7]=Sec%10;
}
}
4、修改時間的問題,還是等你自己忙吧。放到while(1)裡面讀鍵,修改Hour,Min,Sec即可。
main函數如下:把上面的代碼全部搞到一起,編譯通過後調試吧。
main()
{
InitialT0();
while(1);
}
【補充一下,明天數碼管會閃的厲害。把中斷時間改成2mS,再試一遍。】
『貳』 單片機數字時鍾比實際時間的慢啊怎麼辦
單片機是利用定時器實現計時的,根據定時器的定時計算出的時間常數,是理想狀態下的數值。
如晶振頻率是12M,用定時器T0,按定時20ms 計算的時間常數
TH0=(65536-20000)/256=0XB1
TL0=(65536-20000)%256=0XE0
如果按這個數寫程序,電子鍾計時的時間肯定就比實際的時間慢。當然了,這需要時間長了,才能體現出來,如果只是計時幾個小時是比較不出來的。必須是長時間的計時,比如計時一周以上就體現出來計時的誤差了。
這是因為,單片機計時的誤差還是比較小的,假如一天慢1秒,那計時一周了,就慢7秒,才會發現的。
為什麼會慢呢,是因為定時到,要中斷,單片機從響應中斷,到在中斷程序中重寫時間常數,才能重新計時的,這是需要時間,只是這時間只有幾個微秒。就產生了計時誤差了。可是這向微秒的誤差,累計一周後就累計成幾秒了。
要計時比較准確的還是有辦法的,就是給時間常數的TL0加幾個數,來補償誤差。
通常加8就行,不過,還需要長時間的計時來校正。
在中斷程序中的時間常數改為
TH0=0XB1;
TL0=0XE8; //這低8位加8,補償誤差
這樣補償後,還有誤差,再改這低8位,慢了就加,快了就減
『叄』 基於單片機的數字時鍾怎麼做
#include<reg52.h>
#define uchar unsigned char
#define uint unsigned int
sbit la=P2^6;
sbit wela=P2^7;
sbit rs=P3^5;
sbit lcden=P3^4;
sbit s1=P3^0;
sbit s2=P3^1;
sbit s3=P3^2;
sbit rd=P3^7;
uchar count,s1num;
char miao,shi,fen;
uchar code table[]=" 2007-7-30 MON";
uchar code table1[]=" 00:00:00";
void delay(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
void write_com(uchar com)
{
rs=0;
lcden=0;
P0=com;
delay(5);
lcden=1;
delay(5);
lcden=0;
}
void write_date(uchar date)
{
rs=1;
lcden=0;
P0=date;
delay(5);
lcden=1;
delay(5);
lcden=0;
}
void init()
{
uchar num;
la=0;
wela=0;
lcden=0;
// fen=59;
// miao=53;
// shi=23;
write_com(0x38);
write_com(0x0c);
write_com(0x06);
write_com(0x01);
write_com(0x80);
for(num=0;num<15;num++)
{
write_date(table[num]);
delay(5);
}
write_com(0x80+0x40);
for(num=0;num<12;num++)
{
write_date(table1[num]);
delay(5);
}
TMOD=0x01;
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
EA=1;
ET0=1;
TR0=1;
}
void write_sfm(uchar add,uchar date)
{
uchar shi,ge;
shi=date/10;
ge=date%10;
write_com(0x80+0x40+add);
write_date(0x30+shi);
write_date(0x30+ge);
}
void keyscan()
{
rd=0;
if(s1==0)
{
delay(5);
if(s1==0)
{ s1num++;
while(!s1);
if(s1num==1)
{
TR0=0;
write_com(0x80+0x40+10);
write_com(0x0f);
}
}
if(s1num==2)
{
write_com(0x80+0x40+7);
}
if(s1num==3)
{
write_com(0x80+0x40+4);
}
if(s1num==4)
{
s1num=0;
write_com(0x0c);
TR0=1;
}
}
if(s1num!=0)
{
if(s2==0)
{
delay(5);
if(s2==0)
{
while(!s2);
if(s1num==1)
{
miao++;
if(miao==60)
miao=0;
write_sfm(10,miao);
write_com(0x80+0x40+10);
}
if(s1num==2)
{
fen++;
if(fen==60)
fen=0;
write_sfm(7,fen);
write_com(0x80+0x40+7);
}
if(s1num==3)
{
shi++;
if(shi==24)
shi=0;
write_sfm(4,shi);
write_com(0x80+0x40+4);
}
}
}
if(s3==0)
{
delay(5);
if(s3==0)
{
while(!s3);
if(s1num==1)
{
/* if(miao==0)
{
miao=59;
write_sfm(10,miao);
write_com(0x80+0x40+10);
}*/
miao--;
if(miao==-1)
miao=59;
write_sfm(10,miao);
write_com(0x80+0x40+10);
}
if(s1num==2)
{
fen--;
if(fen==-1)
fen=59;
write_sfm(7,fen);
write_com(0x80+0x40+7);
}
if(s1num==3)
{
shi--;
if(shi==-1)
shi=23;
write_sfm(4,shi);
write_com(0x80+0x40+4);
}
}
}
}
}
void main()
{
init();
while(1)
{
keyscan();
}
// while(1);
}
void timer0() interrupt 1
{
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;
}
write_sfm(4,shi);
}
write_sfm(7,fen);
}
write_sfm(10,miao);
}
}
這個是數字時鍾的源程序,用12864夜晶顯示。
『肆』 怎麼用單片機製作可調數字時鍾
AJMPMAIN
ORG03H
MOVP3,#0FFH
AJMPAJ2
RETI
ORG13H
MOVP3,#0FFH
AJMPAJ1
RETI
ORG1BH
MOVTH1,#0ECH
MOVTL1,#78H
DJNZR6,BACK
MOVR6,#200
AJ:MOVR0,#35H;秒
INC@R0
CJNE@R0,#10,$+3
JCBACK
MOV@R0,#0
MOVR0,#34H
INC@R0
CJNE@R0,#6,$+3
JCBACK
MOV@R0,#0
AJ1:MOVR0,#33H;分
INC@R0
CJNE@R0,#10,$+3
JCBACK
MOV@R0,#0
MOVR0,#32H
INC@R0
CJNE@R0,#6,$+3
JCBACK
MOV@R0,#0
AJ2:MOVR0,#31H;時
INC@R0
CJNE@R0,#4,$+3
JCBACK
CJNE@R0,#5,$+3
JCS24
CJNE@R0,#10,$+3
JCBACK
MOV@R0,#0
MOVR0,#30H
INC@R0
BACK:RETI
S24:DECR0
CJNE@R0,#2,$+3
JCBACK
MOV@R0,#0
MOV31H,#0
RETI
MAIN:MOVR1,#30H
MOV@R1,#0
INCR1
CJNER1,#36H,MAIN+2
MOVP3,#0FFH
MOVP0,#0
MOVDPTR,#SEGPT
MOVR6,#200
MOVTMOD,#10H
MOVTH1,#0ECH
MOVTH1,#78H
SETBIT0
SETBIT1
MOVIP,#15H
MOVIE,#9FH
SETBTR1
LOOPO:MOVR1,#30H
MOVR7,#20H
LOOPI:MOVP2,#0
MOVA,@R1
MOVCA,@A+DPTR
MOVP1,A
MOVP2,R7
INCR1
MOVA,R7
RRA
MOVR7,A
CJNER7,#80H,LOOPI
SJMPLOOPO
SEGPT:DB40H,79H,24H,30H,19H,12H,2,78H,0,18H
『伍』 單片機課程設計:簡易數字鍾
20. 數字鍾[★]
1. 實驗任務
(1. 開機時,顯示12:00:00的時間開始計時;
(2. P0.0/AD0控制「秒」的調整,每按一次加1秒;
(3. P0.1/AD1控制「分」的調整,每按一次加1分;
(4. P0.2/AD2控制「時」的調整,每按一次加1個小時;
#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;
}
}
『陸』 單片機數字鍾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;//設置定時器工作方式為2,8位定時狀態,自動裝入初值。
TH0=0x06;//裝入初值
TL0=0x06;
TR0=1;//起動定時器
ET0=1;//開啟定時器中斷
EA=1;//開總中斷
while(1)
{//主循環
if(P0_0==0)//如果P0.0位等於0,往下走
{
for(i=5;i>0;i--)
for(j=248;j>0;j--);//延時防抖動
if(P0_0==0)//再次判斷P0.0是否等於0,如果是,則設置秒
{
second++;//秒加1
if(second==60)//如果秒等於60,又重0開始,以便開始走時
{
second=0;
}
dispbuf[0]=second%10;//刷新秒個位,並裝驅動顯示緩沖寄存器
dispbuf[1]=second/10;//刷新秒十位,同上。
while(P0_0==0);//等待P0.0放開。(等待按鍵放開)
}
}
if(P0_1==0)//如果P0.1位等於0,往下走
{
for(i=5;i>0;i--)
for(j=248;j>0;j--);//延時防抖動
if(P0_1==0)//再次判斷P0.1是否等於0,如果是,則設置分鍾值
{
minite++;//分鍾加1
if(minite==60)//
{
minite=0;
}
dispbuf[3]=minite%10;//刷新分鍾個位,並裝驅動顯示緩沖寄存器
dispbuf[4]=minite/10;//刷新分鍾十位,同上
while(P0_1==0);//等待P0.1放開。(等待按鍵放開)
}
}
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++;//用於刷新所顯示的數據,第中斷8次顯示1位數碼管(動態顯示)
if(mstcnt==8)//判斷中斷8次沒,如果是,則顯示數據
{
mstcnt=0;
P1=dispcode[dispbuf[dispbitcnt]];//段位碼送P1口,驅動數碼管顯示
P3=dispbitcode[dispbitcnt];//選中數碼管顯示位
dispbitcnt++;//顯示索引,用於調哪一位數據
if(dispbitcnt==8)//判斷調完沒,如果調完了,則又從第一位開始。
{
dispbitcnt=0;
}
}
tcnt++;//第中斷一次自動加1,如果中斷4000次,則秒自動加1(這里的中斷次數可以跟據你所置的定時器初值來改變)
if(tcnt==4000)
{
tcnt=0;
second++;//秒加1
if(second==60)//如果秒等於60,則分鍾自動加1,並且秒回0
{
second=0;
minite++;//分鍾加1
if(minite==60)//如果分鍾等於0,則小時值自動加1,並且分鍾回0
{
minite=0;
hour++;//小時值加1
if(hour==24)//如果小時值等於24,則回0
{
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;
}
}
『柒』 單片機數字時鍾原理
給你個程序看看,主要是看時分顯示哪裡!這個程序已經調試通過了,在走時的同時流水燈進行流動,時分之間有一個小數點作為分隔。還有整點報時功能,在早上八點到中午十二點以及下午三點到晚上八點兩個時間段內逢整點報時,其他時間不報時(是因為考慮到人們要午休及晚間休息),除此之外還有調時、調分功能。整個程序基於單片機AT89S52(可用C51、C52、S51等代替)。
#include <reg52.h>
#define uint unsigned int
sbit P3_0=P3^0;
sbit K1=P3^2;
sbit K2=P3^3;
sbit K3=P3^4;
sbit K4=P3^5;
uint count,min,hour,i,j=0;
uint code tab1[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
uint code tab2[]={0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10};
uint code tab3[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f,0xff,
0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe,0xff,0x00,0xff,0x00,0xff,
0xfe,0xfb,0xef,0xbf,0xfd,0xf7,0xdf,0x7f,0x7e,0x3c,0x18,0x00,0x81,
0xc3,0xe7,0xff,0xe7,0xdb,0xbd,0x7e,0xff,0x7e,0xbd,0xdb,0xe7,0xff,
0x00,0xff,0x00,0xff,0xfe,0xfc,0xf8,0xf0,0xe0,0xc0,0x80,0x00,0x80,
0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff,0x00,0xff,0x00,0xff,0xfe,0xfc,
0xf8,0xf0,0xe0,0xc0,0x80,0x00,0x01,0x03,0x07,0x0f,0x1f,0x3f,0x7f,
0xff,0xfc,0xf9,0xf3,0xe7,0xcf,0x9f,0x3f,0xff,0x00,0xff,0x00,0xff};//流水燈
void adjust(void)
{
if(!K3) //分調整
{
for(i=0;i<20000;i++);min++;
if(min==60)min=0;
}
if(!K4) //時調整
{
for(i=0;i<20000;i++);hour++;
if(hour==24)hour=0;
}
}
void display(void)
{
P0=tab1[min%10];P2=0xf7;for(i=0;i<5;i++);P2=0xff;//分個位顯示
P0=tab1[min/10];P2=0xfb;for(i=0;i<5;i++);P2=0xff;//分十位顯示
P0=tab2[hour%10];P2=0xfd;for(i=0;i<5;i++);P2=0xff;//時個位顯示
P0=tab1[hour/10];P2=0xfe;for(i=0;i<5;i++);P2=0xff;//時十位顯示
}
void ring(void)
{
if(hour/10==0&&(hour%10>=8&&hour%10<=9))P3_0=0;//早上7:00到晚上7:00自動整點報時,其中13、14點不報時
if(hour/10==1&&(hour%10>=0&&hour%10<=2))P3_0=0;
if(hour/10==1&&(hour%10>=5&&hour%10<=9))P3_0=0;
}
void update(void)
{
if(count==1200)
{
count=0;min++;
if(min==60)
{
min=0;hour++;
if(hour==24)hour=0;
ring();
}
}
}
void main(void)
{
TMOD=0x01;
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
TR0=1;
EA=1;
ET0=1;
while(1)
{
if(count==120)P3_0=1;//報時六秒後自動關閉蜂鳴器
adjust();
display();
}
}
void timer0_rupt(void) interrupt 1 // 定時器0中斷
{
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
count++;
if(count%10==0)
{
P1=tab3[j];
j++;
if(j>99)j=0;
}
update();
}
『捌』 利用單片機(STC89C52)設計倒計時數字鍾
#include<reg51.h>
#define uchar unsigned char
uchar code ledtab[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40};//0-9
unsigned char sec=0,min=0,hour=24,scanled;
unsigned char key,mode,time;
unsigned char disdat[8];
unsigned char alarm[3]={23,59,0},dly;
sbit keyhu=P1^0;
sbit keyhd=P1^1;
sbit keymu=P1^2;
sbit keymd=P1^3;
sbit keysu=P1^4;
sbit keysd=P1^5;
sbit keyst=P1^6;
sbit fmq=P3^0;
bit flag=0;
void delay(unsigned int x)
{
unsigned int i,j;
for(i=0;i<x;i++)
for(j=0;j<120;j++);
}
void dischg()
{
disdat[0]=sec%10;
disdat[1]=sec/10;
disdat[2]=min%10;
disdat[3]=min/10;
disdat[4]=hour%10;
disdat[5]=hour/10;
}
void t0isr() interrupt 1//秒計時
{
TH0=0x3c;
TL0=0xb0;
time++;
switch(mode)
{
case 0:
if(time==20)
{
time=0;
sec++;
if(sec>59)
{
sec=0;
min++;
if(min>59)
{
min=0;
hour++;
if(hour>23)hour=0;
}
}
}
break;
case 1:
if(time==20)
{
time=0;
if(sec>0 && flag==0)sec--;
else if(min>0 && flag==0){sec=59;min--;}
else if(hour>0 && flag==0){sec=59;min=59;hour--;}
if((hour == alarm[0]) && (min == alarm[1]) && (sec == alarm[2])){fmq=1;flag=1;dly++;}
}
break;
}
if(dly>=2){fmq=0;flag=0;TR0=0;dly=0;}
dischg();
}
void t1isr() interrupt 3//顯示
{
TH1=0xec;
TL1=0x78;
switch(scanled)
{
case 0:
P2=0x20;
P0=~ledtab[disdat[5]];
break;
case 1:
P2=0x10;
P0=~ledtab[disdat[4]]&0x7f;
break;
case 2:
P2=0x08;
P0=~ledtab[disdat[3]];
break;
case 3:
P2=0x04;
P0=~ledtab[disdat[2]]&0x7f;
break;
case 4:
P2=0x02;
P0=~ledtab[disdat[1]];
break;
case 5:
P2=0x01;
P0=~ledtab[disdat[0]];
break;
default:break;
}
scanled++;
scanled%=6;
}
main()
{
TMOD=0x11;
TH0=0x3c;
TL0=0xb0;
TH1=0xec;
TL1=0x78;
TR1=1;
TR0=0;
ET0=1;
ET1=1;
EA=1;
fmq=0;
scanled=0;
time=0;
mode=1;
dischg();
while(1)
{
if(keyhu==0)
{
while(keyhu==0);
TR0=0;
hour++;
hour%=24;
}
if(keyhd==0)
{
while(keyhd==0);
TR0=0;
if(hour>0)hour--;
if(hour==0)hour=23;
}
if(keymu==0)
{
while(keymu==0);
TR0=0;
min++;
min%=60;
}
if(keymd==0)
{
while(keymd==0);
TR0=0;
if(min>0)min--;
if(min==0)min=59;
}
if(keysu==0)
{
while(keysu==0);
TR0=0;
sec++;
sec%=60;
}
if(keysd==0)
{
while(keysd==0);
TR0=0;
if(sec>0)sec--;
if(sec==0)sec=59;
}
if(keyst==0)
{
while(keyst==0);
TR0=~TR0;
}
dischg();
}
}
『玖』 基於單片機的數字鍾 論文設計
ORG 0000H ;程序入口地址
LJMP START
ORG 000BH ;定時器0中斷入口地址
LJMP TIMER_0
ORG 0300H
/*****程序開始,初始化*****/
START:
SETB 48H ;使用一個bit位用於調時閃爍標志
SETB 47H ;使用一個bit位用於產生脈沖用於調時快進時基
MOV R1,#0 ;調整選擇鍵功能標志:0正常走時、1調時、2調分、3調秒
MOV 20H,#00H ;用於控制秒基準時鍾源的產生
MOV 21H,#00H ;清零秒寄存器
MOV 22H,#00H ;清零分寄存器
MOV 23H,#00H ;清零時寄存器
MOV 24H,#00H ;用於控制調時閃爍的基準時鍾的產生
MOV IP,#02H ;IP,IE初始化
MOV IE,#82H
MOV TMOD,#01H ;設定定時器0工作方式1
MOV TH0,#3CH
MOV TL0,#0B0H ;賦定時初值,定時50ms
SETB TR0 ;啟動定時器0
MOV SP,#40H ;重設堆棧指針
/*****主程序*****/
MAIN:
LCALL DISPLAY ;調用顯示子程序
LCALL KEY_SCAN ;調用按鍵檢測子程序
JZ MAIN ;無鍵按下則返回重新循環
LCALL SET_KEY ;調用選擇鍵處理子程序
JB 46H,MAIN ;如果已進行長按調整(調時快進),則不再執行下面的單步調整
LCALL ADD_KEY ;調用增加鍵處理子程序,加一
LCALL DEC_KEY ;調用減少鍵處理子程序,減一
LJMP MAIN ;重新循環
/*****定時器中斷服務程序*****/
TIMER_0:
PUSH ACC
PUSH PSW ;保護現場
MOV TH0,#3CH
MOV TL0,#0B0H ;重新賦定時初值
CPL 47H ;產生脈沖用於調時快進時基
INC 24H
MOV A,24H
CJNE A,#10,ADD_TIME ;產生0.5秒基準時鍾,用於調時閃爍
CPL 48H ;取反調時閃爍標志位
MOV 24H,#00H
ADD_TIME: ;走時
INC 20H
MOV A,20H
CJNE A,#20,RETI1 ;產生1秒基準時鍾
MOV 20H,#00H ;一秒鍾時間到,清零20H
MOV A,21H
ADD A,#01H
DA A ;作十進制調整
MOV 21H,A
CJNE A,#60H,RETI1
MOV 21H,#00H ;一分鍾到
MOV A,22H
ADD A,#01H
DA A
MOV 22H,A
CJNE A,#60H,RETI1
MOV 22H,#00H ;一小時到
MOV A,23H
ADD A,#01H
DA A
MOV 23H,A
CJNE A,#24H,RETI1
MOV 23H,#00H ;到24點,清零小時
RETI1:
POP PSW
POP ACC ;恢復現場
RETI ;中斷返回
/*****顯示處理*****/
DISPLAY:
MOV A,21H ;秒
ANL A,#0FH
MOV 2FH,A ;轉換出秒個位,存入2FH
MOV A,21H
ANL A,#0F0H
SWAP A
MOV 2EH,A ;轉換出秒十位,存入2EH
JB 46H,MIN ;如果長按按鍵(調時快進),則跳過閃爍處理程序
CJNE R1,#3,MIN ;如果R1為3,閃爍秒位待調整
JB 48H,MIN
MOV 2FH,#0AH ;使該位為10,查表得到使該位不顯示的輸出
MOV 2EH,#0AH
MIN:
MOV A,22H ;分
ANL A,#0FH
MOV 2DH,A ;轉換出分個位,存入2DH
MOV A,22H
ANL A,#0F0H
SWAP A
MOV 2CH,A ;轉換出分十位,存入2CH
JB 46H,HOUR ;如果長按按鍵(調時快進),則跳過閃爍處理程序
CJNE R1,#2,HOUR ;如果R1為2,閃爍分位待調整
JB 48H,HOUR
MOV 2DH,#0AH ;使該位為10,查表得到使該位不顯示的輸出
MOV 2CH,#0AH
HOUR:
MOV A,23H ;時
ANL A,#0FH
MOV 2BH,A ;轉換出時個位,存入2BH
MOV A,23H
ANL A,#0F0H
SWAP A
MOV 2AH,A ;轉換出時十位,存入2AH
JB 46H,DISP ;如果長按按鍵(調時快進),則跳過閃爍處理程序
CJNE R1,#1,DISP ;如果R1為1,閃爍時位待調整
JB 48H,DISP
MOV 2BH,#0AH ;使該位為10,查表得到使該位不顯示的輸出
MOV 2AH,#0AH
/*****數碼管動態掃描顯示*****/
DISP:
MOV DPTR,#TABLE
MOV A,2FH
MOVC A,@A+DPTR
MOV P0,A
setb P2.7
LCALL DELAY
clr P2.7 ;顯示秒個位
MOV A,2EH
MOVC A,@A+DPTR
MOV P0,A
setb P2.6
LCALL DELAY
clr P2.6 ;顯示秒十位
MOV A,#0BFH
MOV P0,A
setb P2.5
LCALL DELAY
clr P2.5 ;顯示"-"
MOV A,2DH
MOVC A,@A+DPTR
MOV P0,A
setb P2.4
LCALL DELAY
clr P2.4 ;顯示分個位
MOV A,2CH
MOVC A,@A+DPTR
MOV P0,A
setb P2.3
LCALL DELAY
clr P2.3 ;顯示分十位
MOV A,#0BFH
MOV P0,A
setb P2.2
LCALL DELAY
clr P2.2 ;顯示"-"
MOV A,2BH
MOVC A,@A+DPTR
MOV P0,A
setb P2.1
LCALL DELAY
clr P2.1 ;顯示時個位
MOV DPTR,#TABLE1 ;該位使用TABLE1以消除前置0
MOV A,2AH
MOVC A,@A+DPTR
MOV P0,A
setb P2.0
LCALL DELAY
clr P2.0 ;顯示時十位
RET
/*****按鍵檢測子程序*****/
KEY_SCAN:
CLR 46H ;關閉長按調整(調時快進)標志
MOV P1,#0FFH ;將P1口設置成輸入狀態
MOV A,P1
CPL A
ANL A,#07H ;P1口低3位連接3個按鍵,只判斷該3位
JZ EXIT_KEY ;無鍵按下則返回
LCALL DELAY ;延時去抖動
MOV A,P1 ;重新判斷
CPL A
ANL A,#07H
JZ EXIT_KEY ;鍵盤去抖動
MOV R5,A ;臨時將鍵值存入R5
MOV R4,#00H ;用於控制調時快進速度
;設置為00H是為了在進入長按處理前加長延時區分用戶的長按與短按,防止誤快進
LOOP: ;進入長按處理
LCALL DISPLAY ;使長按時顯示正常
MOV A,P1
CPL A
ANL A,#07H
JB 47H,LOOP1
INC R4 ;調時快進間隔時間基準加1
LOOP1:
CJNE R1,#03H,LOOP2 ;如果調秒時長按,則不處理
LJMP LOOP3
LOOP2:
CJNE R4,#99H,LOOP3
MOV R4,#70H ;確認用戶長按後,重新設定起始值,加快調時快進速度
SETB 46H ;長按調整(調時快進)標志
LCALL ADD_KEY
LCALL DEC_KEY
LOOP3:
JNZ LOOP ;等待鍵釋放
MOV A,R5 ;輸出鍵值
RET
EXIT_KEY:
RET
/*****延時子程序*****/
DELAY:
MOV R7,#150
DJNZ R7,$
RET
/*****選擇鍵處理子程序*****/
SET_KEY:
CJNE R5,#01H,EXIT ;選擇鍵鍵值
INC R1 ;調整選擇功能標志加一
CJNE R1,#4,EXIT
MOV R1,#0
MOV 24H,#00H ;調時閃爍基準清零
RET
/*****增加鍵處理子程序*****/
ADD_KEY:
CJNE R5,#02H,EXIT ;增加鍵鍵值
CJNE R1,#01H,NEXT1 ;選擇鍵功能標志為1,調時,否則跳出
MOV A,23H
ADD A,#01H
DA A
MOV 23H,A
CJNE A,#24H,EXIT
MOV 23H,#00H
NEXT1:
CJNE R1,#02H,NEXT2 ;選擇鍵功能標志為2,調分,否則跳出
MOV A,22H
ADD A,#01H
DA A
MOV 22H,A
CJNE A,#60H,EXIT
MOV 22H,#00H
NEXT2:
CJNE R1,#03H,EXIT ;選擇鍵功能標志為3,調秒,否則跳出
MOV 21H,#00H ;如增加鍵按下直接清零秒
RET
/*****減少鍵處理子程序*****/
DEC_KEY:
CJNE R5,#04H,EXIT ;減少鍵鍵值
CJNE R1,#01H,NEXT3 ;選擇鍵功能標志為1,調時,否則跳出
MOV A,23H
ADD A,#99H
DA A
MOV 23H,A
CJNE A,#99H,EXIT
MOV 23H,#23H
NEXT3:
CJNE R1,#02H,NEXT4 ;選擇鍵功能標志為2,調分,否則跳出
MOV A,22H
ADD A,#99H
DA A
MOV 22H,A
CJNE A,#99H,EXIT
MOV 22H,#59H
NEXT4:
CJNE R1,#03H,EXIT ;選擇鍵功能標志為3,調秒,否則跳出
MOV 21H,#00H ;如較少鍵按下直接清零秒
RET
/*****萬用返回子程序*****/
EXIT:
RET
/*****數碼管字形編碼表*****/
TABLE:
DB 0C0H,0F9H,0A4H,0B0H,99H,92H,82H,0F8H,80H,90H,0FFH ;字形顯示編碼
TABLE1:
DB 0FFH,0F9H,0A4H,0B0H,99H,92H,82H,0F8H,80H,90H,0FFH ;小時位的十位數編碼,該位如果為0則不顯示
END ;程序結束
『拾』 單片機數字時鍾匯編程序設計分析
時鍾設計基本上就是通過電子 定時器定時 到1s給一個中斷 讓單片機去執行中斷 跳轉至相應的數碼管位 然後修改當前顯示值 再設置到10進位加一 之後就出來數字時鍾的效果 弄懂定時器 一切就順下來了
這是一個C得時鍾程序 你看明白思想 就好說匯編的語句了
#include <reg52.h>
#include <intrins.h>
#define uchar unsigned char
sbit la=P3^7;
sbit L1=P2^0;
sbit L2=P2^1;
sbit L3=P2^2;
sbit key1=P3^0;
sbit key2=P3^1;
sbit key3=P3^2;
sbit key4=P3^3;
uchar aa;
uchar code table[]={0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71
};
uchar nummiao,numfen,numshi,t0;
void delayms(uchar xms)
{
uchar i,j;
for(i=xms;i>0;i--)
for(j=110;j>0;j--);
}
void init()
{
TMOD=0x11;
TH0=(65536-50000)%256;
TL0=(65536-50000)/256;
EA=1;
ET0=1;
}
void display(uchar nummiao,numfen,numshi)
{
uchar shishi,geshi,shifen,gefen,shimiao,gemiao;
shimiao=nummiao/10;
gemiao=nummiao%10;
shifen=numfen/10;
gefen=numfen%10;
shishi=numshi/10;
geshi=numshi%10;
la=1;
P0=table[shimiao];
la=0;
L1=0;
L2=1;
L3=1;
delayms(5);
la=1;
P0=table[gemiao];
la=0;
L1=1;
L2=1;
L3=1;
delayms(5);
la=1;
P0=0x40;
la=0;
L1=1;
L2=0;
L3=1;
delayms(5);
la=1;
P0=table[gefen];
la=0;
L1=0;
L2=0;
L3=1;
delayms(5);
la=1;
P0=table[shifen];
la=0;
L1=1;
L2=1;
L3=0;
delayms(5);
la=1;
P0=0x40;
la=0;
L1=0;
L2=1;
L3=0;
delayms(5);
la=1;
P0=table[geshi];
la=0;
L1=1;
L2=0;
L3=0;
delayms(5);
la=1;
P0=table[shishi];
la=0;
L1=0;
L2=0;
L3=0;
delayms(5);
}
void keyscan()
{
if(key1==0)
{
delayms(10);
if(key1==0)
{
numshi++;
if(numshi==24)
numshi=0;
while(!key1);
}
}
if(key2==0)
{
delayms(10);
if(key2==0)
{
if(numfen==60)
numfen=0;
numfen++;
while(!key2);
}
}
if(key3==0)
{
delayms(10);
if(key3==0)
{
nummiao=0;
while(!key3);
}
}
if(key4==0)
{
delayms(10);
if(key4==0)
{
while(!key4);
TR0=~TR0;
}
}
}
void main()
{
init();
aa=0xfe;
while(1)
{
P1=aa;
if(nummiao==60)
{
numfen++;
nummiao=0;}
if(numfen==60)
{ numshi++;
numfen=0;}
if(numshi==24)
numshi=0;
keyscan();
display(nummiao,numfen,numshi);
}
}
void t0time()interrupt 1
{
TH0=(65535-50000)/256;
TL0=(65535-50000)%256;
t0++;
if(t0==20)
{
t0=0;
nummiao++;}
aa=_crol_(aa,1);
}