当前位置:   article > 正文

完美实现STM32单总线挂多个DS18B20_stm32多路18b20

stm32多路18b20

  一般常见的STM32的关于DS18B20的例程都是检测一个传感器,代码一般都是跳过ROM检测,直接获取温度值。这种写法并不适用于单总线上挂载多个DS18B20的情况,Sandeepin的这个代码就是针对这种情况完善的单总线挂多个DS18B20检测,实现获取每个DS18B20的ID和温度。

  主要的DS18B20时序代码没变,增加了搜索ROM函数,获取温度时先匹配ID。

  核心代码如下:

  DS18B20.c文件代码:

  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. #include "stm32f10x.h"
  4. u8 DS18B20_Init(void);
  5. u8 DS18B20_Read_Byte(void);
  6. u8 DS18B20_Read_Bit(void);
  7. u8 DS18B20_Answer_Check(void);
  8. void DS18B20_GPIO_Config(void);
  9. void DS18B20_Mode_IPU(void);
  10. void DS18B20_Mode_Out(void);
  11. void DS18B20_Rst(void);
  12. void DS18B20_Search_Rom(void);
  13. void DS18B20_Write_Byte(u8 dat);
  14. float DS18B20_Get_Temp(u8 i);
  15. #endif
  main.c文件代码:

  1. #include "stm32f10x.h"
  2. #include "stdio.h"
  3. #include "string.h"//strlen、memset用到
  4. #include "USART.h"
  5. #include "Delay.h"
  6. #include "DS18B20.h"
  7. extern unsigned char DS18B20_ID[8][8];//检测到的传感器ID存数组
  8. extern unsigned char DS18B20_SensorNum;
  9. int main(void)
  10. {
  11. u8 num=0;
  12. USART1_init(9600);
  13. while(DS18B20_Init())//初始化DS18B20,兼检测18B20
  14. {
  15. printf("DS18B20 Check Failed!\r\n");
  16. }
  17. printf("DS18B20 Ready!\r\n");
  18. while(1)
  19. {
  20. DS18B20_Search_Rom();
  21. printf("DS18B20_SensorNum:%d\r\n",DS18B20_SensorNum);
  22. for(num=0;num<DS18B20_SensorNum;num++)
  23. {
  24. printf("ID:%02x%02x%02x%02x%02x%02x%02x%02x TM:%.2f\r\n",DS18B20_ID[num][0],DS18B20_ID[num][1],DS18B20_ID[num][2],DS18B20_ID[num][3],DS18B20_ID[num][4],DS18B20_ID[num][5],DS18B20_ID[num][6],DS18B20_ID[num][7],DS18B20_Get_Temp(num));
  25. }
  26. printf("\r\n");
  27. Delay_s(2);
  28. }
  29. }

  运行结果如图:


  帮严博士出本科题的时候,出了一个DS18B20的分布式温度检测系统,要求肯定不仅仅是这篇文章的简略例子了。不仅单总线,一块单片机还要挂多总线,实现更多传感器数据采集,最好还配上上位机,反正把自己能想到的东西都加进来了,把一个简单的DS18B20包装得高大上。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/647923
推荐阅读
相关标签
  

闽ICP备14008679号