找回密码
 立即注册

QQ登录

只需一步,快速开始

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

51单片机写的温度报警器程序,下载到板子上功能是正常的,用Protues仿真不了

[复制链接]
跳转到指定楼层
楼主
  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_()函数所在头文件


  7. /*----------------音乐函数申明------------------------------*/
  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初始化函数
  16. void display();                        //显示控制模块

  17. /*-------------------LCD1602显示缓存-------------------------*/
  18. //LCD1602函数调用申明
  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!      ";//报警显示文字
  22. unsigned char code waringStrCol[] = "      Cold!     ";//报警显示文字
  23. unsigned char code striswaring[] = "            ";//取消报警显示文字


  24. /*----------------------其他全局变量-------------------------*/
  25. int Temp = 0;                //读取到的当前温度值(16bit二进制)
  26. int intT;                        //温度值的整数和小数部分
  27. bit iswaring = 0;        //是否报警标志位


  28. void main()
  29. {
  30. //        int n = 0;
  31. //        char s[1];
  32.         bit isReay = 0;
  33.         bit sta;                                //是否成功读取标志
  34.         unsigned int cnt = 0;        //检测标志,主要用于控制检测温度的频率
  35.         
  36.         InitBuzz();                                        //蜂鸣器初始化
  37.         Start18B20();                        //启动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转化好
  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);        //读取当前温度
  59.                         isGetTemp = 0;
  60.                         if (sta)                                        //读取成功时,刷新当前温度显示
  61.                         {
  62.                                 intT = Temp >> 4;                //分离出温度值整数部分
  63.                         }
  64.                         Start18B20();                                        //重新启动下一次转换
  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显示驱动------------------*/
  78. //定义LCD1602显示相关的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;        //温度值的整数部分备份
  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.                 /*备份当前值*/
  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;//个位

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

  114. //等待液晶准备好
  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;   //读取状态字
  125.         LCD1602_E = 0;      //避免干扰其他器件
  126.     } while (sta & 0x80);   //第七位等于1表示液晶正忙,重复检测直到第七位等于0为止
  127. }
  128. //向LCD1602液晶写入一字节命令,cmd为待写入命令值
  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液晶写入一字节数据,dat为待写入数据值
  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. //设置显示RAM起始地址,亦即光标位置,(x,y)对应屏幕上的字符的坐标
  149. void LcdSetCursor(unsigned char x, unsigned char y)
  150. {
  151.     unsigned char addr;
  152.      
  153.     if (y == 0)                          //由输入的屏幕坐标计算显示RAM的地址
  154.         addr = 0x00 + x;        //第一行字符地址从0x00起始
  155.     else
  156.         addr = 0x40 + x;        //第二行字符地址从0x40起始
  157.     LcdWriteCmd(addr | 0x80);        //设置RAM地址
  158. }
  159. //在液晶上显示字符串,(x,y)-对应屏幕上的起始坐标,
  160. //str-字符串指针,len-需显示的字符长度
  161. void LcdShowStr(unsigned char x, unsigned char y,unsigned char *str, unsigned char len)
  162. {
  163.     LcdSetCursor(x, y);   //设置起始地址
  164.     while (len--)         //连续写入len个字符数据
  165.     {
  166.         LcdWriteDat(*str++);  //先取str指向的数据,然后str自加1
  167.     }
  168. }

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

  173.     LcdWriteCmd(0x38);  //16*2显示,5*7点阵,8位数据接口
  174.     LcdWriteCmd(0x0C);  //显示器开,光标关闭
  175.     LcdWriteCmd(0x06);  //文字不动,地址自动+1
  176.     LcdWriteCmd(0x01);  //清屏
  177. }


  178. /*-----------------------以下是温度传感器驱动------------------*/
  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_()函数在12M晶振中延迟1us,为什么这里是8个_nop_()
  194.         因为while和--t也是需要时间的,这里不一定是准确的10us/循环
  195.         只是大致的时间*/
  196. }
  197. bit Get18B20Ack() //DS18B20存在检测函数
  198. {
  199.         bit ack;

  200.         EA = 0;                                //关中断
  201.         IO_18B20 = 0;                //拉低引脚
  202.         DelayX10us(50);                //延时500us(480us - 960us)
  203.         IO_18B20 = 1;                //释放总线
  204.         DelayX10us(6);                //延时60us(15us - 60us)
  205.         ack = IO_18B20;                //读取响应(60us - 240us)
  206.         while(!IO_18B20);        //等待DS18B20释放总线 (60us - 240us)
  207.         EA = 1;                                //取消关中断

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

  210. void  Write18B20(unsigned char dat) //写DS18B20
  211. {
  212.         unsigned char mask;                        //临时变量定义
  213.         EA = 0;                                                //关中断
  214.         for(mask=0x01; mask!= 0; mask<<=1)        //循环发送单个bit位
  215.         {
  216.                 IO_18B20 = 0;                        //拉低(请求读写操作)
  217.                 _nop_();                                //延时(1us < time <= 15us)
  218.                 _nop_();
  219.                 if((mask&dat) == 0)                //按位读取dat
  220.                         IO_18B20 = 0;                //本位是0,拉低
  221.                 else
  222.                         IO_18B20 = 1;                //本位是1,拉高
  223.                         //上面这个操作DS18B20读取(最小时间 0us<time<15us,
  224.                         //典型时间 15us,最大时间45us)
  225.                 DelayX10us(6);                        //等待60us(足够DS18B20读取)
  226.                 IO_18B20 = 1;                        //释放总线
  227.         }
  228.         EA = 1;                                                //取消关中断
  229. }

  230. unsigned char Read18B20()                //读DS18B20
  231. {
  232.         unsigned char dat;                        //数据缓存变量
  233.         unsigned char mask;                        //临时变量

  234.         EA = 0;                                                //关中断
  235.         for(mask=0x01; mask!=0; mask<<=1)//同上循环按位操作
  236.         {
  237.                 IO_18B20 = 0;                        //读写请求
  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释放总线
  248.         }
  249.         EA = 1;                                                //取消关中断

  250.         return dat;                                        //返回数据
  251. }

  252. bit Start18B20()                //初始化DS18B20
  253. {
  254.         bit ack;                        //存在标志

  255.         ack = Get18B20Ack();//检测存在
  256.         if(ack == 0)                //存在
  257.         {                                        //写命令使工作
  258.                 Write18B20(0xCC);         //跳过ROM检测
  259.                 Write18B20(0x44);        //启动温度转换
  260.         }
  261.         return ~ack;                //返回是否成功(1是,0否)
  262. }

  263. bit Get18B20Temp(int *temp)        //获取DS18B20温度存于temp
  264. {
  265.         bit ack;                                //存在标志
  266.         unsigned char LSB, MSB;        //数据低/高位

  267.         ack = Get18B20Ack();        //检测存在
  268.         if(ack == 0)                        //存在
  269.         {                                                //写指令
  270.                 Write18B20(0xCC);        //跳过ROM检测
  271.                 Write18B20(0xBE);        //读寄存器
  272.                 LSB = Read18B20();        //读低位
  273.                 MSB = Read18B20();        //读高位
  274.                 *temp = ((int)MSB<<8) + LSB;        //合并
  275.         }
  276.         return ~ack;                        //返回结果(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. }

复制代码


51hei图片20221122091640.png (352.25 KB, 下载次数: 76)

51hei图片20221122091640.png

51hei图片20221122091449.png (45.99 KB, 下载次数: 75)

51hei图片20221122091449.png
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

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

回复

使用道具 举报

板凳
ID:77589 发表于 2022-11-23 15:05 | 只看该作者
Protues仿真对程序要求更严谨,也就是说在实物上通过的代码,在Protues上仿真不一定能过;在Protues上仿真能过,电路一样的情况下,在实物板上基本都能过。
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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