標題:
51單片機的lcd1602+ds18b20+ds1302熱水器控制,軟硬件
[打印本頁]
作者:
qsfan1
時間:
2018-10-15 21:07
標題:
51單片機的lcd1602+ds18b20+ds1302熱水器控制,軟硬件
仿真原理圖如下(proteus仿真工程文件可到本帖附件中下載)
0.png
(17.66 KB, 下載次數: 67)
下載附件
2018-10-16 01:44 上傳
0.png
(44.59 KB, 下載次數: 66)
下載附件
2018-10-16 01:44 上傳
單片機源程序如下:
// 辛苦了 幾天總算好了,呵呵
#include <reg51.h>
#define uchar unsigned char
#define uint unsigned int
#define LCD_DATA P0
sbit RST=P1^4; //ds1302復位引腳,高電平有效
sbit IO=P1^3; //ds1302數據輸入輸出
sbit SCLK=P1^2; //ds1302串行時鐘
sbit LCD_RS=P2^5;
sbit LCD_RW=P2^6;
sbit LCD_E =P2^7;
sbit DQ=P3^4;
sbit baojing=P3^5;
bit add,dec,changett,ok=0;
uchar wendu,flag ,temp2[7],HH,LL;//功能標志
uchar code zidiyi[]={0x08,0x0F,0x12,0x0F,0x0A,0x1F,0x02,0x02, //年字點陣
0x0F,0x09,0x0F,0x09,0x0F,0x09,0x11,0x10, //月字點陣
0x0F,0x09,0x09,0x0F,0x09,0x09,0x0F,0x00, //日字點陣
0x10,0x06,0x09,0x08,0x08,0x09,0x06,0x00} ; //℃點陣
uchar idata buffer[3]={0X00,0X00,0X03};//定義兩段緩沖區(qū)
uchar code week[]={"MonTueWedThuFriSatSun"};//星期
uchar code wradd[]={0x80,0x82,0x84,0x86,0x88,0x8a,0x8c}; //ds1302寫地址,秒、分、時、日、月、星期、年
uchar code rdadd[]={0x81,0x83,0x85,0x87,0x89,0x8b,0x8d}; //ds1302讀地址
uchar idata temp[]={0x30,0x30,0x12,0x29,0x06,0x07,0x10};
uchar h_time[7],l_time[7]; //溫度個位,十位分別存放
uchar H=31,L=21; //溫度上下限
//void LCD_Init(void);
void LCD_Write_Data(uchar dat);
void LCD_Write_Cmd(uchar cmd,BusyC);
//uchar LCD_Read_Data(void);
void LCD_Delay(uint ms);
uchar LCD_Check_Busy(void);
//void writetab(void);
//***********由于實驗時電路板1602高低位數據接反,所以在向1602讀寫數據時調用此函數進行高低位調整***********//
uchar Convert (uchar In_Date)
{
uchar i, Out_Date, temp;
for(i=0; i<8; i++)
{
temp = (In_Date >> i) & 0x01;
Out_Date |= (temp << (7 - i));
}
return Out_Date;
}
//*******毫秒級延時********//
void delayus(uint x)
{
while(x--);
}
//********** 將自定義點陣輸入庫**********//
void ziding(void)
{uchar i;
LCD_Write_Cmd(0x40,1);// 自定義存儲地址從0X40開始
for(i=0;i<32;i++)
LCD_Write_Data(zidiyi[i]);
}
/*初始化lcd1602 */
/*******************************************************************/
void LCD_Init(void)
{
LCD_DATA=0;
LCD_Write_Cmd(0x38,1); //顯示模式設置,開始要求檢測忙信號:8位、2行、5X7點陣
LCD_Write_Cmd(0x08,1); //關閉顯示
LCD_Write_Cmd(0x01,1); //清屏
LCD_Write_Cmd(0x06,1); //顯示光標移動設置:文字不動,光標自動右移
LCD_Write_Cmd(0x0C,1); //顯示開及光標設置:光標關、光標不閃爍
ziding();
}
//************lcd寫數據***************//
void LCD_Write_Data(uchar dat)
{
LCD_Check_Busy();
LCD_DATA=Convert(dat);
LCD_RS=1;
LCD_RW=0;
LCD_E=0;
LCD_Delay(5);
LCD_E=1;
}
//*****************LCD寫命令******************//
void LCD_Write_Cmd(uchar cmd,BusyC)
{
if(BusyC) LCD_Check_Busy();
LCD_DATA=Convert(cmd);
LCD_RS=0;
LCD_RW=0;
LCD_E=0;
LCD_Delay(5);
LCD_E=1;
}
//***************lcd測忙*******************//
uchar LCD_Check_Busy(void)
{
LCD_DATA=0xFF;
LCD_RS=0;
LCD_RW=1;
LCD_E=0;
LCD_Delay(5);
LCD_E=1;
while(LCD_DATA & 0x01);
return(LCD_DATA);
}
//*****************************ms級延時函數*************************************//
void LCD_Delay(uint ms)
{
uchar i;
while(--ms)
{
for(i=0;i<123;i++);
}
}
//***************************設置顯示位置 ****************************************//
void LCD_Position(uchar pos)
{
pos|=0x80;
LCD_Write_Cmd(pos,0); //數據指針=80+地址變量
}
//************顯示十位個位**********//
void displayshige(uchar a ,uchar b, uchar adress)
{
LCD_Write_Cmd(adress,1);
delayus(2);
LCD_Write_Data(a);
delayus(2);
LCD_Write_Data(b);
delayus(2);
}
//....................ds18B20溫度檢測..........................//
void init18b20(void) //ds18b20初始化
{
uchar x;
DQ=1;
delayus(5);
DQ=0;
delayus(80);
DQ=1;
delayus(10);
x=DQ;
delayus(10);
}
void write18b20(uchar dat) //寫數據
{
uchar i;
for(i=0;i<8;i++)
{
DQ=0;
DQ=dat&0x01;
delayus(5);
DQ=1;
dat>>=1;
}
delayus(5);
}
uchar read18b20(void) //讀數據
{
uchar dat=0;
uchar i;
for(i=0;i<8;i++)
{
DQ=0;
dat>>=1;
DQ=1;
if(DQ) dat|=0x80;
delayus(5);
}
return(dat);
}
void readtmp(void) //讀溫度
{ uchar a,b,c;
uint aa;
init18b20();
write18b20(0xcc);//跳過讀序列號
write18b20(0x44);//開始轉換
init18b20();
write18b20(0xcc);//跳過讀序列號
write18b20(0xbe);//讀取溫度
a=read18b20();
b=read18b20();
c=a&0x0f;//分離出小數部分
b=(b&0x0f)<<4;
b|=(a&0xf0)>>4;//b里放整數
wendu=b;
aa=625*c;//可以直接用移位
displayshige(aa/1000+0x30,0x03, 0x83);
aa=0;
displayshige(b/10+0x30 ,b%10+0x30, 0x80);
LCD_Write_Data('.');
}
//****************DS1302寫 一字節(jié)數據*********//
void writebyte(uchar dat)
{
uchar i;
for(i=0;i<8;i++)
{
SCLK=0;
delayus(2);
IO=dat&0x01;
dat>>=1;
SCLK=1;
delayus(2);
}
}
//****************DS1302 寫 一字節(jié)數據*********//
void write1302(uchar addr,uchar dat) //傳遞地址與要寫的數據
{
RST=0;
delayus(2);
SCLK=0;
delayus(2);
RST=1;
delayus(2);
writebyte(addr);
writebyte(dat);
RST=0;
delayus(2);
}
//****************DS1302讀 一字節(jié)數據*********//
uchar read(uchar addr)
{
uchar i,dat=0;
RST=0;
delayus(2);
SCLK=0;
delayus(2);
RST=1;
delayus(2);
writebyte(addr);
for(i=0;i<8;i++)
{
dat>>=1;
SCLK=1;
delayus(2);
SCLK=0;
delayus(2);
if(IO) dat|=0x80;
}
RST=0;
delayus(2);
return(dat);
}
//*************1302初始化***************//
void init1302(void)
{
uchar i;
write1302(0x8e,0x00);//禁止寫保護?
for(i=0;i<7;i++)
{
write1302(wradd[i],temp[i]);
}
write1302(0x8e,0x80);// 寫保護
}
//*********** 讀出所有的數據***********//
void read1302(void)
{
uchar i;
for(i=0;i<7;i++)
{
temp[i]=read(rdadd[i]);
}
}
//**************將十位個位分離************//
void chang(void)
{
uchar i;
for(i=0;i<7;i++)
{if(i!=5)
{h_time[i]=temp[i]/16+0x30;
l_time[i]=temp[i]%16+0x30;}
else
{l_time[i]=temp[i]%16;}
}
}
//************顯示時間和日期、溫度**********//
void display(void)
{uchar i;
displayshige(h_time[6],l_time[6], 0xc0) ;//年
LCD_Write_Data(0);
displayshige(h_time[4],l_time[4], 0xc3) ;//月
LCD_Write_Data(1);
displayshige(h_time[3],l_time[3], 0xc6);//日
LCD_Write_Data(2);
displayshige(h_time[2],l_time[2], 0x85);//時
LCD_Write_Data(':');
displayshige(h_time[1],l_time[1], 0x88);//分
LCD_Write_Data(':');
displayshige(h_time[0],l_time[0], 0x8b);//秒
i=(l_time[5]-1)*3; //星期的顯示,先選出數組中的第幾位
LCD_Write_Cmd(0x8d,1); //顯示星期
LCD_Write_Data(week[i]);
LCD_Delay(2);
i++;
LCD_Write_Data(week[i]);
LCD_Delay(2);
i++;
LCD_Write_Data(week[i]); //顯示星期數
LCD_Delay(2);
if(!changett)//如果要修改時間,則不執(zhí)行下面高低溫度顯示
{LCD_Write_Cmd(0xca,1);
LCD_Write_Data('H');
displayshige(H/10+0x30,H%10+0x30, 0xcb);
LCD_Write_Cmd(0xcd,1);
LCD_Write_Data('L');
displayshige(L/10+0x30,L%10+0x30, 0xce);
}
}
//*********鍵掃描并確定功能********//
void keyscan(void)
{
uchar scode,recode,key,t;
P1=0xf0;
if((P1 & 0xf0)!=0xf0)
{
LCD_Delay(10);
if((P1 & 0xf0)!=0xf0)
{scode=0xfe;
while((scode &0x10)!=0)
{P1=scode;
if ((P1 & 0xf0)!=0xf0)
{
recode=(P1 & 0xf0)| 0x0f;
key=(~scode)+(~recode);
switch(key)
{case 0x11:changett=0; break;
case 0x21:if(changett)flag=1; break;//年
case 0x41:if(changett)flag=2; break;//月
case 0x81:if(changett)flag=3; break;//日
case 0x12:if(changett)flag=4; break;//時
case 0x22:if(changett)flag=5; break;//分
case 0x42:if(changett)flag=6; break;//秒
case 0x82:if(changett)flag=7; break;//周
case 0x14:if(changett)flag=8; break;//H
case 0x24:if(changett)flag=9; break;//L
case 0x44:if(flag>=1&&flag<=9){add=1; dec=0;}break;//加
case 0x84:if(flag>=1&&flag<=9){add=0; dec=1;}break;//減
case 0x18:break;//保存溫度
case 0x28:changett=1;for(t=0;t<7;t++)
temp2[t]=temp[t];HH=H;LL=L;;break;//改變時間,溫度
case 0x48:if(changett)ok=1;break;//確定設置的時間,溫度
}
}
else scode=(scode<<1)|0x01;
}
}
}
}
//***********設置時間和上下限溫度**********//
void timechange()
{
uchar num;
if(flag==1) //年
{
num=temp2[6]%16+(temp2[6]>>4)*10;
if(add)
{num++;add=0;}
if(dec)
{ num--;dec=0;}
temp[6]=num/10*16+num%10;
temp2[6]=temp[6];
}
if(flag==2) //月
{
num=temp2[4]%16+(temp2[4]>>4)*10;
if(add)
{num++;add=0;}
if(num==13) num=1;
if(dec)
{ num--;dec=0;}
if(num==00) num=12;
temp[4]=num/10*16+num%10;
temp2[4]=temp[4];
}
if(flag==3) //日
{
num=temp2[3]%16+(temp2[3]>>4)*10;
delayus(2);
if(add)
{num++;add=0;}
if(num==32) num=1;
if(dec)
{ num--;dec=0;}
if(num==00) num=31;
temp[3]=num/10*16+num%10;
temp2[3]=temp[3];
}
if(flag==4) //時
{
num=temp[2]%16+(temp2[2]>>4)*10;
if(add)
{num++;add=0;}
if(num==24) num=00;
if(dec)
{ num--;dec=0;}
if(num==-1) num=23;
temp[2]=num/10*16+num%10;
temp2[2]=temp[2];
}
if(flag==5) //分
{
num=temp2[1]%16+(temp2[1]>>4)*10;
if(add)
{num++;add=0;}
if(num==60) num=00;
if(dec)
{ num--;dec=0;}
if(num==-1) num=59;
temp[1]=num/10*16+num%10;
temp2[1]=temp[1];
}
if(flag==6) //秒
{
num=temp2[0]%16+(temp2[0]>>4)*10;
if(add)
{num++;add=0;}
if(num==60) num=00;
if(dec)
{ num--;dec=0;}
if(num==-1) num=59;
temp[0]=num/10*16+num%10;
temp2[0]=temp[0];
}
if(flag==7) //周
{
num=temp2[5]%16;
if(add)
{num++;add=0;}
if(num==0x08) num=1;
if(dec)
{ num--;dec=0;}
if(num==0x0) num=7;
temp[5]=num%10;
temp2[5]=temp[5];
}
if(flag==8) //H
{
if(add)
{HH++;add=0;}
if(dec)
{ HH--;dec=0;}
}
displayshige(0x20,'H', 0xc8);//高溫顯示
displayshige(HH/10+0x30,HH%10+0x30, 0xca);
if(flag==9) //L
{
if(add)
{LL++;add=0;}
if(dec)
{ LL--;dec=0;}
}
displayshige(0x20,'L', 0xcc);//高溫顯示
displayshige(LL/10+0x30,LL%10+0x30, 0xce);
}
……………………
…………限于本文篇幅 余下代碼請從51黑下載附件…………
復制代碼
所有資料51hei提供下載:
51的lcd1602 ds18b20 ds1302熱水器控制,軟硬件.rar
(48.75 KB, 下載次數: 89)
2018-10-15 21:06 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
作者:
nicene
時間:
2019-3-28 13:00
熱水器上顯示個時分秒就差不多了吧,顯示太多東西!操作過于復雜就違背了熱水器的初衷了吧
歡迎光臨 (http://www.torrancerestoration.com/bbs/)
Powered by Discuz! X3.1