找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開(kāi)始

搜索
查看: 1311|回復(fù): 2
打印 上一主題 下一主題
收起左側(cè)

51單片機(jī)寫(xiě)的溫度報(bào)警器程序,下載到板子上功能是正常的,用Protues仿真不了

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
  1. #include <reg52.h>
  2. #include <intrins.h>
  3. #define T_MAX 25 // 最大溫度限定值
  4. #define T_MIN 22 // 最小溫度限定值

  5. sbit BUZZ = P1^6;
  6. //_nop_()函數(shù)所在頭文件


  7. /*----------------音樂(lè)函數(shù)申明------------------------------*/
  8. void InitBuzz();
  9. bit isBuzz = 0; //蜂鳴器是否在響


  10. /*----------------溫度傳感器申明----------------------------*/
  11. bit Start18B20();                        //初始化DS18B20
  12. bit Get18B20Temp(int *temp);//讀取溫度
  13. bit isGetTemp = 0;                   //是否在獲取溫度


  14. /*----------------LCD1602顯示模塊申明------------------------*/
  15. void InitLcd1602();                        //LCD1602初始化函數(shù)
  16. void display();                        //顯示控制模塊

  17. /*-------------------LCD1602顯示緩存-------------------------*/
  18. //LCD1602函數(shù)調(diào)用申明
  19. void LcdShowStr(unsigned char x, unsigned char y,unsigned char *str, unsigned char len);
  20. unsigned char strbuff[4];//格式:“25°C”
  21. unsigned char code waringStrHot[] = "      Hot!      ";//報(bào)警顯示文字
  22. unsigned char code waringStrCol[] = "      Cold!     ";//報(bào)警顯示文字
  23. unsigned char code striswaring[] = "            ";//取消報(bào)警顯示文字


  24. /*----------------------其他全局變量-------------------------*/
  25. int Temp = 0;                //讀取到的當(dāng)前溫度值(16bit二進(jìn)制)
  26. int intT;                        //溫度值的整數(shù)和小數(shù)部分
  27. bit iswaring = 0;        //是否報(bào)警標(biāo)志位


  28. void main()
  29. {
  30. //        int n = 0;
  31. //        char s[1];
  32.         bit isReay = 0;
  33.         bit sta;                                //是否成功讀取標(biāo)志
  34.         unsigned int cnt = 0;        //檢測(cè)標(biāo)志,主要用于控制檢測(cè)溫度的頻率
  35.         
  36.         InitBuzz();                                        //蜂鳴器初始化
  37.         Start18B20();                        //啟動(dòng)DS18B20
  38.   InitLcd1602();              //初始化LCD1602液晶模塊
  39.         
  40.         while(1)
  41. {
  42.                 if(isReay == 0)
  43.                 {
  44.                         cnt++;
  45.                 }

  46.                 if((cnt>28000&&isBuzz == 0)||(cnt>14000&&isBuzz == 1))                                 //大約0.8s(仿真得到) DS18B20最多750ms轉(zhuǎn)化好
  47.                 {
  48.                         cnt = 0;
  49.                         isReay = 1;
  50.                 }
  51.                   
  52.                 if(isReay == 1 && isBuzz == 0)
  53.                 {
  54. //                        n++;
  55. //                        s[0] = n+'0';
  56. //                        LcdShowStr(0, 0,s, 1);
  57.                         isGetTemp = 1;
  58.                         sta = Get18B20Temp(&Temp);        //讀取當(dāng)前溫度
  59.                         isGetTemp = 0;
  60.                         if (sta)                                        //讀取成功時(shí),刷新當(dāng)前溫度顯示
  61.                         {
  62.                                 intT = Temp >> 4;                //分離出溫度值整數(shù)部分
  63.                         }
  64.                         Start18B20();                                        //重新啟動(dòng)下一次轉(zhuǎn)換
  65.         
  66.                         if(intT > T_MAX || intT < T_MIN)
  67.                         {
  68.                                 iswaring = 1;
  69.                         }else{
  70.                                 iswaring = 0;
  71.                         }

  72.                         isReay = 0;
  73.                 }

  74.                 display();//顯示
  75.         }
  76. }

  77. /*-----------------------以下是LCD1602顯示驅(qū)動(dòng)------------------*/
  78. //定義LCD1602顯示相關(guān)的IO接口
  79. #define LCD1602_DB  P0
  80. sbit LCD1602_RS = P1^0;
  81. sbit LCD1602_RW = P1^1;
  82. sbit LCD1602_E  = P1^5;


  83. //顯示控制模塊
  84. void display()
  85. {
  86.         static int intTb;        //溫度值的整數(shù)部分備份
  87.         static bit isBuzzb;

  88.         if(isBuzzb != isBuzz)
  89.         {
  90.                 if(isBuzz == 0 && iswaring == 1)
  91.                 {
  92.                         if(intT > T_MAX)
  93.                         {
  94.                                 LcdShowStr(0,1,waringStrHot,16);
  95.                         }else{
  96.                                 LcdShowStr(0,1,waringStrCol,16);
  97.                         }
  98.                         
  99.                 }else{
  100.                         LcdShowStr(0,1,striswaring,11);
  101.                 }
  102.                 isBuzzb = isBuzz;
  103.         }

  104.         if(intTb != intT)//如果有變化
  105.         {
  106.                 /*備份當(dāng)前值*/
  107.                 intTb = intT;
  108.                
  109.                 if((intT/10) == 0)strbuff[0] = ' ';else strbuff[0] = ((intT/10)%10)+0x30;//十位
  110.                 strbuff[1] = ((intT/1)%10)+0x30;//個(gè)位

  111.                 LcdShowStr(6,0,strbuff,4);        //顯示,初始位置隨意,只要能顯示完整就好
  112.         }
  113. }

  114. //等待液晶準(zhǔn)備好
  115. void LcdWaitReady()
  116. {
  117.     unsigned char sta;
  118.      
  119.     LCD1602_DB = 0xFF;
  120.     LCD1602_RS = 0;
  121.     LCD1602_RW = 1;
  122.     do {
  123.         LCD1602_E = 1;      //使能LCD1602
  124.         sta = LCD1602_DB;   //讀取狀態(tài)字
  125.         LCD1602_E = 0;      //避免干擾其他器件
  126.     } while (sta & 0x80);   //第七位等于1表示液晶正忙,重復(fù)檢測(cè)直到第七位等于0為止
  127. }
  128. //向LCD1602液晶寫(xiě)入一字節(jié)命令,cmd為待寫(xiě)入命令值
  129. void LcdWriteCmd(unsigned char cmd)
  130. {
  131.     LcdWaitReady();
  132.     LCD1602_RS = 0;
  133.     LCD1602_RW = 0;
  134.     LCD1602_DB = cmd;
  135.     LCD1602_E  = 1;
  136.     LCD1602_E  = 0;
  137. }
  138. //向LCD1602液晶寫(xiě)入一字節(jié)數(shù)據(jù),dat為待寫(xiě)入數(shù)據(jù)值
  139. void LcdWriteDat(unsigned char dat)
  140. {
  141.     LcdWaitReady();
  142.     LCD1602_RS = 1;
  143.     LCD1602_RW = 0;
  144.     LCD1602_DB = dat;
  145.     LCD1602_E  = 1;
  146.     LCD1602_E  = 0;
  147. }
  148. //設(shè)置顯示RAM起始地址,亦即光標(biāo)位置,(x,y)對(duì)應(yīng)屏幕上的字符的坐標(biāo)
  149. void LcdSetCursor(unsigned char x, unsigned char y)
  150. {
  151.     unsigned char addr;
  152.      
  153.     if (y == 0)                          //由輸入的屏幕坐標(biāo)計(jì)算顯示RAM的地址
  154.         addr = 0x00 + x;        //第一行字符地址從0x00起始
  155.     else
  156.         addr = 0x40 + x;        //第二行字符地址從0x40起始
  157.     LcdWriteCmd(addr | 0x80);        //設(shè)置RAM地址
  158. }
  159. //在液晶上顯示字符串,(x,y)-對(duì)應(yīng)屏幕上的起始坐標(biāo),
  160. //str-字符串指針,len-需顯示的字符長(zhǎng)度
  161. void LcdShowStr(unsigned char x, unsigned char y,unsigned char *str, unsigned char len)
  162. {
  163.     LcdSetCursor(x, y);   //設(shè)置起始地址
  164.     while (len--)         //連續(xù)寫(xiě)入len個(gè)字符數(shù)據(jù)
  165.     {
  166.         LcdWriteDat(*str++);  //先取str指向的數(shù)據(jù),然后str自加1
  167.     }
  168. }

  169. void InitLcd1602()//初始化1602液晶
  170. {
  171.         strbuff[2] = 0XDF;
  172.         strbuff[3] = 'C';

  173.     LcdWriteCmd(0x38);  //16*2顯示,5*7點(diǎn)陣,8位數(shù)據(jù)接口
  174.     LcdWriteCmd(0x0C);  //顯示器開(kāi),光標(biāo)關(guān)閉
  175.     LcdWriteCmd(0x06);  //文字不動(dòng),地址自動(dòng)+1
  176.     LcdWriteCmd(0x01);  //清屏
  177. }


  178. /*-----------------------以下是溫度傳感器驅(qū)動(dòng)------------------*/
  179. //DS18B20通信引腳
  180. sbit IO_18B20 = P3^2;
  181. void DelayX10us(unsigned char t)
  182. {
  183.     do {
  184.         _nop_();
  185.         _nop_();
  186.         _nop_();
  187.         _nop_();
  188.         _nop_();
  189.         _nop_();
  190.         _nop_();
  191.         _nop_();
  192.     } while (--t);
  193.     /*_nop_()函數(shù)在12M晶振中延遲1us,為什么這里是8個(gè)_nop_()
  194.         因?yàn)閣hile和--t也是需要時(shí)間的,這里不一定是準(zhǔn)確的10us/循環(huán)
  195.         只是大致的時(shí)間*/
  196. }
  197. bit Get18B20Ack() //DS18B20存在檢測(cè)函數(shù)
  198. {
  199.         bit ack;

  200.         EA = 0;                                //關(guān)中斷
  201.         IO_18B20 = 0;                //拉低引腳
  202.         DelayX10us(50);                //延時(shí)500us(480us - 960us)
  203.         IO_18B20 = 1;                //釋放總線(xiàn)
  204.         DelayX10us(6);                //延時(shí)60us(15us - 60us)
  205.         ack = IO_18B20;                //讀取響應(yīng)(60us - 240us)
  206.         while(!IO_18B20);        //等待DS18B20釋放總線(xiàn) (60us - 240us)
  207.         EA = 1;                                //取消關(guān)中斷

  208.         return ack;                        //返回是否存在 (0:存在 1:不存在)
  209. }

  210. void  Write18B20(unsigned char dat) //寫(xiě)DS18B20
  211. {
  212.         unsigned char mask;                        //臨時(shí)變量定義
  213.         EA = 0;                                                //關(guān)中斷
  214.         for(mask=0x01; mask!= 0; mask<<=1)        //循環(huán)發(fā)送單個(gè)bit位
  215.         {
  216.                 IO_18B20 = 0;                        //拉低(請(qǐng)求讀寫(xiě)操作)
  217.                 _nop_();                                //延時(shí)(1us < time <= 15us)
  218.                 _nop_();
  219.                 if((mask&dat) == 0)                //按位讀取dat
  220.                         IO_18B20 = 0;                //本位是0,拉低
  221.                 else
  222.                         IO_18B20 = 1;                //本位是1,拉高
  223.                         //上面這個(gè)操作DS18B20讀。ㄗ钚r(shí)間 0us<time<15us,
  224.                         //典型時(shí)間 15us,最大時(shí)間45us)
  225.                 DelayX10us(6);                        //等待60us(足夠DS18B20讀取)
  226.                 IO_18B20 = 1;                        //釋放總線(xiàn)
  227.         }
  228.         EA = 1;                                                //取消關(guān)中斷
  229. }

  230. unsigned char Read18B20()                //讀DS18B20
  231. {
  232.         unsigned char dat;                        //數(shù)據(jù)緩存變量
  233.         unsigned char mask;                        //臨時(shí)變量

  234.         EA = 0;                                                //關(guān)中斷
  235.         for(mask=0x01; mask!=0; mask<<=1)//同上循環(huán)按位操作
  236.         {
  237.                 IO_18B20 = 0;                        //讀寫(xiě)請(qǐng)求
  238.                 _nop_();                                //等待(1us < time < 15us)
  239.                 _nop_();
  240.                 IO_18B20 = 1;                        //初始化讀操作
  241.                 _nop_();                                //等待DS18B20輸出
  242.                 _nop_();
  243.                 if(!IO_18B20)                        //讀
  244.                         dat &= ~mask;                //“0”
  245.                 else
  246.                         dat |= mask;                //“1”
  247.                 DelayX10us(6);                        //等待DS18B20釋放總線(xiàn)
  248.         }
  249.         EA = 1;                                                //取消關(guān)中斷

  250.         return dat;                                        //返回?cái)?shù)據(jù)
  251. }

  252. bit Start18B20()                //初始化DS18B20
  253. {
  254.         bit ack;                        //存在標(biāo)志

  255.         ack = Get18B20Ack();//檢測(cè)存在
  256.         if(ack == 0)                //存在
  257.         {                                        //寫(xiě)命令使工作
  258.                 Write18B20(0xCC);         //跳過(guò)ROM檢測(cè)
  259.                 Write18B20(0x44);        //啟動(dòng)溫度轉(zhuǎn)換
  260.         }
  261.         return ~ack;                //返回是否成功(1是,0否)
  262. }

  263. bit Get18B20Temp(int *temp)        //獲取DS18B20溫度存于temp
  264. {
  265.         bit ack;                                //存在標(biāo)志
  266.         unsigned char LSB, MSB;        //數(shù)據(jù)低/高位

  267.         ack = Get18B20Ack();        //檢測(cè)存在
  268.         if(ack == 0)                        //存在
  269.         {                                                //寫(xiě)指令
  270.                 Write18B20(0xCC);        //跳過(guò)ROM檢測(cè)
  271.                 Write18B20(0xBE);        //讀寄存器
  272.                 LSB = Read18B20();        //讀低位
  273.                 MSB = Read18B20();        //讀高位
  274.                 *temp = ((int)MSB<<8) + LSB;        //合并
  275.         }
  276.         return ~ack;                        //返回結(jié)果(1成功,0失。
  277. }

  278. //下面是蜂鳴器
  279. void InterruptTimer0() interrupt 1
  280. {
  281.         static unsigned int timer;
  282.         TH0 = 0x00;
  283.         TL0 = 0x00;
  284.         timer++;
  285.         if(iswaring)
  286.         {
  287.                 if(timer>3000)
  288.                 {
  289.                         isBuzz = 1;

  290.                         if(timer%5==1)
  291.                         {
  292.                                 BUZZ = ~BUZZ;
  293.                         }

  294.                         if(timer>6000)
  295.                         {
  296.                                 timer = 0;        
  297.                         }
  298.                 }else{
  299.                         isBuzz = 0;
  300.                 }
  301.         }else{
  302.                 isBuzz = 0;
  303.         }
  304. }

  305. void InitBuzz()
  306. {
  307.         TMOD = 0x02;
  308.         TR0 = 1;
  309.         ET0 = 1;        
  310. }

復(fù)制代碼


51hei圖片20221122091640.png (352.25 KB, 下載次數(shù): 77)

51hei圖片20221122091640.png

51hei圖片20221122091449.png (45.99 KB, 下載次數(shù): 76)

51hei圖片20221122091449.png
分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏 分享淘帖 頂 踩
回復(fù)

使用道具 舉報(bào)

沙發(fā)
ID:161164 發(fā)表于 2022-11-22 14:14 | 只看該作者
部份版本的Protues LCD1602仿真不支援查忙 于是你的程序在while (sta & 0x80);中死循環(huán)了

回復(fù)

使用道具 舉報(bào)

板凳
ID:77589 發(fā)表于 2022-11-23 15:05 | 只看該作者
Protues仿真對(duì)程序要求更嚴(yán)謹(jǐn),也就是說(shuō)在實(shí)物上通過(guò)的代碼,在Protues上仿真不一定能過(guò);在Protues上仿真能過(guò),電路一樣的情況下,在實(shí)物板上基本都能過(guò)。
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

手機(jī)版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表