找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2869|回复: 1
收起左侧

51单片机学习:DS18B20测温程序

[复制链接]
ID:161768 发表于 2017-1-14 23:34 | 显示全部楼层 |阅读模式
  1. #include "my51.h"
  2. #include "smg.h"
  3. #include "ds18b20.h"

  4. void main()                          //测试 ,6位数码管显示温度值
  5. {
  6.     u8 i=0;
  7.     u16 temp=0;
  8.     while(1)
  9.     {       
  10.                 temp=ds18b20_readTemperaData();
  11.                 for(i=0;i<100;i++)
  12.                 {
  13.                         displaySMG(ds18b20_processTempData(temp));        
  14.                 }                    
  15.     }
  16. }
复制代码

  1. #ifndef                _DS18B20_H   
  2. #define                _DS18B20_H
  3. #include   "my51.h"
  4. #include   "smg.h"

  5. extern u8 smgWela[7];                          //数码管位选数据
  6. sbit DQ=P2^2;                                          //总线定义
  7. bool ds18b20_init();              //初始化函数
  8. u8*  ds18b20_processTempData(u16 temp);//将temp数据处理成数码管可显示数据
  9. u16  ds18b20_readTemperaData();   //读温度
  10. u8          ds18b20_readByte() ;         //读一个字节
  11. void ds18b20_writeByte(u8 dat);   //mcu向18b20写一个字节

  12. #endif
复制代码


  1. #include "ds18b20.h"

  2. /******************************************************************
  3. 当主机总线t0时刻从高拉至低电平时就产生写时间隙
  4. 从to 时刻开始的1us之后,15us之前将所需写的位送到总线上
  5. DSl820 在t0后的15-60us 对总线采样若低电平写入的位是0 ,若高电平写入的位是1
  6. 连续写2 个位之间的间隙应大于1us
  7. 写1,总时间大于60us,在t0开始延时1us就可以写1,15us之后ic来采样,采样时间最大45us
  8. 写0,总时间是60~120us,15~60us是ic在采样,120以外就没必要了,mcu总得释放总线吧
  9. 不管写1还是写0,大于60us的话,ic肯定已经采样完成了,那mcu就可以释放了
  10. *******************************************************************/
  11. void ds18b20_writeByte(u8 dat)  //mcu向ic写一个字节
  12. {
  13.     u8 i;
  14.         u8 tmep=dat;
  15.     for(i=0;i<8;i++)
  16.     {
  17.         DQ=0;           //产生读写时序的起始信号
  18.         _nop_();        //要求至少1us的延时
  19.         DQ=dat & 0x01; //对总线赋值,从最低位开始写起
  20.         delayXus(10);//延时74us,写0在60~120us之间释放,写1的话大于60us均可释放
  21.         DQ=1;          //释放总线,为下一次mcu送数据做准备,      
  22.                 dat>>=1;           //有效数据移动到最低位,2次写数据间隙至少需1us
  23.     }
  24. }

  25. /**************************************************************************
  26. 下降沿产生读时序
  27. 整个读时序必须至少有60us的持续时间,相邻两个读时序必须要有至少1us的恢复时间
  28. DS18B20在读时序产生1us后输出数据到总线上,也有可能需要2~3个微秒,但不会更多
  29. 而要求主机释放总线和采样总线等动作要在15μs内完成,那么让mcu采样的最佳时机
  30. 是读时序产生后的5~13us之间,在15~60us这段时间是18b20的私有时间,它会在这段
  31. 时间内的任意时刻释放总线,是不稳定期,我们不要让mcu在这段时间里对总线操作
  32. *******************************************************/
  33. u8 ds18b20_readByte()    //mcu读一个字节
  34. {
  35.     u8 i,value=0;
  36.     for(i=0;i<8;i++)
  37.     {
  38.         DQ=0;                       //起始信号
  39.         value>>=1;                  //顺便延时3~4个机器周期
  40.         DQ=1;                       //mcu释放总线
  41.         _nop_();_nop_();_nop_();        //再延时3.3us
  42.         if(DQ)         
  43.         {
  44.             value|=0x80;//保存高电平数据,低电平的话不用保存,移位后默认是0
  45.         }
  46.         delayXus(8); //延时60.76us  
  47.     }
  48.     return value;
  49. }

  50. u16 ds18b20_readTemperaData()  //读取温度值
  51. {
  52.     u16 temp=0;
  53.     if(ds18b20_init())
  54.     {
  55.         ds18b20_writeByte(0xcc);      //写指令:跳过rom检测
  56.         ds18b20_writeByte(0x44);     //写指令:温度转换
  57.         //delayms(750);// 转换延时需要750ms以上,我们不等它
  58.                 //首次转换未完成时,得到的初始化数据是85度,处理一下就可以了
  59.                 //温度转换电路是硬件独立的,不会阻塞初始化功能
  60.         if(ds18b20_init())
  61.         {
  62.             ds18b20_writeByte(0xcc);  //写指令:跳过检测rom
  63.             ds18b20_writeByte(0xbe);  //写指令:读取温度值
  64.             temp=ds18b20_readByte();  //先读低8位数据
  65.                         temp|=(u16)ds18b20_readByte()<<8; //再读高8位数据,然后合并
  66.                         temp&= 0x0FFF;        //高4位数据反正没用上,我们用来存放错误码
  67.         }
  68.                 else
  69.                 {
  70.                         led5=0;                 //调试代码
  71.                         temp=0x2000; //错误码,初始化失败
  72.                 }
  73.     }
  74.         else
  75.         {
  76.                 led6=0;                        //调试代码
  77.                 temp=0x1000;           //错误码,初始化失败,可能器件损坏
  78.         }
  79.     return temp;
  80. }

  81. bool ds18b20_init()   //初始化
  82. {
  83.     u8 checkState=0;
  84.     DQ=1;             //总线初始状态
  85.     _nop_();_nop_();
  86.     DQ=0;             //mcu先将总线拉低
  87.     delayXus(80);     //延时530us,要求480us~960us的低电平信号
  88.                       //当ic接受到此复位信号后会回发一个存在信号
  89.                       //mcu若要接收此存在信号则先要释放总线,让ic控制该总线
  90.                       //当mcu释放总线后的15~60us之后,ic才向总线发一个低电平信号
  91.                       //该信号存在时间为60~240us
  92.     DQ=1;             //mcu释放总线
  93.     delayXus(10);     //mcu释放15~60us以上,(8+6*10)*1.085=73us,
  94.                       //这时DS18B20已经拉低信号,大约60~240us应答保持时间,
  95.     checkState=DQ;    //在这段60~240us时间内,mcu采样是否有器件响应,0表示有响应
  96.     delayXus(70);     //延时464us,加上之前的73us,共537us
  97.                       //虽然ic在拉低电平60~240us之后,会释放总线,但整个时间至少480us
  98.                       //故我们共用时537us,这样是为了不影响后续的操作                    
  99.     if(checkState)    //checkstate为0说明有器件响应,为1无器件响应
  100.     {
  101.         return FALSE;
  102.     }
  103.     return TRUE;          //初始化成功
  104. }

  105. u8* ds18b20_processTempData(u16 temp) //返回数码管可直接显示的数据指针
  106. {
  107.         u8 i=0;       
  108.         if(0x0550==temp)          //如果初始化温度数据是85度的话
  109.         {
  110.                 led7=0;                             //亮灯报警,调试
  111.                 smgWela[5]=18;          //当温度是85度,第6个数码管显示负号
  112.                 return         smgWela;  //一般刚上电时能看到这个负号
  113.         }

  114.         if(1==(temp&0x0800))  //检测第11位是否为1,为1是负温度
  115.         {
  116.                 temp&=0x07ff;          //只取第0~10共11个位
  117.                 temp=(~temp+1) & 0x07ff;//将补码还原
  118.                 smgWela[0]=18;         //第一个数码管显示18号元素,即负号
  119.         }
  120.         else
  121.         {
  122.                 smgWela[0]=dark;           //正温度的话这个数码管就不要显示了
  123.         }
  124.     temp=(u16)(temp*6.25);         //精度的1000倍,我们将小数点另外叠加显示
  125.         if(temp>=10000)
  126.         {
  127.                  smgWela[1]=1;            //第二个数码管显示1,是百位上,100度以上啊
  128.         }
  129.         else
  130.         {
  131.                 smgWela[1]=dark;     //百位上是0的话不要显示这个0
  132.         }
  133.     smgWela[2]=temp%10000/1000;           //第三个数码管 十位
  134.     smgWela[3]=temp%1000/100;           //第四个数码管 个位叠加小数点
  135.     smgWela[4]=temp%100/10;                   //第五个数码管
  136.     smgWela[5]=temp%10;                           //第六个数码管
  137.         smgWela[6]=0xf7;                           //第4个数码管叠加小数点
  138.         return smgWela;                                   //返回数组
  139. }
复制代码


  1. #ifndef _51SMG_H_
  2. #define _51SMG_H_

  3. #include <reg52.h>
  4. #include "mytype.h"
  5. sbit dula =P2^6;                  //段选锁存器控制  控制笔段
  6. sbit wela =P2^7;                  //位选锁存器控制  控制位置

  7. #define dark        0x11//在段中,0x11是第17号元素,0x00是低电平,数码管不亮,即table[17]
  8. #define dotDark 0xff//小数点全暗

  9. void displaySMG(u8* pWela); //数码管显示函数,参数是数组指针

  10. #endif
复制代码


  1. #include "smg.h"
  2. #include "my51.h"

  3. static u8 code table[]= {                 //0~F外加小数点和空输出的数码管编码
  4.         0x3f , 0x06 , 0x5b , 0x4f , // 0 1 2 3
  5.         0x66 , 0x6d , 0x7d , 0x07 , // 4 5 6 7
  6.         0x7f , 0x6f , 0x77 , 0x7c , // 8 9 A B
  7.         0x39 , 0x5e , 0x79 , 0x71 , // C D E F
  8.         0x80 , 0x00 ,0x40           // . 空 负号    空为第17号元素
  9. };

  10. /*  由于此表只能一次显示一个小数点,故已注释掉,仅供查询
  11.         例如想要第一个和第六个数码管小数点同时点亮,
  12.         则执行 pWela->dot = 0xfe & 0xdf  即可
  13.         u8 code dotTable[]={   //小数点位置,某一位置0时,小数点亮
  14.         0xff ,                 //全暗
  15.         0xfe , 0xfd , 0xfb ,   //1 2 3
  16.         0xf7 , 0xef , 0xdf     //4 5 6                    
  17. };*/

  18. u8 data smgWela[7]={0,0,0,0,0,0,0}; //第一位到第六位,最后一个是小数点位置控制

  19. //P0口的数码管位选控制锁存器只用了低6位,我们保留高2位的数据,留作它用
  20. void displaySMG(u8* pWela)
  21. {
  22.         u8 i=0;       
  23.     //控制6位数码管显示函数,不显示的位用参数dark
  24.     u8 preState=P0|0x3f;  //保存高2位状态,其中最高位是ADC0804的片选信号
  25.         wela=0;dula=0;_nop_();//先锁定数据,防止吴亮及位选锁存器高2位数据被改变
  26.                
  27.         P0=0;                                 //由于数码管是共阴极的,阳极送低电平,灯不亮
  28.     dula=1;_nop_();
  29.     dula=0;                                 //段选数据清空并锁定

  30.     P0=preState;                    //共阴极数码管是阴极置高不亮,低6位置1,高2位保留       
  31.     wela=1;_nop_();                  //注:wela和dula上电默认为1                 
  32.     wela=0;                                    //位选锁定,初始保留高2位的数据,低6位置高不亮

  33.         for(i=0;i<6;i++)          //显示6位数码管
  34.         {
  35.                 P0=table[pWela[i]]|(((1<<i) & pWela[6])?0x00:0x80);
  36.             dula=1;_nop_();             //送段数据,叠加小数点的显示,0x00点亮小数点
  37.             dula=0;
  38.             
  39.                    P0=preState&~(1<<i); //不影响高2位数据,低6位是数码管位选,低电平有效
  40.             wela=1;        _nop_();         //送位选号
  41.             wela=0;       
  42.             delayms(1);                         //稍作延时,让灯管亮起来                       
  43.                 {  //消除叠影及误亮,阴极置1不亮,低6位置1,高2位保留并锁定
  44.                 P0=preState;
  45.                 wela=1;        _nop_();                       
  46.                 wela=0;       
  47.             }
  48.         }
  49. }
复制代码


  1. #ifndef _MY51_H
  2. #define _MY51_H
  3. #include <reg52.h>
  4. //#include <math.h>
  5. #include <intrins.h>
  6. #include "mytype.h"


  7. #define high        1   //高电平
  8. #define low                0   //低电平

  9. #define led P1    //灯总线控制

  10. sbit led0=P1^0;     //8个led灯,阴极送低电平点亮
  11. sbit led1=P1^1;
  12. sbit led2=P1^2;
  13. sbit led3=P1^3;
  14. sbit led4=P1^4;
  15. sbit led5=P1^5;
  16. sbit led6=P1^6;
  17. sbit led7=P1^7;       
  18. sbit ledLock=P2^5;        //led锁存的状态,0锁定 ,1不锁定
  19.    
  20. sbit beep=P2^3;     //蜂鸣器

  21. void delayms(u16 ms);
  22. void delayXus(u8 us); //函数执行(8+6x)个机器周期, 即t=(8+6x)*1.085
  23. /////////////////////////////////////////////////////////////////////////////


  24. #endif
复制代码


  1. #include "MY51.h"

  2. void delayms(u16 ms)     //毫秒级软延时函数
  3. {       
  4.         u16 i,j;
  5.         for(i=ms;i>0;i--)
  6.         {
  7.         for(j=113;j>0;j--)
  8.         {}
  9.         }
  10. }

  11. /****************************************************************
  12. 若使用12分频模式的mcu,晶振频率为11059200Hz
  13. 则每个机器周期用时12/11059200=1.085微秒
  14. keil4编译,在默认的8级优化方式下
  15. 参数us=0时,函数执行9个机器周期,即t=9*1.085=9.77 us
  16. 参数us!=0时,函数执行(8+6x)个机器周期, 即t=(8+6x)*1.085 us
  17. *****************************************************************/
  18. void delayXus(u8 us)        //微秒级软延时函数
  19. {
  20.         while(us)           //这种写法有利于减小us=0时的机器周期
  21.         {
  22.                 us--;
  23.         }
  24. }
复制代码




回复

使用道具 举报

ID:829862 发表于 2022-2-7 14:13 | 显示全部楼层
:loveliness::hug::'(
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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