Ds3231+12864液晶顯示AT89C51帶溫度功能的時鐘程序
Ds3231+12864液晶顯示AT89C51帶溫度功能的時鐘程序。
#include
#include
#include
#define uchar unsigned char
#define uint unsigned int
sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_EN=P2^4;
sbit LCD_PSB=P2^3;
sbit DQ=P3^7; //18b20
sbit SDA=P1^4; //ds32321 //模擬I2C數(shù)據(jù)傳送位SDA
sbit SCL=P1^3; //模擬I2C時鐘控制位SCL
//
////
////
////
////
sbit K1=P3^2;
sbit K2=P3^3;
sbit K3=P3^4;
sbit K4=P3^5;
//定義變量
uchar numbr[10]="0123456789"; //字模
uchar dis4[]=" "; // 第四行顯示 自己添加
uchar t[]=" . ℃" ; //18b20
uint sdata,xiaoshu1,xiaoshu2; //整數(shù)、小數(shù)1位、小數(shù)2位
bit fg=1; //溫度正負標(biāo)志
uchar tempL=0,tempH=0; // 變量
uchar year,month,date,hour,min,sec; // ds3231
uchar a[]="2011年22月33日";
uchar b[]="11時22分33秒";
///函數(shù)
/
void write_cmd(uchar cmd)
{
LCD_RS=0;
LCD_RW=0;
LCD_EN=0;
P0=cmd;
delay1ms(5);
LCD_EN=1;
delay1ms(5);
LCD_EN=0;
}
void lcd_pos(uchar X, uchar Y)
{
ucharpos;
if(X== 0)
{
X= 0x80;
}
elseif(X == 1)
{
X= 0x90;
}
elseif(X == 2)
{
X= 0x88;
}
elseif(X == 3)
{
X= 0x98;
}
pos= X + Y;
write_cmd(pos); //顯示地址
}
void write_dat(uchar dat)
{
LCD_RS=1;
LCD_RW=0;
LCD_EN=0;
P0=dat;
delay1ms(5);
LCD_EN=1;
delay1ms(5);
LCD_EN=0;
}
void lcd_init()
{ uinti;
LCD_PSB=1; //并口方式
write_cmd(0x30); //基本操作指令
delay1ms(5);
write_cmd(0x0c); //打開顯示,光標(biāo)關(guān)閉
delay1ms(5);
write_cmd(0x01); //清除LCD顯示類容
delay1ms(5);
lcd_pos(3,0);
i=0;
while(dis4[ i]!='\0')
{
delay1ms(1);
write_dat(dis4);
delay1ms(1);
i++;
}
}
void Init_DS18B20(void) //初始化
{
uchar x=0;
DQ=1; //DQ先置高
delay(8); //稍延時
DQ=0; //發(fā)送復(fù)位脈沖
delay(80); //延時(>480us)
DQ=1; //拉高數(shù)據(jù)線
delay(5); //等待(15~60us)
x=DQ; //用X的值來判斷初始化有沒有成功,18B20存在的話X=0,否則X=1
delay(20);
}
//
ReadOneChar(void) //主機數(shù)據(jù)線先從高拉至低電平1us以上,再使數(shù)據(jù)線升為高電平,從而產(chǎn)生讀信號
{
unsigned char i=0; //每個讀周期最短的持續(xù)時間為60us,各個讀周期之間必須有1us以上的高電平恢復(fù)期
unsigned char dat=0;
for (i=8;i>0;i--) //一個字節(jié)有8位
{
DQ=1;
delay(1);
DQ=0;
dat>>=1;
DQ=1;
if(DQ)
dat|=0x80;
delay(4);
}
return(dat);
}
//
void WriteOneChar(unsigned char dat)
{
unsigned char i=0; //數(shù)據(jù)線從高電平拉至低電平,產(chǎn)生寫起始信號。15us之內(nèi)將所需寫的位送到數(shù)據(jù)線上,
for(i=8;i>0;i--) //在15~60us之間對數(shù)據(jù)線進行采樣,如果是高電平就寫1,低寫0發(fā)生。
{
DQ=0; //在開始另一個寫周期前必須有1us以上的高電平恢復(fù)期。
DQ=dat&0x01;
delay(5);
DQ=1;
dat>>=1;
}
delay(4);
}
void ReadTemperature(void) //讀溫度值(低位放tempL;高位放tempH;)//
{
Init_DS18B20(); //初始化
WriteOneChar(0xcc); //跳過讀序列號的操作
WriteOneChar(0x44); //啟動溫度轉(zhuǎn)換
delay(125); //轉(zhuǎn)換需要一點時間,延時
Init_DS18B20(); //初始化
WriteOneChar(0xcc); //跳過讀序列號的操作
WriteOneChar(0xbe); //讀溫度寄存器(頭兩個值分別為溫度的低位和高位)
tempL=ReadOneChar(); //讀出溫度的低位LSB
tempH=ReadOneChar(); //讀出溫度的高位MSB
if(tempH>0x7f) //最高位為1時溫度是負
{
tempL=~tempL; //補碼轉(zhuǎn)換,取反加一
tempH=~tempH+1;
fg=0; //讀取溫度為負時fg=0
}
sdata= tempL/16+tempH*16; //整數(shù)部分
xiaoshu1= (tempL&0x0f)*10/16; //小數(shù)第一位
xiaoshu2= (tempL&0x0f)*100/16;//小數(shù)第二位
t[0]=numbr[sdata/10];
t[1]=numbr[sdata];
t[3]=numbr[xiaoshu1];
t[4]=numbr[xiaoshu2];
}
#define ADDRTW 0xD0 //器件寫地址
#define ADDRTD 0xD1 //器件讀地址
#define DS3231_SEC 0x00 //秒
#define DS3231_MIN 0x01 //分
#define DS3231_HOUR 0x02 //時
#define DS3231_DAY 0x03 //星期
#define DS3231_DATE 0x04 //日
#define DS3231_MONTH 0x05 //月
#define DS3231_YEAR 0x06 //年
//鬧鈴1
#define DS3231_Al1SEC 0x07 //秒
#define DS3231_AL1MIN 0x08 //分
#define DS3231_AL1HOUR 0x09 //時
#define DS3231_AL1DAY 0x0A //星期/日
//鬧鈴2
#define DS3231_AL2MIN 0x0b //分
#define DS3231_AL2HOUR 0x0c //時
#define DS3231_AL2DAY 0x0d //星期/日
#define DS3231_CONTROL 0x0e //控制寄存器
#define DS3231_STATUS 0x0f //狀態(tài)寄存器
bit ack;
uchar BCD2HEX(uchar val) //BCD轉(zhuǎn)換為Byte
{ uchari;
i= val&0x0f;
val >>= 4;
val &= 0x0f;
val *= 10;
i+= val;
return i;
}
uchar HEX2BCD(uchar val)//B碼轉(zhuǎn)換為BCD碼
{
uchari,j,k;
i=val/10;
j=val;
k=j+(i<<4);
return k;
}
void Start()
{
SDA=1; //發(fā)送起始條件的數(shù)據(jù)信號
delay(1);
SCL=1;
delay(5); //起始條件建立時間大于4.7us,延時
SDA=0; //發(fā)送起始信號
delay(5); // 起始條件鎖定時間大于4μs
SCL=0; //鉗住I2C總線,準(zhǔn)備發(fā)送或接收數(shù)據(jù)
delay(2);
}
void Stop()
{
SDA=0; //發(fā)送結(jié)束條件的數(shù)據(jù)信號
delay(1); //發(fā)送結(jié)束條件的時鐘信號
SCL=1; //結(jié)束條件建立時間大于4us
delay(5);
SDA=1; //發(fā)送I2C總線結(jié)束信號
delay(4);
}
void SendByte(uchar Dat)
{
uchar BitCnt;
for(BitCnt=0;BitCnt<8;BitCnt++) //要傳送的數(shù)據(jù)長度為8位
{
if((Dat<
SDA=1; //判斷發(fā)送位
else
SDA=0;
delay(1);
SCL=1; //置時鐘線為高,通知被控器開始接收數(shù)據(jù)位
delay(5); //保證時鐘高電平周期大于4μs
SCL=0;
}
delay(2);
SDA=1; //8位發(fā)送完后釋放數(shù)據(jù)線,準(zhǔn)備接收應(yīng)答位
delay(2);
SCL=1;
delay(3);
if(SDA==1)
ack=0;
else
ack=1; //判斷是否接收到應(yīng)答信號
SCL=0;
delay(2);
}
uchar RcvByte() //功能: 用來接收從器件傳來的數(shù)據(jù),并判斷總線錯誤(不發(fā)應(yīng)答信號),發(fā)完后請用應(yīng)答函數(shù)應(yīng)答從機。
{
uchar retc;
uchar BitCnt;
retc=0;
SDA=1; //置數(shù)據(jù)線為輸入方式
for(BitCnt=0;BitCnt<8;BitCnt++)
{
delay(1);
SCL=0; //置時鐘線為低,準(zhǔn)備接收數(shù)據(jù)位
delay(5); //時鐘低電平周期大于4.7μs
SCL=1; //置時鐘線為高使數(shù)據(jù)線上數(shù)據(jù)有效
delay(3);
retc=retc<<1;
if(SDA==1)
retc=retc+1; //讀數(shù)據(jù)位,接收的數(shù)據(jù)位放入retc中
delay(2);
}
SCL=0;
delay(2);
return(retc);
}
void I2CACK(bit a) // 功能: 主控器進行應(yīng)答信號(可以是應(yīng)答或非應(yīng)答信號,由位參數(shù)a決定)
{
if(a==0)
SDA=0; //在此發(fā)出應(yīng)答或非應(yīng)答信號
else
SDA=1;
delay(3);
SCL=1;
delay(5); //時鐘低電平周期大于4μs
SCL=0; //清時鐘線,鉗住I2C總線以便繼續(xù)接收
delay(2);
}
uchar I2CRead()
{
uchar read_data;
Start();
SendByte(ADDRTD);
if(ack==0)
{
return(0);
}
read_data = RcvByte();
I2CACK(1);
Stop();
return read_data;
}
uchar I2CReadAdd(uchar addr)
{
Start();
SendByte(ADDRTW);
if(ack==0)
{
return(0);
}
SendByte(addr);
if(ack==0)
{
return(0);
}
return(I2CRead());
}
void Readtime()
{
uchar temp;
temp=I2CReadAdd(DS3231_SEC);//秒
sec=BCD2HEX(temp);
temp=I2CReadAdd(DS3231_MIN);//分
min=BCD2HEX(temp);
temp=I2CReadAdd(DS3231_HOUR); //時
hour=BCD2HEX(temp);
temp=I2CReadAdd(DS3231_DATE); //日
date=BCD2HEX(temp);
temp=I2CReadAdd(DS3231_MONTH); //月
month=BCD2HEX(temp);
temp=I2CReadAdd(DS3231_YEAR); //年
year=BCD2HEX(temp);
}
void InitDS3231() //ds3231初始化
{SCL=1;
delay(5);
SDA=1;
delay(5);
}
void TimeDisplay(uchar Dhour,ucharDmin,uchar Dsec) //時分秒數(shù)組賦值
{ b[0]=numbr[Dhour / 10]; // 時十位
b[1]=numbr[Dhour % 10]; // 時個位
b[4]=numbr[Dmin / 10]; // 分十位
b[5]=numbr[Dmin % 10]; // 分個位
b[8]=numbr[Dsec / 10]; // 秒十位
b[9]=numbr[Dsec % 10]; // 秒個位
}
void DateDisplay(uchar Dyear,ucharDmonth,uchar Dday) //年月天數(shù)組賦值
{ a[2]=numbr[Dyear / 10]; // 年十位
a[3]=numbr[Dyear % 10]; // 年個位
a[6]=numbr[Dmonth / 10]; // 月十位
a[7]=numbr[Dmonth % 10]; // 月個位
a[10]=numbr[Dday / 10]; // 天十位
a[11]=numbr[Dday % 10]; // 天個位
}
void Start_I2C()
{
SDA=1; //發(fā)送起始條件的數(shù)據(jù)信號
delay(1);
SCL=1;
delay(5); //起始條件建立時間大于4.7us,延時
SDA=0; //發(fā)送起始信號
delay(5); // 起始條件鎖定時間大于4μs
SCL=0; //鉗住I2C總線,準(zhǔn)備發(fā)送或接收數(shù)據(jù)
delay(2);
}
void Stop_I2C()
{
SDA=0; //發(fā)送結(jié)束條件的數(shù)據(jù)信號
delay(1); //發(fā)送結(jié)束條件的時鐘信號
SCL=1; //結(jié)束條件建立時間大于4us
delay(5);
SDA=1; //發(fā)送I2C總線結(jié)束信號
delay(4);
}
uchar write_byte(uchar addr, ucharwrite_data)
{
Start_I2C();
SendByte(ADDRTW); ///////////////
if (ack == 0)
return 0;
SendByte(addr);
if (ack == 0)
return 0;
SendByte(write_data);
if (ack == 0)
return 0;
Stop_I2C();
delay1ms(10);
return 1;
}
void ModifyTime(uchar yea,uchar mon,ucharda,uchar hou,uchar min,uchar sec)
{ uchar temp=0;
temp=HEX2BCD(yea);
write_byte(DS3231_YEAR,temp); //修改年
temp=HEX2BCD(mon);
write_byte(DS3231_MONTH,temp); //修改月
temp=HEX2BCD(da); /////////////////////
write_byte(DS3231_DATE,temp); //修改日
temp=HEX2BCD(hou);
write_byte(DS3231_HOUR,temp); //修改時
temp=HEX2BCD(min);
write_byte(DS3231_MIN,temp); //修改分
temp=HEX2BCD(sec);
write_byte(DS3231_SEC,temp); //修改秒
}
void xianshi(void)
{
{uint i;
TimeDisplay(hour,min,sec);
lcd_pos(1,1); //時間
i=0;
while(b[ i]!='\0')
{
delay1ms(1);
write_dat(b);
delay1ms(1);
i++;
}
DateDisplay(year,month,date); //顯示日期
delay1ms(1);
lcd_pos(0,0);
i=0;
while(a[ i]!='\0')
{
delay1ms(1);
write_dat(a);
delay1ms(1);
i++;
}
ReadTemperature(); //顯示溫度
delay1ms(1);
lcd_pos(2,1);
delay1ms(1);
i=0;
while(t[ i]!='\0')
{
delay1ms(1);
write_dat(t);
delay1ms(2);
i++;
}
}
}
void shuaxin(void)
{ uint i;
TimeDisplay(hour,min,sec);
lcd_pos(1,1); //時間
i=0;
while(b[ i]!='\0')
{
delay1ms(1);
write_dat(b);
delay1ms(1);
i++;
}
DateDisplay(year,month,date); //顯示日期
delay1ms(1);
lcd_pos(0,0);
i=0;
while(a[ i]!='\0')
{
delay1ms(1);
write_dat(a);
delay1ms(1);
i++;
}
}
void sotp(void)
{
uinti;
while(1)
{
duan1: if(K1==0)
{
delay1ms(100);
if(K1==0)
{
Readtime();
shuaxin();
i=0;
gotoduan2;
}
}
else
{gotoduan5;}
duan2: if(K2==0)
{
delay1ms(100);
if(K2==0)
{
i++;
if(i>6){i=0;}
shuaxin();
}
}
switch(i)
{
case 0: if(K3==0){delay1ms(100);if(K3==0){year=year+1;} if(year>=100){year=0;} shuaxin();}break;
case 1: if(K3==0){delay1ms(100);if(K3==0){month=month+1;} if(month>=13){month=0;} shuaxin();}break;
case 2: if(K3==0){delay1ms(100);if(K3==0){date=date+1;} if(date>=32){date=0;} shuaxin();}break;
case 3: if(K3==0){delay1ms(100);if(K3==0){hour=hour+1;} if(hour>=25){hour=0;} shuaxin();}break;
case 4: if(K3==0){delay1ms(100);if(K3==0){min=min+1;} if(min>=61){min=0;} shuaxin();}break;
case 5: if(K3==0){delay1ms(100);if(K3==0){sec=sec+1;} if(sec>=61){sec=0;} shuaxin();} break;
}
duan4: if(K4==0)
{
delay1ms(100);
if(K4==0)
{
ModifyTime(year,month,date,hour,min,sec);
gotoduan5; ///////////////////////////
}
}
else
{gotoduan2;}
duan5: Readtime();
xianshi();
}
}
main()
{
lcd_init();
delay1ms(5);
InitDS3231();
delay1ms(5);
delay1ms(5);
sotp();
}