找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2009|回复: 3
打印 上一主题 下一主题
收起左侧

关于stc89c52rc单片机的温度和烟雾检测的问题

[复制链接]
跳转到指定楼层
楼主
刚学习单片机,不管怎么修改程序都是温度显示一直与测量的温度跟99.9一直切换显示,而烟雾检测的数值就在个位数乱飘,求大神能讲一下什么回事,兵说一说哪里出错了

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


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


  8. uchar yushe_wendu=50;                                //温度预设值
  9. uchar yushe_yanwu=100;                                //烟雾预设值
  10. uint wendu;                                                                 //温度值全局变量
  11. uchar yanwu;                                                                 //用于读取ADC数据

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

  18. void delay_ms(uint q)
  19. {
  20.         uint i,j;
  21.         for(i=0;i<q;i++)
  22.                 for(j=0;j<110;j++);
  23. }
  24. /***********************************************************************************************************
  25. LCD1602相关函数
  26. ***********************************************************************************************************/

  27. //LCD管脚声明 (RW引脚实物直接接地,因为本设计只用到液晶的写操作,RW引脚一直是低电平)
  28. sbit LCDRS = P1^6;
  29. sbit LCDEN = P1^7;
  30. sbit D0                 = P0^0;
  31. sbit D1                 = P0^1;
  32. sbit D2                 = P0^2;
  33. sbit D3                 = P0^3;
  34. sbit D4                 = P0^4;
  35. sbit D5                 = P0^5;
  36. sbit D6                 = P0^6;
  37. sbit D7                 = P0^7;



  38. //LCD延时
  39. void LCDdelay(uint z)                  //该延时大约100us(不精确,液晶操作的延时不要求很精确)
  40. {
  41.   uint x,y;
  42.   for(x=z;x>0;x--)
  43.     for(y=10;y>0;y--);
  44. }
  45. void LCD_WriteData(u8 dat)         
  46. {
  47.         if(dat&0x01)D0=1;else D0=0;
  48.         if(dat&0x02)D1=1;else D1=0;
  49.         if(dat&0x04)D2=1;else D2=0;
  50.         if(dat&0x08)D3=1;else D3=0;
  51.         if(dat&0x10)D4=1;else D4=0;
  52.         if(dat&0x20)D5=1;else D5=0;
  53.         if(dat&0x40)D6=1;else D6=0;
  54.         if(dat&0x80)D7=1;else D7=0;
  55. }
  56. //写命令
  57. void write_com(uchar com)
  58. {
  59.   LCDRS=0;                                 
  60.         LCD_WriteData(com);
  61. //  DAT=com;
  62.   LCDdelay(5);
  63.   LCDEN=1;
  64.   LCDdelay(5);
  65.   LCDEN=0;
  66. }
  67. //写数据
  68. void write_data(uchar date)
  69. {
  70.   LCDRS=1;
  71.         LCD_WriteData(date);
  72. //  DAT=date;
  73.   LCDdelay(5);
  74.   LCDEN=1;
  75.   LCDdelay(5);
  76.   LCDEN=0;
  77. }

  78. /*------------------------------------------------
  79.               选择写入位置
  80. ------------------------------------------------*/
  81. void SelectPosition(unsigned char x,unsigned char y)
  82. {     
  83.         if (x == 0)
  84.         {     
  85.                 write_com(0x80 + y);     //表示第一行
  86.         }
  87.         else
  88.         {      
  89.                 write_com(0xC0 + y);      //表示第二行
  90.         }        
  91. }
  92. /*------------------------------------------------
  93.               写入字符串函数
  94. ------------------------------------------------*/
  95. void LCD_Write_String(unsigned char x,unsigned char y,unsigned char *s)
  96. {     
  97.         SelectPosition(x,y) ;
  98.         while (*s)
  99.         {     
  100.                 write_data( *s);     
  101.                 s ++;     
  102.         }
  103. }
  104. void LCD_Write_Char(u8 x,u8 y,u16 s,u8 l)
  105. {     
  106.         SelectPosition(x,y) ;

  107.         if(l>=5)
  108.                 write_data(0x30+s/10000%10);        //万位
  109.         if(l>=4)
  110.                 write_data(0x30+s/1000%10);                //千位
  111.         if(l>=3)
  112.                 write_data(0x30+s/100%10);                //百位
  113.         if(l>=2)
  114.                 write_data(0x30+s/10%10);                        //十位
  115.         if(l>=1)
  116.                 write_data(0x30+s%10);                //个位

  117. }
  118. /*1602指令简介
  119.   write_com(0x38);//屏幕初始化
  120.   write_com(0x0c);//打开显示 无光标 无光标闪烁
  121.   write_com(0x0d);//打开显示 阴影闪烁
  122.   write_com(0x0d);//打开显示 阴影闪烁
  123. */
  124. //1602初始化
  125. void Init1602()
  126. {
  127.   uchar i=0;
  128.   write_com(0x38);//屏幕初始化
  129.   write_com(0x0c);//打开显示 无光标 无光标闪烁
  130.   write_com(0x06);//当读或写一个字符是指针后一一位
  131.   write_com(0x01);//清屏
  132.         
  133. }

  134. void Display_1602(yushe_wendu,yushe_yanwu,c,temp)
  135. {
  136.         //显示预设温度
  137.         LCD_Write_Char(0,6,yushe_wendu,2) ;
  138.         
  139.         //显示预设烟雾
  140.         LCD_Write_Char(0,13,yushe_yanwu,3) ;
  141.         
  142.         //时时温度
  143.         LCD_Write_Char(1,6,c/10,2) ;
  144.         write_data('.');
  145.         LCD_Write_Char(1,9,c%10,1) ;
  146.         
  147.         //时时烟雾
  148.         LCD_Write_Char(1,13,temp,3) ;
  149. }



  150. /***********************************************************************************************************
  151. ADC0832相关函数
  152. ***********************************************************************************************************/
  153. sbit ADCS         =P1^1; //ADC0832 片选
  154. sbit ADCLK  =P1^2; //ADC0832 时钟
  155. sbit ADDI         =P1^3; //ADC0832 数据输入                /*因为单片机的管脚是双向的,且ADC0832的数据输入输出不同时进行,
  156. sbit ADDO         =P1^3; //ADC0832 数据输出                /*为节省单片机引脚,简化电路所以输入输出连接在同一个引脚上

  157. unsigned int Adc0832(unsigned char channel)
  158. {
  159.         uchar i=0;
  160.         uchar j;
  161.         uint dat=0;
  162.         uchar ndat=0;
  163.         uchar  Vot=0;

  164.         if(channel==0)channel=2;
  165.         if(channel==1)channel=3;
  166.         ADDI=1;
  167.         _nop_();
  168.         _nop_();
  169.         ADCS=0;//拉低CS端
  170.         _nop_();
  171.         _nop_();
  172.         ADCLK=1;//拉高CLK端
  173.         _nop_();
  174.         _nop_();
  175.         ADCLK=0;//拉低CLK端,形成下降沿1
  176.         _nop_();
  177.         _nop_();
  178.         ADCLK=1;//拉高CLK端
  179.         ADDI=channel&0x1;
  180.         _nop_();
  181.         _nop_();
  182.         ADCLK=0;//拉低CLK端,形成下降沿2
  183.         _nop_();
  184.         _nop_();
  185.         ADCLK=1;//拉高CLK端
  186.         ADDI=(channel>>1)&0x1;
  187.         _nop_();
  188.         _nop_();
  189.         ADCLK=0;//拉低CLK端,形成下降沿3
  190.         ADDI=1;//控制命令结束
  191.         _nop_();
  192.         _nop_();
  193.         dat=0;
  194.         for(i=0;i<8;i++)
  195.         {
  196.                 dat|=ADDO;//收数据
  197.                 ADCLK=1;
  198.                 _nop_();
  199.                 _nop_();
  200.                 ADCLK=0;//形成一次时钟脉冲
  201.                 _nop_();
  202.                 _nop_();
  203.                 dat<<=1;
  204.                 if(i==7)dat|=ADDO;
  205.         }
  206.         for(i=0;i<8;i++)
  207.         {
  208.                 j=0;
  209.                 j=j|ADDO;//收数据
  210.                 ADCLK=1;
  211.                 _nop_();
  212.                 _nop_();
  213.                 ADCLK=0;//形成一次时钟脉冲
  214.                 _nop_();
  215.                 _nop_();
  216.                 j=j<<7;
  217.                 ndat=ndat|j;
  218.                 if(i<7)ndat>>=1;
  219.         }
  220.         ADCS=1;//拉低CS端
  221.         ADCLK=0;//拉低CLK端
  222.         ADDO=1;//拉高数据端,回到初始状态
  223.         dat<<=8;
  224.         dat|=ndat;

  225.         return(dat);            //return ad data
  226. }

  227. /***********************************************************************************************************
  228. DS18B20相关函数
  229. ***********************************************************************************************************/

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



  231. /*****延时子程序:该延时主要用于ds18b20延时*****/
  232. void Delay_DS18B20(int num)
  233. {
  234.   while(num--) ;
  235. }
  236. /*****初始化DS18B20*****/
  237. void Init_DS18B20(void)
  238. {
  239.   unsigned char x=0;
  240.   DQ = 1;         //DQ复位
  241.   Delay_DS18B20(8);    //稍做延时
  242.   DQ = 0;         //单片机将DQ拉低
  243.   Delay_DS18B20(80);   //精确延时,大于480us
  244.   DQ = 1;         //拉高总线
  245.   Delay_DS18B20(14);
  246.   x = DQ;           //稍做延时后,如果x=0则初始化成功,x=1则初始化失败
  247.   Delay_DS18B20(20);
  248. }
  249. /*****读一个字节*****/
  250. unsigned char ReadOneChar(void)
  251. {
  252.   unsigned char i=0;
  253.   unsigned char dat = 0;
  254.   for (i=8;i>0;i--)
  255.   {
  256.     DQ = 0;     // 给脉冲信号
  257.     dat>>=1;
  258.     DQ = 1;     // 给脉冲信号
  259.     if(DQ)
  260.     dat|=0x80;
  261.     Delay_DS18B20(4);
  262.   }
  263.   return(dat);
  264. }
  265. /*****写一个字节*****/
  266. void WriteOneChar(unsigned char dat)
  267. {
  268.   unsigned char i=0;
  269.   for (i=8; i>0; i--)
  270.   {
  271.     DQ = 0;
  272.     DQ = dat&0x01;
  273.     Delay_DS18B20(5);
  274.     DQ = 1;
  275.     dat>>=1;
  276.   }
  277. }
  278. /*****读取温度*****/
  279. unsigned int ReadTemperature(void)
  280. {
  281.   unsigned char a=0;
  282.   unsigned char b=0;
  283.   unsigned int t=0;
  284.   float tt=0;
  285.   Init_DS18B20();
  286.   WriteOneChar(0xCC);  //跳过读序号列号的操作
  287.   WriteOneChar(0x44);  //启动温度转换
  288.   Init_DS18B20();
  289.   WriteOneChar(0xCC);  //跳过读序号列号的操作
  290.   WriteOneChar(0xBE);  //读取温度寄存器
  291.   a=ReadOneChar();     //读低8位
  292.   b=ReadOneChar();    //读高8位
  293.   t=b;
  294.   t<<=8;
  295.   t=t|a;
  296.   tt=t*0.0625;
  297.   t= tt*10+0.5;     //放大10倍输出并四舍五入
  298.   return(t);
  299. }

  300. /*****校准温度*****/
  301. u16 check_wendu(void)
  302. {
  303.         u16 c;
  304.         c=ReadTemperature()-5;                          //获取温度值并减去DS18B20的温漂误差
  305.         if(c<1) c=0;
  306.         if(c>=999) c=999;
  307.         return c;
  308. }


  309. //按键
  310. sbit Key1=P3^0;                                 //设置键
  311. sbit Key2=P3^1;                                 //加按键
  312. sbit Key3=P3^2;                                 //减按键



  313. #define KEY_SET                 1                //设置
  314. #define KEY_ADD                        2                //加
  315. #define KEY_MINUS                3                //减



  316. u8 Key_Scan()
  317. {         
  318.         static u8 key_up=1;//按键按松开标志
  319.         if(key_up&&(Key1==0||Key2==0||Key3==0))
  320.         {
  321.                 delay_ms(10);//10ms延时去抖动
  322.                 key_up=0;
  323.                 if(Key1==0)                        return 1;
  324.                 else if(Key2==0)return 2;
  325.                 else if(Key3==0)return 3;
  326.         }
  327.         else if(Key1==1&&Key2==1&&Key3==1)
  328.                 key_up=1;            
  329.          return 0;// 无按键按下
  330. }

  331. void main (void)
  332. {
  333.         u8 key;
  334.         Init1602();                //调用初始化显示函数
  335.         LCD_Write_String(0,0,"SET T:00   E:000");  //开机界面
  336.         LCD_Write_String(1,0,"NOW T:00.0 E:000");  
  337.         while (1)                        //主循环
  338.         {
  339.                 key=Key_Scan();                //按键扫描
  340.                 yanwu=Adc0832(0);        //读取烟雾值
  341.                 wendu=check_wendu();          //读取温度值
  342.                
  343.                 if(key==KEY_SET)
  344.                 {
  345.                         Mode++;
  346.                 }        
  347.                 switch(Mode)                //判断模式的值
  348.                 {
  349.                         case 0:                //监控模式
  350.                         {
  351.                                 Display_1602(yushe_wendu,yushe_yanwu,wendu,yanwu);  //显示预设温度,预设烟雾,温度值,烟雾值
  352.                                 if(yanwu>=yushe_yanwu)          //烟雾值大于等于预设值时
  353.                                 {
  354.                                         Led_Reg=0;                  //烟雾指示灯亮
  355.                                         Buzzer=1;                         //蜂鸣器报警
  356.                                 }
  357.                                 else                                        //烟雾值小于预设值时
  358.                                 {
  359.                                 Led_Reg=1;                  //关掉报警灯
  360.                                 }
  361.                                 if(wendu>=(yushe_wendu*10))          //温度大于等于预设温度值时(为什么是大于预设值*10:因为我们要显示的温度是有小数点后一位,是一个3位数,25.9°C时实际读的数是259,所以判断预设值时将预设值*10)
  362.                                 {
  363.                                         Buzzer=1;                         //打开蜂鸣器报警
  364.                                         Led_Yellow=0;                          //打开温度报警灯
  365.                                 }
  366.                                 else                                         //温度值小于预设值时
  367.                                 {
  368.                                         Led_Yellow=1;                  //关闭报警灯
  369.                                 }
  370.                                 if((yanwu<yushe_yanwu)&&(wendu<(yushe_wendu*10)))          //当烟雾小于预设值并且温度也小于预设值时 (&&:逻辑与,左右两边的表达式都成立(都为真,也就是1)时,该if语句才成立)
  371.                                 {
  372.                                         Buzzer=1;                         //停止报警
  373.                                 }
  374.                                 break;
  375.                         }
  376.                         case 1://预设温度模式
  377.                         {
  378.                                 SelectPosition(0,5) ;                //指定位置
  379.                            write_com(0x0d);                        //阴影闪烁
  380.                                 if(key==KEY_ADD)                //加键按下
  381.                                 {
  382.                                         yushe_wendu++;                //预设温度值(阀值)加1
  383.                                         if(yushe_wendu>=85)                //当阀值加到大于等于85时
  384.                                         yushe_wendu=85;                        //阀值固定为85
  385.                                         LCD_Write_Char(0,6,yushe_wendu,2) ;//显示预设温度
  386.                                 }
  387.                                 if(key==KEY_MINUS)                //减键按下
  388.                                 {
  389.                                         if(yushe_wendu<=1)        //当温度上限值减小到1时
  390.                                         yushe_wendu=1;                          //固定为1
  391.                                         yushe_wendu--;                //预设温度值减一,最小为0
  392.                                         LCD_Write_Char(0,6,yushe_wendu,2) ;//显示预设温度
  393.                                 }
  394.                                 break;                         //执行后跳出switch
  395.                         }
  396.                         case 2:                        //预设烟雾模式
  397.                         {
  398.                                 SelectPosition(0,12) ;                //指定位置        
  399.                            write_com(0x0d);                        //打开显示 无光标 光标闪烁
  400.                                 if(key==KEY_ADD)                //加键按下
  401.                                 {
  402.                                         if(yushe_yanwu>=255)        //当阀值加到大于等于255时
  403.                                         yushe_yanwu=254;            //阀值固定为254
  404.                                         yushe_yanwu++;                         //预设烟雾值(阀值)加1,最大为255
  405.                                         LCD_Write_Char(0,13,yushe_yanwu,3) ;//显示预设烟雾
  406.                                 }
  407.                                 if(key==KEY_MINUS)                        //减键按下
  408.                                 {
  409.                                         if(yushe_yanwu<=1)                //当烟雾上限值减小到1时
  410.                                                 yushe_yanwu=1;          //固定为1
  411.                                         yushe_yanwu--;                        //预设温度值减一,最小为0         
  412.                                         LCD_Write_Char(0,13,yushe_yanwu,3) ;//显示预设烟雾
  413.                                 }
  414.                                 break;
  415.                         }
  416.                         default        :        
  417.                         {
  418.                                 write_com(0x38);//屏幕初始化
  419.                                 write_com(0x0c);//打开显示 无光标 无光标闪烁
  420.                                 Mode=0;                        //恢复正常模式
  421.                                 break;
  422.                         }
  423.                 }
  424.                
  425.         }

  426. }
复制代码



分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:280000 发表于 2021-4-14 23:40 | 只看该作者
显示位置是否重复了,还有显示屏初始化有没有成功

评分

参与人数 1黑币 +20 收起 理由
admin + 20 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

板凳
ID:880912 发表于 2021-4-15 07:40 | 只看该作者
湖南 发表于 2021-4-14 23:40
显示位置是否重复了,还有显示屏初始化有没有成功

请问一下那该如何去改
回复

使用道具 举报

地板
ID:446775 发表于 2021-4-15 13:39 | 只看该作者
一是屏幕的初始化,二是显示界面的切换问题,这两个都要考虑,烟雾检测的个位数值乱飘,是否与你设置的采样率有关,把采样率降低试试看

评分

参与人数 1黑币 +20 收起 理由
admin + 20 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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