找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3260|回复: 4
收起左侧

原创 基于DS18B20的温度计设计,含有仿真文件,单片机源程序

[复制链接]
ID:796901 发表于 2020-7-4 18:37 | 显示全部楼层 |阅读模式
这是我学习单片机制作的,设计参数主要有:
   1.温度传感器采用DS18B20芯片;
   2.LCD1602液晶模块作为显示器;
   3.能够实现按键调整温度上下限;
   4.能够显示年月日。

里面有电路仿真图,c程序等,希望能够帮助到大家。

1.png
  1. #include<reg51.h>                                   //将AT89X52.h头文件包含到主程序
  2. #include<intrins.h>                                   //将intrins.h头文件包含到主程序(调用其中的_nop_()空操作函数延时)
  3. #define uint  unsigned int                      //变量类型宏定义,用uint表示无符号整形(16位)
  4. #define uchar unsigned char                   //变量类型宏定义,用uchar表示无符号字符型(8位)
  5. sbit lcdrs=P2^4;
  6. sbit lcdrw=P2^5;
  7. sbit lcden=P2^6;
  8. sbit ds=P1^3;
  9. sbit k1=P3^0;//设置按键
  10. sbit k2=P3^1;//加1按键
  11. sbit k3=P3^2;//减1按键
  12. //sbit k4=P3^3;//关蜂鸣器按键
  13. sbit D1=P1^0;
  14. sbit D2=P1^1;
  15. uchar flag,num;
  16. uint aa,bb;
  17. uchar miao,fen,shi,ri=3,month=7,year=18,num11;
  18. long uint temp,biaozhi;               //参数temp一定要声明为 int 型
  19. //延时函数
  20. void Tempdelay11(uchar us)  //经验表明,这里us=1时约等于6.9us
  21. {
  22.         while(us--);
  23. }
  24. void delay11(uint count) //延时子函数,当count=1是,延时大概2ms
  25. {
  26.         uint i;
  27.         while(count)
  28.         {
  29.                 i=200;
  30.                 while(i>0)
  31.                         i--;
  32.                 count--;
  33.         }
  34. }
  35. void delay(uint z)  
  36. {
  37.         uint x,y;
  38.         for(x=z;x>0;x--)
  39.                   for(y=110;y>0;y--);
  40. }
  41. /******************lcd液晶程序部分**************************/
  42. void write_com(uchar com)        //lcd写指令
  43. {
  44.         lcdrs=0;
  45.     lcdrw=0;
  46.         P0=com;
  47.         lcden=1;
  48.         delay(5);
  49.         lcden=0;        
  50. }
  51. void write_date(uchar date)                //lcd写数据
  52. {
  53.         lcdrs=1;
  54.     lcdrw=0;
  55.         P0=date;
  56.         lcden=1;
  57.         delay(5);
  58.         lcden=0;        
  59. }
  60. void init()                                  //lcd初始化
  61. {
  62.         lcdrw=0;
  63.         write_com(0x38);                 //lcd液晶 显示模式设置
  64.         write_com(0x0c);                  //lcd液晶 开显示 关光标 关闪烁
  65.         write_com(0x06);                  //读一个字节 光标指针加一  不整屏移动
  66.         write_com(0x01);                  //清屏
  67.         write_com(0x80);                  //设置数据指针
  68. }
  69. void key()
  70. {
  71.         if(k1==0)//判断k1按键是否按下
  72.         {
  73.                 delay(10);//延时,消抖
  74.                 if(k1==0)//再次判断k1按键是否按下
  75.                 {
  76.                         while(k1==0);//按键松手检测
  77.                         num++;
  78.                         if(num==1)
  79.                         {
  80.                                 write_com(0x80+9);
  81.                                 write_com(15);        
  82.                         }
  83.                         if(num==2)
  84.                         {
  85.                                 write_com(0x80+15);        
  86.                         }
  87.                         if(num==3)
  88.                         {
  89.                                 num=0;
  90.                                 write_com(12);        
  91.                         }
  92.                 }
  93.         }
  94.         if(num!=0)
  95.         {
  96.                 if(k2==0)//判断k1按键是否按下
  97.                 {
  98.                         delay(10);//延时,消抖
  99.                         if(k2==0)//再次判断k1按键是否按下
  100.                         {
  101.                                 while(k2==0);//按键松手检测
  102.                                 if(num==1)
  103.                                 {
  104.                                         aa++;
  105.                                         if(aa==1000)
  106.                                                 aa=0;
  107.                                         write_com(0x80+6);
  108.                                         write_date(48+aa/100);
  109.                                         write_com(0x80+7);
  110.                                         write_date(48+aa/10%10);
  111.                                         write_com(0x80+9);
  112.                                         write_date(48+aa%10);
  113.                                         write_com(0x80+8);
  114.                                         write_date('.');
  115.                                 }
  116.                                 if(num==2)
  117.                                 {
  118.                                         if(bb<aa)
  119.                                                 bb++;
  120.                                         if(bb==1000)
  121.                                                 bb=0;
  122.                                         write_com(0x80+12);
  123.                                         write_date(48+bb/100);
  124.                                         write_date(48+bb/10%10);
  125.                                         write_com(0x80+15);
  126.                                         write_date(48+bb%10);
  127.                                         write_com(0x80+14);
  128.                                         write_date('.');
  129.                                 }
  130.                         }
  131.                 }
  132.                 if(k3==0)//判断k1按键是否按下
  133.                 {
  134.                         delay(10);//延时,消抖
  135.                         if(k3==0)//再次判断k1按键是否按下
  136.                         {
  137.                                 while(k3==0);//按键松手检测
  138.                                 if(num==1)
  139.                                 {
  140.                                         if(aa>0)
  141.                                                 aa--;
  142.                                         if(aa==-1)
  143.                                                 aa=999;
  144.                                         write_com(0x80+6);
  145.                                         write_date(48+aa/100);
  146.                                         write_date(48+aa/10%10);
  147.                                         write_com(0x80+9);
  148.                                         write_date(48+aa%10);
  149.                                         write_com(0x80+8);
  150.                                         write_date('.');
  151.                                 }
  152.                                 if(num==2)
  153.                                 {
  154.                                         if(bb>0)
  155.                                                 bb--;
  156.                                         if(bb==-1)
  157.                                                 bb=999;
  158.                                         write_com(0x80+12);
  159.                                         write_date(48+bb/100);
  160.                                         write_date(48+bb/10%10);
  161.                                         write_com(0x80+15);
  162.                                         write_date(48+bb%10);
  163.                                         write_com(0x80+14);
  164.                                         write_date('.');
  165.                                 }
  166.                         }
  167.                 }
  168.         }
  169. }
  170. //LCD1602液晶的显示
  171. void display(uint temp)
  172. {   
  173.     uchar bai,shi,ge;
  174.         bai=temp/100;
  175.         shi=temp/10%10;
  176.         ge=temp%10;
  177.         if(num==0)
  178.         {
  179.                 if(biaozhi==1)
  180.                 {
  181.                         biaozhi=0;
  182.                 }
  183.                 write_com(0x80);
  184.                 write_date(48+bai);
  185.                 write_date(48+shi);
  186.                 write_date('.');
  187.                 write_date(48+ge);
  188.                 write_date(' ');
  189.                 write_date('H');
  190.                 write_date(48+aa/100);
  191.                 write_date(48+aa/10%10);
  192.                 write_date('.');
  193.                 write_date(48+aa%10);
  194.                 write_date(' ');
  195.                 write_date('L');
  196.                 write_date(48+bb/100);
  197.                 write_date(48+bb/10%10);
  198.                 write_date('.');
  199.                 write_date(48+bb%10);
  200.                 if(temp>aa)
  201.                 {
  202.                         D1=0;
  203.                 }
  204.                 else
  205.                         D1=1;
  206.                 if(temp<bb)
  207.                         D2=0;
  208.                 else
  209.                         D2=1;
  210.         }
  211.         write_com(0xc0+3);
  212.         write_date('2');
  213.         write_date('0');
  214.         write_date(48+year/10);
  215.         write_date(48+year%10);
  216.         write_date('-');
  217.         write_date(48+month/10);
  218.         write_date(48+month%10);
  219.         write_date('-');
  220.         write_date(48+ri/10);
  221.         write_date(48+ri%10);
  222. }
  223. /*****************************************
  224. 时序:初始化时序、读时序、写时序。
  225. 所有时序都是将主机(单片机)作为主设备,单总
  226. 线器件作为从设备。而每一次命令和数据的传输
  227. 都是从主机主动启动写时序开始,如果要求单总
  228. 线器件回送数据,在进行写命令后,主机需启动
  229. 读时序完成数据接收。数据和命令的传输都是低
  230. 位在先。
  231. 初始化时序:复位脉冲 存在脉冲
  232.         读;1 或 0时序
  233.         写;1 或 0时序
  234. 只有存在脉冲信号是从18b20(从机)发出的,其
  235. 它信号都是由主机发出的。
  236. 存在脉冲:让主机(总线)知道从机(18b20)已
  237. 经做好了准备。
  238. ******************************************/
  239. /*--------------------------------------------------------------------------------------------------------------------
  240. 初始化:检测总线控制器发出的复位脉冲
  241. 和ds18b20的任何通讯都要从初始化开始

  242. 初始化序列包括一个由总线控制器发出的复位脉冲
  243. 和跟在其后由从机发出的存在脉冲。

  244. 初始化:复位脉冲+存在脉冲

  245. 具体操作:
  246. 总线控制器发出(TX)一个复位脉冲 (一个最少保持480μs 的低电平信号),然后释放总线,
  247. 进入接收状态(RX)。单线总线由5K 上拉电阻拉到高电平。探测到I/O 引脚上的上升沿后
  248. DS1820 等待15~60μs,然后发出存在脉冲(一个60~240μs 的低电平信号)。

  249. 具体看18b20 单线复位脉冲时序和1-wire presence detect "的时序图
  250. -------------------------------------------------------------------------------------------------------------------*/
  251. void ds_reset()
  252. {
  253.         ds=1;
  254.            _nop_();        //1us
  255.            ds=0;
  256.            Tempdelay11(80); //当总线停留在低电平超过480us,总线上所以器件都将被复位,这里
  257.         //延时约530us总    线停留在低电平超过480μs,总线上的所有器件都将被复位。
  258.            _nop_();
  259.            ds=1;           //产生复位脉冲后,微处理器释放总线,让总线处于空闲状态,原因查
  260.         //18b20中文资料

  261.            Tempdelay11(5); //释放总线后,以便从机18b20通过拉低总线来指示其是否在线,
  262.                   //存在检测高电平时间:15~60us, 所以延时44us,进行1-wire presence //detect(单线存在检测)
  263.            _nop_();
  264.            _nop_();
  265.            _nop_();
  266.            if(ds==0)
  267.             flag=1;       //detect 18b20 success
  268.            else
  269.         flag=0;       //detect 18b20 fail
  270.         Tempdelay11(20);    //存在检测低电平时间:60~240us,所以延时约140us
  271.            _nop_();
  272.            _nop_();
  273.            ds=1;          //再次拉高总线,让总线处于空闲状态
  274. }
  275. /*----------------------------------------
  276. 读/写时间隙:
  277. DS1820 的数据读写是通过时间隙处理
  278. 位和命令字来确认信息交换。
  279. ------------------------------------------*/
  280. bit ds_read_bit()    //读一位
  281. {
  282.         bit dat;
  283.            ds=0;         //单片机(微处理器)将总线拉低
  284.         _nop_();       //读时隙起始于微处理器将总线拉低至少1us
  285.            ds=1;        //拉低总线后接着释放总线,让从机18b20能够接管总线,输出有效数据
  286.            _nop_();
  287.            _nop_();          //小延时一下,读取18b20上的数据 ,因为从ds18b20上输出的数据
  288.         //在读"时间隙"下降沿出现15us内有效
  289.            dat=ds;           //主机读从机18b20输出的数据,这些数据在读时隙的下降沿出现15us内有效
  290.            Tempdelay11(10);    //所有读"时间隙"必须60~120us,这里77us
  291.            return(dat);       //返回有效数据
  292. }
  293. uchar ds_read_byte() //读一字节
  294. {
  295.         uchar value,i,j;
  296.         value=0;           //一定别忘了给初值
  297.         for(i=0;i<8;i++)
  298.         {
  299.             j=ds_read_bit();
  300.              value=(j<<7)|(value>>1);   //这一步的说明在一个word文档里面
  301.         }
  302.         return(value);        //返回一个字节的数据
  303. }
  304. void ds_write_byte(uchar dat) //写一个字节
  305. {
  306.         uchar i;
  307.         bit onebit;        //一定不要忘了,onebit是一位
  308.         for(i=1;i<=8;i++)
  309.         {
  310.             onebit=dat&0x01;
  311.             dat=dat>>1;
  312.                 if(onebit)      //写 1
  313.                 {
  314.                         ds=0;
  315.                         _nop_();   
  316.                       _nop_();      //看时序图,至少延时1us,才产生写"时间隙"
  317.                         ds=1;       //写时间隙开始后的15μs内允许数据线拉到高电平
  318.                      Tempdelay11(5); //所有写时间隙必须最少持续60us
  319.                 }
  320.                 else         //写 0
  321.                 {
  322.                         ds=0;
  323.                      Tempdelay11(8);    //主机要生成一个写0 时间隙,必须把数据线拉到低电平并保持至少60μs,这里64us
  324.                         ds=1;
  325.                         _nop_();
  326.                      _nop_();
  327.                 }
  328.         }
  329. }
  330. /*****************************************
  331. 主机(单片机)控制18B20完成温度转换要经过三个步骤:
  332. 每一次读写之前都要18B20进行复位操作,复位成功后发送
  333. 一条ROM指令,最后发送RAM指令,这样才能对DS18b20进行
  334. 预定的操作。
  335. 复位要求主CPU将数据线下拉500us,然后释放,当ds18B20
  336. 受到信号后等待16~60us,后发出60~240us的存在低脉冲,
  337. 主CPU收到此信号表示复位成功
  338. ******************************************/

  339. /*----------------------------------------
  340. 进行温度转换:
  341. 先初始化
  342. 然后跳过ROM:跳过64位ROM地址,直接向ds18B20发温度转换命令,适合单片工作
  343. 发送温度转换命令
  344. ------------------------------------------*/
  345. void tem_change()
  346. {
  347.         ds_reset();
  348.         delay11(1);              //约2ms
  349.         ds_write_byte(0xcc);
  350.         ds_write_byte(0x44);
  351. }

  352. /*----------------------------------------
  353. 获得温度:
  354. ------------------------------------------*/
  355. uint get_temperature()
  356. {
  357.         float wendu;
  358.         uchar a,b;
  359.         ds_reset();
  360.         delay11(1);              //约2ms
  361.         ds_write_byte(0xcc);
  362.         ds_write_byte(0xbe);
  363.         a=ds_read_byte();
  364.         b=ds_read_byte();
  365.         temp=b;
  366.         temp<<=8;
  367.         temp=temp|a;
  368.         /*if((b&0x80)==0x80)
  369.         {
  370.                    biaozhi=1;//设置温度正负的标志
  371.               temp=0xffff-temp;
  372.                    temp=temp+1;
  373.         }*/
  374.         wendu=temp*0.0625;     //得到真实十进制温度值,因为DS18B20
  375.                        //可以精确到0.0625度,所以读回数据的最低位代表的是0.0625度
  376.         temp=wendu*10.0+0.5;       //放大十倍,这样做的目的将小数点后第一位
  377.                          //也转换为可显示数字,同时进行一个四舍五入操作。
  378.         return temp;
  379. }
  380. void main()
  381. {
  382.         aa=500;
  383.         bb=50;
  384.         EA=1;
  385.         ET0=1;
  386.         TMOD=0x01;
  387.         TH0=(65536-50000)/256;
  388.         TL0=(65536-50000)%256;
  389.         TR0=1;
  390.            init();
  391.            while(1)
  392.            {        
  393.                 key();
  394.                 if(num==0)
  395.                 {
  396.                         tem_change();    //开始转换12位转换时间最大为750ms
  397.                         get_temperature();//000000000000
  398.                 }
  399.                 display(temp);
  400.            }
  401. }
  402. //定时器0中断子函数
  403. void t0() interrupt 1
  404. {
  405.         TH0=(65536-50000)/256;
  406.         TL0=(65536-50000)%256;
  407.         num11++;
  408.         if(num11==20)
  409.         {
  410.                 num11=0;
  411.                 miao++;
  412.                 if(miao==60)
  413.                 {
  414.                         miao=0;
  415.                         fen++;
  416.                         if(fen==60)
  417.                         {
  418.                                 fen=0;
  419.                                 shi++;
  420.                                 if(shi==24)
  421.                                 {
  422.                                         shi=0;
  423.                                         fen=0;
  424.                                         miao=0;
  425.                                         ri++;
  426.                                         if(ri==29)
  427.                                                 if((year%4!=0)&&(month==2))
  428.                                                 {
  429.                                                         ri=1;
  430.                                                         month++;
  431.                                                         if(month==13)
  432.                                                         {
  433.                                                                 month=1;
  434.                                                                 year++;
  435.                                                         }
  436.                                                 }
  437.                                         if(ri==30)
  438.                                                 if((year%4==0)&&(month==2))
  439.                                                 {
  440.                                                         ri=1;
  441.                                                         month++;
  442.                                                         if(month==13)
  443.                                                         {
  444.                                                                 month=1;
  445.                                                                 year++;
  446.                                                         }
  447.                                                 }
  448.                                         if(ri==31)
  449.                                                 if((month==4)||(month==6)||(month==9)||(month==11))
  450.                                                 {
  451.                                                         ri=1;
  452.                                                         month++;
  453.                                                         if(month==13)
  454.                                                         {
  455.                                                                 month=1;
  456.                                                                 year++;
  457.                                                         }
  458.                                                 }
  459.                                         if(ri==32)
  460.                                                 if((month==1)||(month==3)||(month==5)||(month==7)||(month==8)||(month==10)||(month==12))
  461.                                                 {
  462.                                                         ri=1;
  463.                                                         month++;
  464.                                                         if(month==13)
  465.                                                         {
  466.                                                                 month=1;
  467.                                                                 year++;
  468.                                                         }
  469.                                                 }
  470.                                 }
  471.                         }
  472.                 }
  473.         }
  474. }        
复制代码
全部资料51hei下载地址:
基于DS18B20的温度计.zip (79.31 KB, 下载次数: 132)
回复

使用道具 举报

ID:592038 发表于 2021-2-25 23:49 | 显示全部楼层
怎么添加蜂鸣器
回复

使用道具 举报

ID:592038 发表于 2021-2-26 01:49 | 显示全部楼层
通电显示温度85,一秒后恢复正常,怎么修改这个85
回复

使用道具 举报

ID:917252 发表于 2021-5-26 10:13 | 显示全部楼层
负数部分怎么不显示呢
回复

使用道具 举报

ID:917252 发表于 2021-5-26 10:13 | 显示全部楼层
大佬可以加上负数部分显示吗
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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