找回密码
 立即注册

QQ登录

只需一步,快速开始

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

第19章 单总线DS18B20通信(无线通信)

  [复制链接]
跳转到指定楼层
楼主
51单片机轻松入门—基于STC15W4K系列(C语言版)
李友全
编著 详见:http://www.51hei.com/bbs/dpj-37954-1.html

第19章 单总线DS18B20通信(无线通信)
1 电路图
2 程序移植
3 多点测温

DS18B20是一种常用的高精度数字温度传感器,长距离(1KM以上)无线通信

在实际工程中也经常用到。

1 电 路 图

DS18B20是一种很常用的数字温度传感器,温度检测范围是-55~+125度,手册 说明在-10~+85度范围内检测误差为±0.5度,作者在自己的产品中随机抽样验证 了几只传感器,在-25度误差0.1度,+25度与+50度误差小于0.1度,可见这种传感 器实际精度是很高的,传感器引脚如图19-1所示,工作电压范围是3.0~5.5V,通 常使用+5V,电源接反或接错一般是不会损坏传感器的,对于单只DS18B20的使

用,我们按图19-2连接即可。







2 程序移植

例 19.1 单 只 DS18B20 的 温 度 检 测 , 测 温 范 围 -55 ~ +125 度 , 1602 液 晶 显 示 。 R/C 时 钟 频 率 :

22.1184MHz。程序移植时只需要修改DS18B20.H中的18B20信号引脚定义(sbit DQ=P1^5;)与myfun.c
中的延时函数参数保证延时时间基本准确即可,主要程序代码与运行结果如图所示。
while(1)
{
gettemp();
if(flag) // 负温度
{
WriteChar(0,1,'-');
}
if(!flag) // 正温度
{
WriteChar(0,1,'+');
}
WriteChar(1,1,baiw); WriteChar(2,1,shiw);
WriteChar(3,1,gew);
WriteChar(4,1,'.'); WriteChar(5,1,point_1);
WriteChar(6,1,point_2); WriteChar(7,1,point_3);
WriteChar(8,1,point_4);
SetCur(NoCur); // 有显示无光标
}


3 多点测温
当一个系统只使用几只18B20进行温度检测时,可将它们的信号端分别接到单片机的几个IO 口上,然后使用前面介绍的单点温度检测程序即可分别读出传感器温度,当一个系统使用几 百只甚至更多的18B20进行温度检测时,需要将多只18B20信号端与电源端分别并接到一起, 多点测温首先必须取得各个传感器代码,类似每个人的身份证号码一样是没有重复的。
例19-4 读取18B20内部代码。程序说明:此程序读取P1口(P1.0、P1.1、P1.2、P1.3)4只

DS18B20代码并发送给计算机,计算机只接收显示数据,不向单片机发送任何信息,效果如图 所示,前面的数据01、02、03、04分别表示单片机P1.0、P1.1、P1.2、P1.3引脚,后面的8 字节才是18B20的内部代码,代码这里就不写出来了,需要的读者请查看配套资源。

下图是通过计算机操作,运用无线电波传送数据的完整结构图,整个系统使

用一台计算机作主机对数据进行显示与存储,使用多个单片机作分机对18B20 进行温度采集。

单片机系统电路图,只画了1组IO口,可同时使用多组IO口



多点测温程序(部分文件预览,如需下载全部源码请下载本帖附件):ds18b20.h文件:
  1. #include "DS18b20.h"
  2. #include "myfun.h"
  3. /****************《51单片机轻松入门-基于STC15W4K系列》配套例程 *************
  4. ★★★★★★★★★★★★★★★★★★★★★★★★
  5. 《51单片机轻松入门-基于STC15W4K系列》 一书已经由北航出版社正式出版发行。
  6.   作者亲手创作的与教材配套的51双核实验板(2个MCU)对程序下载、调试、仿真方便,不需要外部
  7.   仿真器与编程器,这种设计方式彻底解决了系统中多个最高优先级谁也不能让谁的中断竞争问题。
  8.   QQ群:STC51-STM32(3) :515624099 或 STC51-STM32(2):99794374。
  9.         验证信息:STC15单片机
  10.   邮箱:[email]xgliyouquan@126.com[/email]
  11.   ★★★★★★★★★★★★★★★★★★★★★★★★*/

  12. unsigned char  *p;
  13. extern unsigned char Port,Pin;        
  14. extern unsigned char ReceivdID_buff[8];
  15. extern unsigned char temp_buff[9];
  16. /****************************************************************/
  17. //P0的Pin脚置1 Pin为脚所在地址,如第3脚就是0x04。
  18. void Set1toP0()
  19. {
  20.         P0|=Pin;
  21. }
  22. /**************************************************************/
  23. //P0的Pin脚置0,Pin为脚所在地址,如第3脚就是0x04。
  24. void Set0toP0()
  25. {
  26.         P0&=~Pin;
  27. }
  28. /********************************************************/
  29. //检查P0的Pin脚电平,为0返回0,为1返回非0
  30. unsigned char CheckP0Level()
  31. {
  32.         return(P0&Pin);
  33. }
  34. /********************************************************/
  35. unsigned char DS18B20_Reset()
  36. {
  37.         unsigned char x=0;
  38.         DIR=1;                        // 单片机输出                                         
  39.         delay(3);            // 延时约2uS,等待硬件稳定         
  40.         Set1toP0();     //DQ=1;  DQ拉高                                         
  41.                         DQTest=1;   //时间调整观察参考引脚
  42.         delay(3);            //延时约2uS                                                
  43.         Set0toP0();     //DQ=0;  DQ拉低                                    
  44.                     DQTest=0;          //时间调整观察参考引脚
  45.         delay720us();   // 要求延时 480us~960us (这里取中心值720uS)         
  46.         Set1toP0();     //DQ=1;  DQ拉高释放总线                                                
  47.                             DQTest=1;          //时间调整观察参考引脚
  48.                         // 以下是由单片机产生"复位脉冲"
  49.         delay(3);            // 延时约2uS,等待硬件稳定                                    
  50.         DIR=0;                        // 单片机输入                                                            
  51.         delay(205);     // 要求延时大于60 us  (这里取75uS)                  
  52.         x=CheckP0Level();   //x=DQ;  DS18B20产生"存在脉冲"
  53.                         // 检测DQ 如果为低,说明复位成功,DS18B20存在
  54.                         // 如果为高,说明复位失败,DS18B20损坏或不存在
  55.         delay500us();   // 让18B20释放总线,避免影响到下一步操作。
  56.         DIR=1;          // 单片机输出
  57.         delay(3);            // 延时约2uS,等待硬件稳定
  58.         Set1toP0();                // 总线拉高
  59.                                         DQTest=1;          //时间调整观察参考引脚
  60.         return x;            // 返回复位结果
  61. }
  62. //单字节写入P0上18b20子程序(低位在前,高位在后)
  63. void WriteByteP0 (unsigned char dat)
  64. {
  65.         unsigned char i;
  66.     DIR=1;                        // 单片机输出
  67.         delay(3);            // 延时约2uS,等待硬件稳定        
  68.         for (i=0;i<8;i++)
  69.         {
  70.             Set1toP0();          //DQ=1;  将数据线置为高电平
  71.                                           DQTest=1;        //时间调整观察参考引脚
  72.                 delay(3);          //两次写过程间隔大于1us,这里延时约2uS(没考虑外部调用时间)
  73.                 Set0toP0();          //DQ=0; 开始一个写过程
  74.                                           DQTest=0;        //时间调整观察参考引脚
  75.                 delay(9);     // 低电平保持1us以上,这里延时约4uS,
  76.             if(dat&0x01)  // dat & 0x01;  最低位移出需要写入的数据
  77.                 {
  78.                         Set1toP0();
  79.                 }
  80.                 else
  81.                 {
  82.                         Set0toP0();
  83.                 }
  84.             delay(178);     // 延时65uS,写过程开始15us后DS18B20对数据线进行采样
  85.             Set1toP0();                // DQ=1; 释放总线
  86.                                                 DQTest=1;        //时间调整观察参考引脚
  87.             dat >>= 1;
  88.         }
  89. }

  90. //从P0上18b20读取单字节子程序(低位在前,高位在后)
  91. unsigned char ReadByteP0()
  92. {
  93.         unsigned char i,dat=0;
  94.         for(i=0;i<8;i++)
  95.         {
  96.                 dat=dat>>1;
  97.                 DIR=1;                      // 输出
  98.                 delay(3);           // 延时约2uS,等待硬件稳定        
  99.                 Set1toP0();           //DQ=1;  将数据线置为高电平
  100.                                            DQTest=1;        //时间调整观察参考引脚        ////////
  101.                 delay(9);      // 两次读过程间隔大于1us  (实测约4uS) ////////
  102.                 Set0toP0();           // DQ=0;  开始一个读过程
  103.                                            DQTest=0;        //时间调整观察参考引脚 //////////
  104.                 delay(9);      // 低电平保持1us以上 (实测约4uS)         /////////
  105.                 Set1toP0();           // DQ=1;释放总线进入接收状态                         ////
  106.                                            DQTest=1;   //时间调整观察参考引脚      //
  107.                 delay(3);           // 延时约2uS,读时间片开始后15us内主机对数据线进行采样
  108.                 DIR=0;                   // 输入
  109.                 delay(3);           // 延时约2uS,等待硬件稳定
  110.                 if(CheckP0Level())
  111.                 {
  112.                         dat |= 0x80;
  113.                 }
  114.                 delay(165);   // 读周期60us<t<120us (60="" us)
  115.         }
  116.         return(dat);
  117. }
  118. //从P0上18b20连续读取数个字节子程序
  119. void read_bytesP0 (unsigned char j)
  120. {
  121.         unsigned char i;
  122.         for(i=0;i<j;i++)
  123.         {
  124.                 *p = ReadByteP0();
  125.                 p++;
  126.         }
  127. }

  128. //匹配ROM命令,只有P0上8位ID相同的18b20才能响应以后的命令
  129. void MatchRomP0()
  130. {
  131.         unsigned char i;
  132.         DS18B20_Reset();
  133.         WriteByteP0(Match_ROM);  //发出匹配ROM命令0x55,后带8字节ROM ID
  134.         for(i=0;i<8;i++)
  135.         {
  136.                 WriteByteP0(ReceivdID_buff[i]);
  137.         }
  138. }
  139. //读取P0上温度子程序
  140. void GetTempP0 ()
  141. {
  142.         DS18B20_Reset ();
  143.         MatchRomP0();                            // 匹配ROM
  144.         WriteByteP0(Read_Scratchpad);   // 读暂存器命令0xbe(RAM)
  145.         p = temp_buff;
  146.         read_bytesP0(9);
  147. }
  148. //P0-P2上所有温度传感器开始采集温度存放在传感器上内存中
  149. void TempConvertAll()
  150. {
  151.         unsigned char i;
  152.         unsigned char a;        
  153.         a=Pin;                       // 保存Pin不被此程序修改,Pin只能由主程序提供
  154.         Pin=0x01;                   // 1——8 脚分别进行转换
  155.         DIR=1;                       // 输出
  156.         delay(3);               // 延时约2uS,等待硬件稳定        
  157.         for(i=0;i<8;i++)   // P0上的18b20开始采集温度
  158.         {
  159.                 DS18B20_Reset ();
  160.                 WriteByteP0(Skip_ROM);   // 跳过ROM操作(0xCC)
  161.                 WriteByteP0(Convert_T);  // 启动温度转换(0x44)
  162.                 Set1toP0();                                 // 释放总线
  163.                 Pin<<=1;
  164.         }
  165.         delay800ms();   // 发出温度转换命令后800ms必定已转换完成。     
  166.         Pin=a;         
  167. }
  168. /******************************************************/  
  169. //得到P0-P2口上Pin脚的温度,存放在temp_buff.
  170. void GetTemp()
  171. {
  172.         switch(Port)
  173.         {
  174.                 case 0x00:GetTempP0();break;
  175.                 // case 0x01:GetTempP1();break;   
  176.                 default:break;
  177.         }
  178. }
复制代码

主程序:


  1. /****************《51单片机轻松入门-基于STC15W4K系列》配套例程 *************
  2. ★★★★★★★★★★★★★★★★★★★★★★★★
  3. 《51单片机轻松入门-基于STC15W4K系列》 一书已经由北航出版社正式出版发行。
  4.   作者亲手创作的与教材配套的51双核实验板(2个MCU)对程序下载、调试、仿真方便,不需要外部
  5.   仿真器与编程器,这种设计方式彻底解决了系统中多个最高优先级谁也不能让谁的中断竞争问题。
  6.   QQ群:STC51-STM32(3) :515624099 或 STC51-STM32(2):99794374。
  7.         验证信息:STC15单片机
  8.   邮箱:[email]xgliyouquan@126.com[/email]
  9.   ★★★★★★★★★★★★★★★★★★★★★★★★*/

  10. //18B20多点测温程序,11.0592M晶振
  11. #include "STC15W4K.H"
  12. #include "usart.h"
  13. #include "ds18b20.h"
  14. #define CONVERT 0x44        // 收主机转换温度命令
  15. #define GETTEMP 0xaa        // 收主机读温度命令
  16. #define GETHOUSE 0xcc       // 收主机读仓库湿度命令
  17. #define GETAREA 0xd6        // 收主机读库区湿度命令
  18. #define GETSTATE 0x11       // 收主机通信检测命令
  19. #define SENDAREA 0xdd       // 向主机发库区湿度
  20. #define SENDHOUSE 0xce      // 向主机发仓库湿度
  21. #define CVTOK 0x88          // 向主机发转换温度完毕命令
  22. #define CPUOK 0x22                        // 向主机发通信正常命令
  23. #define TEMPDATA 0xbb       // 向主机发温度命令         
  24. unsigned char Port,Pin,count=0;         //单片机端口P0、P1、P2、P3,端口具体引脚(1-8),接收计数器

  25. unsigned char send_buff[14];          // 发送缓冲区14字节,加帧头帧尾共16字节每帧
  26. unsigned char ReceivdID_buff[8];  // 存储主机发来的rom ID为8字节
  27. unsigned char receivedcmd[16];    // 存放接收到的命令 1:帧头,2发送机号,3本机ID,4命令,5port,6pin,7-14ID,15CRC,16帧尾
  28. unsigned char temp_buff[9];       // 存储读取的温度字节,读温度为9字节,读rom ID为8字节

  29. unsigned char code CrcTable [256]={
  30. 0, 94, 188, 226, 97, 63, 221, 131, 194, 156, 126, 32, 163, 253, 31, 65,
  31. 157, 195, 33, 127, 252, 162, 64, 30, 95, 1, 227, 189, 62, 96, 130, 220,
  32. 35, 125, 159, 193, 66, 28, 254, 160, 225, 191, 93, 3, 128, 222, 60, 98,
  33. 190, 224, 2, 92, 223, 129, 99, 61, 124, 34, 192, 158, 29, 67, 161, 255,
  34. 70, 24, 250, 164, 39, 121, 155, 197, 132, 218, 56, 102, 229, 187, 89, 7,
  35. 219, 133, 103, 57, 186, 228, 6, 88, 25, 71, 165, 251, 120, 38, 196, 154,
  36. 101, 59, 217, 135, 4, 90, 184, 230, 167, 249, 27, 69, 198, 152, 122, 36,
  37. 248, 166, 68, 26, 153, 199, 37, 123, 58, 100, 134, 216, 91, 5, 231, 185,
  38. 140, 210, 48, 110, 237, 179, 81, 15, 78, 16, 242, 172, 47, 113, 147, 205,
  39. 17, 79, 173, 243, 112, 46, 204, 146, 211, 141, 111, 49, 178, 236, 14, 80,
  40. 175, 241, 19, 77, 206, 144, 114, 44, 109, 51, 209, 143, 12, 82, 176, 238,
  41. 50, 108, 142, 208, 83, 13, 239, 177, 240, 174, 76, 18, 145, 207, 45, 115,
  42. 202, 148, 118, 40, 171, 245, 23, 73, 8, 86, 180, 234, 105, 55, 213, 139,
  43. 87, 9, 235, 181, 54, 104, 138, 212, 149, 203, 41, 119, 244, 170, 72, 22,
  44. 233, 183, 85, 11, 136, 214, 52, 106, 43, 117, 151, 201, 74, 20, 246, 168,
  45. 116, 42, 200, 150, 21, 75, 169, 247, 182, 232, 10, 84, 215, 137, 107, 53};        

  46. //反序CRC查表校验
  47. unsigned char crc8_f_table (unsigned char *ptr, unsigned char len)
  48. {
  49.         unsigned char i;
  50.         unsigned char crc =0;
  51.         for(i=0;i<len;i++) 查表校验
  52.         {
  53.                 crc= CrcTable[crc^ptr[i]];   // ^是按位异或运算符
  54.         }
  55.         return(crc);
  56. }
  57. void port_mode()            // 端口模式
  58. {
  59.         P0M1=0x00; P0M0=0x00;P1M1=0x00; P1M0=0x00;P2M1=0x00; P2M0=0x00;P3M1=0x00; P3M0=0x00;
  60.         P4M1=0x00; P4M0=0x00;P5M1=0x00; P5M0=0x00;P6M1=0x00; P6M0=0x00;P7M1=0x00; P7M0=0x00;
  61. }
  62. void main()         
  63. {
  64.         unsigned char i;
  65.         unsigned char crccount;          // crc校验次数        
  66.         unsigned char crc_data;          // crc校验结果
  67.         port_mode();                  // 所有IO口设为准双向弱上拉方式。
  68.         com_init();                              // 串口初始化         
  69.         while(1)
  70.         {                        
  71.                 if(count==16)    //count是全局变量,表示串口已收到的字节数
  72.                 {         
  73.                         count=0;
  74.                                          
  75.                         for(i=0;i<14;i++)
  76.                         {
  77.                                 send_buff[i]=receivedcmd[i+1];          //取出接收帧2——15字节(舍弃帧头帧尾),准备CRC校验
  78.                         }               
  79.                         crc_data=crc8_f_table(send_buff,14);  //发送缓冲区14字节全部参与CRC校验               
  80.                         if(crc_data==0&&receivedcmd[15]==FMEND)//如果CRC正确且帧尾有效
  81.                         {         
  82.                                 switch(send_buff[2])
  83.                                 {
  84.                                         case CONVERT:                           // 温度转换命令 0x44
  85.                                         {
  86.                                                 REN=0;                 // 禁止串口接收
  87.                                                 ES=0;                  // 关串口中断
  88.                                                 TempConvertAll();
  89.                                                 ES=1;                  //开串口中断
  90.                                                 REN=1;
  91.                                                 send_buff[0]=MYID;           // 本分机ID
  92.                                                 send_buff[1]=MAINID;   // 主机ID=0x00
  93.                                                 send_buff[2]=CVTOK;           // 温度转换完毕命令0x88
  94.                                                 crc_data=crc8_f_table(send_buff,13);
  95.                                                 send_buff[13]=crc_data;
  96.                                                 sendcombytes();                   // 发送一帧完整数据
  97.                                                 break;
  98.                             }
  99.                                         case GETTEMP:                           // 读取温度命令 0xaa
  100.                                         {                                                
  101.                                                 Port=send_buff[3];          // 确定端口(P0、P1、P2、P3)
  102.                                                 Pin=send_buff[4];          // 确定端口具体引脚(数据0x80、0x40、0x20、0x010、0x08、0x04、0x02、0x01)
  103.                                                 for(i=0;i<8;i++)
  104.                                                 {
  105.                                                         ReceivdID_buff[i]=send_buff[i+5];        // 匹配ROM命令必须用ReceivdID_buff[i]
  106.                                                 }
  107.                                                 REN=0;                // 禁止串口接收
  108.                                                 ES=0;                 // 关串口中断
  109.                                                 crccount=0;
  110.                                                 do                                          //同一ID传感器允许读4次温度,4次失败则退出。
  111.                                                 {
  112.                                                         GetTemp();
  113.                                                         crc_data=crc8_f_table(temp_buff,9);         //要使用校验码,读温度必然是连续9字节
  114.                                                         crccount++;
  115.                                                 }while(!(crccount>4||crc_data==0));             //校验次数>4或校验正确立即退出循环
  116.                                                 ES=1;                 // 开串口中断
  117.                                                 REN=1;                // 允许串口接收                                                                                                
  118.                                                 send_buff[0]=MYID;
  119.                                                 send_buff[1]=MAINID;
  120.                                                 send_buff[2]=TEMPDATA;        // 向主机发温度命令        0xbb
  121.                                                 if(crc_data==0)
  122.                                                 {
  123.                                                         send_buff[3]=temp_buff[0];        // 原始温度低字节
  124.                                                         send_buff[4]=temp_buff[1];        // 原始温度高字节
  125.                                                 }
  126.                                                 else
  127.                                                 {
  128.                                                         send_buff[3]=0xff;
  129.                                                         send_buff[4]=0xff;
  130.                                                 }
  131.                                                 for(i=0;i<8;i++)
  132.                                                 {
  133.                                                         send_buff[i+5]=ReceivdID_buff[i];        
  134.                                                 }                                                        
  135.                                                 crc_data=crc8_f_table(send_buff,13);
  136.                                                 send_buff[13]=crc_data;
  137.                                                 sendcombytes();
  138.                                                 break;
  139.                                         }
  140.                                         case GETSTATE:                           // 主机通信检测命令0x11,确认主机与分机通信是否正常  
  141.                                         {
  142.                                                 send_buff[0]=MYID;
  143.                                                 send_buff[1]=MAINID;
  144.                                                 send_buff[2]=CPUOK;           // CPUOK 0x22
  145.                                                 for(i=0;i<10;i++)
  146.                                                 {
  147.                                                         send_buff[i+3]=0x55;
  148.                                                 }
  149.                                                 crc_data=crc8_f_table(send_buff,13);
  150.                                                 send_buff[13]=crc_data;
  151.                                                 sendcombytes();
  152.                                                 break;
  153.                                         }
  154.                                         case GETHOUSE:                                  //仓库湿度命令 0xce
  155.                                         {
  156.                                                 ;        
  157.                                         }
  158.                                         case GETAREA:                              // 库区湿度命令 0xd6
  159.                                         {
  160.                                                 ;
  161.                                         }
  162.                                         default:break;
  163.                                 }                                 
  164.                         }                        
  165.                 }
  166.         }
  167. }
复制代码


单片机单只18B20测温程序(使用Float处理数据):http://www.51hei.com/bbs/dpj-47289-1.html
单只18B20测温程序(1602写字符串方式) :http://www.51hei.com/bbs/dpj-47288-1.html
单只DS18B20测温程序(1602写单字符方式):http://www.51hei.com/bbs/dpj-47287-1.html
IR中断方式的单片机红外解码程序http://www.51hei.com/bbs/dpj-47283-1.html
DS18B20无线多点测温单片机程序:http://www.51hei.com/bbs/dpj-47291-1.html
单片机读取DS18B20内部温度上传到上位机(电脑) :http://www.51hei.com/bbs/dpj-47290-1.html

5个完整源码下载: 第19章 单总线18B20.rar (6.95 MB, 下载次数: 166)
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏9 分享淘帖 顶2 踩
回复

使用道具 举报

沙发
ID:188698 发表于 2017-4-12 22:18 | 只看该作者
您好为啥我打不开呢
回复

使用道具 举报

板凳
ID:190731 发表于 2017-4-29 17:37 | 只看该作者
支持支持支持
回复

使用道具 举报

地板
ID:75062 发表于 2017-10-23 17:20 | 只看该作者
谢谢分享!!
回复

使用道具 举报

5#
ID:393796 发表于 2018-10-23 23:52 | 只看该作者
好东西!感谢楼主
回复

使用道具 举报

6#
ID:510842 发表于 2019-10-30 21:01 | 只看该作者
感谢楼主,太有用了
回复

使用道具 举报

7#
ID:462361 发表于 2019-12-24 13:09 | 只看该作者
太好用了,感谢分享!!!
回复

使用道具 举报

8#
ID:584195 发表于 2021-8-6 21:15 | 只看该作者
无私的楼主!
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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