找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 7763|回复: 8
收起左侧

51单片机的智能热水器系统源码+原理图设计

  [复制链接]
ID:398752 发表于 2018-11-24 21:46 | 显示全部楼层 |阅读模式
  无水警报,自动加水,防溢出,利用电子称检测水位, DS18B20检测温度。

制作出来的实物图如下:
控制系统.jpg

电路原理图如下:

原理图

原理图


单片机源程序如下:
  1. #include <reg52.h>
  2. #include <intrins.h>
  3. #include <string.h>

  4. bit bdata flag_key;
  5. #include "main.h"
  6. #include "LCD1602.h"
  7. #include "HX711.h"
  8. #include "keyboard.h"

  9. sfr AUXR = 0x8e;   

  10. #define uchar unsigned char
  11. #define uint  unsigned int

  12. unsigned char code digit[10]={"0123456789"};     //定义字符数组显示数字
  13. unsigned char code Temp[]={"Temp:"};             //说明显示的是温度
  14. unsigned char code Cent[]={"C"};              //温度单位
  15. unsigned long HX711_Buffer = 0;
  16. unsigned long Weight_Maopi = 0;
  17. unsigned long Weight_Maopi_0 = 0;
  18. unsigned int qupi=0;
  19. long Weight_Shiwu = 100;
  20. //键盘处理变量
  21. unsigned char keycode;
  22. //unsigned char DotPos;                                   //小数点标志及位置

  23. uint GapValue,GapValue1;

  24. unsigned int idata price=50;     //温度设定值,长整型值

  25. //定义标识
  26. volatile bit FlagTest = 0;                //定时测试标志,每0.5秒置位,测完清0
  27. volatile bit FlagKeyPress = 0;  //有键按下标志,处理完毕清0
  28. //校准参数
  29. //因为不同的传感器特性曲线不是很一致,因此,每一个传感器需要矫正这里这个参数才能使测量值很准确。
  30. //当发现测试出来的重量偏大时,增加该数值。
  31. //如果测试出来的重量偏小时,减小改数值。
  32. //该值可以为小数
  33. //#define GapValue 349
  34. sbit LED=P1^1;

  35. sbit motor = P2^1;                                                           //水泵加水
  36. sbit jiare = P2^0;                                                           //启动热水壶的继电器控制位


  37. volatile bit ClearWeighFlag = 0; //传感器调零标志位,清除0漂

  38.                                                                                                                
  39. //显示温度设置

  40. void Display_Price()
  41. {
  42.                         unsigned char a,b,c,d;
  43.                         a = price /1000%10;
  44.                         b = price /100%10;
  45.                         c = price /10%10;
  46.                         d = price %10;
  47.             WriteAddress(0x86);
  48.                         WriteData(digit[a] );
  49.                         WriteData(digit[b] );

  50.                         WriteData(digit[c] );
  51. //                           WriteData(digit[d] );
  52. }

  53. //显示温度,第二行

  54. /************************************************************************
  55. 以下是DS18B20的操作程序
  56. ************************************************************************/
  57. sbit DQ=P2^2;
  58. unsigned char time;   //设置全局变量,专门用于严格延时
  59. /*****************************************************
  60. 函数功能:将DS18B20传感器初始化,读取应答信号
  61. 出口参数:flag
  62. ***************************************************/
  63. bit Init_DS18B20(void)
  64. {
  65. bit flag;         //储存DS18B20是否存在的标志,flag=0,表示存在;flag=1,表示不存在
  66. DQ = 1;           //先将数据线拉高
  67. for(time=0;time<2;time++) //略微延时约6微秒
  68.      ;
  69. DQ = 0;           //再将数据线从高拉低,要求保持480~960us
  70. for(time=0;time<200;time++) //略微延时约600微秒
  71.      ;         //以向DS18B20发出一持续480~960us的低电平复位脉冲
  72. DQ = 1;           //释放数据线(将数据线拉高)
  73. for(time=0;time<10;time++)
  74.      ; //延时约30us(释放总线后需等待15~60us让DS18B20输出存在脉冲)
  75. flag=DQ;          //让单片机检测是否输出了存在脉冲(DQ=0表示存在)      
  76. for(time=0;time<200;time++) //延时足够长时间,等待存在脉冲输出完毕
  77.       ;
  78. return (flag);    //返回检测成功标志
  79. }
  80. /*****************************************************
  81. 函数功能:从DS18B20读取一个字节数据
  82. 出口参数:dat
  83. ***************************************************/
  84. unsigned char ReadOneChar(void)
  85. {
  86.    unsigned char i=0;
  87.    unsigned char dat; //储存读出的一个字节数据
  88.    for (i=0;i<8;i++)
  89.    {
  90.      
  91.      DQ =1;       // 先将数据线拉高
  92.      _nop_();     //等待一个机器周期
  93.      DQ = 0;      //单片机从DS18B20读书据时,将数据线从高拉低即启动读时序
  94.     dat>>=1;
  95.      _nop_();     //等待一个机器周期     
  96.      DQ = 1;     //将数据线"人为"拉高,为单片机检测DS18B20的输出电平作准备
  97.      for(time=0;time<2;time++)
  98.              ;      //延时约6us,使主机在15us内采样
  99.      if(DQ==1)
  100.         dat|=0x80; //如果读到的数据是1,则将1存入dat
  101.     else
  102.      dat|=0x00;//如果读到的数据是0,则将0存入dat
  103.        //将单片机检测到的电平信号DQ存入r[i]
  104.      for(time=0;time<8;time++)
  105.         ;              //延时3us,两个读时序之间必须有大于1us的恢复期
  106.      }                     
  107. return(dat);    //返回读出的十进制数据
  108. }
  109. /*****************************************************
  110. 函数功能:向DS18B20写入一个字节数据
  111. 入口参数:dat
  112. ***************************************************/
  113. WriteOneChar(unsigned char dat)
  114. {
  115. unsigned char i=0;
  116. for (i=0; i<8; i++)
  117.    {
  118.     DQ =1;         // 先将数据线拉高
  119.     _nop_();      //等待一个机器周期
  120.     DQ=0;          //将数据线从高拉低时即启动写时序      
  121.     DQ=dat&0x01;   //利用与运算取出要写的某位二进制数据,
  122.                        //并将其送到数据线上等待DS18B20采样
  123.    for(time=0;time<10;time++)
  124.        ;//延时约30us,DS18B20在拉低后的约15~60us期间从数据线上采样
  125.     DQ=1;          //释放数据线      
  126.     for(time=0;time<1;time++)
  127.      ;//延时3us,两个写时序间至少需要1us的恢复期
  128.     dat>>=1;       //将dat中的各二进制位数据右移1位
  129.    }
  130.    for(time=0;time<4;time++)
  131.                ; //稍作延时,给硬件一点反应时间
  132. }
  133. /*****************************************************
  134. 函数功能:延时1ms
  135. (3j+2)*i=(3×33+2)×10=1010(微秒),可以认为是1毫秒
  136. ***************************************************/
  137. void delay1ms()
  138. {
  139.    unsigned char i,j;
  140. for(i=0;i<4;i++)
  141.    for(j=0;j<33;j++)
  142.     ;   
  143. }
  144. /*****************************************************
  145. 函数功能:延时若干毫秒
  146. 入口参数:n
  147. ***************************************************/
  148. void delaynms(unsigned char n)
  149. {
  150.    unsigned char i;
  151.     for(i=0;i<n;i++)
  152.     delay1ms();
  153. }
  154. /***********************************************************
  155. //温度显示相关程序
  156. ***********************************************************/
  157. void display_symbol(void)
  158. {
  159.        unsigned char i;
  160.       WriteAddress(0x40);    //写显示地址,将在第2行第1列开始显示
  161.       i = 0;                //从第一个字符开始显示
  162.      while(Temp[i] != '\0') //只要没有写到结束标志,就继续写
  163.      {      
  164.       WriteData(Temp[i]);   //将字符常量写入LCD
  165.       i++;                 //指向下一个字符
  166.       delaynms(50);        //延时1ms给硬件一点反应时间
  167.      }
  168. }
  169. /*****************************************************
  170. 函数功能:显示温度的小数点
  171. ***************************************************/   
  172. void display_dot(void)
  173. {         
  174. WriteAddress(0x49);   //写显示地址,将在第2行第10列开始显示     
  175. WriteData('.');      //将小数点的字符常量写入LCD
  176. delaynms(50);         //延时1ms给硬件一点反应时间  
  177. }
  178. /*****************************************************
  179. 函数功能:显示温度的单位(C)
  180. ***************************************************/   
  181. void display_cent(void)
  182. {
  183.            unsigned char i;   
  184.       WriteAddress(0x4c);        //写显示地址,将在第2行第13列开始显示
  185.       i = 0;                    //从第一个字符开始显示
  186.      while(Cent[i] != '\0')     //只要没有写到结束标志,就继续写
  187.      {     
  188.       WriteData(Cent[i]);     //将字符常量写入LCD
  189.       i++;                 //指向下一个字符
  190.       delaynms(50);        //延时1ms给硬件一点反应时间
  191.      }
  192. }

  193. /*****************************************************
  194. 函数功能:显示温度的整数部分
  195. 入口参数:x
  196. ***************************************************/
  197. void display_temp1(unsigned char x)
  198. {
  199. unsigned char j,k,l;     //j,k,l分别储存温度的百位、十位和个位
  200. j=x/100;              //取百位
  201. k=(x%100)/10;    //取十位
  202. l=x%10;             //取个位
  203. WriteAddress(0x46);    //写显示地址,将在第2行第7列开始显示
  204. WriteData(digit[j]);    //将百位数字的字符常量写入LCD
  205. WriteData(digit[k]);    //将十位数字的字符常量写入LCD
  206. WriteData(digit[l]);    //将个位数字的字符常量写入LCD
  207. delaynms(50);         //延时1ms给硬件一点反应时间     
  208. }
  209. /*****************************************************
  210. 函数功能:显示温度的小数数部分
  211. 入口参数:x
  212. ***************************************************/
  213. void display_temP3(unsigned char x)
  214. {
  215.    WriteAddress(0x4a);      //写显示地址,将在第2行第11列开始显示
  216. WriteData(digit[x]);     //将小数部分的第一位数字字符常量写入LCD
  217. delaynms(50);          //延时1ms给硬件一点反应时间
  218. }
  219. void ReadyReadTemp(void)
  220. {
  221.       Init_DS18B20();     //将DS18B20初始化
  222.       WriteOneChar(0xCC); // 跳过读序号列号的操作
  223.       WriteOneChar(0x44); // 启动温度转换   
  224.       for(time=0;time<100;time++)
  225.              ; //温度转换需要一点时间
  226.    Init_DS18B20();     //将DS18B20初始化
  227.    WriteOneChar(0xCC); //跳过读序号列号的操作
  228.    WriteOneChar(0xBE); //读取温度寄存器,前两个分别是温度的低位和高位
  229. }


  230. /***********************************************************/

  231. //数据初始化
  232. void Data_Init()
  233. {
  234.    price = 0;
  235. //   DotPos = 0;
  236. }
  237. //定时器0初始化               

  238. void Timer0_Init()
  239. {
  240.         ET0 = 1;        //允许定时器0中断
  241.         TMOD = 1;       //定时器工作方式选择
  242.         TL0 = 0xb0;     
  243.         TH0 = 0x3c;     //定时器赋予初值
  244.         TR0 = 1;        //启动定时器
  245. //        AUXR &= 0x7F;                //定时器时钟12T模式
  246. //        TMOD &= 0xF0;                //设置定时器模式
  247. //        TMOD |= 0x01;                //设置定时器模式
  248. //        TL0 = 0xCE;                //设置定时初值
  249. //        TH0 = 0xFF;                //设置定时初值
  250. //        TF0 = 0;                //清除TF0标志
  251. //        TR0 = 1;                //定时器0开始计时
  252. //                 ET0 = 1;        //允许定时器0中断
  253. //                EA = 1;
  254. }

  255. //定时器0中断
  256. void Timer0_ISR (void) interrupt 1 //using 0
  257. {
  258. uchar Counter;
  259.         TL0 = 0xb0;
  260.         TH0 = 0x3c;     //定时器赋予初值
  261. //        TL0 = 0xCE;                //设置定时初值
  262. //        TH0 = 0xFF;                //设置定时初值

  263.         //每0.5秒钟刷新重量
  264.     Counter ++;
  265.     if (Counter >= 10)
  266.     {
  267.        FlagTest = 1;
  268.            Counter = 0;
  269.     }
  270. }


  271. //按键响应程序,参数是键值
  272. //返回键值:

  273. //        14   0    15  13                          //11:清除设置
  274. //        7    8    9   12                          //12:开启motor控制继电器
  275. //                  4    5    6   11                     //13:开启jiare控制继电器
  276. //        1    2    3   10                          //15:关闭两个继电器
  277. void KeyPress(uchar keycode)
  278. {
  279.         switch (keycode)
  280.         {
  281.                 case 0:
  282.                 case 1:
  283.                 case 2:
  284.                 case 3:
  285.                 case 4:
  286.                 case 5:
  287.                 case 6:
  288.                 case 7:
  289.                 case 8:
  290.                 case 9:        //目前在设置整数位,要注意price是整型,存储单位为分
  291. //                        if (DotPos == 0)
  292. //                        {                        //最多只能设置到千位
  293.                                 if (price<10000)
  294.                                 {
  295.                                         price=price*10+keycode*10;

  296.                                 }
  297. //                        }//目前在设置小数位
  298. //                        else if (DotPos==1)  //小数点后第一位
  299. //                        {
  300. //                                price=price+keycode;
  301. //                                DotPos=2;
  302. //                        }
  303.                         Display_Price();
  304.                         break;
  305.                 case 10:   //去皮键

  306.                         Display_Price();
  307.                         break;
  308.                 case 11:        //删除键
  309.                         price=0;
  310. //                        DotPos=0;
  311.                         Display_Price();
  312.                         break;
  313.                 case 12:           //
  314.                         motor = 1;       

  315.                         break;
  316.                 case 13:   //
  317.                         jiare = 1;
  318.                              
  319.                         break;
  320.                 case 15:   //                                 停止加热,停止加水
  321.                            motor = 0;
  322.                            jiare = 0;
  323.                         break;

  324.    }
  325. }
  326. //****************************************************
  327. //主函数
  328. //****************************************************
  329. void main()
  330. {         
  331.     unsigned char TL;       //储存暂存器的温度低位
  332.     unsigned char TH;       //储存暂存器的温度高位
  333.     unsigned char TN;       //储存温度的整数部分
  334.     unsigned char TD;       //储存温度的小数部分
  335.         unsigned int h;
  336.            GapValue = 2200;

  337.         Init_LCD1602();                                                                        //初始化LCD1602
  338.     EA = 0;
  339.     Data_Init();
  340.     Timer0_Init();
  341.    //初中始化完成,开断
  342.     EA = 1;
  343.          motor = 0;
  344.          jiare = 0;
  345.          
  346.          if(Init_DS18B20()==1)
  347.          
  348.              display_symbol();
  349.               display_dot();       //显示温度的小数点
  350.          display_cent();       //显示温度的单位

  351.    LCD1602_write_com(0x80);                                                //指针设置
  352.    LCD1602_write_word(" Welcome To Use ");        //  
  353.    LCD1602_write_com(0x80+0x40);                                                //指针设置
  354.    LCD1602_write_word("Temp:");

  355.    Get_Maopi();
  356.    LCD1602_write_com(0x80);                                                //指针设置
  357.    LCD1602_write_word("Set:        C  ");

  358.    Display_Price();

  359.         while(1)
  360.         {
  361. //每0.5秒称重一次         

  362.           if (FlagTest==1)
  363.                 {                    
  364.                         Get_Weight();  
  365.                         FlagTest = 0;
  366.                 }
  367.           if ( h == 1)
  368.           {
  369.                 if (TN >= (price/10) )
  370.                 {
  371.                         jiare =0;
  372.                         Buzzer = 0;
  373.                 }

  374.                 if( (TN < (price/10))&&(Weight_Shiwu > 700))
  375.                 {
  376.                    jiare = 1;
  377.                    Buzzer = 1;
  378.                 }

  379.            }
  380.                 ReadyReadTemp();     //读温度准备
  381.         TL=ReadOneChar();    //先读的是温度值低位
  382.         TH=ReadOneChar();    //接着读的是温度值高位
  383.         TN=TH*16+TL/16;      //实际温度值=(TH*256+TL)/16,即:TH*16+TL/16
  384.                      //这样得出的是温度的整数部分,小数部分被丢弃了
  385.         TD=(TL%16)*10/16;    //计算温度的小数部分,将余数乘以10再除以16取整,
  386.                      //这样得到的是温度小数部分的第一位数字(保留1位小数)
  387.         display_temp1(TN);    //显示温度的整数部分
  388.         display_temP3(TD);    //显示温度的小数部分
  389.         delaynms(10);     
  390.                  
  391.                  
  392.           keycode = Getkeyboard();
  393.           //有效键值0-15
  394.           if (keycode<16)
  395.           {
  396.                  KeyPress(keycode);
  397.                  Buzzer=0;
  398.                  Delay_ms(100);
  399.                  Buzzer=1;
  400.                  while(keycode<16)
  401.                  {
  402.                         if(keycode==12||keycode==13||keycode==15)
  403.                         {
  404.                                 Buzzer=0;
  405.                                  Delay_ms(10);
  406.                                  Buzzer=1;                               
  407.                                  KeyPress(keycode);
  408.                                  Get_Weight();
  409.                                  flag_key=1;
  410.                                  h = 1;
  411.                         }
  412.                         keycode = Getkeyboard();
  413.                  }

  414.           }
  415.         }
  416. }
  417. //****************************************************
  418. //称重
  419. //****************************************************
  420. void Get_Weight()
  421. {
  422.         Weight_Shiwu = HX711_Read();
  423.         Weight_Shiwu = Weight_Shiwu - Weight_Maopi;                //获取净重
  424.        
  425.         Weight_Shiwu = (unsigned int)((float)Weight_Shiwu*6/GapValue)-qupi ;         //计算实物的实际重量
  426.                                                                                                                                        
  427. ……………………

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

所有资料51hei提供下载:
智能饮水系统.rar (90.4 KB, 下载次数: 181)

评分

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

查看全部评分

回复

使用道具 举报

ID:401170 发表于 2018-12-12 19:00 | 显示全部楼层
想要那个电路图QWQ能发一份给我吗,我的7805画不出来
回复

使用道具 举报

ID:220936 发表于 2018-12-13 08:38 | 显示全部楼层
这个创意挺好,用电子秤测水位
回复

使用道具 举报

ID:600397 发表于 2019-8-15 12:22 来自手机 | 显示全部楼层
不错哦
回复

使用道具 举报

ID:634919 发表于 2019-11-3 18:26 | 显示全部楼层
想看一下完整的实物图,谢谢
回复

使用道具 举报

ID:634898 发表于 2019-11-3 20:22 | 显示全部楼层
创意太好了  赞一个
回复

使用道具 举报

ID:642942 发表于 2019-11-15 23:32 | 显示全部楼层
你好 我的设计是这个能不能提供具体流程软件介绍
回复

使用道具 举报

ID:562553 发表于 2019-11-26 14:18 | 显示全部楼层
感谢分享
回复

使用道具 举报

ID:662319 发表于 2020-1-4 12:56 | 显示全部楼层
谢谢大佬的分享
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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