基于ds1302的電子日歷系統在硬件選擇上主要采用AT89S51作為主控制系統;DS1302提供時鐘;DS18B20作為數字式溫度傳感器;LCD1602液晶屏作為顯示。
AT89C51單片機
單片機最小系統
AT89C51單片機采用Flash ROM,內部具有4KB ROM存儲空間,相對于本設計而言程序空間完全夠用。能于3V的超低壓工作,而且與MCS-51系列單片機完全兼容,而且運用于電路設計中時具備ISP在線編程技術,當在對電路進行調試時,由于程序的錯誤修改或對程序的新增功能需要燒入程序時,避免芯片的多次拔插對芯片造成的損壞。
ds1302
DS1302與單片機的連接
DS130是美國DALLAS公司推出的一種高性能、低功耗、帶RAM的實時時鐘電路,它可以對年、月、日、周日、時、分、秒進行計時,具有閏年補償功能,工作電壓為2.5V~5.5V。采用三線接口與CPU進行同步通信,并可采用突發方式一次傳送多個字節的時鐘信號或RAM數據。DS1302內部有一個31×8的用于臨時性存放數據的RAM寄存器。DS1302是DS1202的升級產品,與DS1202兼容,但增加了主電源/后背電源雙電源引腳,同時提供了對后背電源進行涓細電流充電的能力。主要特點是采用串行數據傳輸,可為掉電保護電源提供可編程的充電功能,并且可以關閉充電功能。采用普通32.768kHz晶振。而且DS1302有使用壽命長,誤差小等優點。
1602LCM點陣液晶顯示屏
LCM1602與單片機的連接
LCD液晶顯示屏,液晶顯示屏的顯示功能強大,可顯示大量文字,圖形,顯示多樣,清晰可見,對于電子萬年歷而言,一個1602的液晶屏即可,價格也還能接受,需要的接口線較多,但會給調試帶來諸多方便,
數字式溫度傳感器DS18B20
DS18B20管腳連線
此類傳感器為數字式傳感器而且僅需要一條數據線進行數據傳輸,易于與單片機連接,可以避免A/D模數轉換模塊,降低硬件成本,簡化系統電路。另外,數字式溫度傳感器還具有測量精度高、測量范圍廣等優點。
DS1302原理及說明
(1) 時鐘芯片DS1302的工作原理
DS1302在每次進行讀、寫程序前都必須初始化,先把SCLK端置 “0”,接著把RST端置“1”,最后才給予SCLK脈沖;讀/寫時序如下圖7所示。圖6為DS1302的控制字,此控制字的位7必須置1,若為0則不能把對DS1302進行讀寫數據。對于位6,若對程序進行讀/寫時RAM=1,對時間進行讀/寫時,CK=0。位1至位5指操作單元的地址。位0是讀/寫操作位,進行讀操作時,該位為1;該位為0則表示進行的是寫操作。控制字節總是從最低位開始輸入/輸出的。表2為DS1302的日歷、時間寄存器內容:“CH”是時鐘暫停標志位,當該位為1時,時鐘振蕩器停止,DS1302處于低功耗狀態;當該位為0時,時鐘開始運行。“WP”是寫保護位,在任何的對時鐘和RAM的寫操作之前,WP必須為0。當“WP”為1時,寫保護位防止對任一寄存器的寫操作。
(2) DS1302的控制字
DS1302的控制字如圖6所示。控制字節的高有效位(位7)必須是邏輯1,如果它為0,則不能把數據寫入DS1302中,位6如果0,則表示存取日歷時鐘數據,為1表示存取RAM數據;位5至位1指示操作單元的地址;最低有效位(位0)如為0表示要進行寫操作,為1表示進行讀操作,控制字節總是從最低位開始輸出。
DS1302的控制字
(3) 數據輸入輸出
在控制指令字輸入后的下一個SCLK時鐘的上升沿時,數據被寫入DS1302,數據輸入從低位即位0開始。同樣,在緊跟8位的控制指令字后的下一個SCLK脈沖的下降沿讀出DS1302的數據,讀出數據時從低位0位到高位7。
DS1302讀與寫的時序圖
(4) DS1302的寄存器
DS1302有12個寄存器,其中有7個寄存器與日歷、時鐘相關,存放的數據位為BCD碼形式,其日歷、時間寄存器及其控制字見圖。
DS1302的日歷、時間寄存器
此外,DS1302 還有年份寄存器、控制寄存器、充電寄存器、時鐘突發寄存器及與RAM相關的寄存器等。時鐘突發寄存器可一次性順序讀寫除充電寄存器外的所有寄存器內容。 DS1302與RAM相關的寄存器分為兩類:一類是單個RAM單元,共31個,每個單元組態為一個8位的字節,其命令控制字為C0H~FDH,其中奇數為讀操作,偶數為寫操作;另一類為突發方式下的RAM寄存器,此方式下可一次性讀寫所有的RAM的31個字節,命令控制字為FEH(寫)、FFH(讀)。
系統設計
主程序流程圖
時間調整程序流程圖
主程序:
#include《reg51.h》
#define uint unsigned int
#define uchar unsigned char
uchar a,miao,shi,fen,ri,yue,nian,week,key1n,temp;
#define yh 0x80
#define er 0x80+0x40
sbit DQ = P3^5;
sbit RS=P1^7;
sbit E=P2^4;
sbit RW=P1^6;
sbit IO=P1^5;
sbit SCLK=P1^4;
sbit RST=P2^2;
sbit ACC0=ACC^0;
sbit ACC7=ACC^7;
sbit key1=P1^0;
sbit key2=P1^2;
sbit key3=P1^3;
uchar code tab1[]={“20 - - ”};
uchar code tab2[]={“ : : ”};
void delay(uint xms)
{
uint x,y;
for(x=xms;x》0;x--) ;
for(y=110;y》0;y--);
}
//液晶寫入指令函數
write_1602com(uchar com)
{
RS=0;
RW=0;
P0=com;
delay(1);
E=1;
delay(1);
E=0;
}
//液晶寫入數據函數
write_1602dat(uchar dat)
{
RS=1;
RW=0;
P0=dat;
delay(1);
E=1;
delay(1);
E=0;
}
//液晶初始化函數
lcd_init()
{
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+2);
for(a=0;a《8;a++)
{
write_1602dat(tab2[a]);
delay(3);
}
}
/***************DS1302有關子函數********************/
//寫一個字節
void write_byte(uchar dat)
{
ACC=dat;
RST=1;
for(a=8;a》0;a--)
{
IO=ACC0;
SCLK=0;
SCLK=1;
ACC=ACC》》1;
}
}
//讀一個字節
uchar read_byte()
{
RST=1;
for(a=8;a》0;a--)
{
ACC7=IO;
SCLK=1;
SCLK=0;
ACC=ACC》》1;
}
return (ACC);
}
//向1302芯片寫函數,指定寫入地址,數據
void write_1302(uchar add,uchar dat)
{
RST=0;
SCLK=0;
RST=1;
write_byte(add);
write_byte(dat);
SCLK=1;
RST=0;
}
//從1302讀數據函數,指定讀取數據來源地址
uchar read_1302(uchar add)
{
uchar temp;
RST=0;
SCLK=0;
RST=1;
write_byte(add);
temp=read_byte(); SCLK=1;
RST=0; return(temp);
}
//BCD碼轉十進制函數,輸入BCD,返回十進制
uchar BCD_Decimal(uchar bcd)
{
uchar Decimal;
Decimal=bcd》》4;
return(Decimal=Decimal*10+(bcd&=0x0F));
}
//1302芯片初始化子函數(2012-06-26,00:00:00,week2)
void ds1302_init()
{
RST=0;
SCLK=0;
write_1302(0x8e,0x00);
write_1302(0x80,0x00);
write_1302(0x82,0x00);
write_1302(0x84,0x00);
write_1302(0x8a,0x02);
write_1302(0x86,0x26);
write_1302(0x88,0x06);
write_1302(0x8c,0x12);
write_1302(0x8e,0x80);
}
//時分秒顯示子函數
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’);
write_1602dat(‘O’);
write_1602dat(‘N’);
break;
case 2:
write_1602dat(‘T’);
write_1602dat(‘U’);
write_1602dat(‘E’);
break;
case 3:
write_1602dat(‘W’);
write_1602dat(‘E’);
write_1602dat(‘D’);
break;
case 4:
write_1602dat(‘T’
write_1602dat(‘H’);
write_1602dat(‘U’);
break;
case 5:
write_1602dat(‘F’);
write_1602dat(‘R’);
write_1602dat(‘I’);
break;
case 6:
write_1602dat(‘S’);
write_1602dat(‘T’);
write_1602dat(‘A’);
break;
case 7:
write_1602dat(‘S’);
write_1602dat(‘U’);
write_1602dat(‘N’);
break;
}
}
//*鍵盤掃描有關函數 void keyscan()
{
if(key1==0)
{
delay(9);
if(key1==0)
{
delay(20);
while(!key1);
key1n++;
if(key1n==9) key1n=1;
switch(key1n)
{
case 1:
TR0=0;
write_1602com(er+0x09);
write_1602com(0x0f);
temp=(miao)/10*16+(miao)%10;
write_1302(0x8e,0x00);
write_1302(0x80,0x80|temp);
write_1302(0x8e,0x80);
break; case 2: write_1602com(er+6);
break;
case 3:
write_1602com(er+3);
break;
case 4:
write_1602com(yh+0x0e);
break;
case 5:
write_1602com(yh+0x0a);
break;
case 6:
write_1602com(yh+0x07);
break;
case 7:
write_1602com(yh+0x04);
break;
case 8:
write_1602com(0x0c);
TR0=1;
temp=(miao)/10*16+(miao)%10;
write_1302(0x8e,0x00);
write_1302(0x80,0x00|temp);
write_1302(0x8e,0x80);
break;
}
}
}
if(key1n!=0)
{
if(key2==0)
{
delay(10);
if(key2==0)
{
delay(20);
while(!key2);
switch(key1n) {
case 1:miao++;
if(miao==60)
miao=0;
write_sfm(0x08,miao);
temp=(miao)/10*16+(miao)%10;
write_1302(0x8e,0x00);
write_1302(0x80,temp);
write_1302(0x8e,0x80);
write_1602com(er+0x09);
break;
case 2:fen++;
if(fen==60)
fen=0;
write_sfm(0x05,fen);
temp=(fen)/10*16+(fen)%10;
write_1302(0x8e,0x00);
write_1302(0x82,temp);
write_1302(0x8e,0x80);
write_1602com(er+6);
break; case 3:shi++;
if(shi==24)
shi=0;
write_sfm(2,shi);
temp=(shi)/10*16+(shi)%10;
write_1302(0x8e,0x00);
write_1302(0x84,temp);
write_1302(0x8e,0x80);
write_1602com(er+3);
break; case 4:week++;
if(week==8) week=1;
write_1602com(yh+0x0C);
write_week(week);
temp=(week)/10*16+(week)%10;
write_1302(0x8e,0x00);
write_1302(0x8a,temp);
write_1302(0x8e,0x80);
write_1602com(yh+0x0e);
break; case 5:ri++;
if(ri==32)
ri=1;
write_nyr(9,ri);
temp=(ri)/10*16+(ri)%10;
write_1302(0x8e,0x00);
write_1302(0x86,temp);
write_1302(0x8e,0x80);
write_1602com(yh+10);
break;
case 6:yue++;
if(yue==13)
yue=1;
write_nyr(6,yue);
temp=(yue)/10*16+(yue)%10;
write_1302(0x8e,0x00);
write_1302(0x88,temp);
write_1302(0x8e,0x80);
write_1602com(yh+7);
break;
case 7:nian++;
if(nian==100) nian=0;
write_nyr(3,nian);
temp=(nian)/10*16+(nian)%10;
write_1302(0x8e,0x00);
write_1302(0x8c,temp);
write_1302(0x8e,0x80);
write_1602com(yh+4);
break;
}
}
}
if(key3==0)
{
delay(10);
if(key3==0)
{
delay(20);
while(!key3);
switch(key1n)
{
case 1:miao--;
if(miao==-1)
miao=59;
write_sfm(0x08,miao);
temp=(miao)/10*16+(miao)%10;
write_1302(0x8e,0x00);
write_1302(0x80,temp);
write_1302(0x8e,0x80);
write_1602com(er+0x09);
break; case 2:fen--;
if(fen==-1)
fen=59;
write_sfm(5,fen);
temp=(fen)/10*16+(fen)%10;
write_1302(0x8e,0x00);
write_1302(0x82,temp);
write_1302(0x8e,0x80);
write_1602com(er+6);
break;
case 3:shi--;
if(shi==-1)
shi=23;
write_sfm(2,shi);
temp=(shi)/10*16+(shi)%10;
write_1302(0x8e,0x00);
write_1302(0x84,temp);
write_1302(0x8e,0x80);
write_1602com(er+3);
break; case 4:week--;
if(week==0)
week=7;
write_1602com(yh+0x0C);
write_week(week);
temp=(week)/10*16+(week)%10;
write_1302(0x8e,0x00);
write_1302(0x8a,temp);
write_1302(0x8e,0x80);
write_1602com(yh+0x0e);
break; case 5:ri--;
if(ri==0)
ri=31;
write_nyr(9,ri);
temp=(ri)/10*16+(ri)%10;
write_1302(0x8e,0x00);
write_1302(0x86,temp);
write_1302(0x8e,0x80);
write_1602com(yh+10);
break; case 6:yue--;
if(yue==0)
yue=12;
write_nyr(6,yue);
temp=(yue)/10*16+(yue)%10;
write_1302(0x8e,0x00);
write_1302(0x88,temp);
write_1302(0x8e,0x80);
write_1602com(yh+7);
break;
case 7:nian--;
if(nian==-1) nian=99;
write_nyr(3,nian);
temp=(nian)/10*16+(nian)%10;
write_1302(0x8e,0x00);
write_1302(0x8c,temp);
write_1302(0x8e,0x80);
write_1602com(yh+4);
break;
}
}
}
}
}
//定時器、計數器設置函數
void init()
{
TMOD=0x11;
TH0=0;
TL0=0;
EA=1;
ET0=1;
TR0=1;
}
/******************************* 延時函數 ********************************
* 功能:在11.059MHz的晶振條件下調用本函數需要24μs ,然后每次計數需16μs
**************************************************************************/
void DS18_delay(int useconds)
{
int s;
for (s=0; s《useconds;s++);
}
/******************************* 復位函數 *******************************
* 功能:完成單總線的復位操作
* 復位時間為480μs,因此延時時間為(480-24)/16 = 28.5,取29μs。
* 經過70μs之后檢測存在脈沖,因此延時時間為(70-24)/16 = 2.875,取3μs。
**************************************************************************/
unsigned char ow_reset(void)
{
unsigned char presence;
DQ = 0;
DS18_delay(29);
DQ = 1;
DS18_delay(3);
presence = DQ;
DS18_delay(25);
return(presence);
}
/****************************** 位寫入函數 *******************************
* 功能:向單總線寫入1位值:bitval
*************************************************************************/
void write_bit(char bitval) { DQ = 0;
if(bitval==1) DQ =1;
DS18_delay(5);
DQ = 1;
}
/**************************** 字節寫入函數 *******************************
* 功能:向單總線寫入一個字節值:val
*************************************************************************/
void ds18write_byte(char val)
{
unsigned char i;
unsigned char temp;
for (i=0; i《8; i++) {
temp = val》》i;
temp &= 0x01;
write_bit(temp);
}
DS18_delay(5);
}
/**************************** 位讀取函數 ********************************
* 功能:從單總線上讀取一位信號,所需延時時間為15μs,因此無法調用前面定義 * 的DS18_delay()函數,而采用一個for()循環來實現延時。 *
***********************************************************************/
unsigned char read_bit(void)
{
unsigned char i;
DQ = 0;
DQ = 1;
for (i=0; i《3; i++);
return(DQ);
}
/**************************** 字節讀取函數 *******************************
*功能:從單總線讀取一個字節的值*
*************************************************************************/
unsigned char DSread_byte(void)
{
unsigned char i; unsigned char value = 0; for (i=0;i《8;i++)
{
if(read_bit()) value|=0x01《《i;
DS18_delay(6);
}
return(value);
}
//*******************主函數**************************
void main() { lcd_init();
ds1302_init();
init();
delay(80);
while(1)
{
keyscan();
}
}
//取得并顯示日歷和時間
void timer0() interrupt 1
{
miao = BCD_Decimal(read_1302(0x81));
fen = BCD_Decimal(read_1302(0x83));
shi = BCD_Decimal(read_1302(0x85));
ri = BCD_Decimal(read_1302(0x87));
yue = BCD_Decimal(read_1302(0x89));
nian=BCD_Decimal(read_1302(0x8d));
week=BCD_Decimal(read_1302(0x8b));
write_sfm(8,miao);
write_sfm(5,fen);
write_sfm(2,shi);
write_nyr(9,ri);
write_nyr(6,yue);
write_nyr(3,nian);
write_week(week);
}
評論
查看更多