Ⅰ 求C51單片機數字電子時鍾課程設計
#include<reg52.h>
#include<absacc.h>
#include<intrins.h>
#define
unit
unsigned
int
#define
uchar
unsigned
char
//#define
HZ
12
sbit
key0=P0^0;
//
分鍾調整
sbit
key1=P0^1;
//
小時調整
sbit
P2_0=P2^7;
//秒
指示燈
sbit
MN_RXD=P3^6;
sbit
MN_TXD=P3^7;
uchar
data
CLOCK[4]={0,0,0,12};//存放時鍾時間(百分秒,秒,分,和時位)
//數碼管顯示表0-f
滅
uchar
code
TABLE[]={0xBE,0x06,0xEA,0x6E,0x56,0x7C,0xFC,0x0E,0xFE,0x7E,0x00};
//**********************************
//模擬串口發送一個位元組數據
函數
//**********************************
void
SendData(unsigned
char
senddata)
{
unsigned
char
i;
for(i=0;i<8;i++)
{
if((senddata&0x01)==0)
MN_RXD=0;
else
MN_RXD=1;
_nop_();
MN_TXD=0;
_nop_();
MN_TXD=1;
senddata=senddata>>1;
}
}
//**********************************
//顯示程序函數
//**********************************
void
display(void)
{
//
unsigned
int
n;
uchar
temp;
temp=CLOCK[1];
temp=temp%10;
SendData(TABLE[temp]);
temp=CLOCK[1];
temp=temp/10;
SendData(TABLE[temp]);
temp=CLOCK[2];
temp=temp%10;
SendData(TABLE[temp]);
temp=CLOCK[2];
temp=temp/10;
SendData(TABLE[temp]);
temp=CLOCK[3];
temp=temp%10;
SendData(TABLE[temp]);
temp=CLOCK[3];
temp=temp/10;
SendData(TABLE[temp]);
/*
for(n=0;n<5000;n++);
for(n=0;n<6;n++)
{
SendData(TABLE[10]);
}
*/
}
//**********************************
//按鍵控制函數
//**********************************
void
keycan()
{
unsigned
int
n;
EA=0;
if(key0==0)
//
分鍾調整
{
for(n=0;n<10000;n++);
//延時去抖動
while(key0==0);
CLOCK[2]=CLOCK[2]+1;
if(CLOCK[2]==60)
//到一時
{
CLOCK[2]=0;
}
display();
}
if(key1==0)
//
小時調整
{
for(n=0;n<10000;n++);
//延時去抖動
while(key1==0);
CLOCK[3]=CLOCK[3]+1;
if(CLOCK[3]==24)
{
CLOCK[3]=0;
}
display();
}
EA=1;
}
//**********************************
//T0中斷服務函數
//**********************************
void
time0()
interrupt
1
//using
1
{
TH0=0xD8;
TL0=0xF0;
//重置初值
//
TH0=0xB1;
TL0=0xE0;
//時鍾處理
CLOCK[0]=CLOCK[0]+1;
}
//**********************************
//主函數
//**********************************
void
main()
{
EA=1;
ET0=1;
TMOD=0x01;
//T0方式1定時
TH0=0xD8;
TL0=0xF0;
//D8F0
定時10ms
//
TH0=0xB1;
TL0=0xE0;
//定時
20ms
TR0=1;
for(;;)
{
if(CLOCK[0]==100)
//到一秒
10ms*100
{
CLOCK[0]=0;
P2_0=~P2_0;
CLOCK[1]=CLOCK[1]+1;
if(CLOCK[1]==60)
//到一分
{
CLOCK[1]=0;
CLOCK[2]=CLOCK[2]+1;
if(CLOCK[2]==60)
//到一時
{
CLOCK[2]=0;
CLOCK[3]=CLOCK[3]+1;
if(CLOCK[3]==24)
{
CLOCK[3]=0;
}
}
}
display();
}
keycan();
}
}
Ⅱ 單片機課程設計(數字時鍾) 麻煩大家不要發鏈接 直接幫我把程序寫過來。
哈哈有個1602顯示的不過程序太長貼不上給你個數碼管的吧不行再聯系
1302.c
#include<DS1302.h>
#include<key.h>
ucharbit_ser[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf};
ucharseven_seg[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
/***********************時間顯示*****************/
voidtimer0_init(void) //T0初始化函數,用於時間的動態顯示
{
TMOD=0x21;
TL0=(65536-5000)%256;
TH0=(65536-5000)/256;
EA=1;
ET0=1;
TR0=1;
}
voidtimer0_isr(void)interrupt1 //T0中斷處理函數
{
charflag; //flag用於表示調整時閃爍的亮或滅
TR0=0;
TL0=(65536-5000)%256;
TH0=(65536-5000)/256;
TR0=1;
flag=x/100*0xff; //設置閃爍標志,如果x大於100則flag為0xff,小於100則為0x00
x++;
if(x>200)
x=0;
switch(i)
{
case0:
P2=bit_ser[0];
if(setflag==3) //根據setflag的值判斷當前位是否需要閃爍
P0=flag|seven_seg[dis_buffer[0]];
else
P0=seven_seg[dis_buffer[0]];
break;
case1:
P2=bit_ser[1];
if(setflag==3)
P0=flag|seven_seg[dis_buffer[1]];
else
P0=seven_seg[dis_buffer[1]];
break;
case2:
P2=bit_ser[2];
if(setflag==2)
P0=flag|seven_seg[dis_buffer[2]];
else
P0=seven_seg[dis_buffer[2]];
break;
case3:
P2=bit_ser[3];
if(setflag==2)
P0=flag|seven_seg[dis_buffer[3]];
else
P0=seven_seg[dis_buffer[3]];
break;
case4:
P2=bit_ser[4];
if(setflag==1)
P0=flag|seven_seg[dis_buffer[4]];
else
P0=seven_seg[dis_buffer[4]];
break;
case5:
P2=bit_ser[5];
if(setflag==1)
P0=flag|seven_seg[dis_buffer[5]];
else
P0=seven_seg[dis_buffer[5]];
break;
}
i++;
if(i>=6)
{
i=0;
if(j==10)
{
j=0;
if(setflag==0)
DS1302_GetTime(&Time); //如果setflag是0,就從1302中讀出時間,因為setflag不是0時,說明處於調整狀態,不需要讀時間
dis_buffer[5]=Time.Second%10; //把當前時間放入顯示緩沖區
dis_buffer[4]=Time.Second/10;
dis_buffer[3]=Time.Minute%10;
dis_buffer[2]=Time.Minute/10;
dis_buffer[1]=Time.Hour%10;
dis_buffer[0]=Time.Hour/10;
}
j++;
}
}
voidmain()
{
Initial_DS1302(Time);
timer0_init();
while(1)
{
set_down();
timer_down();
up_down();
down_down();
beepflag_down();
if(setflag==0&&Time.Hour==romhour&&Time.Minute==romminute&&Beepflag==1) //判斷蜂鳴器是否要響
Beep=!Beep;
}
}
//key.c
#include<reg51.h>
#defineucharunsignedchar
#defineuintunsignedint
uchari=0,j=0,x=0,setflag,flag_set,flag_timer;//setflag用來表示調整的位置,flag_set和flag_timer分別表示當前處於調整狀態還是定時狀態
SYSTEMTIMETime={0,20,15,3,30,6,10}; //系統時間的初始值2010年6月30日星期三,15時20分0秒
chardis_buffer[6]; //存放顯示數據的緩沖區
sbitBeep_flag=P3^2; //蜂鳴器的介面
sbitkey_timer=P3^4; //定時按鈕
sbitkey_set=P3^5; //調整按鈕
sbitkey_up=P3^6; //增加按鈕
sbitkey_down=P3^7; //減小按鈕
charromhour,romminute,romsec; //分別存放定時的時,分,秒
bitBeepflag; //標記鬧鍾是否開啟
//延時函數
voiddelays(ucharx)
{
while(x)x--;
}
//設置鍵的處理函數
voidset()
{
setflag++;
flag_set=1;
if(setflag>=4)
{
setflag=0;
flag_set=0;
Initial_DS1302(Time);
}
}
//定時間的處理函數
voidtimer()
{
setflag++;
flag_timer=1;
if(setflag==1)
{
Time.Hour=romhour;
Time.Minute=romminute;
Time.Second=romsec;
}
elseif(setflag>=4)
{
setflag=0;
flag_timer=0;
romhour=Time.Hour;
romminute=Time.Minute;
romsec=Time.Second;
}
}
//增加鍵的處理函數
voip()
{
switch(setflag)
{
case0:
break;
case1:
Time.Second++;
if(Time.Second>=60)
Time.Second=0;
break;
case2:
Time.Minute++;
if(Time.Minute>=60)
Time.Minute=0;
break;
case3:
Time.Hour++;
if(Time.Hour>=24)
Time.Hour=0;
break;
}
}
//減小鍵的處理函數
voiddown()
{
switch(setflag)
{
case0:
break;
case1:
Time.Second--;
if(Time.Second<0)
Time.Second=59;
break;
case2:
Time.Minute--;
if(Time.Minute<0)
Time.Minute=59;
break;
case3:
Time.Hour--;
if(Time.Hour<0)
Time.Hour=23;
break;
}
}
//設置鍵的掃描函數
voidset_down()
{
if(key_set==0&&flag_timer==0)
{
delays(100);
if(key_set==0)
{
set();
}
while(!key_set);
}
}
//定時鍵的掃描函數
voidtimer_down()
{
if(key_timer==0&&flag_set==0)
{
delays(100);
if(key_timer==0)
{
timer();
}
while(!key_timer);
}
}
//增加鍵的掃描函數
voip_down()
{
if(key_up==0&&setflag!=0)
{
delays(100);
if(key_up==0)
{
up();
while(!key_up);
}
}
}
//減少鍵的處理函數
voiddown_down()
{
if(key_down==0&&setflag!=0)
{
delays(100);
if(key_down==0)
{
down();
while(!key_down);
}
}
}
//定時開關的掃描處理函數
voidbeepflag_down()
{
if(Beep_flag==0)
{
delays(100);
{
Beepflag=!Beepflag;
while(!Beep_flag);
}
}
}
//ds1302.h
#ifndef_REAL_TIMER_DS1302
#define_REAL_TIMER_DS1302
#include<REG51.h>
sbitDS1302_CLK=P1^1;//實時時鍾時鍾線引腳
sbitDS1302_IO=P1^2;//實時時鍾數據線引腳
sbitDS1302_RST=P1^3;//實時時鍾復位線引腳
sbitACC0=ACC^0;
sbitACC7=ACC^7;
sbitBeep=P2^7;
typedefstruct__SYSTEMTIME__
{ charSecond;
charMinute;
charHour;
charWeek;
charDay;
charMonth;
charYear;
}SYSTEMTIME; //定義的時間類型
#defineAM(X) X
#definePM(X) (X+12) //轉成24小時制
#defineDS1302_SECOND 0x80//秒寄存器
#defineDS1302_MINUTE 0x82//分寄存器
#defineDS1302_HOUR 0x84
#defineDS1302_WEEK 0x8A
#defineDS1302_DAY 0x86
#defineDS1302_MONTH 0x88
#defineDS1302_YEAR 0x8C
#defineDS1302_RAM(X) (0xC0+(X)*2) //用於計算DS1302_RAM地址的宏
voidDS1302InputByte(unsignedchard) //實時時鍾寫入一位元組(內部函數)
{unsignedchari;
ACC=d;
for(i=8;i>0;i--)
{ DS1302_IO=ACC0; //相當於匯編中的RRC
DS1302_CLK=1;
DS1302_CLK=0;//發一個高跳變到低的脈沖
ACC=ACC>>1;
}
}
unsignedcharDS1302OutputByte(void) //實時時鍾讀取一位元組(內部函數)
{ unsignedchari;
for(i=8;i>0;i--)
{ ACC=ACC>>1; //相當於匯編中的RRC
ACC7=DS1302_IO;
DS1302_CLK=1;
DS1302_CLK=0;//發一個高跳變到低的脈沖
}
return(ACC);
}
voidWrite1302(unsignedcharucAddr,unsignedcharucDa)//ucAddr:DS1302地址,ucData:要寫的數據
{ DS1302_RST=0;
DS1302_CLK=0;
DS1302_RST=1;
DS1302InputByte(ucAddr); //地址,命令
DS1302InputByte(ucDa); //寫1Byte數據
DS1302_CLK=1;
DS1302_RST=0;//RST0->1->0,CLK0->1
}
unsignedcharRead1302(unsignedcharucAddr) //讀取DS1302某地址的數據
{ unsignedcharucData;
DS1302_RST=0;
DS1302_CLK=0;
DS1302_RST=1;//enable
DS1302InputByte(ucAddr|0x01);//地址,命令
ucData=DS1302OutputByte();//讀1Byte數據
DS1302_CLK=1;//RST0->1->0,CLK0->1
DS1302_RST=0;
return(ucData);
}
voidDS1302_SetProtect(bitflag)//是否防寫
{ if(flag)
Write1302(0x8E,0x80);//WP=1,不能寫入
else
Write1302(0x8E,0x00);//WP=0,可以寫入
}
voidDS1302_SetTime(unsignedcharAddress,unsignedcharValue)//設置時間函數
{ DS1302_SetProtect(0);
Write1302(Address,((Value/10)<<4|(Value%10)));//高4位為十位,低4位為個位
DS1302_SetProtect(1);
}
//獲取時間函數,從DS1302內讀取時間然後存入Time內
voidDS1302_GetTime(SYSTEMTIME*Time)
{ unsignedcharReadValue;
ReadValue=Read1302(DS1302_SECOND);
Time->Second=((ReadValue&0x70)>>4)*10+(ReadValue&0x0F);//轉換成10進制的秒
ReadValue=Read1302(DS1302_MINUTE);
Time->Minute=((ReadValue&0x70)>>4)*10+(ReadValue&0x0F);
ReadValue=Read1302(DS1302_HOUR);
Time->Hour=((ReadValue&0x70)>>4)*10+(ReadValue&0x0F);
ReadValue=Read1302(DS1302_DAY);
Time->Day=((ReadValue&0x70)>>4)*10+(ReadValue&0x0F);
ReadValue=Read1302(DS1302_WEEK);
Time->Week=((ReadValue&0x70)>>4)*10+(ReadValue&0x0F);
ReadValue=Read1302(DS1302_MONTH);
Time->Month=((ReadValue&0x70)>>4)*10+(ReadValue&0x0F);
ReadValue=Read1302(DS1302_YEAR);
Time->Year=((ReadValue&0x70)>>4)*10+(ReadValue&0x0F);
}
//利用STime初始化DS1302
voidInitial_DS1302(SYSTEMTIMESTime)
{ unsignedcharSecond=Read1302(DS1302_SECOND);
if(Second&0x80) DS1302_SetTime(DS1302_SECOND,0);//如果第七為1(表明沒有啟動),則啟動時鍾
DS1302_SetTime(DS1302_SECOND,STime.Second); //設定起始時間
DS1302_SetTime(DS1302_MINUTE,STime.Minute);
DS1302_SetTime(DS1302_HOUR,STime.Hour);
DS1302_SetTime(DS1302_DAY,STime.Day);
DS1302_SetTime(DS1302_MONTH,STime.Month);
DS1302_SetTime(DS1302_YEAR,STime.Year);
DS1302_SetTime(DS1302_WEEK,STime.Week);
}
#endif
Ⅲ 單片機實現電子時鍾
ORG 0000H ;程序執行開始地址
LJMP START ;跳到標號START執行
ORG 0003H ;外中斷0中斷程序入口
LJMP OUTINTT0 ;外中斷0中斷返回
ORG 000BH ;定時器T0中斷程序入口
LJMP INTT0 ;跳至INTTO執行
ORG 0013H ;外中斷1中斷程序入口
RETI;外中斷1中斷返回
ORG 001BH ;定時器T1中斷程序入口
LJMP INTT1 ;跳至INTT1執行;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; 主 程 序 ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
START:
MOV R0,#70H ;清70H-7AH共11個內存單元
MOV R7,#0BH ;
CLEARDISP:
MOV @R0,#00H ;
INC R0 ;
DJNZ R7,CLEARDISP ;
MOV 70H,#07H;
MOV 71H,#05H;
MOV 76H,#09H;
MOV 77H,#05H;
MOV 78H,#05H;
MOV 79H,#00H;
MOV 20H,#00H ;清20H(標志用)
MOV 7AH,#0AH ;放入"熄滅符"數據
MOV 7BH,#00H ;清報時寄存器
MOV TMOD,#11H ;設T0、T1為16位定時器
MOV TL0,#0B0H ;50MS定時初值(T0計時用)
MOV TH0,#3CH ;50MS定時初值
MOV TL1,#0B0H ;50MS定時初值(T1閃爍定時用)
MOV TH1,#3CH ;50MS定時初值
SETB PT1;定時器T1為高優先順序
SETB EA ;總中斷開放
SETB ET0 ;允許T0中斷
SETB TR0 ;開啟T0定時器
SETB EX0 ;開啟外部中斷0
MOV R4,#14H ;1秒定時用初值(50MS×20)
MOV R2,#06H ;0.3秒的閃動初值(50MS*6)
START1:
LCALL DISPLAY;調用顯示子程序
LCALL BELL;
LCALL DISCLOSE;
SJMP START1 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; 計時程序 ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;T0中斷服務程序
INTT0:
PUSH ACC ;累加器入棧保護
PUSH PSW ;狀態字入棧保護
CLR ET0 ;關T0中斷允許
CLR TR0 ;關閉定時器T0
MOV TL0,#0B0H ;重裝初值(低8位修正值)
MOV TH0,#3CH ;重裝初值(高8位修正值)
SETB TR0 ;開啟定時器T0
DJNZ R4, OUTT0 ;20次中斷未到中斷退出
ADDSS:
MOV R4,#14H ;20次中斷到(1秒)重賦初值
MOV R0,#71H ;指向秒計時單元(70H-71H)
ACALL DBchange ;調用數據處理程序(加1並存入顯示單元)
MOV A,R3 ;秒數據放入A(R3為2位十進制數組合)
CLR C ;清進位標志
CJNE A,#60H,ADDMM ;
ADDMM:
JC OUTT0 ;小於60秒時中斷退出
LCALL CLR0 ;大於或等於60秒時對秒計時單元清0
MOV R0,#77H ;指向分計時單元(76H-77H)
ACALL DBchange ;
MOV A,R3 ;分數據放入A
CLR C ;清進位標志
CJNE A,#60H,ADDHH ;
ADDHH:
JC OUTT0 ;小於60分時中斷退出
ACALL CLR0 ;大於或等於60分時分計時單元清0
MOV R0,#79H ;指向小時計時單元(78H-79H)
ACALL DBchange ;
MOV A,R3 ;時數據放入A
CLR C ;清進位標志
MOV 7BH,#01H
CJNE A,#24H,HOUR ;
HOUR:
JC OUTT0 ;小於24小時中斷退出
ACALL CLR0 ;大於或等於24小時小時計時單元清0
OUTT0:
MOV 72H,76H ;中斷退出時將分、時計時單元數據移
MOV 73H,77H ;入對應顯示單元
MOV 74H,78H ;
MOV 75H,79H ;
POP PSW ;恢復狀態字(出棧)
POP ACC ;恢復累加器
SETB ET0 ;開放T0中斷
RETI ;中斷返回;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; 閃動調時 程 序 ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;T1中斷服務程序,用作時間調整時調整單元閃爍指示
INTT1:
PUSH ACC ;中斷現場保護
PUSH PSW ;
MOV TL1, #0B0H ;裝定時器T1定時初值
MOV TH1, #3CH ;
DJNZ R2,INTT1OUT ;0.3秒未到退出中斷(50MS中斷6次)
MOV R2,#06H ;重裝0.3秒定時用初值
CPL 02H ;0.3秒定時到對閃爍標志取反
JB 02H,FLASH1 ;02H位為1時顯示單元"熄滅"
MOV 72H,76H ;02H位為0時正常顯示
MOV 73H,77H ;
MOV 74H,78H ;
MOV 75H,79H ;
INTT1OUT:
POP PSW ;恢復現場
POP ACC ;
RETI ;中斷退出
FLASH1:
JB 01H,FLASH2 ;01H位為1時,轉小時熄滅控制
MOV 72H,7AH ;01H位為0時,"熄滅符"數據放入分
MOV 73H,7AH ;顯示單元(72H-73H),將不顯示分數據
MOV 74H,78H ;
MOV 75H,79H ;
AJMP INTT1OUT ;轉中斷退出
FLASH2:
MOV 72H,76H ;01H位為1時,"熄滅符"數據放入小時
MOV 73H,77H ;顯示單元(74H-75H),小時數據將不顯示
MOV 74H,7AH ;
MOV 75H,7AH ;
AJMP INTT1OUT ;轉中斷退出
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; 數據處理程序,把6個數碼管顯示內容存入相應的地址;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
DBchange:
MOV A,@R0 ;取當前計時單元數據到A
DEC R0 ;指向前一地址
SWAP A ;A中數據高四位與低四位交換
ORL A,@R0 ;前一地址中數據放入A中低四位
ADD A,#01H ;A加1操作
DA A ;十進制調整
MOV R3,A ;移入R3寄存器
ANL A,#0FH ;高四位變0
MOV @R0,A ;放回前一地址單元
MOV A,R3 ;取回R3中暫存數據
INC R0 ;指向當前地址單元
SWAP A ;A中數據高四位與低四位交換
ANL A,#0FH ;高四位變0
MOV @R0,A ;數據放入當削地址單元中
RET ;子程序返回
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; 清零程序 ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;對計時單元復零用
CLR0:
CLR A ;清累加器
MOV @R0,A ;清當前地址單元
DEC R0 ;指向前一地址
MOV @R0,A ;前一地址單元清0
RET ;子程序返回
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; 時鍾調整中斷程序 ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;當調時按鍵按下時進入此程序
OUTINTT0:
PUSH ACC;
PUSH PSW;
CLR ET0 ;關定時器T0中斷
CLR TR0 ;關閉定時器T0
CLR EX0 ;關閉外部中斷0
MOV R2,#06H ;進入調時狀態,賦閃爍定時初值
SETB ET1 ;允許T1中斷
SETB TR1 ;開啟定時器T1
SET2: JNB P1.0,SET1 ;P1.0口為0(鍵未釋放),等待
SETB 00H ;鍵釋放,分調整閃爍標志置1
SET4:
JB P1.0,SET3 ;p1.0沒有按下時進入分調整程序
LJMP SETHH ;p1.0按下轉調小時狀態
SET3:
LCALL DISPLAY ;等待調分按鍵時時鍾顯示用
JB P1.1,SET4;等待p1.1按下
LCALL DL1S; MOV R0,#77H;按下時加1分鍾操作
LCALL DBchange ;調用加1子程序
MOV A,R3 ;取調整單元數據
CLR C ;清進位標志
CJNE A,#60H,HHH ;調整單元數據與60比較
HHH:
JC SET4 ;調整單元數據小於60轉SET4循環
LCALL CLR0 ;調整單元數據大於或等於60時清0
CLR C ;清進位標志
lJMP SET4 SETHH:
CLR 00H ;分閃爍標志清除(進入調小時狀態)
SETHH1:
JNB P1.0,SET5 ;等待鍵釋放
SETB 01H ;小時調整標志置1
SET6:
JNB P1.0,SETOUT ;P1.0再次按下時退出時間調整
LCALL DISPLAY;
JB P1.1,SET6;等待按鍵按下
LCALL DL1S;
MOV R0,#79H ;按下P1.1時加1小時操作
LCALL DBchange ;調加1子程序
MOV A,R3 ;
CLR C ;
CJNE A,#24H,HOUU ;計時單元數據與24比較
HOUU:
JC SET6;小於24轉SET6循環
LCALL CLR0 ;大於或等於24時清0操作
AJMP SET6;跳轉到SET6循環
SETOUT:
JNB P1.0,SETOUT1 ;調時退出程序。等待鍵釋放
LCALL DISPLAY ;延時削抖
JNB P1.0,SETOUT ;是抖動,返回SETOUT再等待
OUTRETEND:
CLR 01H ;清調小時標志
CLR 00H ;清調分標志
CLR 02H ;清閃爍標志
CLR TR1 ;關閉定時器T1
CLR ET1 ;關定時器T1中斷
SETB TR0 ;開啟定時器T0
SETB ET0 ;開定時器T0中斷(計時開始)
SETB EX0;開啟外部中斷0
POP PSW;
POP ACC;
RETI ;反回主程序
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
SET1:
LCALL DISPLAY ;鍵釋放等待時調用顯示程序(調分)
LJMP SET2 ;防止鍵按下時無時鍾顯示
SET5:
LCALL DISPLAY ;鍵釋放等待時調用顯示程序(調小時)
LJMP SETHH1 ;防止鍵按下時無時鍾顯示
SETOUT1:
LCALL DISPLAY ;退出時鍾調整時鍵釋放等待
LJMP SETOUT ;防止鍵按下時無時鍾顯示
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; 顯示程序 ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; 顯示數據在70H-75H單元內,用六位LED共陽數碼管顯示,P0口輸出段碼數據,P2口作
; 掃描控制,每個LED數碼管亮1MS時間再逐位循環。
DISPLAY:
MOV R1,#70H ;指向顯示數據首址
MOV R5,#01H ;掃描控制字初值
PLAY:
MOV A,R5 ;掃描字放入A
MOV P2,A ;從P2口輸出
MOV A,@R1 ;取顯示數據到A
MOV DPTR,#TAB ;取段碼表地址
MOVC A,@A+DPTR ;查顯示數據對應段碼
MOV P0,A ;段碼放入P0口
LCALL DL1MS ;顯示1MS
INC R1 ;指向下一地址
MOV A,R5 ;掃描控制字放入A
JB ACC.5,ENDOUT ;ACC.5=1時一次顯示結束
RL A ;A中數據循環左移
MOV R5,A ;放回R5內
LJMP PLAY ;跳回PLAY循環
ENDOUT:
MOV P0,#00H ;P0口復位
RET ;子程序返回
TAB: DB 3FH,06H,5BH,4FH,66H,6DH,7DH,07H,7FH,6FH,00H
;共陰段碼表 "0""1""2" "3""4""5""6""7" "8""9""不亮"
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;整點報時;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
BELL:
MOV A,7BH;
CLR C;
MOV 7BH,#00H ;
CJNE A,#01H,BELLEND MOV A,79H;
SWAP A;
ORL A,78H;
MOV 7CH ,ABELLRING:
CLR P1.7;
LCALL DL05S;
SETB P1.7;
LCALL DL05S;
DJNZ 7CH,BELLRING; MOV A ,#00H;
MOV 7BH,#00H ;BELLEND:RET
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;省電模式
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
DISCLOSE:
JB P1.3,OUTDISCLOSE;
CLOSE1: MOV P2,#0FFH;
JNB P1.3,CLOSE1;
JB P1.3,CLOSE1;
CLOSE2: JNB P1.3,CLOSE2;
MOV P2,R5;
OUTDISCLOSE:RET;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; 延時程序 ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;1MS延時程序,LED顯示程序用
DL1MS: MOV R6,#14H
DL1: MOV R7,#19H
DL2: DJNZ R7,DL2
DJNZ R6,DL1
RET
;20MS延時程序,採用調用顯示子程序以改善LED的顯示閃爍現象
DS20MS: ACALL DISPLAY
ACALL DISPLAY
ACALL DISPLAY
RET
;延時程序,用作按鍵時間的長短判斷
DL1S: LCALL DL05S
LCALL DL05S
RET
DL05S: MOV R3,#20H ;8毫秒*32=0.196秒
DL05S1: LCALL DISPLAY
DJNZ R3,DL05S1
RET
END ;程序結束 但是做這個是自己做的,是可以調時間,不要的話可以把那個部分刪除。
Ⅳ 用單片機設計一個電子時鍾
MAIN
ORG 0000H
AJMP MAIN
ORG 000BH
AJMP CLOCK
ORG 0030H
PORT EQU 8000H
PORTA EQU 8001H
PORTB EQU 8002H
PORTC EQU 8003H
DISP0 EQU 30H
DISP1 EQU 31H
DISP2 EQU 32H
DISP3 EQU 33H
DISP4 EQU 34H
DISP5 EQU 35H
HOUR EQU 3CH
MIN EQU 3DH
SEC EQU 3EH
MSEC EQU 3FH
AHOUR EQU 40H
AMIN EQU 41H
ASEC EQU 42H
F1 BIT PSW.1
MAIN: MOV SP, #50H ;設置堆棧區
MOVX DPTR, #PORT
MOV A, #03H
MOVX @DPTR, A ;8155初始化
CLR F1 ;清零鬧鍾標志位
CLR F0 ;允許計時顯示
MOV AHOUR, #0FFH
MOV AMIN, #0FFH
MOV ASEC, #0FFH
MOV R7, #10H
MOV R0, #DISP0
CLR A
LOOP: MOV @R0, A
INC R0
DJNZ R7, LOOP ;設置初值
MOV TMOD, #01H
MOV TL0, #0B0H
MOV TH0, #3CH ;定時器0初始化,定時時間100ms
SETB TR0 ; 啟動定時器
SETB EA ;開中斷
SETB ET0
BEGIN: ACALL ALARM ;調用定時比較
ACALL KEYSCAN
CJNE A, #0AH, NEXT1 ;是CLR/RST鍵否?
CLR TR0 ;是則暫停計時
MOV R1, #HOUR ;地址指針指向計時緩沖區首地址
AJMP MOD
NEXT1: CJNE A, #0BH, BEGIN ;是ALARM鍵否?
JB F1, NEXT2 ;鬧鍾正在鬧響否?
MOV R1, #AHOUR ;地址指針指向鬧鍾值寄存區首地址
MOD: SETB F0 ;置位時間設置/鬧鍾定時標志禁止顯示計時時間ACALL MODIFY ;調用時間設置/鬧鍾定時程序
SETB TR0 ;重新開始計時
CLR F0 ;清零時間設置/鬧鍾定時標志,恢復顯示計時時間
AJMP BEGIN
NEXT2: SETB P1.0 ;鬧鍾正在鬧響,停鬧
CLR F1 ;清零鬧鍾標志
AJMP BEGIN
MODIFY: ACALL KEYIN ;調用鍵盤設置子程序
ACALL COMB ;調用合字子程序
RET
KEYIN: PUSH PSW
PUSH ACC
SETB RS1 ;保護現場
MOV R0, #DISP0 ;R0指向顯示緩沖區首地址
MOV R7, #06H ;設置鍵盤輸入次數
L1: CLR RS1
ACALL KEYSCAN ;調用數合法性檢測(是否在於9)
SETB RS1R
CJNE A, #0AH, L2
L2: JNC L1 ;大於9,重新鍵入
MOV @R1, A ;鍵號送顯示緩沖區
INC R1
DJNZ R7, L1 ;6位時間輸入完否?未完繼續,否則返回
POP ACC
POP PSW
CLR RS1 ;恢復現場
RET
KEYSCAN: ACALL TEST ;調判按鍵是否按下子程序TEST
JNZ REMOV ;有鍵按下調消抖延時
ACALL DISPLAY
ACALL ALARM
AJMP KEYSCAN ;無按鍵按下繼續判斷是否按鍵
REMOV: ACALL DISPLAY ;調用顯示子程序延時消抖
ACALL TEST ;再判是否有鍵按下
JNZ LIST ;有鍵按下轉逐列掃描
ACALL DISPLAY
ACALL ALARM
AJMP KEYSCAN ;無鍵按下繼續判斷是否按鍵
LIST: MOV R2, #0FEH ;首列掃描字送R2
MOV R3, #00H ;首列鍵號送R3
LINE0: MOV DPTR, #PORTA ;DPTR指針指向8155的A口
MOV A, R2 ;首列掃描字送R2
MOVX @DPTR, A ;首列掃描字送8155的A口
MOV DPTR, #PORTC ;DPTR指針指向8155的C口
MOVX A, @DPTR ;讀入C口的行狀態
JB ACC.0, EXIT ;第0行無鍵按下轉第一行
MOV A, #00H ;第0行有鍵按下,行首鍵號送A
AJMP TRYK ;求鍵號
NEXT: INC R3 ;掃描下一列
MOV A, R2 ;掃描字送A
JNB ACC.3, EXIT ;4列掃描完,重新進行下一輪掃描
RL A ;4列未掃描完,掃描字左移掃描下一列
MOV R2, A ;掃描字送A
AJMP LINE0 ;轉向掃描下一列
EXIT: AJMP KEYSCAN ;等待下一次按鍵
TRYK: ADD A, R3 ;按公式計算鍵碼,求得鍵號
PUSH ACC ;鍵號入棧保護
LETK: ACALL TEST ;等待按鍵釋放
JNZ LETK ;按鍵未釋放,繼續等待
POP ACC ;按鍵釋放,鍵號出棧
RET
TEST: MOV DPTR, #PORTA ;DPTR指針指向8155的A口
MOV A, #00H
MOVX @DPTR, A ;全掃描字00H送8155的A口
MOV DPTR, #PORTC ;DPTR指針指向8155的C口
MOVX A, @DPTR ;讀入C口行狀態
CPL A ;A取反,以高電平表示有鍵按下
ANL A, #07H ;屏蔽高5位
RET
DISPLAY:JB F0, DISP ;允許時間顯示標志F0=1轉DISP
ACALL SEPA ;否則調用SEPA刷新顯示緩沖區
DISP: PUSH PSW ;動態掃描顯示子程序
PUSH ACC
SETB RS0
MOV DPTR, #PORTA
MOV A, #0FFH
MOVX @DPTR, A ;關顯示
MOV R0, #DISP0
MOV R7, #00H
MOV R6, #06H
MOV R5, #0FEH
DIS1: MOV DPTR, #TAB
MOV A, @R0
MOVC A, @A+DPTR
MOV DPTR, #PORTB
MOVX @DPTR, A
MOV DPTR, #PORTA
MOV A, R5
MOVX @DPTR, A
HERE: DJNZ R7, HERE
INC R0
MOV A, R5
RL A
MOV R5, A
DJNZ R6, DIS1
CLR RS0
POP ACC
POP PSW
RET
TAB:DB 3FH,06H,5BH,4FH,66H,6DH,7DH,07H,7FH,6FH
COMB: MOV R0, #DISP1 ;R0指向顯示緩沖區小時低位
ACALL COMB1 ;合字
CJNE A, #24, CHK ;小時大於24否?
CHK: JNC EXIT1 ;大於24則取消本次設置,退出
MOV @R1, A ;否則小時送計時緩沖區/鬧鍾值寄存區小時單元
INC R1
MOV R0, #DISP3 ;R0指向顯示緩沖區分低位
ACALL COMB1
CJNE A, #60H, CHK1
CHK1: JNC EXIT1
MOV @R1, A
INC R1
MOV R0, #DISP5 ;R0指向顯示緩沖區秒低位
ACALL COMB1
CJNE A, #60H,CHK2
CHK2: JNC EXIT1
MOV @R1, A
RET
EXIT1: AJMP MAIN ;輸入不合法退出,重新清零計時
COMB1: MOV A, @R0
ANL A, #0FH ;取出低位
MOV 43H,A ;暫存於43H單元
DEC R0 ;指向高位
MOV A, @R0
ANL A, #0FH
SWAP A ;高位送高4位
ORL A, 43H ;高低位合並
RET
SEPA: PUSH PSW
PUSH ACC
SETB RS0
MOV R0, #DISP5 ;指向顯示緩沖區秒低位
MOV A, SEC
ACALL SEPA1
MOV A, MIN
ACALL SEPA1
MOV A, HOUR
ACALL SEPA1
POP ACC
POP PSW
RET
SEPA1: MOV 44H,A ;暫存44H
ANL A, #0FH ;取出低位
MOV @R0, A ;送顯示緩沖區低位
DEC R0 ;指向顯示緩沖區高位
MOV A, 44H
ANL A, #0F0H ;取出高位
SWAP A ;高位送往低四位形成高位數據
MOV @R0, A ;高位數據送顯示緩沖區高位
RET
ALARM: MOV A, ASEC
CJNE A, SEC, BACK ;秒單元相同則繼續比較,否則返回
MOV A, AMIN
CJNE A, MIN, BACK ;分單元相同則繼續比較,否則返回
MOV A, AHOUR
CJNE A, HOUR, BACK ;小時單元相同定時時間到
CLR P1.0 ;啟動鬧鍾鳴叫
SETB F1 ;置位鬧鍾標志
BACK: RET
CLOCK: MOV TL0, #0B7H
MOV TH0, #3CH ;重裝初值,時間校正
PUSH PSW
PUSH ACC ;保護現場
INC MSEC
MOV A, MSEC
CJNE A, #14H, DONE
MOV MSEC, #00H
MOV A, SEC
INC A
DA A ;二—十進制轉換
MOV SEC, A
CJNE A, #60H, DONE
MOV SEC, #00H
MOV A, MIN
INC A
DA A
MOV MIN, A
CJNE A, #60H, DONE
MOV MIN, #00H
MOV A, HOUR
INC A
DA A
MOV HOUR, A
CJNE A, #24H, DONE
MOV HOUR, #00H
DONE: POP ACC
POP PSW ;恢復現場
RETI
Ⅳ 急求:單片機課程設計電子時鍾
A方案
--------------------------
外加一顆時鍾晶元DS1302(非常准確)。
按鍵為單片機中斷。
--------------------------
1、上電時自動顯示時、分、秒;
實現方式:上電時單片機去啟動DS1202,然後讀取裡面的時間值,自動顯示時、分、秒;
2、設置一個控制按鍵,按下按鍵,則時鍾以秒為單位開始計時;
實現方式:將DS1302此時的值暫時保存,最為計時開始的時間。
然後不停地讀取DS1302里的新的時間值,
並將新的時間值 - 計時開始的時間 = 已計時數值
3、運行狀態下可通過控制按鍵使時鍾暫停,同時顯示已計時數值;
實現方式:顯示步驟2里的已計時數值。
4、停止狀態下(已上電),按下復位按鈕,時鍾復位(清零),並進入下一次計時狀態。
實現方式:計時開始的時間換成當前時間。
B方案
--------------------------
採用單片機內部定時器計時(不準)。
按鍵為單片機中斷。
--------------------------
步驟類似,不用去讀DS1302的時間,讀自己內部的時間。
Ⅵ 51單片機設計電子時鍾。
#include <reg51.h>
#define uint unsigned int
#define uchar unsigned char
sbit key1=P3^0;
sbit key2=P3^1;
uchar code table[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
uchar shi,fen,miao,num1 ,num2,num3,num4,num5,num6,num7;
void delayms (uint xms)
{
uint i,j;
for(i=xms;i>0;i--)
for(j=110;j>0;j--);
}
void miaodisplay (uchar num6,uchar num5)
{
P2=0x00;
P2=0x80;
P1=table[num6];
delayms(5);
P2=0x00;
P2=0x40;
P1=table[num5];
delayms(5);
}
void fendisplay(uchar num4,uchar num3)
{
P2=0x00;
P2=0x10;
P1=table[num4];
delayms(5);
P2=0x00;
P2=0x08;
P1=table[num3];
delayms(5);
}
void shidisplay(uchar num2,uchar num1)
{
P2=0x00;
P2=0x02;
P1=table[num2];
delayms(5);
P2=0x00;
P2=0x01;
P1=table[num1];
delayms(5);
}
void main ()
{
TMOD=0x01;
TH0=(65535-50000)/256;
TL0=(65535-50000)%256;
EA=1;
ET0=1;
TR0=1;
shi=0;
fen=0;
miao=0;
num7=0;
while (1)
{
num1=shi/10;
num2=shi%10;
num3=fen/10;
num4=fen%10;
num5=miao/10;
num6=miao%10;
miaodisplay(num6,num5);
P2=0x00;
P2=0x20;
P1=0xbf;
delayms(5);
fendisplay(num4,num3);
P2=0x00;
P2=0x04;
P1=0xbf;
delayms(5);
shidisplay(num2,num1);
}
}
void T0_time () interrupt 1
{
TH0=(65535-50000)/256;
TL0=(65535-50000)%256;
num7++;
if(num7==20)
{
num7=0;
miao++;
if(miao==60)
{
miao=0;
fen++;
if(fen==60)
{
fen=0;
shi++;
if(shi==24)
{
shi=0;
fen=0;
miao=0;
}
}
}
}
}
Ⅶ 單片機數字時鍾課程設計
這個 我正在學單片機,也剛剛做過了這個實驗沒多久,不過我的是8098單片機,確實是匯編語言。不過我做的僅僅是個電子鍾,你可以隨時改變你輸入的時間然後它就會按時分秒跳動,我做的是24小時制的。不過我沒有弄鬧鍾額……不過也簡單,可以弄一個中斷申請就ok。話說你的鬧鍾要求是什麼?我記得8098是不能響的,只有一個發光二極體可以亮一亮……
話說能請你把問題補充一下么?我的程序寫在紙上,然後我們還要求是要把程序翻譯出機器碼然後在單片機上實驗出結果的。所以我連機器碼都翻譯了的……實在不知道你們的要求。
原理可以先和你說一下:主程序先是一系列的初始化(中斷懸掛的清零和寄存器的設置,堆棧的設置等),然後開啟中斷,寫顯示程序(顯示程序前要弄好你顯示的寄存器以及掃描子程序的地址,還要對十六進制數進行轉換變成十進制數,只要做一個除法就行,用十六進制數除以A就能夠得出相應的十進制數。)
然後就是你的中斷程序了,比如你的中斷申請是每10ms申請一次,那你就計數,如果到了100次中斷了,那就秒加一,再查看秒是否到60,是則清零讓分加一,否則跳到中斷程序末端;然後再依次查分和時。最後中斷程序的末端還要用一次計時器軟體中斷申請。再跳回主程序反復運行。可能比較麻煩,我記得我打的草稿就好多張紙呢,後來在16進制向10進制轉換的時候還出了個寄存器的問題。
不知道和你程序的要求是否相同= =。
期待你能夠補充一下你的問題。
Ⅷ 單片機89c51的電子時鍾課程設計
#include <reg52.h>
#include<stddef.h>
#define uchar unsigned char
#define uint unsigned int
#define LCD1602_FLAG
#define LCD1602_PORT P0
sbit lcd1602_rs=P2^0;
sbit lcd1602_e=P2^2;
sbit lcd1602_rw=P2^1;
sbit lcd1602_busy=P0^7;
sbit key_ch=P3^5;
sbit key_add=P3^6;
sbit key_minus=P3^7;
uchar i,sec,min,h,date,month,flag;
uint year;
uchar *chgstr[7]={" ","sec","min","hour","date","min","year"};
uchar j,k,m,n,o,p;
uchar code table[]={
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71};
uchar timestr[10],datestr[10];
void init();
void delay(uint);
void time_display();
void date_display();
void control();
void time();
/*
************************************
* 函數名稱:lcd1602_CheckBusy()
* 函數功能:狀態查詢
************************************
*/
void lcd1602_CheckBusy()
{
do
{
lcd1602_busy=1;
lcd1602_rs=0;
lcd1602_rw=1;
lcd1602_e=0;
lcd1602_e=1;
}
while(lcd1602_busy);
}
/*
***************************************
* 函數名稱: lcd1602_WriteCmd()
* 函數功能:寫命令
* 入口參數:命令字
* 出口參數:無
***************************************
*/
void lcd1602_WriteCmd(const uchar cmd)
{
lcd1602_CheckBusy();
lcd1602_rs=0;
lcd1602_rw=0;
lcd1602_e=1;
LCD1602_PORT=cmd;
lcd1602_e=0;
}
/*
*******************************************
* 函數名稱:lcd1602_WriteData()
* 函數功能:寫數據
* 入口參數:c--待寫數據
* 出口參數:無
*********************************************
*/
void lcd1602_WriteData(const uchar c)
{
lcd1602_CheckBusy();
lcd1602_rs=1;
lcd1602_rw=0;
lcd1602_e=1;
LCD1602_PORT=c;
lcd1602_e=0;
}
/*
***********************************************
* 函數名稱:lcd1602_Init()
* 函數功能:初始化LCD
* 入口參數:無
* 出口參數:無
***********************************************
*/
void lcd1602_Init()
{
lcd1602_WriteCmd(0x38); //顯示模式為8位2行5*7點陣
lcd1602_WriteCmd(0x0c); //display enable,flag enable,flash enable,
lcd1602_WriteCmd(0x06); //flag move to right,screen don't move
lcd1602_WriteCmd(0x01); //clear screen
}
/*
************************************************
* 函數名稱:lcd1602_Display()
* 函數功能: 字元顯示
* 入口參數:ptr--字元或字元串指針
* 出口參數:無
* 說 明:用戶可通過以下方式來調用:
* 1)lcd1602_Display("Hello,world!");
* 2) INT8U 存儲類型 txt[]="要顯示的字元串";
* 或者 INT8U 存儲類型 txt[]={'t','x','t',..,'