設計目的:通過設計,培養運用已學知識解決實際問題的能力、查閱資料的能力、自學能力和獨立分析問題、解決問題的能力和能通過獨立思考。
設計要求:設計一個時、分可調的數字電子鐘、斷電後將數據保存,開啟後時間將從斷電後時間繼續行走。
二、 設計內容與方案制定具有校時功能,按鍵控制電路其中時鍵、分鍵六個鍵分別控制時、分時間的調整。按下小時數實現對小時數加減,按下分鐘數實現對分鐘數進行加減,並設置有復位鍵,啟始鍵。
以AT89C51單片機進行實現秒、分、時上的正常顯示和進位,其中顯示功能由單片機控制共陰極數碼管來實現,數碼管進行動態顯示。
通過AT24C02分別寫入時、分、秒數據在斷電後實現保存,在下次通電後將數據讀出保持為斷電前數據。
三、 晶片簡介1、 AT89C52AT89C52是一個低電壓,高性能CMOS8位單片機,片內含8k bytes的可反覆擦寫的Flash只讀程序存儲器和256 bytes的隨機存取數據存儲器(RAM),器件採用ATMEL公司的高密度、非易失性存儲技術生產,兼容標準MCS-51指令系統,片內置通用8位中央處理器和Flash存儲單元,AT89C52單片機在電子行業中有著廣泛的應用。
AT89C52有40個引腳,32個外部雙向輸入/輸出(I/O)埠,同時內含2個外中斷口,3個16位可編程定時計數器,2個全雙工串行通信口,2 個讀寫口線,AT89C52可以按照常規方法進行編程,也可以在線編程。其將通用的微處理器和Flash存儲器結合在一起,特別是可反覆擦寫的 Flash存儲器可有效地降低開發成本。
AT89C52為8 位通用微處理器,採用工業標準的C51內核,在內部功能及管腳排布上與通用的8xc52 相同,其主要用於會聚調整時的功能控制。功能包括對會聚主IC 內部寄存器、數據RAM及外部接口等功能部件的初始化,會聚調整控制,會聚測試圖控制,紅外遙控信號IR的接收解碼及與主板CPU通信等。主要管腳有:XTAL1(19 腳)和XTAL2(18 腳)為振蕩器輸入輸出埠,外接12MHz 晶振。RST/Vpd(9 腳)為復位輸入埠,外接電阻電容組成的復位電路。VCC(40 腳)和VSS(20 腳)為供電埠,分別接+5V電源的正負端。P0~P3 為可編程通用I/O 腳,其功能用途由軟體定義,在本設計中,P0 埠(32~39 腳)被定義為N1功能控制埠,分別與N1的相應功能管腳相連接,13 腳定義為IR輸入端,10 腳和11腳定義為I2C總線控制埠,分別連接N1的SDAS(18腳)和SCLS(19腳)埠,12 腳、27 腳及28 腳定義為握手信號功能埠,連接主板CPU的相應功能端,用於當前制式的檢測及會聚調整狀態進入的控制功能。
2、 AT24C02AT24C02支持I2C,總線數據傳送協議I2C,總線協議規定任何將數據傳送到總線的器件作為發送器。任何從總線接收數據的器件為接收器。數據傳送是由產生串行時鐘和所有起始停止信號的主器件控制的。主器件和從器件都可以作為發送器或接收器,但由主器件控制傳送數據(發送或接收)的模式,由於A0、A1和A2可以組成000~111八種情況,即通過器件地址輸入端A0、A1和A2可以實現將最多8個AT24C02器件連接到總線上,通過進行不同的配置進行選擇器件。
AT24C02的存儲容量為2K bit,內容分成32頁,每頁8Byte,共256Byte,操作時有兩種尋址方式:晶片尋址和片內子地址尋址。
(1)晶片尋址:AT24C02的晶片地址為1010,其地址控制字格式為1010A2A1A0R/W。其中A2,A1,A0可編程地址選擇位。A2,A1,A0引腳接高、低電平後得到確定的三位編碼,與1010形成7位編碼,即為該器件的地址碼。R/W為晶片讀寫控制位,該位為0,表示晶片進行寫操作。
(2)片內子地址尋址:晶片尋址可對內部256B中的任一個進行讀/寫操作,其尋址範圍為00~FF,共256個尋址單位。
(1)按鍵控制電路
鍵盤可實現對時間的校對,用四個按鍵來實現。按下小時數加實現對小時數進行加一,按下小時數減實現對小時數減一,按下分鐘數加一實現對分鐘數加一,按下分鐘數減一實現對分鐘數減一。當按下復位鍵時時間回到初始時間,按下啟停鍵時時鐘開始工作在次按下停止工作。
其電路連接圖如下:
(3)AT24C02連接電路
AT24C02支持I2C,總線數據傳送協議I2C,總線協議規定任何將數據傳送到總線的器件作為發送器。任何從總線接收數據的器件為接收器。數據傳送是由產生串行時鐘和所有起始停止信號的主器件控制的。通過AT24C02分別寫入時、分、秒數據在斷電後實現保存,在下次通電後將數據讀出保持為斷電前數據。
1.3.繪製原理圖其計時周期為24小時,顯示滿刻度為23時59分59秒。整個設計圖由復位電路、AT89C51單片機、鍵盤控制電路組成。 顯示電路將「時」、「分」、「秒」通過七段顯示器顯示出來,6個數碼管的段選接到單片機的P0口,位選接到單片機的P2口。數碼管按照數碼管動態顯示的工作原理工作。 把定時器定時時間設為50ms,則計數溢出20次即得時鐘計時最小單位秒,而20次計數可用軟體方法實現,每累計60秒進1分,每累計60分鐘,進1小時。時採用24進位計時器,可實現對一天24小時的累計。校時電路時用來對「時」、「分」顯示數字進行校對調整,時分秒三個控制鍵分別接單片機的p3.2、p3.3、P3.4、P3.5進行控制。按一下分鍵秒單元就加1 ,按一下時鍵分就加1。將AT24C02接入P3.1和P3.2對斷電後數據保存,通電後數據從斷電前恢復運行。
單片機
AT89C51
*1
數碼管
7SEG-MPX8-CA-BLUE
*1
三極體
NPN
*8
按鈕
BUTTON
*6
上位排阻
RESPACK-8
*1
EEPROM
AT24C02
*1
數字電子鐘採用內部硬體定時器來進行定時。sec等於60,應將sec清零,同時min加1。如果min等於60,應將min清零,同時h加1。如果h大於23時,應將h清零,當h小於10時十位不顯示。通過分析可知,程序中可分別由
{
num2=0;
sec++;
if(sec==60)
{
sec=0;
min++;
if(min==60)
{
min=0;
h++;
if(h==24)
h=0;
}
}
}
這段程序負責秒、分、時的計時。
按鈕K1、K2和K3、K4為調時、調分控制按鍵。這兩個按鈕信號的輸入採用外部中斷方式來實現。若產生外部中斷時,通過調用H或_min來實現調時或調分操作。通過displays()顯示時分秒中間用「-」隔開每隔一秒實現閃爍。
斷電後數據保存,通過AT24C02晶片採用IIC串口通信解決掉電保護,具體將時、分、秒,數據每隔一秒時間將數據寫入AT24C02中,在斷電後數據停留在斷電前,通電後數據恢復。
2.2主程序:
void main()
{
init();
sec=read_add(0);
if(sec>60)
sec=0;
min=read_add(1);
if(min>60)
min=0;
h=read_add(2);
if(h>24)
h=0;
if(write==1)
{
write=0;
write_add(0,sec);
write_add(1,min);
write_add(2,h);
}
}
}
在主程序中先將讀出保存數據分別賦給h、min、sec然後判斷計時器是否到了一秒,如果到了就在24C02的地址0中寫入sec在地址1中寫入min在地址2中寫入h。最終實現數據斷電的保存。
#include<reg52.h>
#define uchar unsigned char
#define uint unsigned int
Ucharcode tab[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
bit write=0;
sbit key1=P3^2;
sbit key2=P3^3;
sbit key3=P3^4;
sbit key4=P3^5;
sbit key5=P3^6;
sbit key6=P3^7;
sbit sda=P3^1;
sbit scl=P3^0;
void delayms(uint);
void display();
sbit key=P3^2;
ucharnum2,secshi,secge,minshi,minge,hshi,hge;
uchar mun=0,sec=0,min=20,h=5;
void displays();
void keyscan();
void delay()
{;;}
void start()
{
sda=1;
delay();
scl=1;
delay();
sda=0;
delay();
}
void stop()
{
sda=0;
delay();
scl=1;
delay();
sda=1;
delay();
}
void respons()
{
uchari;
scl=1;
delay();
while((sda==1)&&(i<250))
i++;
scl=0;
delay();
}
void init()
{
sda=1;
delay();
scl=1;
delay();
}
void write_byte(uchar date)
{
uchari,temp;
temp=date;
for(i=0;i<8;i++)
{
temp=temp<<1;
scl=0;
delay();
sda=CY;
delay();
scl=1;
delay();
}
scl=0;
delay();
sda=1;
delay();
}
uchar read_byte()
{
uchari,k;
scl=0;
delay();
sda=1;
delay();
for(i=0;i<8;i++)
{
scl=1;
delay();
k=(k<<1)|sda;
scl=0;
delay();
}
returnk;
}
void write_add(ucharaddress,uchar date)
{
start();
write_byte(0xa0);
respons();
write_byte(address);
respons();
write_byte(date);
respons();
stop();
start();
write_byte(0xa1);
respons();
write_byte(address);
respons();
write_byte(date);
respons();
stop();
start();
write_byte(0xa2);
respons();
write_byte(address);
respons();
write_byte(date);
respons();
stop();
}
uchar read_add(uchar address)
{
uchardate;
start();
write_byte(0xa0);
respons();
write_byte(address);
respons();
start();
write_byte(0xa1);
respons();
date=read_byte();
stop();
start();
write_byte(0xa2);
respons();
write_byte(address);
respons();
start();
write_byte(0xa3);
respons();
write_byte(address);
respons();
returndate;
}
void main()
{
init();
sec=read_add(0);
if(sec>60)
sec=0;
min=read_add(1);
if(min>60)
min=0;
h=read_add(2);
if(h>24)
h=0;
TMOD=0x01;
EA=1;
ET0=1;
TH0=(65536-45872)/256;
TL0=(65536-45872)%256;
TR0=1;
while(1)
{
displays();
display();
if(write==1)
{
write=0;
write_add(0,sec);
write_add(1,min);
write_add(2,h);
}
keyscan();
}
}
void displays()
{
if(num2==0)
{
P2=0xdb;
P0=0x40;
delayms(2);
}
}
void display( )
{
secshi=sec/10;
secge=sec%10;
minshi=min/10;
minge=min%10;
hshi=h/10;
hge=h%10;
P2=0xbf;
P0=tab[secshi];
delayms(2);
P2=0x7f;
P0=tab[secge];
delayms(2);
P2=0xf7;
P0=tab[minshi];
delayms(2);
P2=0xef;
P0=tab[minge];
delayms(2);
P2=0xfe;
P0=tab[hshi];
delayms(2);
P2=0xfd;
P0=tab[hge];
delayms(2);
}
void delayms(uint xms)
{
uintx,y;
for(x=xms;x>0;x--)
for(y=110;y>0;y--);
}
void keyscan()
{
if(key1==0)
{
delayms(10);
if(key1==0)
{
h++;
if(h==24)
{
h=0;
}
while(!key1);
}
}
if(key2==0)
{
delayms(10);
if(key2==0)
{
h--;
if(h==0)
{
h=24;
}
while(!key2);
}
}
if(key3==0)
{
delayms(10);
if(key3==0)
{
min++;
if(min==60)
min=0;
while(!key3);
}
}
if(key4==0)
{
delayms(10);
if(key4==0)
{
if(min==0)
min=60;
min--;
while(!key4);
}
}
if(key5==0)
{
delayms(10);
if(key5==0)
{
min=20;
h=5;
sec=0;
while(!key5);
}
}
if(key6==0)
{
delayms(10);
if(key6==0)
{
while(!key6);
TR0=~TR0;
}
}
}
void T0_time()interrupt 1
{
TH0=(65536-45872)/256;
TL0=(65536-45872)%256;
num2++;
if(num2==20)
{
num2=0;
sec++;
write=1;
if(sec==60)
{
sec=0;
min++;
if(min==60)
{
min=0;
h++;
if(h==24)
{
h=0;
}
}
}
}
}