[牛人杂谈] 单总线挂多个DS18B20

[复制链接]
 楼主| zhuotuzi 发表于 2023-2-25 19:55 | 显示全部楼层 |阅读模式
  1. #include "DS18B20.h"
  2. #include "Delay.h"
  3. #include "stdio.h" // printf用

  4. #define DS18B20_GPIO_NUM                                 GPIO_Pin_5
  5. #define DS18B20_GPIO_X                                        GPIOC
  6. #define RCC_APB2Periph_DS18B20_GPIO_X        RCC_APB2Periph_GPIOC

  7. #define DS18B20_DQ_OUT_Low                        GPIO_ResetBits(DS18B20_GPIO_X,DS18B20_GPIO_NUM)
  8. #define DS18B20_DQ_OUT_High                        GPIO_SetBits(DS18B20_GPIO_X,DS18B20_GPIO_NUM)
  9. #define DS18B20_DQ_IN                                GPIO_ReadInputDataBit(DS18B20_GPIO_X,DS18B20_GPIO_NUM)

  10. #define MaxSensorNum 8
  11. unsigned char DS18B20_ID[MaxSensorNum][8];        // 存检测到的传感器DS18B20_ID的数组,前面的维数代表单根线传感器数量上限
  12. unsigned char DS18B20_SensorNum;                        // 检测到的传感器数量(从1开始,例如显示1代表1个,8代表8个)

  13. // 配置DS18B20用到的I/O口
  14. void DS18B20_GPIO_Config(void)
  15. {
  16.         GPIO_InitTypeDef GPIO_InitStructure;
  17.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_DS18B20_GPIO_X, ENABLE);
  18.         GPIO_InitStructure.GPIO_Pin = DS18B20_GPIO_NUM;
  19.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  20.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  21.         GPIO_Init(DS18B20_GPIO_X, &GPIO_InitStructure);
  22.         GPIO_SetBits(DS18B20_GPIO_X, DS18B20_GPIO_NUM);
  23. }

  24. // 引脚输入
  25. void DS18B20_Mode_IPU(void)
  26. {
  27.         GPIO_InitTypeDef GPIO_InitStructure;
  28.         GPIO_InitStructure.GPIO_Pin = DS18B20_GPIO_NUM;
  29.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
  30.         GPIO_Init(DS18B20_GPIO_X, &GPIO_InitStructure);
  31. }

  32. // 引脚输出
  33. void DS18B20_Mode_Out(void)
  34. {
  35.         GPIO_InitTypeDef GPIO_InitStructure;
  36.         GPIO_InitStructure.GPIO_Pin = DS18B20_GPIO_NUM;
  37.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  38.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  39.         GPIO_Init(DS18B20_GPIO_X, &GPIO_InitStructure);

  40. }

  41. // 复位,主机给从机发送复位脉冲
  42. void DS18B20_Rst(void)
  43. {
  44.         DS18B20_Mode_Out();
  45.         DS18B20_DQ_OUT_Low;                // 产生至少480us的低电平复位信号
  46.         Delay_us(480);
  47.         DS18B20_DQ_OUT_High;        // 在产生复位信号后,需将总线拉高
  48.         Delay_us(15);
  49. }

  50. // 检测从机给主机返回的应答脉冲。从机接收到主机的复位信号后,会在15~60us后给主机发一个应答脉冲
  51. u8 DS18B20_Answer_Check(void)
  52. {
  53.         u8 delay = 0;
  54.         DS18B20_Mode_IPU(); // 主机设置为上拉输入
  55.         // 等待应答脉冲(一个60~240us的低电平信号 )的到来
  56.         // 如果100us内,没有应答脉冲,退出函数,注意:从机接收到主机的复位信号后,会在15~60us后给主机发一个存在脉冲
  57.         while (DS18B20_DQ_IN&&delay < 100)
  58.         {
  59.                 delay++;
  60.                 Delay_us(1);
  61.         }
  62.         // 经过100us后,如果没有应答脉冲,退出函数
  63.         if (delay >= 100)//Hu200
  64.                 return 1;
  65.         else
  66.                 delay = 0;
  67.         // 有应答脉冲,且存在时间不超过240us
  68.         while (!DS18B20_DQ_IN&&delay < 240)
  69.         {
  70.                 delay++;
  71.                 Delay_us(1);
  72.         }
  73.         if (delay >= 240)
  74.                 return 1;
  75.         return 0;
  76. }

  77. // 从DS18B20读取1个位
  78. u8 DS18B20_Read_Bit(void)
  79. {
  80.         u8 data;
  81.         DS18B20_Mode_Out();
  82.         DS18B20_DQ_OUT_Low; // 读时间的起始:必须由主机产生 >1us <15us 的低电平信号
  83.         Delay_us(2);
  84.         DS18B20_DQ_OUT_High;
  85.         Delay_us(12);
  86.         DS18B20_Mode_IPU();// 设置成输入,释放总线,由外部上拉电阻将总线拉高
  87.         if (DS18B20_DQ_IN)
  88.                 data = 1;
  89.         else
  90.                 data = 0;
  91.         Delay_us(50);
  92.         return data;
  93. }

  94. // 从DS18B20读取2个位
  95. u8 DS18B20_Read_2Bit(void)//读二位 子程序
  96. {
  97.         u8 i;
  98.         u8 dat = 0;
  99.         for (i = 2; i > 0; i--)
  100.         {
  101.                 dat = dat << 1;
  102.                 DS18B20_Mode_Out();
  103.                 DS18B20_DQ_OUT_Low;
  104.                 Delay_us(2);
  105.                 DS18B20_DQ_OUT_High;
  106.                 DS18B20_Mode_IPU();
  107.                 Delay_us(12);
  108.                 if (DS18B20_DQ_IN)        dat |= 0x01;
  109.                 Delay_us(50);
  110.         }
  111.         return dat;
  112. }

  113. // 从DS18B20读取1个字节
  114. u8 DS18B20_Read_Byte(void)        // read one byte
  115. {
  116.         u8 i, j, dat;
  117.         dat = 0;
  118.         for (i = 0; i < 8; i++)
  119.         {
  120.                 j = DS18B20_Read_Bit();
  121.                 dat = (dat) | (j << i);
  122.         }
  123.         return dat;
  124. }

  125. // 写1位到DS18B20
  126. void DS18B20_Write_Bit(u8 dat)
  127. {
  128.         DS18B20_Mode_Out();
  129.         if (dat)
  130.         {
  131.                 DS18B20_DQ_OUT_Low;// Write 1
  132.                 Delay_us(2);
  133.                 DS18B20_DQ_OUT_High;
  134.                 Delay_us(60);
  135.         }
  136.         else
  137.         {
  138.                 DS18B20_DQ_OUT_Low;// Write 0
  139.                 Delay_us(60);
  140.                 DS18B20_DQ_OUT_High;
  141.                 Delay_us(2);
  142.         }
  143. }

  144. // 写1字节到DS18B20
  145. void DS18B20_Write_Byte(u8 dat)
  146. {
  147.         u8 j;
  148.         u8 testb;
  149.         DS18B20_Mode_Out();
  150.         for (j = 1; j <= 8; j++)
  151.         {
  152.                 testb = dat & 0x01;
  153.                 dat = dat >> 1;
  154.                 if (testb)
  155.                 {
  156.                         DS18B20_DQ_OUT_Low;// 写1
  157.                         Delay_us(10);
  158.                         DS18B20_DQ_OUT_High;
  159.                         Delay_us(50);
  160.                 }
  161.                 else
  162.                 {
  163.                         DS18B20_DQ_OUT_Low;// 写0
  164.                         Delay_us(60);
  165.                         DS18B20_DQ_OUT_High;// 释放总线
  166.                         Delay_us(2);
  167.                 }
  168.         }
  169. }

  170. //初始化DS18B20的IO口,同时检测DS的存在
  171. u8 DS18B20_Init(void)
  172. {
  173.         DS18B20_GPIO_Config();
  174.         DS18B20_Rst();
  175.         return DS18B20_Answer_Check();
  176. }

  177. // 从ds18b20得到温度值,精度:0.1C,返回温度值(-550~1250),Temperature1返回浮点实际温度
  178. float DS18B20_Get_Temp(u8 i)
  179. {
  180.         //u8 flag;
  181.         u8 j;//匹配的字节
  182.         u8 TL, TH;
  183.         short Temperature;
  184.         float Temperature1;
  185.         DS18B20_Rst();
  186.         DS18B20_Answer_Check();
  187.         DS18B20_Write_Byte(0xcc);// skip rom
  188.         DS18B20_Write_Byte(0x44);// convert
  189.         DS18B20_Rst();
  190.         DS18B20_Answer_Check();

  191.         // DS18B20_Write_Byte(0xcc);// skip rom
  192.         //匹配ID,i为形参
  193.         DS18B20_Write_Byte(0x55);
  194.         for (j = 0; j < 8; j++)
  195.         {
  196.                 DS18B20_Write_Byte(DS18B20_ID[i][j]);
  197.         }

  198.         DS18B20_Write_Byte(0xbe);// convert
  199.         TL = DS18B20_Read_Byte(); // LSB   
  200.         TH = DS18B20_Read_Byte(); // MSB  
  201.         if (TH & 0xfc)
  202.         {
  203.                 //flag=1;
  204.                 Temperature = (TH << 8) | TL;
  205.                 Temperature1 = (~Temperature) + 1;
  206.                 Temperature1 *= 0.0625;
  207.         }
  208.         else
  209.         {
  210.                 //flag=0;
  211.                 Temperature1 = ((TH << 8) | TL)*0.0625;
  212.         }
  213.         return Temperature1;
  214. }

  215. // 自动搜索ROM
  216. void DS18B20_Search_Rom(void)
  217. {
  218.         u8 k, l, chongtuwei, m, n, num;
  219.         u8 zhan[5];
  220.         u8 ss[64];
  221.         u8 tempp;
  222.         l = 0;
  223.         num = 0;
  224.         do
  225.         {
  226.                 DS18B20_Rst(); //注意:复位的延时不够
  227.                 Delay_us(480); //480、720
  228.                 DS18B20_Write_Byte(0xf0);
  229.                 for (m = 0; m < 8; m++)
  230.                 {
  231.                         u8 s = 0;
  232.                         for (n = 0; n < 8; n++)
  233.                         {
  234.                                 k = DS18B20_Read_2Bit();//读两位数据

  235.                                 k = k & 0x03;
  236.                                 s >>= 1;
  237.                                 if (k == 0x01)//01读到的数据为0 写0 此位为0的器件响应
  238.                                 {
  239.                                         DS18B20_Write_Bit(0);
  240.                                         ss[(m * 8 + n)] = 0;
  241.                                 }
  242.                                 else if (k == 0x02)//读到的数据为1 写1 此位为1的器件响应
  243.                                 {
  244.                                         s = s | 0x80;
  245.                                         DS18B20_Write_Bit(1);
  246.                                         ss[(m * 8 + n)] = 1;
  247.                                 }
  248.                                 else if (k == 0x00)//读到的数据为00 有冲突位 判断冲突位
  249.                                 {
  250.                                         //如果冲突位大于栈顶写0 小于栈顶写以前数据 等于栈顶写1
  251.                                         chongtuwei = m * 8 + n + 1;
  252.                                         if (chongtuwei > zhan[l])
  253.                                         {
  254.                                                 DS18B20_Write_Bit(0);
  255.                                                 ss[(m * 8 + n)] = 0;
  256.                                                 zhan[++l] = chongtuwei;
  257.                                         }
  258.                                         else if (chongtuwei < zhan[l])
  259.                                         {
  260.                                                 s = s | ((ss[(m * 8 + n)] & 0x01) << 7);
  261.                                                 DS18B20_Write_Bit(ss[(m * 8 + n)]);
  262.                                         }
  263.                                         else if (chongtuwei == zhan[l])
  264.                                         {
  265.                                                 s = s | 0x80;
  266.                                                 DS18B20_Write_Bit(1);
  267.                                                 ss[(m * 8 + n)] = 1;
  268.                                                 l = l - 1;
  269.                                         }
  270.                                 }
  271.                                 else
  272.                                 {
  273.                                         //没有搜索到
  274.                                 }
  275.                         }
  276.                         tempp = s;
  277.                         DS18B20_ID[num][m] = tempp; // 保存搜索到的ID
  278.                 }
  279.                 num = num + 1;// 保存搜索到的个数
  280.         } while (zhan[l] != 0 && (num < MaxSensorNum));
  281.         DS18B20_SensorNum = num;
  282.         //printf("DS18B20_SensorNum=%d\r\n",DS18B20_SensorNum);
  283. }
DS18B20.h文件代码:
  1. #ifndef __DS18B20_H
  2. #define __DS18B20_H
  3.   
  4. #include "stm32f10x.h"

  5. u8 DS18B20_Init(void);
  6. u8 DS18B20_Read_Byte(void);
  7. u8 DS18B20_Read_Bit(void);
  8. u8 DS18B20_Answer_Check(void);
  9. void  DS18B20_GPIO_Config(void);
  10. void  DS18B20_Mode_IPU(void);
  11. void  DS18B20_Mode_Out(void);
  12. void  DS18B20_Rst(void);
  13. void  DS18B20_Search_Rom(void);
  14. void  DS18B20_Write_Byte(u8 dat);
  15. float DS18B20_Get_Temp(u8 i);

  16. #endif


dongnanxibei 发表于 2023-2-26 20:06 | 显示全部楼层
是不是理论上可以挂无数个,只要ROM地址不同。
jiekou001 发表于 2023-2-26 20:21 | 显示全部楼层
自动搜索ROM的原理是什么
jiekou001 发表于 2023-2-26 20:22 | 显示全部楼层
Arduino的库很不错,可以参考参考。
643757107 发表于 2023-2-26 20:54 | 显示全部楼层
一直没学会搜索那个ROM的方法,看不懂。
小夏天的大西瓜 发表于 2023-2-27 14:26 | 显示全部楼层
DS18B20是常用的数字温度传感器,其输出的是数字信号,具有体积小,硬件开销低,抗干扰能力强,精度高的特点
星辰大海不退缩 发表于 2023-2-27 15:02 | 显示全部楼层
自动搜索没搞明白
AloneKaven 发表于 2023-3-1 20:08 | 显示全部楼层
搜索rom是怎么实现的啊?
bartonalfred 发表于 2023-4-16 22:21 | 显示全部楼层
在连接多个 DS18B20 温度传感器时,需要考虑总线的电气特性、传输速率等因素对通信稳定性和精度的影响。
豌豆爹 发表于 2023-4-17 15:13 来自手机 | 显示全部楼层
自动搜索ROM是什么原理
youtome 发表于 2023-4-17 18:01 | 显示全部楼层
使用单总线通信协议读取和写入 DS18B20 温度传感器的数据。在通信过程中,需要使用每个传感器的唯一 ROM 码进行地址匹配,以区分不同的传感器。
jkl21 发表于 2023-4-18 16:20 | 显示全部楼层
将多个 DS18B20 温度传感器的数据线(DQ)和上拉电阻连接在一起,形成一个物理上共享的单总线。
wwppd 发表于 2023-4-18 17:57 | 显示全部楼层
需要注意防止总线上存在干扰信号和冲突情况。
gygp 发表于 2023-4-18 19:58 | 显示全部楼层
可以使用单总线协议同时连接多个 DS18B20 温度传感器。
Jacquetry 发表于 2023-4-18 23:05 | 显示全部楼层
自动搜寻ROM怎么实现啊?
huangcunxiake 发表于 2023-4-19 19:09 | 显示全部楼层
很少这么用, 但是很重要的场合都这么用。
chenqianqian 发表于 2023-4-19 21:21 来自手机 | 显示全部楼层
现在还在用DS18B20来测温嘛?
Stahan 发表于 2023-4-19 23:05 | 显示全部楼层
如何自动匹配ROM码啊?
OKAKAKO 发表于 2023-4-20 13:24 | 显示全部楼层
一般情况下轮询读取应该就没问题,楼主这个程序比较经典
小小蚂蚁举千斤 发表于 2023-4-22 17:02 | 显示全部楼层
确实对自动获取ROM这部分不太清楚
您需要登录后才可以回帖 登录 | 注册

本版积分规则

214

主题

3368

帖子

7

粉丝
快速回复 在线客服 返回列表 返回顶部