标题:
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};//定义两段缓冲区
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写 一字节数据*********//
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 写 一字节数据*********//
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读 一字节数据*********//
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)//如果要修改时间,则不执行下面高低温度显示
{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.51hei.com/bbs/)
Powered by Discuz! X3.1