|
|
|
/*By david QQ:26914190 */
/*此程序的目的是利用51hei提供的實(shí)驗(yàn)板實(shí)現(xiàn)一個(gè)簡(jiǎn)單的電子時(shí)鐘功能,其中用到了DS1302和LCD1602,以及獨(dú)立按鍵中的IT0和S4,S5,應(yīng)該說(shuō)我們的胡老師設(shè)計(jì)
板子的時(shí)候,真是煞費(fèi)苦心啊,剛剛好留了3個(gè)獨(dú)立鍵可以用,不多不少啊,哈哈。言歸正傳啊*/
/*此電子鐘能準(zhǔn)確的計(jì)時(shí),掉電后能繼續(xù)計(jì)時(shí)(應(yīng)該是要裝電池才行,嘿嘿),能手動(dòng)調(diào)節(jié)時(shí)間(星期是自己加的,1302中沒(méi)這個(gè)參數(shù)的哦),最主要的是能和我們的實(shí)驗(yàn)班完全兼容啊
燒錄進(jìn)去就可以用 ~O(∩_∩)0~ 。需要注意的是,這個(gè)程序需要初始化一下才能準(zhǔn)確計(jì)時(shí)的,初始化的方法是按住IT0鍵,然后再上電,等待1~3秒鐘之后松手即可*/
/*嘿嘿,俺是新手,寫(xiě)程序中還有很多不足的地方,希望能和大家多多交流,請(qǐng)各位老師同學(xué)們多多指教*/
#include
#include
#define uchar unsigned char
#define uint unsigned int
sbit sclk=P1^0;//1302
sbit io=P1^1;//1302
sbit rst=P2^0;//1302
sbit lcden=P3^4;//1602
sbit lcdrs=P3^5;//1602
sbit lcdwr=P2^7;//1602
sbit led=P2^6;//控制數(shù)碼管關(guān)斷的,個(gè)人覺(jué)得可有可無(wú),主要是省電,如果液晶亮度不夠,可以考慮一下。另外還有流水燈的也可以考慮關(guān)掉p14
sbit set=P3^2;//設(shè)置鍵定義,按下后依此設(shè)定年月日 小時(shí)分秒等
sbit addkey=P3^6;//設(shè)定時(shí)間時(shí)加數(shù)據(jù)
sbit deckey=P3^7;//設(shè)定時(shí)間時(shí)減數(shù)據(jù)
uchar flag,add,dec,check;
uchar sec,min,hr,day,mon,yr,week;
uchar code table[]="SUNMONTUEWEDTHUFRISAT";//星期顯示的字符串
uchar code table2[]={0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39};//0-9對(duì)應(yīng)的ASII碼
/********************************************************************************************************************/
//以下為1302的基本操作
void delayus()//4us的延時(shí),一個(gè)nop是1us
{
_nop_();
_nop_();
_nop_();
_nop_();
}
void write(uchar dat)//一個(gè)字節(jié)的數(shù)據(jù)
{
uchar i;
sclk=0;
delayus();
for(i=0;i<8;i++)
{
dat=dat>>1;//移位寄存器不管左移或者右移,被移出位都存入溢出位CY;
io=CY;
delayus();
sclk=1;
delayus();
sclk=0;
delayus();
}
}
uchar read()//讀一個(gè)字節(jié)的數(shù)據(jù)
{
uchar i,dat=0;
for(i=0;i<8;i++)
{
sclk=1;
delayus();
sclk=0;
delayus();
dat=_cror_(dat,1)|io;//此處采用的是循環(huán)右移指令,把數(shù)據(jù)讀出
}
return dat;
}
uchar read1302(uchar cmd)//從1302的特定位置cmd讀出數(shù)值
{
uchar dat;
rst=1;
write(cmd);
dat=read();
rst=0;
return dat;
}
void write1302(uchar cmd,uchar dat)//把數(shù)據(jù)dat寫(xiě)到1302的cmd對(duì)應(yīng)位置
{
rst=0;
sclk=0;
rst=1;
write(cmd);
write(dat);
}
/****************************************************************************/
void set1302()//1302設(shè)置,把設(shè)定好的時(shí)間寫(xiě)入1302
{
uchar shi,ge;
write1302(0x8E,0x00); //根據(jù)寫(xiě)狀態(tài)寄存器命令字,寫(xiě)入不保護(hù)指令
shi=sec/10;
ge=sec%10;
sec=(shi<<4)|ge;
write1302(0x80,sec); //根據(jù)寫(xiě)秒寄存器命令字,寫(xiě)入秒的初始值
shi=min/10;
ge=min%10;
min=(shi<<4)|ge;
write1302(0x82,min); //根據(jù)寫(xiě)分寄存器命令字,寫(xiě)入分的初始值
shi=hr/10;
ge=hr%10;
hr=(shi<<4)|ge;
write1302(0x84,hr); //根據(jù)寫(xiě)小時(shí)寄存器命令字,寫(xiě)入小時(shí)的初始值
shi=day/10;
ge=day%10;
day=(shi<<4)|ge;
write1302(0x86,day); //根據(jù)寫(xiě)日寄存器命令字,寫(xiě)入日的初始值
shi=mon/10;
ge=mon%10;
mon=(shi<<4)|ge;
write1302(0x88,mon); //根據(jù)寫(xiě)月寄存器命令字,寫(xiě)入月的初始值
shi=yr/10;
ge=yr%10;
yr=(shi<<4)|ge;
write1302(0x8c,yr); //根據(jù)寫(xiě)年寄存器命令字,寫(xiě)入年的初始值
write1302(0x8f,0x00);
}
void readtime()//從1302中讀取時(shí)間并對(duì)星期進(jìn)行計(jì)算
{
uchar shi,ge;
sec=read1302(0x81);
shi=(sec&0xf0)>>4;
ge=sec&0x0f;
sec=10*shi+ge;
min=read1302(0x83);
shi=(min&0xf0)>>4;
ge=min&0x0f;
min=10*shi+ge;
hr=read1302(0x85);
shi=(hr&0xf0)>>4;
ge=hr&0x0f;
hr=10*shi+ge;
day=read1302(0x87);
shi=(day&0xf0)>>4;
ge=day&0x0f;
day=10*shi+ge;
mon=read1302(0x89);
shi=(mon&0xf0)>>4;
ge=mon&0x0f;
mon=10*shi+ge;
yr=read1302(0x8d);
shi=(yr&0xf0)>>4;
ge=yr&0x0f;
yr=10*shi+ge;
if(day!=check)//計(jì)算星期值
{
week++;
check=day;
}
}
/****************************************************************************************************/
/*以下是1602的基本操作*/
void delay(uint z)//1mS延時(shí)子程序
{
uint a,b;
for(a=z;a>0;a--)
for(b=110;b>0;b--);
}
void write_com(uchar com)//寫(xiě)控制字LCD
{
lcdrs=0;//控制字
P0=com;
delay(5);
lcden=1;
delay(5);
lcden=0;
}
void write_data(uchar date)//寫(xiě)數(shù)據(jù)LCD
{
lcdrs=1;//數(shù)據(jù)
P0=date;
delay(5);
lcden=1;
delay(5);
lcden=0;
}
void write_week(uchar i)//顯示星期的函數(shù)
{
write_data(' ');
write_data(' ');
write_data(table[3*i]);
write_data(table[3*i+1]);
write_data(table[3*i+2]);
}
void write_time(uchar time)//顯示2位數(shù)時(shí)間,年月日均是2位數(shù)的格式
{
uchar shi,ge;
shi=time/10;
ge=time%10;
write_data(table2[shi]);
write_data(table2[ge]);
}
void display()//顯示年月日及星期等
{
write_com(0x80);
write_time(yr);
write_data('-');
write_time(mon);
write_data('-');
write_time(day);
write_week(week);
write_com(0x80+0x40);
write_time(hr);
write_data(':');
write_time(min);
write_data(':');
write_time(sec);
write_data(' ');
write_data(' ');
write_data('D');
write_data('a');
write_data('v');
write_data('i');
write_data('d');
}
void initlcd()//LCD顯示初始化。
{
led=0;
lcdwr=0;
lcden=0;
write_com(0x38);//按照1602的設(shè)定順序依此進(jìn)行設(shè)定、
write_com(0x0c);//不顯示光標(biāo)和閃爍
write_com(0x06);//每寫(xiě)一個(gè)字符,光標(biāo)+1
write_com(0x01);//清屏
}
/************************************************************************************/
//以下是鍵盤(pán)控制部分
void keyscan()//鍵盤(pán)掃描程序,看按下的是哪個(gè)鍵
{
if(set==0)
{
delay(30);
if(set==0)
{
while(!set);
delay(30);
while(!set);
flag=1;
}
}
if(addkey==0)
{
delay(30);
if(addkey==0)
{
while(!addkey);
delay(30);
while(!addkey);
add=1;
}
}
if(deckey==0)
{
delay(30);
if(deckey==0)
{
while(!deckey);
delay(30);
while(!deckey);
dec=1;
}
}
}
void timeset()//時(shí)間設(shè)定函數(shù),依此設(shè)置年,月,日(星期),小時(shí),分秒
{
if(flag==1)
{
flag=0;
write_com(0x0f);//開(kāi)啟光標(biāo)閃爍
write_com(0x80);//設(shè)置年的起始坐標(biāo)
while(!flag&&!add&&!dec)keyscan();//掃描鍵盤(pán),看是否有按鍵按下
while(!flag)
{
keyscan();
if(add==1)
{
add=0;
yr++;
write_time(yr);
}
if(dec==1)
{
dec=0;
yr--;
write_time(yr);
}
write_com(0x80);//年光標(biāo)設(shè)置歸位,等待下一次的設(shè)定
}
flag=0;
write_com(0x80+3);//設(shè)置月坐標(biāo)起始位
while(!flag&&!add&&!dec)keyscan();//掃描鍵盤(pán),看是否有按鍵按下
while(!flag)//如果有開(kāi)始判斷按鍵,
{
keyscan();
if(add==1)
{
add=0;
mon++;
if(mon>12)mon=1;
write_time(mon);
}
if(dec==1)
{
dec=0;
mon--;
if(mon>12)mon=1;
write_time(mon);
}
write_com(0x80+3);//月光標(biāo)設(shè)置歸位,等待下一次的設(shè)定
}
flag=0;
write_com(0x80+6);//設(shè)置天坐標(biāo)起始位
while(!flag&&!add&&!dec)keyscan();//掃描鍵盤(pán),看是否有按鍵按下
while(!flag)//如果有開(kāi)始判斷按鍵,
{
keyscan();
if(add==1)
{
add=0;
day++;
week++;
if(week>6)week=0;
if(day==29)
{
if((mon==2)&&(yr%4!=0))day=1;
}
if(day==30)
{
if((mon==2)&&(yr%4==0))day=1;
}
if(day==31)
{
if((mon==4)||(mon==6)||(mon==9)||(mon==11))day=1;
}
if(day>31)day=0;
write_time(day);
write_week(week);
}
if(dec==1)
{
dec=0;
day--;
week--;
if(week>6)week=6;
if(day==0)
{
if((mon==2)&&(yr%4!=0))day=28;
if((mon==2)&&(yr%4==0))day=29;
if((mon==4)||(mon==6)||(mon==9)||(mon==11))day=30;
if((mon==1)||(mon==3)||(mon==5)||(mon==7)||(mon==8)||(mon==10)||(mon==12))day=31;
}
write_time(day);
check=day;
write_week(week);
}
write_com(0x80+6);//天光標(biāo)設(shè)置歸位,等待下一次的設(shè)定
}
flag=0;
write_com(0x80+0x40);//設(shè)置小時(shí)坐標(biāo)起始位
while(!flag&&!add&&!dec)keyscan();//掃描鍵盤(pán),看是否有按鍵按下
while(!flag)
{
keyscan();
if(add==1)
{
add=0;
hr++;
if(hr>23)hr=0;
write_time(hr);
}
if(dec==1)
{
dec=0;
hr--;
if(hr>23)hr=23;
write_time(hr);
}
write_com(0x80+0x40);//小時(shí)光標(biāo)設(shè)置歸位,等待下一次的設(shè)定
}
flag=0;
write_com(0x80+0x40+3);//設(shè)置分鐘坐標(biāo)起始位
while(!flag&&!add&&!dec)keyscan();//掃描鍵盤(pán),看是否有按鍵按下
while(!flag)//如果有開(kāi)始判斷按鍵,
{
keyscan();
if(add==1)
{
add=0;
min++;
if(min>59)min=0;
write_time(min);
}
if(dec==1)
{
dec=0;
min--;
if(min>59)min=59;
write_time(min);
}
write_com(0x80+0x40+3);//小時(shí)光標(biāo)設(shè)置歸位,等待下一次的設(shè)定
}
flag=0;
write_com(0x80+0x40+6);//設(shè)置分鐘坐標(biāo)起始位
while(!flag&&!add&&!dec)keyscan();//掃描鍵盤(pán),看是否有按鍵按下
while(!flag)//如果有開(kāi)始判斷按鍵,
{
keyscan();
if(add==1)
{
add=0;
sec++;
if(sec>59)sec=0;
write_time(sec);
}
if(dec==1)
{
dec=0;
sec--;
if(sec>59)sec=59;
write_time(sec);
}
write_com(0x80+0x40+6);//小時(shí)光標(biāo)設(shè)置歸位,等待下一次的設(shè)定
}
flag=0;
set1302();
write_com(0x0c);
}
}
/**********************************************************************/
//主程序
void main()
{
while(set==0)//這里是給系統(tǒng)送初始值的,使用的方法是斷電之后,按住set鍵,然后上電,set鍵按住1~3s,松開(kāi)即設(shè)置完成
{
sec=11;min=20;hr=13;day=29;mon=2;yr=12;week=3;//初始值設(shè)定,這里要注意,星期的設(shè)定必須正確,不然后續(xù)的走時(shí)會(huì)出錯(cuò)。
set1302();
initlcd();
readtime();
display();
}
write1302(0x8f,0x00);//讀取數(shù)據(jù)時(shí),必須把1302設(shè)置為此狀態(tài),讀數(shù)據(jù)的寫(xiě)保護(hù)打開(kāi)
initlcd();
while(1)
{
keyscan();//鍵盤(pán)掃描
timeset();//如果設(shè)置鍵按下就設(shè)定時(shí)間,否則就往下執(zhí)行
readtime();
display();
}
} |
|