找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3917|回复: 1
收起左侧

51单片机的lcd1602+ds18b20+ds1302热水器控制,软硬件

[复制链接]
ID:92643 发表于 2018-10-15 21:07 | 显示全部楼层 |阅读模式
仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
0.png 0.png

单片机源程序如下:
  1. //   辛苦了 几天总算好了,呵呵

  2. #include <reg51.h>
  3. #define uchar unsigned char
  4. #define uint  unsigned int        
  5. #define LCD_DATA P0


  6. sbit RST=P1^4;      //ds1302复位引脚,高电平有效
  7. sbit IO=P1^3;       //ds1302数据输入输出
  8. sbit SCLK=P1^2;     //ds1302串行时钟

  9. sbit LCD_RS=P2^5;
  10. sbit LCD_RW=P2^6;
  11. sbit LCD_E =P2^7;
  12. sbit DQ=P3^4;
  13. sbit baojing=P3^5;
  14. bit add,dec,changett,ok=0;
  15. uchar  wendu,flag ,temp2[7],HH,LL;//功能标志
  16. uchar code  zidiyi[]={0x08,0x0F,0x12,0x0F,0x0A,0x1F,0x02,0x02, //年字点阵
  17.                      0x0F,0x09,0x0F,0x09,0x0F,0x09,0x11,0x10, //月字点阵
  18.                      0x0F,0x09,0x09,0x0F,0x09,0x09,0x0F,0x00,   //日字点阵
  19.                      0x10,0x06,0x09,0x08,0x08,0x09,0x06,0x00} ; //℃点阵

  20. uchar idata buffer[3]={0X00,0X00,0X03};//定义两段缓冲区  
  21. uchar code week[]={"MonTueWedThuFriSatSun"};//星期
  22. uchar code wradd[]={0x80,0x82,0x84,0x86,0x88,0x8a,0x8c}; //ds1302写地址,秒、分、时、日、月、星期、年
  23. uchar code rdadd[]={0x81,0x83,0x85,0x87,0x89,0x8b,0x8d}; //ds1302读地址
  24. uchar idata temp[]={0x30,0x30,0x12,0x29,0x06,0x07,0x10};                                          
  25. uchar h_time[7],l_time[7];  //温度个位,十位分别存放
  26. uchar H=31,L=21;                  //温度上下限

  27. //void LCD_Init(void);
  28. void LCD_Write_Data(uchar dat);
  29. void LCD_Write_Cmd(uchar cmd,BusyC);
  30. //uchar LCD_Read_Data(void);
  31. void LCD_Delay(uint ms);
  32. uchar LCD_Check_Busy(void);
  33. //void writetab(void);

  34. //***********由于实验时电路板1602高低位数据接反,所以在向1602读写数据时调用此函数进行高低位调整***********//
  35. uchar Convert (uchar In_Date)
  36. {
  37.     uchar i, Out_Date, temp;
  38.     for(i=0; i<8; i++)
  39.     {
  40.         temp = (In_Date >> i) & 0x01;
  41.         Out_Date |= (temp << (7 - i));
  42.     }
  43.     return Out_Date;
  44. }


  45. //*******毫秒级延时********//
  46. void delayus(uint x)
  47. {
  48. while(x--);
  49. }


  50. //********** 将自定义点阵输入库**********//
  51. void ziding(void)
  52. {uchar i;
  53. LCD_Write_Cmd(0x40,1);// 自定义存储地址从0X40开始
  54.   for(i=0;i<32;i++)
  55.   LCD_Write_Data(zidiyi[i]);
  56. }


  57. /*初始化lcd1602                                      */
  58. /*******************************************************************/
  59. void LCD_Init(void)
  60. {
  61. LCD_DATA=0;      

  62. LCD_Write_Cmd(0x38,1);   //显示模式设置,开始要求检测忙信号:8位、2行、5X7点阵
  63. LCD_Write_Cmd(0x08,1);   //关闭显示
  64. LCD_Write_Cmd(0x01,1);   //清屏
  65. LCD_Write_Cmd(0x06,1);   //显示光标移动设置:文字不动,光标自动右移
  66. LCD_Write_Cmd(0x0C,1);   //显示开及光标设置:光标关、光标不闪烁
  67. ziding();
  68. }
  69. //************lcd写数据***************//
  70. void LCD_Write_Data(uchar dat)
  71. {
  72. LCD_Check_Busy();
  73. LCD_DATA=Convert(dat);
  74. LCD_RS=1;
  75. LCD_RW=0;
  76. LCD_E=0;
  77. LCD_Delay(5);
  78. LCD_E=1;
  79. }
  80. //*****************LCD写命令******************//
  81. void LCD_Write_Cmd(uchar cmd,BusyC)
  82. {
  83. if(BusyC) LCD_Check_Busy();
  84. LCD_DATA=Convert(cmd);
  85. LCD_RS=0;
  86. LCD_RW=0;
  87. LCD_E=0;
  88. LCD_Delay(5);
  89. LCD_E=1;
  90. }
  91. //***************lcd测忙*******************//
  92. uchar LCD_Check_Busy(void)
  93. {
  94.   LCD_DATA=0xFF;
  95.   LCD_RS=0;
  96.   LCD_RW=1;
  97.   LCD_E=0;
  98.   LCD_Delay(5);
  99.   LCD_E=1;
  100.   while(LCD_DATA & 0x01);
  101.   return(LCD_DATA);
  102. }

  103.      
  104. //*****************************ms级延时函数*************************************//
  105. void LCD_Delay(uint ms)
  106. {
  107.   uchar i;
  108.   while(--ms)
  109.   {
  110.     for(i=0;i<123;i++);
  111.    }
  112. }

  113.                                     
  114. //***************************设置显示位置 ****************************************//
  115. void LCD_Position(uchar pos)
  116. {
  117.   pos|=0x80;
  118.   LCD_Write_Cmd(pos,0);  //数据指针=80+地址变量
  119. }


  120. //************显示十位个位**********//
  121. void displayshige(uchar a ,uchar b, uchar adress)
  122. {
  123. LCD_Write_Cmd(adress,1);
  124. delayus(2);
  125. LCD_Write_Data(a);   
  126. delayus(2);
  127. LCD_Write_Data(b);
  128. delayus(2);
  129. }


  130. //....................ds18B20温度检测..........................//
  131. void init18b20(void)  //ds18b20初始化
  132. {
  133. uchar x;
  134. DQ=1;
  135. delayus(5);
  136. DQ=0;
  137. delayus(80);
  138. DQ=1;
  139. delayus(10);
  140. x=DQ;
  141. delayus(10);
  142. }

  143. void write18b20(uchar dat)  //写数据
  144. {
  145. uchar i;
  146. for(i=0;i<8;i++)
  147. {
  148.   DQ=0;
  149.   DQ=dat&0x01;
  150.   delayus(5);
  151.   DQ=1;
  152.   dat>>=1;
  153. }
  154. delayus(5);
  155. }

  156. uchar read18b20(void)    //读数据
  157. {
  158. uchar dat=0;
  159. uchar i;
  160. for(i=0;i<8;i++)
  161. {
  162.   DQ=0;
  163.   dat>>=1;
  164.   DQ=1;
  165.   if(DQ) dat|=0x80;
  166.   delayus(5);
  167. }
  168. return(dat);
  169. }


  170. void readtmp(void)    //读温度
  171. { uchar a,b,c;
  172. uint aa;

  173. init18b20();
  174. write18b20(0xcc);//跳过读序列号
  175. write18b20(0x44);//开始转换
  176. init18b20();

  177. write18b20(0xcc);//跳过读序列号
  178. write18b20(0xbe);//读取温度
  179. a=read18b20();
  180. b=read18b20();
  181. c=a&0x0f;//分离出小数部分
  182. b=(b&0x0f)<<4;
  183. b|=(a&0xf0)>>4;//b里放整数
  184. wendu=b;

  185.   aa=625*c;//可以直接用移位
  186. displayshige(aa/1000+0x30,0x03, 0x83);
  187. aa=0;
  188. displayshige(b/10+0x30 ,b%10+0x30, 0x80);
  189. LCD_Write_Data('.');
  190. }

  191. //****************DS1302写 一字节数据*********//
  192. void writebyte(uchar dat)
  193. {
  194. uchar i;
  195. for(i=0;i<8;i++)
  196. {
  197.   SCLK=0;
  198.   delayus(2);
  199.   IO=dat&0x01;
  200.   dat>>=1;
  201.   SCLK=1;
  202.   delayus(2);
  203. }
  204. }

  205. //****************DS1302 写 一字节数据*********//
  206. void write1302(uchar addr,uchar dat)  //传递地址与要写的数据
  207. {
  208. RST=0;
  209. delayus(2);
  210. SCLK=0;
  211. delayus(2);
  212. RST=1;
  213. delayus(2);
  214. writebyte(addr);
  215. writebyte(dat);
  216. RST=0;
  217. delayus(2);
  218. }
  219. //****************DS1302读 一字节数据*********//
  220. uchar read(uchar addr)   
  221. {
  222. uchar i,dat=0;
  223. RST=0;
  224. delayus(2);
  225. SCLK=0;
  226. delayus(2);
  227. RST=1;
  228. delayus(2);
  229. writebyte(addr);
  230. for(i=0;i<8;i++)
  231. {
  232.   dat>>=1;
  233.   SCLK=1;
  234.   delayus(2);
  235.   SCLK=0;
  236.   delayus(2);
  237.   if(IO) dat|=0x80;
  238. }
  239. RST=0;
  240. delayus(2);
  241. return(dat);
  242. }
  243. //*************1302初始化***************//
  244. void init1302(void)   
  245. {
  246. uchar i;
  247. write1302(0x8e,0x00);//禁止写保护?
  248. for(i=0;i<7;i++)
  249. {
  250.   write1302(wradd[i],temp[i]);
  251. }
  252. write1302(0x8e,0x80);// 写保护
  253. }
  254. //*********** 读出所有的数据***********//
  255. void read1302(void)   
  256. {
  257. uchar i;

  258. for(i=0;i<7;i++)
  259. {
  260.   temp[i]=read(rdadd[i]);
  261. }

  262. }
  263. //**************将十位个位分离************//
  264. void chang(void)   
  265. {
  266. uchar i;
  267. for(i=0;i<7;i++)
  268. {if(i!=5)
  269.   {h_time[i]=temp[i]/16+0x30;
  270.   l_time[i]=temp[i]%16+0x30;}
  271. else
  272.    {l_time[i]=temp[i]%16;}
  273. }
  274. }





  275. //************显示时间和日期、温度**********//

  276. void display(void)   
  277. {uchar i;


  278. displayshige(h_time[6],l_time[6], 0xc0) ;//年
  279. LCD_Write_Data(0);

  280. displayshige(h_time[4],l_time[4], 0xc3) ;//月
  281. LCD_Write_Data(1);

  282. displayshige(h_time[3],l_time[3], 0xc6);//日
  283. LCD_Write_Data(2);

  284. displayshige(h_time[2],l_time[2], 0x85);//时
  285. LCD_Write_Data(':');

  286. displayshige(h_time[1],l_time[1], 0x88);//分
  287. LCD_Write_Data(':');

  288. displayshige(h_time[0],l_time[0], 0x8b);//秒


  289.   
  290. i=(l_time[5]-1)*3;     //星期的显示,先选出数组中的第几位
  291. LCD_Write_Cmd(0x8d,1); //显示星期
  292. LCD_Write_Data(week[i]);  
  293. LCD_Delay(2);  
  294. i++;
  295. LCD_Write_Data(week[i]);  
  296. LCD_Delay(2);  
  297. i++;
  298. LCD_Write_Data(week[i]); //显示星期数
  299. LCD_Delay(2);  

  300. if(!changett)//如果要修改时间,则不执行下面高低温度显示
  301. {LCD_Write_Cmd(0xca,1);
  302. LCD_Write_Data('H');
  303. displayshige(H/10+0x30,H%10+0x30, 0xcb);

  304. LCD_Write_Cmd(0xcd,1);
  305. LCD_Write_Data('L');
  306. displayshige(L/10+0x30,L%10+0x30, 0xce);
  307. }

  308. }

  309. //*********键扫描并确定功能********//
  310. void keyscan(void)
  311. {
  312. uchar scode,recode,key,t;
  313.       P1=0xf0;
  314.      if((P1 & 0xf0)!=0xf0)
  315.        {
  316.      LCD_Delay(10);
  317.        if((P1 & 0xf0)!=0xf0)
  318.            {scode=0xfe;
  319.              while((scode &0x10)!=0)
  320.               {P1=scode;
  321.                if ((P1 & 0xf0)!=0xf0)
  322.                  {
  323.        recode=(P1 & 0xf0)| 0x0f;
  324.                    key=(~scode)+(~recode);
  325.                  switch(key)
  326.                  {case 0x11:changett=0; break;
  327.                   case 0x21:if(changett)flag=1; break;//年
  328.                   case 0x41:if(changett)flag=2; break;//月
  329.                   case 0x81:if(changett)flag=3; break;//日
  330.                   case 0x12:if(changett)flag=4; break;//时
  331.                   case 0x22:if(changett)flag=5; break;//分
  332.                   case 0x42:if(changett)flag=6; break;//秒
  333.                   case 0x82:if(changett)flag=7; break;//周
  334.                   case 0x14:if(changett)flag=8; break;//H
  335.                   case 0x24:if(changett)flag=9; break;//L
  336.                   case 0x44:if(flag>=1&&flag<=9){add=1; dec=0;}break;//加
  337.                   case 0x84:if(flag>=1&&flag<=9){add=0; dec=1;}break;//减
  338.                   case 0x18:break;//保存温度
  339.                   case 0x28:changett=1;for(t=0;t<7;t++)
  340.                                           temp2[t]=temp[t];HH=H;LL=L;;break;//改变时间,温度
  341.                   case 0x48:if(changett)ok=1;break;//确定设置的时间,温度
  342.                      
  343.                    }     
  344.                  }
  345.        else scode=(scode<<1)|0x01;
  346.          }
  347.        }
  348.      }
  349. }
  350.   //***********设置时间和上下限温度**********//
  351. void timechange()
  352. {
  353. uchar num;
  354. if(flag==1)        //年
  355. {
  356.   num=temp2[6]%16+(temp2[6]>>4)*10;
  357.   if(add)
  358.   {num++;add=0;}

  359.   if(dec)
  360.   { num--;dec=0;}


  361. temp[6]=num/10*16+num%10;

  362. temp2[6]=temp[6];
  363. }


  364. if(flag==2)        //月
  365. {
  366.   num=temp2[4]%16+(temp2[4]>>4)*10;

  367.   if(add)
  368.   {num++;add=0;}

  369.   if(num==13)  num=1;

  370.   if(dec)
  371.   { num--;dec=0;}

  372. if(num==00)  num=12;

  373. temp[4]=num/10*16+num%10;
  374. temp2[4]=temp[4];
  375. }


  376. if(flag==3)        //日
  377. {
  378. num=temp2[3]%16+(temp2[3]>>4)*10;
  379.   delayus(2);
  380. if(add)
  381.   {num++;add=0;}
  382.   if(num==32)  num=1;

  383.   if(dec)
  384.   { num--;dec=0;}
  385.   if(num==00)   num=31;

  386. temp[3]=num/10*16+num%10;
  387. temp2[3]=temp[3];

  388. }


  389. if(flag==4)        //时
  390. {
  391.   num=temp[2]%16+(temp2[2]>>4)*10;
  392.   
  393. if(add)
  394.   {num++;add=0;}
  395.   if(num==24)  num=00;

  396.   if(dec)
  397.   { num--;dec=0;}
  398.    if(num==-1)  num=23;
  399. temp[2]=num/10*16+num%10;
  400. temp2[2]=temp[2];


  401. }



  402. if(flag==5)        //分
  403. {
  404.   num=temp2[1]%16+(temp2[1]>>4)*10;
  405.   if(add)
  406.   {num++;add=0;}
  407. if(num==60)  num=00;

  408.   if(dec)
  409.   { num--;dec=0;}

  410.   if(num==-1)   num=59;
  411.   
  412. temp[1]=num/10*16+num%10;
  413. temp2[1]=temp[1];
  414. }

  415. if(flag==6)        //秒
  416. {
  417.   num=temp2[0]%16+(temp2[0]>>4)*10;
  418.   
  419.   if(add)
  420.   {num++;add=0;}
  421.   if(num==60)  num=00;

  422.   if(dec)
  423.   { num--;dec=0;}
  424.   if(num==-1)   num=59;
  425.   temp[0]=num/10*16+num%10;
  426.   temp2[0]=temp[0];
  427. }



  428. if(flag==7)        //周
  429. {
  430.   num=temp2[5]%16;
  431.   
  432.   if(add)
  433.   {num++;add=0;}
  434.   if(num==0x08) num=1;

  435.   if(dec)
  436.   { num--;dec=0;}
  437.   if(num==0x0) num=7;
  438.   
  439. temp[5]=num%10;
  440. temp2[5]=temp[5];
  441. }


  442. if(flag==8)        //H
  443. {


  444. if(add)
  445.   {HH++;add=0;}

  446.   if(dec)
  447.   { HH--;dec=0;}

  448. }

  449. displayshige(0x20,'H', 0xc8);//高温显示
  450. displayshige(HH/10+0x30,HH%10+0x30, 0xca);

  451. if(flag==9)        //L
  452. {
  453.   

  454.   if(add)
  455.   {LL++;add=0;}

  456.   if(dec)
  457.   { LL--;dec=0;}

  458.   }
  459. displayshige(0x20,'L', 0xcc);//高温显示
  460. displayshige(LL/10+0x30,LL%10+0x30, 0xce);
  461.   
  462. }

  463. ……………………

  464. …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码

所有资料51hei提供下载:
51的lcd1602 ds18b20 ds1302热水器控制,软硬件.rar (48.75 KB, 下载次数: 89)

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

回复

使用道具 举报

ID:496193 发表于 2019-3-28 13:00 | 显示全部楼层
热水器上显示个时分秒就差不多了吧,显示太多东西!操作过于复杂就违背了热水器的初衷了吧
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表