完美实现STM32单总线挂多个DS18B20

完美实现STM32单总线挂多个DS18B20

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

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

  核心代码如下:

  DS18B20.c文件代码:

[cpp]  view plain  copy
  1. #include "DS18B20.h"  
  2. #include "Delay.h"  
  3. #include "stdio.h" // printf用  
  4.   
  5. #define DS18B20_GPIO_NUM                 GPIO_Pin_5  
  6. #define DS18B20_GPIO_X                  GPIOC  
  7. #define RCC_APB2Periph_DS18B20_GPIO_X   RCC_APB2Periph_GPIOC  
  8.   
  9. #define DS18B20_DQ_OUT_Low          GPIO_ResetBits(DS18B20_GPIO_X,DS18B20_GPIO_NUM)   
  10. #define DS18B20_DQ_OUT_High         GPIO_SetBits(DS18B20_GPIO_X,DS18B20_GPIO_NUM)   
  11. #define DS18B20_DQ_IN               GPIO_ReadInputDataBit(DS18B20_GPIO_X,DS18B20_GPIO_NUM)   
  12.   
  13. #define MaxSensorNum 8  
  14. unsigned char DS18B20_ID[MaxSensorNum][8];  // 存检测到的传感器DS18B20_ID的数组,前面的维数代表单根线传感器数量上限  
  15. unsigned char DS18B20_SensorNum;            // 检测到的传感器数量(从1开始,例如显示1代表1个,8代表8个)  
  16.   
  17. // 配置DS18B20用到的I/O口  
  18. void DS18B20_GPIO_Config(void)  
  19. {  
  20.     GPIO_InitTypeDef GPIO_InitStructure;  
  21.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_DS18B20_GPIO_X, ENABLE);  
  22.     GPIO_InitStructure.GPIO_Pin = DS18B20_GPIO_NUM;  
  23.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  
  24.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  
  25.     GPIO_Init(DS18B20_GPIO_X, &GPIO_InitStructure);  
  26.     GPIO_SetBits(DS18B20_GPIO_X, DS18B20_GPIO_NUM);  
  27. }  
  28.   
  29. // 引脚输入  
  30. void DS18B20_Mode_IPU(void)  
  31. {  
  32.     GPIO_InitTypeDef GPIO_InitStructure;  
  33.     GPIO_InitStructure.GPIO_Pin = DS18B20_GPIO_NUM;  
  34.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;  
  35.     GPIO_Init(DS18B20_GPIO_X, &GPIO_InitStructure);  
  36. }  
  37.   
  38. // 引脚输出  
  39. void DS18B20_Mode_Out(void)  
  40. {  
  41.     GPIO_InitTypeDef GPIO_InitStructure;  
  42.     GPIO_InitStructure.GPIO_Pin = DS18B20_GPIO_NUM;  
  43.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  
  44.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  
  45.     GPIO_Init(DS18B20_GPIO_X, &GPIO_InitStructure);  
  46.   
  47. }  
  48.   
  49. // 复位,主机给从机发送复位脉冲  
  50. void DS18B20_Rst(void)  
  51. {  
  52.     DS18B20_Mode_Out();  
  53.     DS18B20_DQ_OUT_Low;     // 产生至少480us的低电平复位信号  
  54.     Delay_us(480);  
  55.     DS18B20_DQ_OUT_High;    // 在产生复位信号后,需将总线拉高  
  56.     Delay_us(15);  
  57. }  
  58.   
  59. // 检测从机给主机返回的应答脉冲。从机接收到主机的复位信号后,会在15~60us后给主机发一个应答脉冲  
  60. u8 DS18B20_Answer_Check(void)  
  61. {  
  62.     u8 delay = 0;  
  63.     DS18B20_Mode_IPU(); // 主机设置为上拉输入  
  64.     // 等待应答脉冲(一个60~240us的低电平信号 )的到来  
  65.     // 如果100us内,没有应答脉冲,退出函数,注意:从机接收到主机的复位信号后,会在15~60us后给主机发一个存在脉冲  
  66.     while (DS18B20_DQ_IN&&delay < 100)  
  67.     {  
  68.         delay++;  
  69.         Delay_us(1);  
  70.     }  
  71.     // 经过100us后,如果没有应答脉冲,退出函数  
  72.     if (delay >= 100)//Hu200  
  73.         return 1;  
  74.     else  
  75.         delay = 0;  
  76.     // 有应答脉冲,且存在时间不超过240us  
  77.     while (!DS18B20_DQ_IN&&delay < 240)  
  78.     {  
  79.         delay++;  
  80.         Delay_us(1);  
  81.     }  
  82.     if (delay >= 240)  
  83.         return 1;  
  84.     return 0;  
  85. }  
  86.   
  87. // 从DS18B20读取1个位  
  88. u8 DS18B20_Read_Bit(void)  
  89. {  
  90.     u8 data;  
  91.     DS18B20_Mode_Out();  
  92.     DS18B20_DQ_OUT_Low; // 读时间的起始:必须由主机产生 >1us <15us 的低电平信号  
  93.     Delay_us(2);  
  94.     DS18B20_DQ_OUT_High;  
  95.     Delay_us(12);  
  96.     DS18B20_Mode_IPU();// 设置成输入,释放总线,由外部上拉电阻将总线拉高  
  97.     if (DS18B20_DQ_IN)  
  98.         data = 1;  
  99.     else  
  100.         data = 0;  
  101.     Delay_us(50);  
  102.     return data;  
  103. }  
  104.   
  105. // 从DS18B20读取2个位  
  106. u8 DS18B20_Read_2Bit(void)//读二位 子程序  
  107. {  
  108.     u8 i;  
  109.     u8 dat = 0;  
  110.     for (i = 2; i > 0; i--)  
  111.     {  
  112.         dat = dat << 1;  
  113.         DS18B20_Mode_Out();  
  114.         DS18B20_DQ_OUT_Low;  
  115.         Delay_us(2);  
  116.         DS18B20_DQ_OUT_High;  
  117.         DS18B20_Mode_IPU();  
  118.         Delay_us(12);  
  119.         if (DS18B20_DQ_IN)  dat |= 0x01;  
  120.         Delay_us(50);  
  121.     }  
  122.     return dat;  
  123. }  
  124.   
  125. // 从DS18B20读取1个字节  
  126. u8 DS18B20_Read_Byte(void)  // read one byte  
  127. {  
  128.     u8 i, j, dat;  
  129.     dat = 0;  
  130.     for (i = 0; i < 8; i++)  
  131.     {  
  132.         j = DS18B20_Read_Bit();  
  133.         dat = (dat) | (j << i);  
  134.     }  
  135.     return dat;  
  136. }  
  137.   
  138. // 写1位到DS18B20  
  139. void DS18B20_Write_Bit(u8 dat)  
  140. {  
  141.     DS18B20_Mode_Out();  
  142.     if (dat)  
  143.     {  
  144.         DS18B20_DQ_OUT_Low;// Write 1  
  145.         Delay_us(2);  
  146.         DS18B20_DQ_OUT_High;  
  147.         Delay_us(60);  
  148.     }  
  149.     else  
  150.     {  
  151.         DS18B20_DQ_OUT_Low;// Write 0  
  152.         Delay_us(60);  
  153.         DS18B20_DQ_OUT_High;  
  154.         Delay_us(2);  
  155.     }  
  156. }  
  157.   
  158. // 写1字节到DS18B20  
  159. void DS18B20_Write_Byte(u8 dat)  
  160. {  
  161.     u8 j;  
  162.     u8 testb;  
  163.     DS18B20_Mode_Out();  
  164.     for (j = 1; j <= 8; j++)  
  165.     {  
  166.         testb = dat & 0x01;  
  167.         dat = dat >> 1;  
  168.         if (testb)  
  169.         {  
  170.             DS18B20_DQ_OUT_Low;// 写1  
  171.             Delay_us(10);  
  172.             DS18B20_DQ_OUT_High;  
  173.             Delay_us(50);  
  174.         }  
  175.         else  
  176.         {  
  177.             DS18B20_DQ_OUT_Low;// 写0  
  178.             Delay_us(60);  
  179.             DS18B20_DQ_OUT_High;// 释放总线  
  180.             Delay_us(2);  
  181.         }  
  182.     }  
  183. }  
  184.   
  185. //初始化DS18B20的IO口,同时检测DS的存在  
  186. u8 DS18B20_Init(void)  
  187. {  
  188.     DS18B20_GPIO_Config();  
  189.     DS18B20_Rst();  
  190.     return DS18B20_Answer_Check();  
  191. }  
  192.   
  193. // 从ds18b20得到温度值,精度:0.1C,返回温度值(-550~1250),Temperature1返回浮点实际温度  
  194. float DS18B20_Get_Temp(u8 i)  
  195. {  
  196.     //u8 flag;  
  197.     u8 j;//匹配的字节  
  198.     u8 TL, TH;  
  199.     short Temperature;  
  200.     float Temperature1;  
  201.     DS18B20_Rst();  
  202.     DS18B20_Answer_Check();  
  203.     DS18B20_Write_Byte(0xcc);// skip rom  
  204.     DS18B20_Write_Byte(0x44);// convert  
  205.     DS18B20_Rst();  
  206.     DS18B20_Answer_Check();  
  207.   
  208.     // DS18B20_Write_Byte(0xcc);// skip rom  
  209.     //匹配ID,i为形参  
  210.     DS18B20_Write_Byte(0x55);  
  211.     for (j = 0; j < 8; j++)  
  212.     {  
  213.         DS18B20_Write_Byte(DS18B20_ID[i][j]);  
  214.     }  
  215.   
  216.     DS18B20_Write_Byte(0xbe);// convert  
  217.     TL = DS18B20_Read_Byte(); // LSB     
  218.     TH = DS18B20_Read_Byte(); // MSB    
  219.     if (TH & 0xfc)  
  220.     {  
  221.         //flag=1;  
  222.         Temperature = (TH << 8) | TL;  
  223.         Temperature1 = (~Temperature) + 1;  
  224.         Temperature1 *= 0.0625;  
  225.     }  
  226.     else  
  227.     {  
  228.         //flag=0;  
  229.         Temperature1 = ((TH << 8) | TL)*0.0625;  
  230.     }  
  231.     return Temperature1;  
  232. }  
  233.   
  234. // 自动搜索ROM  
  235. void DS18B20_Search_Rom(void)  
  236. {  
  237.     u8 k, l, chongtuwei, m, n, num;  
  238.     u8 zhan[5];  
  239.     u8 ss[64];  
  240.     u8 tempp;  
  241.     l = 0;  
  242.     num = 0;  
  243.     do  
  244.     {  
  245.         DS18B20_Rst(); //注意:复位的延时不够  
  246.         Delay_us(480); //480、720  
  247.         DS18B20_Write_Byte(0xf0);  
  248.         for (m = 0; m < 8; m++)  
  249.         {  
  250.             u8 s = 0;  
  251.             for (n = 0; n < 8; n++)  
  252.             {  
  253.                 k = DS18B20_Read_2Bit();//读两位数据  
  254.   
  255.                 k = k & 0x03;  
  256.                 s >>= 1;  
  257.                 if (k == 0x01)//01读到的数据为0 写0 此位为0的器件响应  
  258.                 {  
  259.                     DS18B20_Write_Bit(0);  
  260.                     ss[(m * 8 + n)] = 0;  
  261.                 }  
  262.                 else if (k == 0x02)//读到的数据为1 写1 此位为1的器件响应  
  263.                 {  
  264.                     s = s | 0x80;  
  265.                     DS18B20_Write_Bit(1);  
  266.                     ss[(m * 8 + n)] = 1;  
  267.                 }  
  268.                 else if (k == 0x00)//读到的数据为00 有冲突位 判断冲突位  
  269.                 {  
  270.                     //如果冲突位大于栈顶写0 小于栈顶写以前数据 等于栈顶写1  
  271.                     chongtuwei = m * 8 + n + 1;  
  272.                     if (chongtuwei > zhan[l])  
  273.                     {  
  274.                         DS18B20_Write_Bit(0);  
  275.                         ss[(m * 8 + n)] = 0;  
  276.                         zhan[++l] = chongtuwei;  
  277.                     }  
  278.                     else if (chongtuwei < zhan[l])  
  279.                     {  
  280.                         s = s | ((ss[(m * 8 + n)] & 0x01) << 7);  
  281.                         DS18B20_Write_Bit(ss[(m * 8 + n)]);  
  282.                     }  
  283.                     else if (chongtuwei == zhan[l])  
  284.                     {  
  285.                         s = s | 0x80;  
  286.                         DS18B20_Write_Bit(1);  
  287.                         ss[(m * 8 + n)] = 1;  
  288.                         l = l - 1;  
  289.                     }  
  290.                 }  
  291.                 else  
  292.                 {  
  293.                     //没有搜索到  
  294.                 }  
  295.             }  
  296.             tempp = s;  
  297.             DS18B20_ID[num][m] = tempp; // 保存搜索到的ID  
  298.         }  
  299.         num = num + 1;// 保存搜索到的个数  
  300.     } while (zhan[l] != 0 && (num < MaxSensorNum));  
  301.     DS18B20_SensorNum = num;  
  302.     //printf("DS18B20_SensorNum=%d\r\n",DS18B20_SensorNum);  
  303. }  

  DS18B20.h文件代码:

[cpp]  view plain  copy
  1. #ifndef __DS18B20_H  
  2. #define __DS18B20_H   
  3.     
  4. #include "stm32f10x.h"  
  5.   
  6. u8 DS18B20_Init(void);  
  7. u8 DS18B20_Read_Byte(void);  
  8. u8 DS18B20_Read_Bit(void);  
  9. u8 DS18B20_Answer_Check(void);  
  10. void  DS18B20_GPIO_Config(void);  
  11. void  DS18B20_Mode_IPU(void);  
  12. void  DS18B20_Mode_Out(void);  
  13. void  DS18B20_Rst(void);  
  14. void  DS18B20_Search_Rom(void);  
  15. void  DS18B20_Write_Byte(u8 dat);  
  16. float DS18B20_Get_Temp(u8 i);  
  17.   
  18. #endif  
  main.c文件代码:

[cpp]  view plain  copy
  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.   
  8. extern unsigned char DS18B20_ID[8][8];//检测到的传感器ID存数组  
  9. extern unsigned char DS18B20_SensorNum;  
  10.   
  11. int main(void)  
  12. {  
  13.     u8 num=0;  
  14.     USART1_init(9600);  
  15.     while(DS18B20_Init())//初始化DS18B20,兼检测18B20  
  16.     {  
  17.         printf("DS18B20 Check Failed!\r\n");    
  18.     }  
  19.     printf("DS18B20 Ready!\r\n");  
  20.     while(1)  
  21.     {       
  22.         DS18B20_Search_Rom();  
  23.         printf("DS18B20_SensorNum:%d\r\n",DS18B20_SensorNum);  
  24.       for(num=0;num<DS18B20_SensorNum;num++)  
  25.         {  
  26.             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));  
  27.         }  
  28.         printf("\r\n");  
  29.         Delay_s(2);  
  30.     }     
  31. }  

  运行结果如图:


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


posted @ 2018-03-12 15:56  SuperThinker  阅读(85)  评论(0编辑  收藏  举报  来源