仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
单片机源程序如下:
- // 辛苦了 几天总算好了,呵呵
- #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)
|