找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 7523|回复: 13
收起左侧

LCD1604液晶+51单片机温度压力报警系统仿真和源程序

  [复制链接]
ID:304204 发表于 2018-5-31 21:52 | 显示全部楼层 |阅读模式
该系统是根据烟雾报警系统程序修改,LCD1604液晶屏显示的,感谢论坛朋友们的帮助
仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)
QQ截图20180531215124.png 0.png

单片机源程序如下:
  1. #include <reg52.h> //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
  2. #include "intrins.h"                                                                                          

  3. #define     u8                          unsigned char
  4. #define     u16                   unsigned int
  5. #define     uchar                          unsigned char
  6. #define     uint                   unsigned int

  7. uchar yushe_wendu=80;                                //温度预设值
  8. uchar yushe_yali1=250;
  9. uchar yushe_yali2=150;                                //压力预设值
  10. uint wendu;                                                                 //温度值全局变量
  11. uchar yali;                                                                 //用于读取ADC数据

  12. //运行模式  
  13. uchar Mode=0;                                                                 //=1是设置温度阀值  =2是设置压力阀值        =0是正常监控模式
  14. //管脚声明
  15. sbit Led_Reg                 =P2^2;                                 //红灯
  16. sbit Led_Yellow  =P2^4;                                 //黄灯
  17. sbit Buzzer             =P2^0;                                 //蜂鸣器
  18. sbit Fan                      =P3^3;                                 //
  19. sbit Led_green   =P3^0;

  20. /********************************************************************
  21. * 名称 : delay_1ms()
  22. * 功能 : 延时1ms函数
  23. * 输入 : q
  24. * 输出 : 无
  25. ***********************************************************************/
  26. void delay_ms(uint q)
  27. {
  28.         uint i,j;
  29.         for(i=0;i<q;i++)
  30.                 for(j=0;j<110;j++);
  31. }
  32. /***********************************************************************************************************
  33. LCD1602相关函数
  34. ***********************************************************************************************************/

  35. //LCD管脚声明 (RW引脚实物直接接地,因为本设计只用到液晶的写操作,RW引脚一直是低电平)
  36. sbit LCDRS = P2^7;
  37. sbit LCDEN = P2^6;
  38. sbit D0                 = P0^0;
  39. sbit D1                 = P0^1;
  40. sbit D2                 = P0^2;
  41. sbit D3                 = P0^3;
  42. sbit D4                 = P0^4;
  43. sbit D5                 = P0^5;
  44. sbit D6                 = P0^6;
  45. sbit D7                 = P0^7;


  46. void delay10s(void)
  47. {
  48.         uchar i,j,k;
  49.         for(i=50;i>0;i--)
  50.         {
  51.          for(j=200;j>0;j--)
  52.          {
  53.           for(k=250;k>0;k--)
  54.           {;}
  55.           }
  56.         }
  57. }


  58. //LCD延时
  59. void LCDdelay(uint z)                  //该延时大约100us(不精确,液晶操作的延时不要求很精确)
  60. {
  61.   uint x,y;
  62.   for(x=z;x>0;x--)
  63.     for(y=10;y>0;y--);
  64. }
  65. void LCD_WriteData(u8 dat)         
  66. {
  67.         if(dat&0x01)D0=1;else D0=0;
  68.         if(dat&0x02)D1=1;else D1=0;
  69.         if(dat&0x04)D2=1;else D2=0;
  70.         if(dat&0x08)D3=1;else D3=0;
  71.         if(dat&0x10)D4=1;else D4=0;
  72.         if(dat&0x20)D5=1;else D5=0;
  73.         if(dat&0x40)D6=1;else D6=0;
  74.         if(dat&0x80)D7=1;else D7=0;
  75. }
  76. //写命令
  77. void write_com(uchar com)
  78. {
  79.   LCDRS=0;                                 
  80.         LCD_WriteData(com);
  81. //  DAT=com;
  82.   LCDdelay(5);
  83.   LCDEN=1;
  84.   LCDdelay(5);
  85.   LCDEN=0;
  86. }
  87. //写数据
  88. void write_data(uchar date)
  89. {
  90.   LCDRS=1;
  91.         LCD_WriteData(date);
  92. //  DAT=date;
  93.   LCDdelay(5);
  94.   LCDEN=1;
  95.   LCDdelay(5);
  96.   LCDEN=0;
  97. }

  98. /*------------------------------------------------
  99.               选择写入位置
  100. ------------------------------------------------*/
  101. void SelectPosition(unsigned char x,unsigned char y)
  102. {     
  103.         if (x == 0)
  104.         {     
  105.                 write_com(0x80 + y);     //表示第一行
  106.         }

  107.         else if (x == 1)
  108.         {      
  109.                 write_com(0xC0 + y);      //表示第二行
  110.         }
  111.         else if (x == 2)
  112.         {
  113.             write_com(0x90 + y);
  114.         }
  115.         else if (x ==3)
  116.         {
  117.             write_com(0xD0 + y);
  118.         }
  119. }
  120. /*------------------------------------------------
  121.               写入字符串函数
  122. ------------------------------------------------*/
  123. void LCD_Write_String(unsigned char x,unsigned char y,unsigned char *s)
  124. {     
  125.         SelectPosition(x,y) ;
  126.         while (*s)
  127.         {     
  128.                 write_data( *s);     
  129.                 s ++;     
  130.         }
  131. }
  132. //========================================================================
  133. // 函数: void LCD_Write_Char(u8 x,u8 y,u16 s,u8 l)
  134. // 应用: LCD_Write_Char(0,1,366,4) ;
  135. // 描述: 在第0行第一个字节位置显示366的后4位,显示结果为 0366
  136. // 参数: x:行,y:列,s:要显示的字,l:显示的位数
  137. // 返回: none.
  138. // 版本: VER1.0
  139. // 日期: 2013-4-1
  140. // 备注: 最大显示65535
  141. //========================================================================
  142. void LCD_Write_Char(u8 x,u8 y,u16 s,u8 l)
  143. {     
  144.         SelectPosition(x,y) ;

  145.         if(l>=5)
  146.                 write_data(0x30+s/10000%10);        //万位
  147.         if(l>=4)
  148.                 write_data(0x30+s/1000%10);                //千位
  149.         if(l>=3)
  150.                 write_data(0x30+s/100%10);                //百位
  151.         if(l>=2)
  152.                 write_data(0x30+s/10%10);                        //十位
  153.         if(l>=1)
  154.                 write_data(0x30+s%10);                //个位

  155. }
  156. /*1604指令简介
  157.   write_com(0x38);//屏幕初始化
  158.   write_com(0x0c);//打开显示 无光标 无光标闪烁
  159.   write_com(0x0d);//打开显示 阴影闪烁
  160.   write_com(0x0d);//打开显示 阴影闪烁
  161. */
  162. //1604初始化
  163. void Init1602()
  164. {
  165.   uchar i=0;
  166.   write_com(0x38);//屏幕初始化
  167.   write_com(0x0c);//打开显示 无光标 无光标闪烁
  168.   write_com(0x06);//当读或写一个字符是指针后一一位
  169.   write_com(0x01);//清屏
  170.         
  171. }

  172. void Display_1602(yushe_wendu,yushe_yali,c,temp)
  173. {
  174.         //显示预设温度
  175.         LCD_Write_Char(1,6,yushe_wendu,2) ;
  176.         
  177.         //显示预设压力
  178.         LCD_Write_Char(0,6,yushe_yali1,3) ;
  179.         LCD_Write_Char(0,13,yushe_yali2,3) ;
  180.         
  181.         //时时温度
  182.         LCD_Write_Char(2,6,c/10,2) ;
  183.         write_data('.');
  184.         LCD_Write_Char(2,9,c%10,1) ;
  185.         
  186.         //时时温度
  187.         LCD_Write_Char(2,13,temp,3) ;
  188. }



  189. /***********************************************************************************************************
  190. ADC0832相关函数
  191. ***********************************************************************************************************/
  192. sbit ADCS         =P1^5; //ADC0832 片选
  193. sbit ADCLK  =P1^2; //ADC0832 时钟
  194. sbit ADDI         =P1^3; //ADC0832 数据输入                /*因为单片机的管脚是双向的,且ADC0832的数据输入输出不同时进行,
  195. sbit ADDO         =P1^3; //ADC0832 数据输出                /*为节省单片机引脚,简化电路所以输入输出连接在同一个引脚上



  196. //========================================================================
  197. // 函数: unsigned int Adc0832(unsigned char channel)
  198. // 应用:                 temp=Adc0832(0);
  199. // 描述: 读取0通道的AD值
  200. // 参数: channel:通道0和通道1选择
  201. // 返回: 选取通道的AD值
  202. // 版本: VER1.0
  203. // 日期: 2015-05-29
  204. // 备注:
  205. //========================================================================
  206. unsigned int Adc0832(unsigned char channel)
  207. {
  208.         uchar i=0;
  209.         uchar j;
  210.         uint dat=0;
  211.         uchar ndat=0;
  212.         uchar  Vot=0;

  213.         if(channel==0)channel=2;
  214.         if(channel==1)channel=3;
  215.         ADDI=1;
  216.         _nop_();
  217.         _nop_();
  218.         ADCS=0;//拉低CS端
  219.         _nop_();
  220.         _nop_();
  221.         ADCLK=1;//拉高CLK端
  222.         _nop_();
  223.         _nop_();
  224.         ADCLK=0;//拉低CLK端,形成下降沿1
  225.         _nop_();
  226.         _nop_();
  227.         ADCLK=1;//拉高CLK端
  228.         ADDI=channel&0x1;
  229.         _nop_();
  230.         _nop_();
  231.         ADCLK=0;//拉低CLK端,形成下降沿2
  232.         _nop_();
  233.         _nop_();
  234.         ADCLK=1;//拉高CLK端
  235.         ADDI=(channel>>1)&0x1;
  236.         _nop_();
  237.         _nop_();
  238.         ADCLK=0;//拉低CLK端,形成下降沿3
  239.         ADDI=1;//控制命令结束
  240.         _nop_();
  241.         _nop_();
  242.         dat=0;
  243.         for(i=0;i<8;i++)
  244.         {
  245.                 dat|=ADDO;//收数据
  246.                 ADCLK=1;
  247.                 _nop_();
  248.                 _nop_();
  249.                 ADCLK=0;//形成一次时钟脉冲
  250.                 _nop_();
  251.                 _nop_();
  252.                 dat<<=1;
  253.                 if(i==7)dat|=ADDO;
  254.         }
  255.         for(i=0;i<8;i++)
  256.         {
  257.                 j=0;
  258.                 j=j|ADDO;//收数据
  259.                 ADCLK=1;
  260.                 _nop_();
  261.                 _nop_();
  262.                 ADCLK=0;//形成一次时钟脉冲
  263.                 _nop_();
  264.                 _nop_();
  265.                 j=j<<7;
  266.                 ndat=ndat|j;
  267.                 if(i<7)ndat>>=1;
  268.         }
  269.         ADCS=1;//拉低CS端
  270.         ADCLK=0;//拉低CLK端
  271.         ADDO=1;//拉高数据端,回到初始状态
  272.         dat<<=8;
  273.         dat|=ndat;

  274.         return(dat);            //return ad data
  275. }

  276. /***********************************************************************************************************
  277. DS18B20相关函数
  278. ***********************************************************************************************************/

  279. sbit DQ = P1^0;                                 //ds18b20的数据引脚



  280. /*****延时子程序:该延时主要用于ds18b20延时*****/
  281. void Delay_DS18B20(int num)
  282. {
  283.   while(num--) ;
  284. }
  285. /*****初始化DS18B20*****/
  286. void Init_DS18B20(void)
  287. {
  288.   unsigned char x=0;
  289.   DQ = 1;         //DQ复位
  290.   Delay_DS18B20(8);    //稍做延时
  291.   DQ = 0;         //单片机将DQ拉低
  292.   Delay_DS18B20(80);   //精确延时,大于480us
  293.   DQ = 1;         //拉高总线
  294.   Delay_DS18B20(14);
  295.   x = DQ;           //稍做延时后,如果x=0则初始化成功,x=1则初始化失败
  296.   Delay_DS18B20(20);
  297. }
  298. /*****读一个字节*****/
  299. unsigned char ReadOneChar(void)
  300. {
  301.   unsigned char i=0;
  302.   unsigned char dat = 0;
  303.   for (i=8;i>0;i--)
  304.   {
  305.     DQ = 0;     // 给脉冲信号
  306.     dat>>=1;
  307.     DQ = 1;     // 给脉冲信号
  308.     if(DQ)
  309.     dat|=0x80;
  310.     Delay_DS18B20(4);
  311.   }
  312.   return(dat);
  313. }
  314. /*****写一个字节*****/
  315. void WriteOneChar(unsigned char dat)
  316. {
  317.   unsigned char i=0;
  318.   for (i=8; i>0; i--)
  319.   {
  320.     DQ = 0;
  321.     DQ = dat&0x01;
  322.     Delay_DS18B20(5);
  323.     DQ = 1;
  324.     dat>>=1;
  325.   }
  326. }
  327. /*****读取温度*****/
  328. unsigned int ReadTemperature(void)
  329. {
  330.   unsigned char a=0;
  331.   unsigned char b=0;
  332.   unsigned int t=0;
  333.   float tt=0;
  334.   Init_DS18B20();
  335.   WriteOneChar(0xCC);  //跳过读序号列号的操作
  336.   WriteOneChar(0x44);  //启动温度转换
  337.   Init_DS18B20();
  338.   WriteOneChar(0xCC);  //跳过读序号列号的操作
  339.   WriteOneChar(0xBE);  //读取温度寄存器
  340.   a=ReadOneChar();     //读低8位
  341.   b=ReadOneChar();    //读高8位
  342.   t=b;
  343.   t<<=8;
  344.   t=t|a;
  345.   tt=t*0.0625;
  346.   t= tt*10+0.5;     //放大10倍输出并四舍五入
  347.   return(t);
  348. }
  349. //=====================================================================================
  350. //=====================================================================================
  351. //=====================================================================================


  352. /*****校准温度*****/
  353. u16 check_wendu(void)
  354. {
  355.         u16 c;
  356.         c=ReadTemperature()-5;                          //获取温度值并减去DS18B20的温漂误差
  357.         if(c<1) c=0;
  358.         if(c>=999) c=999;
  359.         return c;
  360. }


  361. /***********************************************************************************************************
  362. 按键检测相关函数
  363. ***********************************************************************************************************/
  364. //按键
  365. sbit Key1=P1^6;                                 //设置键
  366. sbit Key2=P1^7;                                 //加按键
  367. sbit Key3=P3^2;                                 //减按键



  368. #define KEY_SET                 1                //设置
  369. #define KEY_ADD                        2                //加
  370. #define KEY_MINUS                3                //减


  371. //========================================================================
  372. // 函数: u8 Key_Scan()
  373. // 应用: temp=u8 Key_Scan();
  374. // 描述: 按键扫描并返回按下的键值
  375. // 参数: NONE
  376. // 返回: 按下的键值
  377. // 版本: VER1.0
  378. // 日期: 2015-05-29
  379. // 备注: 该函数带松手检测,按下键返回一次键值后返回0,直至第二次按键按下
  380. //========================================================================
  381. u8 Key_Scan()
  382. {         
  383.         static u8 key_up=1;//按键按松开标志
  384.         if(key_up&&(Key1==0||Key2==0||Key3==0))
  385.         {
  386.                 delay_ms(10);//去抖动
  387.                 key_up=0;
  388.                 if(Key1==0)                        return 1;
  389.                 else if(Key2==0)return 2;
  390.                 else if(Key3==0)return 3;
  391.         }
  392.         else if(Key1==1&&Key2==1&&Key3==1)
  393.                 key_up=1;            
  394.          return 0;// 无按键按下
  395. }



  396. void main (void)
  397. {
  398.         u8 key;
  399.         Init1602();                          //调用初始化显示函数
  400.         LCD_Write_String(0,0,"YS PH:000 PL:00");  //开机界面

  401.         //delay10s();
  402.         LCD_Write_String(1,0,"YS  T:00 ");
  403.         wendu=check_wendu();                  //初始化时调用温度读取函数 防止开机85°C
  404.         LCD_Write_String(2,0,"NOW T:     P:0");  
  405.         delay_ms(1000);
  406.         wendu=check_wendu();                  //初始化时调用温度读取函数 防止开机85°C
  407.         while (1)                                                //主循环
  408.         {
  409.                 key=Key_Scan();                                        //按键扫描
  410.                 yali=Adc0832(0);                                //读取压力值
  411.                 wendu=check_wendu();          //读取温度值
  412.                
  413.                 if(key==KEY_SET)
  414.                 {
  415.                         Mode++;
  416.                 }
  417.                
  418.                 switch(Mode)                                                //判断模式的值
  419.                 {
  420.                         case 0:                                                                //监控模式
  421.                         {
  422.                                 Display_1602(yushe_wendu,yushe_yali1,wendu,yali);  //显示预设温度,预设压力,温度值,压力值
  423.                                 if(yali>=yushe_yali1)          //压力值大于等于预设值时
  424.                                 {
  425.                                         Led_Reg=0;                                          //压力指示灯亮
  426.                                         Fan=0;
  427.                                         Buzzer=0;                                                  //蜂鸣器报警
  428.                                 }
  429.                                 else                                                                                  //压力值小于预设值时
  430.                                 {
  431.                                         Led_Reg=1;                                          //关掉报警灯
  432.                                         Fan=1;
  433.                                 }
  434.                                 if(yali<=yushe_yali2)          //压力值大于等于预设值时
  435.                                 {
  436.                                         Led_green=0;                                          //压力指示灯亮
  437.                                         Fan=0;
  438.                                         Buzzer=0;                                                  //蜂鸣器报警
  439.                                 }
  440.                                 else                                                                                  //压力值小于预设值时
  441.                                 {
  442.                                         Led_green=1;                                          //关掉报警灯
  443.                                         Fan=1;
  444.                                 }
  445.                                 if(wendu>=(yushe_wendu*10))          //温度大于等于预设温度值时(为什么是大于预设值*10:因为我们要显示的温度是有小数点后一位,是一个3位数,25.9°C时实际读的数是259,所以判断预设值时将预设值*10)
  446.                                 {
  447.                                         Buzzer=0;                                                  //打开蜂鸣器报警
  448.                                         Led_Yellow=0;                                          //打开温度报警灯
  449.                                 }
  450.                                 else                                                                                  //温度值小于预设值时
  451.                                 {
  452.                                         Led_Yellow=1;                                          //关闭报警灯
  453.                                 }
  454. ……………………

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

所有资料51hei提供下载:
基础模板.zip (141.32 KB, 下载次数: 201)

评分

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

查看全部评分

回复

使用道具 举报

ID:409773 发表于 2018-10-15 10:00 | 显示全部楼层
1604可以显示中文吗
回复

使用道具 举报

ID:428114 发表于 2019-3-19 11:54 | 显示全部楼层
1604只能显示英文或自造字符
回复

使用道具 举报

ID:188008 发表于 2019-4-13 22:01 | 显示全部楼层
PROTUS 不能用啊
回复

使用道具 举报

ID:519576 发表于 2019-4-23 15:07 | 显示全部楼层
正好需要这个,好贴
回复

使用道具 举报

ID:527470 发表于 2019-5-15 16:40 | 显示全部楼层
朋友,你用的是Proteus哪个版本呢?
回复

使用道具 举报

ID:527470 发表于 2019-5-15 16:41 | 显示全部楼层
请问这用的是哪个版本的Proteus呢
回复

使用道具 举报

ID:728073 发表于 2020-4-13 11:25 | 显示全部楼层
LCD1604是哪个版本的proteus啊
回复

使用道具 举报

ID:906376 发表于 2021-5-3 14:28 来自手机 | 显示全部楼层
看着好高级好复杂
回复

使用道具 举报

ID:705815 发表于 2021-5-6 11:13 | 显示全部楼层
小太太 发表于 2018-10-15 10:00
1604可以显示中文吗

可以的
回复

使用道具 举报

ID:1013437 发表于 2022-3-27 13:55 | 显示全部楼层
温度压力正好设计里面涉及到,纯小白一个,感谢老铁♪(・ω・)ノ
回复

使用道具 举报

ID:1013437 发表于 2022-3-28 18:46 | 显示全部楼层
就是proteus的两个错误,怎么搞,完全看不懂,我都不知道哪错了o(╥﹏╥)o
回复

使用道具 举报

ID:1026899 发表于 2022-5-28 14:34 | 显示全部楼层
传感器的数值与lcd显示的好像有点差距
回复

使用道具 举报

ID:409251 发表于 2022-7-28 13:57 | 显示全部楼层
强啊,谢谢大佬。
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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