標題: 關于stc89c52rc單片機的溫度和煙霧檢測的問題 [打印本頁]

作者: XIDAIDAI    時間: 2021-4-14 23:27
標題: 關于stc89c52rc單片機的溫度和煙霧檢測的問題
剛學習單片機,不管怎么修改程序都是溫度顯示一直與測量的溫度跟99.9一直切換顯示,而煙霧檢測的數(shù)值就在個位數(shù)亂飄,求大神能講一下什么回事,兵說一說哪里出錯了

單片機源程序如下:
  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數(shù)據(jù)

  12. //運行模式
  13. uchar Mode=0;                                                                 //=1是設置溫度閥值  =2是設置煙霧閥值        =0是正常監(jiān)控模式
  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相關函數(shù)
  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. //寫數(shù)據(jù)
  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.               寫入字符串函數(shù)
  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);//當讀或?qū)懸粋字符是指針后一一位
  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相關函數(shù)
  152. ***********************************************************************************************************/
  153. sbit ADCS         =P1^1; //ADC0832 片選
  154. sbit ADCLK  =P1^2; //ADC0832 時鐘
  155. sbit ADDI         =P1^3; //ADC0832 數(shù)據(jù)輸入                /*因為單片機的管腳是雙向的,且ADC0832的數(shù)據(jù)輸入輸出不同時進行,
  156. sbit ADDO         =P1^3; //ADC0832 數(shù)據(jù)輸出                /*為節(jié)省單片機引腳,簡化電路所以輸入輸出連接在同一個引腳上

  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;//控制命令結(jié)束
  191.         _nop_();
  192.         _nop_();
  193.         dat=0;
  194.         for(i=0;i<8;i++)
  195.         {
  196.                 dat|=ADDO;//收數(shù)據(jù)
  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;//收數(shù)據(jù)
  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;//拉高數(shù)據(jù)端,回到初始狀態(tài)
  223.         dat<<=8;
  224.         dat|=ndat;

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

  227. /***********************************************************************************************************
  228. DS18B20相關函數(shù)
  229. ***********************************************************************************************************/

  230. sbit DQ = P1^0;                                 //ds18b20的數(shù)據(jù)引腳



  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. /*****讀一個字節(jié)*****/
  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. /*****寫一個字節(jié)*****/
  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);  //啟動溫度轉(zhuǎn)換
  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();                //調(diào)用初始化顯示函數(shù)
  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)                        //主循環(huán)
  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:                //監(jiān)控模式
  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:因為我們要顯示的溫度是有小數(shù)點后一位,是一個3位數(shù),25.9°C時實際讀的數(shù)是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;                         //執(zhí)行后跳出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. }
復制代碼




作者: 湖南    時間: 2021-4-14 23:40
顯示位置是否重復了,還有顯示屏初始化有沒有成功
作者: XIDAIDAI    時間: 2021-4-15 07:40
湖南 發(fā)表于 2021-4-14 23:40
顯示位置是否重復了,還有顯示屏初始化有沒有成功

請問一下那該如何去改
作者: karolyte    時間: 2021-4-15 13:39
一是屏幕的初始化,二是顯示界面的切換問題,這兩個都要考慮,煙霧檢測的個位數(shù)值亂飄,是否與你設置的采樣率有關,把采樣率降低試試看




歡迎光臨 (http://www.torrancerestoration.com/bbs/) Powered by Discuz! X3.1