液晶顯示AT89C52單片機DS1302實時時鐘程序
#include'reg52.h' //包含單片機寄存器的頭文件
#include'intrins.h' //包含_nop_()的頭文件
sbit RS=P2^0; //LCD讀寫選擇位
sbit RW=P2^1; //LCD讀寫選擇位
sbit E=P2^2; //LCD使能端
sbit BF=P0^7; //忙信號
sbit SCLK=P1^0; //1302時鐘輸出端
sbit DATA=P1^1; //1302數(shù)據(jù)端
sbit RST=P1^2; //1302復(fù)位端
unsigned char code digit[]="0123456789";
void delay1ms(unsigned int n)
{
unsigned char i;
while(n--)
for(i=0;i<115;i++);
}
void Write1302(unsigned char dat)
{
unsigned char i;
SCLK=0; //確保寫數(shù)據(jù)前SCLK為低電平
_nop_();
_nop_(); //給硬件反應(yīng)時間
for(i=0;i<8;i++){
DATA=dat&0x01; //取數(shù)據(jù)的最低位 低位在前,高位在后
_nop_();
_nop_(); //給硬件反應(yīng)時間
SCLK=1; //正跳變寫數(shù)據(jù)
_nop_();
_nop_(); //給硬件反應(yīng)時間
SCLK=0; //重新拉低SCLK,形成脈沖
dat>>=1; //dat右移,為寫入下位數(shù)據(jù)做準備
}
}
void WriteSet1302(unsigned char cmd, unsigned char dat)
{
RST=0; //禁止數(shù)據(jù)傳輸 .?。?!這條很重要
SCLK=0; //確保寫數(shù)據(jù)前SCLK為低電平
RST=1; //開啟數(shù)據(jù)傳輸
_nop_();
_nop_();
Write1302(cmd);
Write1302(dat);
SCLK=1; // 將時鐘電平置于高電平狀態(tài) ,處于已知狀態(tài)
RST=0;
}
unsigned char Read1302()
{
unsigned char i,dat=0;
for(i=0;i<8;i++){
dat>>=1;
if(DATA==1) //如果讀出的數(shù)據(jù)是1
dat|=0x80; //將1取出,寫在dat的最高位
SCLK=1; //將SCLK置于高電平,為下降沿讀出
_nop_();
_nop_();
SCLK=0; //拉低SCLK,形成脈沖下降沿
}
return dat;
}
unsigned char ReadSet1302(unsigned char cmd)
{
unsigned char dat;
RST=0; //這條很重要
SCLK=0; //確保寫數(shù)居前SCLK被拉低
RST=1; //啟動數(shù)據(jù)傳輸
_nop_();
_nop_();
Write1302(cmd); //寫入命令字
dat=Read1302(); //讀出數(shù)據(jù)
SCLK=1; //將時鐘電平置于已知狀態(tài)
RST=0; //禁止數(shù)據(jù)傳遞
return dat; //將讀出的數(shù)據(jù)返回
}
void DS1302_Int()
{
WriteSet1302(0x8E,0x00); //根據(jù)寫狀態(tài)寄存器命令字,寫入不保護指令
WriteSet1302(0x80,((55/10)<<4|(55))); //根據(jù)寫秒寄存器命令字,寫入秒的初始值
WriteSet1302(0x82,((59/10)<<4|(59))); //根據(jù)寫分寄存器命令字,寫入分的初始值
WriteSet1302(0x84,((23/10)<<4|(23))); //根據(jù)寫小時寄存器命令字,寫入小時的初始值
WriteSet1302(0x86,((18/10)<<4|(18))); //根據(jù)寫日寄存器命令字,寫入日的初始值
WriteSet1302(0x88,((6/10)<<4|(6))); //根據(jù)寫月寄存器命令字,寫入月的初始值
WriteSet1302(0x8c,((9/10)<<4|(9))); //根據(jù)寫年寄存器命令字,寫入年的初始值
WriteSet1302(0x90,0xa5); //打開充電功能 選擇2K電阻充電方式
WriteSet1302(0x8E,0x80); //根據(jù)寫狀態(tài)寄存器命令字,寫入保護指令
}
bit BusyTest()
{
bit result;
RS=0; //根據(jù)規(guī)定,RS為低電平,RW為高電平時,可以讀狀態(tài)
RW=1;
E=1;
_nop_();
_nop_();
result=BF; //將忙碌標志電平賦給result
E=0; //將E恢復(fù)低電平
_nop_();
_nop_();
return result;
}
void WriteInstruction(unsigned char dictate)
{
while(BusyTest()==1); //如果忙就等待
RS=0; //根據(jù)規(guī)定,RS和R/W同時為低電平時,可以寫入指令
RW=0;
E=0; //E置低電平(寫指令時,E為高脈沖,
// 就是讓E從0到1發(fā)生正跳變,所以應(yīng)先置"0"
_nop_();
_nop_();
P0=dictate;
_nop_();
_nop_();
_nop_();
_nop_();
E=1; //E置高電平
_nop_();
_nop_();
_nop_();
_nop_();
E=0; //當E由高電平跳變成低電平時,液晶模塊開始執(zhí)行命令
}
void WriteAddress(unsigned char x)
{
WriteInstruction(x|0x80); //顯示位置的確定方法規(guī)定為"80H+地址碼x"
}
void WriteData(unsigned char dat)
{
while(BusyTest()==1); //如果忙就等待
RS=1; //RS為高電平,RW為低電平時,可以寫入數(shù)據(jù)
RW=0;
E=0; //E置低電平(寫指令時,E為高脈沖,
// 就是讓E從0到1發(fā)生正跳變,所以應(yīng)先置"0"
_nop_();
_nop_();
P0=dat; //將數(shù)據(jù)送入P0口,即將數(shù)據(jù)寫入液晶模塊
_nop_();
_nop_();
_nop_();
_nop_();
E=1; //E置高電平
_nop_();
_nop_();
_nop_();
_nop_();
E=0; //當E由高電平跳變成低電平時,液晶模塊開始執(zhí)行命令
}
void LCD_Int()
{
delay1ms(15); //延時15ms,首次寫指令時應(yīng)給LCD一段較長的反應(yīng)時間
WriteInstruction(0x38); //顯示模式設(shè)置:16×2顯示,5×7點陣,8位數(shù)據(jù)接口
delay1ms(5);
WriteInstruction(0x38);
delay1ms(5);
WriteInstruction(0x38);
delay1ms(5); //連續(xù)三次,確保初始化成功
WriteInstruction(0x0c); //顯示模式設(shè)置:顯示開,無光標,光標不閃爍
delay1ms(5);
WriteInstruction(0x06); //顯示模式設(shè)置:光標右移,字符不移
delay1ms(5);
WriteInstruction(0x01); //清屏幕指令,將以前的顯示內(nèi)容清除
delay1ms(5);
}
void DisplaySecond(unsigned char x)
{
unsigned char i,j; //i,j分別儲存十位和個位
i=x/10;
j=x;
WriteAddress(0x49);
WriteData(digit[i]);
WriteData(digit[j]);
delay1ms(15);
}
void DisplayMinute(unsigned char x)
{
unsigned char i,j;
i=x/10;
j=x;
WriteAddress(0x46);
WriteData(digit[i]);
WriteData(digit[j]);
delay1ms(15);
}
void DisplayHour(unsigned char x)
{
unsigned char i,j;
i=x/10;
j=x;
WriteAddress(0x43);
WriteData(digit[i]);
WriteData(digit[j]);
delay1ms(15);
}
void DisplayDay(unsigned char x)
{
unsigned char i,j;
i=x/10;
j=x;
WriteAddress(0x0c);
WriteData(digit[i]);
WriteData(digit[j]);
delay1ms(15);
}
void DisplayMonth(unsigned char x)
{
unsigned char i,j;
i=x/10;
j=x;
WriteAddress(0x09);
WriteData(digit[i]);
WriteData(digit[j]);
delay1ms(15);
}
void DisplayYear(unsigned char x)
{
unsigned char i,j;
i=x/10;
j=x;
WriteAddress(0x06);
WriteData(digit[i]);
WriteData(digit[j]);
delay1ms(15);
}
void main()
{
unsigned char second,minute,hour,day,month,year; //分別儲存苗、分、小時,日,月,年
unsigned char ReadValue; //儲存從1302讀取的數(shù)據(jù)
LCD_Int(); //將液晶初始化
WriteAddress(0x01); //寫Date的顯示地址,將在第1行第2列開始顯示
WriteData('D');
WriteData('a');
WriteData('t');
WriteData('e');
WriteData(':');
WriteAddress(0x08);
WriteData('-');
WriteAddress(0x0b);
WriteData('-');
WriteAddress(0x45);
WriteData(':');
WriteAddress(0x48);
WriteData(':');
DS1302_Int(); //將1302初始化
while(1){
ReadValue = ReadSet1302(0x81); //從秒寄存器讀數(shù)據(jù)
second=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);//將讀出數(shù)據(jù)轉(zhuǎn)化
DisplaySecond(second); //顯示秒
ReadValue = ReadSet1302(0x83); //從分寄存器讀
minute=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F); //將讀出數(shù)據(jù)轉(zhuǎn)化
DisplayMinute(minute); //顯示分
ReadValue = ReadSet1302(0x85); //從分寄存器讀
hour=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F); //將讀出數(shù)據(jù)轉(zhuǎn)化
DisplayHour(hour); //顯示小時
ReadValue = ReadSet1302(0x87); //從分寄存器讀
day=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F); //將讀出數(shù)據(jù)轉(zhuǎn)化
DisplayDay(day); //顯示日