/***************************************************************************
*標題: 可調的DS1302時鐘在LCD1602上顯示 *
* *******************************************************************************
*接線:JP8接JP4、蜂鳴器短路帽的左端接到P3^2(用一根杜邦線) *
*說明:本實驗是在普中科技單片機開發板HC6800EM3上實現的 ******************************************************************************/
#include<reg52.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
sbit SCK=P3^6; //時鐘
sbit SDA=P3^4; //數據
sbit RST=P3^5; // DS1302復位
sbit lcdrs=P2^6;
sbit lcdrw=P2^5;
sbit lcden=P2^7;
sbit key1=P1^4;
sbit key2=P1^5;
sbit key3=P1^6;
sbit key4=P1^7;
sbit H=P1^1; //矩陣鍵盤第一行四個鍵
sbit beep=P3^2;
bit ReadRTC_Flag; //定義讀DS1302標志
uchar miao,fen,shi,ri,yue,week,nian,a,T,n=0;
char l_tmpdate[7]={50,8,1,7,10,1,12};//設置初始時間,秒分時日月周年12-10-07 01:08:50
uchar code write_rtc_address[7]={0x80,0x82,0x84,0x86,0x88,0x8a,0x8c}; //秒分時日月周年 最低位寫位
uchar code read_rtc_address[7]={0x81,0x83,0x85,0x87,0x89,0x8b,0x8d}; //秒分時日月周年 最低位讀位
uchar code table1[]="SUN"; //星期字表
uchar code table2[]="MON";
uchar code table3[]="TUE";
uchar code table4[]="WED";
uchar code table5[]="THU";
uchar code table6[]="FRI";
uchar code table7[]="SAT";
uchar code tab1[]="20 - -";
uchar code tab2[]=" : :";
/******************************************************************/
/* 函數聲明 */
/******************************************************************/
void Write_Ds1302_byte(uchar temp);
void Write_Ds1302( uchar address,uchar dat );
uchar Read_Ds1302 ( uchar address );
void Read_RTC(void);
void Set_RTC(void);
void delay(uchar a);
void ini_Timer();
void di();
void lcd_mang();
void write_lcd1602(uchar cmd,uchar i);
void ini_lcd1602();
void write_week(uchar xq);
void write_nyr(uchar add,uchar dat);
void write_sfm(uchar add,uchar dat);
void display();
void keyscan();
/******************************************************************/
/* 主函數 */
/******************************************************************/
void main(void)
{
ini_Timer();
ini_lcd1602();
//Set_RTC(); //寫入時鐘值,如果使用備用電池時候,不需要沒每次上電寫入,此程序應該屏蔽
while(1)
{
keyscan();
if(ReadRTC_Flag==0)
{
Read_RTC();
display();
}
}
}
/******************************************************************/
/* BCD轉換成LCD1602能顯示的16進制數,秒、分、時 */
/******************************************************************/
void write_sfm(uchar add,uchar dat)
{
uchar gw,sw;
gw=dat%16;
sw=dat/16;
write_lcd1602(0x80+0x40+add,0);
write_lcd1602(sw+0x30,1);
write_lcd1602(gw+0x30,1);
}
/******************************************************************/
/* BCD轉換成LCD1602能顯示的16進制數,日、月、年 */
/******************************************************************/
void write_nyr(uchar add,uchar dat)
{
uchar gw,sw;
gw=dat%16;
sw=dat/16;
write_lcd1602(0x80+add,0);
write_lcd1602(sw+0x30,1);
write_lcd1602(gw+0x30,1);
}
/******************************************************************/
/* 顯示星期 */
/******************************************************************/
void write_week(uchar xq)
{
uchar x;
write_lcd1602(0x80+12,0);
switch(xq)
{
case 1:
for(x=0;x<3;x++)
{
write_lcd1602(table1[x],1);
}
break;
case 2:
for(x=0;x<3;x++)
{
write_lcd1602(table2[x],1);
}
break;
case 3:
for(x=0;x<3;x++)
{
write_lcd1602(table3[x],1);
}
break;
case 4:
for(x=0;x<3;x++)
{
write_lcd1602(table4[x],1);
}
break;
case 5:
for(x=0;x<3;x++)
{
write_lcd1602(table5[x],1);
}
break;
case 6:
for(x=0;x<3;x++)
{
write_lcd1602(table6[x],1);
}
break;
case 7:
for(x=0;x<3;x++)
{
write_lcd1602(table7[x],1);
}
break;
}
write_lcd1602(0x80+12,0);
}
/******************************************************************/
/* 顯示函數 */
/******************************************************************/
void display()
{
write_sfm(10,miao);
write_sfm(7,fen);
write_sfm(4,shi);
write_nyr(3,nian);
write_nyr(6,yue);
write_nyr(9,ri);
write_week(week);
}
/******************************************************************/
/* 毫秒級延時函數 */
/******************************************************************/
void delay(uchar a)
{
uchar i;
while(a--)
{
for(i=0;i<250;i++)
{
_nop_();
_nop_();
_nop_();
_nop_();
}
}
}
/******************************************************************/
/* 定時器0使蜂鳴器發聲函數 */
/******************************************************************/
void ini_Timer()
{
a=0;
TMOD=0X01;
TH0=(65536-250)/256;
TL0=(65536-250)%256;
EA=1;
ET0=1;
TR0=1;
}
void timer0() interrupt 1
{
TH0=(65536-250)/256;
TL0=(65536-250)%256;
a++;
}
void di()
{
while(key1==0||key2==0||key3==0)
{
if(a==2)
{
a=0;
beep=~beep;
}
}
}
/******************************************************************/
/* LCD1602判忙函數 */
/******************************************************************/
void lcd_mang()
{
lcdrs=0;
lcdrw=1;
lcden=1;
_nop_();
_nop_();
_nop_();
_nop_();
while(P0&0x80);
lcden=0;
}
/******************************************************************/
/* LCD1602寫指令(i=0)、數據(i=1)函數 */
/******************************************************************/
void write_lcd1602(uchar cmd,uchar i)
{
lcd_mang();
lcdrs=i;
lcdrw=0;
lcden=0;
_nop_();
_nop_();
lcden=1;
_nop_();
_nop_();
P0=cmd;
_nop_();
_nop_();
_nop_();
_nop_();
lcden=0;
}
/******************************************************************/
/* LCD1602初始化函數 */
/******************************************************************/
void ini_lcd1602()
{
uchar i;
write_lcd1602(0x38,0);
delay(1);
write_lcd1602(0x0c,0);
delay(1);
write_lcd1602(0x06,0);
delay(1);
write_lcd1602(0x01,0);
delay(1);
write_lcd1602(0x80+1,0);
for(i=0;i<8;i++)
{
write_lcd1602(tab1[i],1);
}
write_lcd1602(0x80+0x40+4,0);
for(i=0;i<6;i++)
{
write_lcd1602(tab2[i],1);
}
}
/******************************************************************/
/* DS1302寫一個字節 */
/******************************************************************/
void Write_Ds1302_Byte(uchar temp)
{
uchar i;
for (i=0;i<8;i++) //循環8次 寫入數據
{
SCK=0;
SDA=temp&0x01; //每次傳輸低字節
temp>>=1; //右移一位
SCK=1;
}
}
/******************************************************************/
/* 寫入DS1302 */
/******************************************************************/
void Write_Ds1302( uchar address,uchar dat )
{
RST=0;
_nop_();
SCK=0;
_nop_();
RST=1;
_nop_(); //啟動
Write_Ds1302_Byte(address); //發送地址
Write_Ds1302_Byte(dat); //發送數據
RST=0; //恢復
}
/******************************************************************/
/* 讀出DS1302數據 */
/******************************************************************/
uchar Read_Ds1302 ( uchar address )
{
uchar i,temp=0x00;
RST=0;
_nop_();
_nop_();
SCK=0;
_nop_();
_nop_();
RST=1;
_nop_();
_nop_();
Write_Ds1302_Byte(address);
for (i=0;i<8;i++) //循環8次 讀取數據
{
if(SDA)
temp|=0x80; //每次傳輸低字節
SCK=0;
temp>>=1; //右移一位
_nop_();
_nop_();
_nop_();
SCK=1;
}
RST=0;
_nop_(); //以下為DS1302復位的穩定時間
_nop_();
RST=0;
SCK=0;
_nop_();
_nop_();
_nop_();
_nop_();
SCK=1;
_nop_();
_nop_();
SDA=0;
_nop_();
_nop_();
SDA=1;
_nop_();
_nop_();
return (temp); //返回
}
/******************************************************************/
/* 讀時鐘數據 */
/******************************************************************/
void Read_RTC(void) //讀取 日歷
{
uchar i,*p;
p=read_rtc_address; //地址傳遞
for(i=0;i<7;i++) //分7次讀取 秒分時日月周年
{
l_tmpdate[i]=Read_Ds1302(*p);
p++;
miao=l_tmpdate[0];
fen =l_tmpdate[1];
shi =l_tmpdate[2];
ri =l_tmpdate[3];
yue =l_tmpdate[4];
week=l_tmpdate[5];
nian=l_tmpdate[6];
}
}
/******************************************************************/
/* 設定時鐘數據 */
/******************************************************************/
void Set_RTC(void) //設定 日歷
{
uchar i,*p,tmp;
for(i=0;i<7;i++)
{ //BCD處理
tmp=l_tmpdate[i]/10;
l_tmpdate[i]=l_tmpdate[i]%10;
l_tmpdate[i]=l_tmpdate[i]+tmp*16;
}
Write_Ds1302(0x8E,0X00); //允許寫,禁止寫保護
p=write_rtc_address; //傳地址
for(i=0;i<7;i++) //7次寫入 秒分時日月周年
{
Write_Ds1302(*p,l_tmpdate[i]);
p++;
}
Write_Ds1302(0x8E,0x80); //打開寫保護
}
/******************************************************************/
/* 鍵盤掃描函數 */
/******************************************************************/
void keyscan()
{
H=0; //矩陣鍵盤第一排公共端拉低用于矩陣鍵盤的掃描檢測
if(key1==0) //功能鍵
{
delay(1);
if(key1==0)
{
di();
while(!key1); //松手檢測
++n;
ReadRTC_Flag=1; //停止走時
switch(n)
{
case 1: write_lcd1602(0x80+0x40+11,0); //按一次功能鍵秒閃爍
write_lcd1602(0x0f,0);
Write_Ds1302(0x8e,0x00); //允許寫,禁止寫保護
Write_Ds1302(0x80,0x80|miao); //寫入DS1302秒位
Write_Ds1302(0x8e,0x80); //打開寫保護
break;
case 2: write_lcd1602(0x80+0x40+8,0); //按兩次功能鍵分閃爍
break;
case 3: write_lcd1602(0x80+0x40+5,0); //按三次功能鍵時閃爍
break;
case 4: write_lcd1602(0x80+10,0); //按四次功能鍵日閃爍
break;
case 5: write_lcd1602(0x80+7,0); //按五次功能鍵月閃爍
break;
case 6:write_lcd1602(0x80+4,0); //按六次功能鍵年閃爍
break;
case 7: write_lcd1602(0x80+12,0); //按七次功能鍵周閃爍
break;
case 8: n=0; //按八次功能鍵開始走時,停止閃爍
ReadRTC_Flag=0;
write_lcd1602(0x0c,0);
Write_Ds1302(0x8e,0x00);
Write_Ds1302(0x80,0x00|miao);
Write_Ds1302(0x8e,0x80);
break;
}
}
}
if(n!=0) //功能加鍵
{
if(key2==0)
{
delay(1);
if(key2==0)
{
di();
while(!key2);
switch(n)
{
case 1: miao++;
if(miao>=60)
miao=0;
write_lcd1602(0x80+0x40+10,0); //使LCD1602在秒位上顯示“加”設好的秒數
write_lcd1602((miao)/10+'0',1); //十進制轉換成LCD1602能顯示的字符,顯示出來
write_lcd1602((miao)%10+'0',1);
T=(miao)/10*16+(miao)%10; //十進制轉換成DS1302能寫的BCD碼
Write_Ds1302(0x8e,0x00); //允許寫,禁止寫保護
Write_Ds1302(0x80,T); //寫入DS1302
Write_Ds1302(0x8e,0x80); //打開寫保護
write_lcd1602(0x80+0x40+11,0); //寫完數據后光標自動右移,所以要歸位
break;
case 2: fen++;
if(fen>=60)
fen=0;
write_lcd1602(0x80+0x40+7,0);
write_lcd1602((fen)/10+'0',1);
write_lcd1602((fen)%10+'0',1);
T=(fen)/10*16+(fen)%10;
Write_Ds1302(0x8e,0x00);
Write_Ds1302(0x82,T);
Write_Ds1302(0x8e,0x80);
write_lcd1602(0x80+0x40+8,0);
break;
case 3: shi++;
if(shi>=24)
shi=0;
write_lcd1602(0x80+0x40+4,0);
write_lcd1602((shi)/10+'0',1);
write_lcd1602((shi)%10+'0',1);
T=(shi)/10*16+(shi)%10;
Write_Ds1302(0x8e,0x00);
Write_Ds1302(0x84,T);
Write_Ds1302(0x8e,0x80);
write_lcd1602(0x80+0x40+5,0);
break;
case 4: ri++;
if(ri>31)
ri=1;
write_lcd1602(0x80+9,0);
write_lcd1602((ri)/10+'0',1);
write_lcd1602((ri)%10+'0',1);
T=(ri)/10*16+(ri)%10;
Write_Ds1302(0x8e,0x00);
Write_Ds1302(0x86,T);
Write_Ds1302(0x8e,0x80);
write_lcd1602(0x80+10,0);
break;
case 5: yue++;
if(yue>12)
yue=1;
write_lcd1602(0x80+6,0);
write_lcd1602((yue)/10+'0',1);
write_lcd1602((yue)%10+'0',1);
T=(yue)/10*16+(yue)%10;
Write_Ds1302(0x8e,0x00);
Write_Ds1302(0x88,T);
Write_Ds1302(0x8e,0x80);
write_lcd1602(0x80+7,0);
break;
case 6: nian++;
if(nian>=100)
nian=0;
write_lcd1602(0x80+3,0);
write_lcd1602((nian)/10+'0',1);
write_lcd1602((nian)%10+'0',1);
T=(nian)/10*16+(nian)%10;
Write_Ds1302(0x8e,0x00);
Write_Ds1302(0x8c,T);
Write_Ds1302(0x8e,0x80);
write_lcd1602(0x80+4,0);
break;
case 7: week++;
if(week>=8)
week=1;
write_week(week);
T=(week)/10*16+(week)%10;
Write_Ds1302(0x8e,0x00);
Write_Ds1302(0x8a,T);
Write_Ds1302(0x8e,0x80);
break;
}
}
}
}
if(key3==0) //功能減鍵
{
delay(1);
if(key3==0)
{
di();
while(!key3);
switch(n)
{
case 1: miao--;
if(miao<=0)
miao=59;
write_lcd1602(0x80+0x40+10,0);
write_lcd1602((miao)/10+'0',1);
write_lcd1602((miao)%10+'0',1);
T=(miao)/10*16+(miao)%10;
Write_Ds1302(0x8e,0x00);
Write_Ds1302(0x80,T);
Write_Ds1302(0x8e,0x80);
write_lcd1602(0x80+0x40+11,0);
break;
case 2: fen--;
if(fen<0)
fen=59;
write_lcd1602(0x80+0x40+7,0);
write_lcd1602((fen)/10+'0',1);
write_lcd1602((fen)%10+'0',1);
T=(fen)/10*16+(fen)%10;
Write_Ds1302(0x8e,0x00);
Write_Ds1302(0x82,T);
Write_Ds1302(0x8e,0x80);
write_lcd1602(0x80+0x40+8,0);
break;
case 3: shi--;
if(shi<0)
shi=23;
write_lcd1602(0x80+0x40+4,0);
write_lcd1602((shi)/10+'0',1);
write_lcd1602((shi)%10+'0',1);
T=(shi)/10*16+(shi)%10;
Write_Ds1302(0x8e,0x00);
Write_Ds1302(0x84,T);
Write_Ds1302(0x8e,0x80);
write_lcd1602(0x80+0x40+5,0);
break;
case 4: ri--;
if(ri<1)
ri=31;
write_lcd1602(0x80+9,0);
write_lcd1602((ri)/10+'0',1);
write_lcd1602((ri)%10+'0',1);
T=(ri)/10*16+(ri)%10;
Write_Ds1302(0x8e,0x00);
Write_Ds1302(0x86,T);
Write_Ds1302(0x8e,0x80);
write_lcd1602(0x80+10,0);
break;
case 5: yue--;
if(yue<0)
yue=12;
write_lcd1602(0x80+6,0);
write_lcd1602((yue)/10+'0',1);
write_lcd1602((yue)%10+'0',1);
T=(yue)/10*16+(yue)%10;
Write_Ds1302(0x8e,0x00);
Write_Ds1302(0x88,T);
Write_Ds1302(0x8e,0x80);
write_lcd1602(0x80+7,0);
break;
case 6: nian--;
if(nian<0)
nian=99;
write_lcd1602(0x80+3,0);
write_lcd1602((nian)/10+'0',1);
write_lcd1602((nian)%10+'0',1);
T=(nian)/10*16+(nian)%10;
Write_Ds1302(0x8e,0x00);
Write_Ds1302(0x8c,T);
Write_Ds1302(0x8e,0x80);
write_lcd1602(0x80+4,0);
break;
case 7: week--;
if(week<1)
week=7;
write_week(week);
T=(week)/10*16+(week)%10;
Write_Ds1302(0x8e,0x00);
Write_Ds1302(0x8a,T);
Write_Ds1302(0x8e,0x80);
break;
}
}
}
}
自己看吧 |