干翻全岛蛙蛙 发表于 2024-10-8 23:02:24

STM32-HAL库 驱动DS18B20温度传感器 -- 2024.10.8

目录
一、教程简介
二、驱动理论讲解
三、CubeMX生成底层代码
四、Keil5编写代码
五、实验效果
一、教程简介

        本教程面向初学者,只介绍DS18B20的常用功能,但也能满意大部分的运用需求。跟着本教程操作,可在10分钟内解决DS18b20通信难题。
二、驱动理论讲解

        DS18b20支持多传感器共用一个引脚,但本教程只教利用一个温湿度传感器。利用DS18b20可分为下面两个步骤进行
(一)初始化:
        1、将引脚初始化为推挽输出、上拉。
        2、发送复位脉冲:引脚输出大于480us的低电平复位信号(发起600us),延时600us之后,需将引脚拉高并延时15us。
        3、检测存在脉冲:将引脚设置为上拉输入,并检测低电平到来的时间,若高出100us还没检测到低电平,则初始化失败。检测到低电平后开始盘算时间,若低高出240us还没检测到高电平,则初始化失败。
(二)获取温度:
        1、配置单DS18b20模式:重复初始化操作后发送下令:0xCC
        2、发送温度转换下令:发送0x44
        3、配置单DS18b20模式:重复初始化操作后发送下令:0xCC
        4、发送读取下令:发送0xBE
        5、吸收两个字节的温度数据
三、CubeMX生成底层代码

1、芯片选择:这里选用STM32F103C8t6
https://i-blog.csdnimg.cn/direct/29dd6819ab7542b5ad040241d346d111.png
 2、配置Debug模式
https://i-blog.csdnimg.cn/direct/4063795c36424fb89f5bb06332947442.png
3、 配置外部高速时钟
https://i-blog.csdnimg.cn/direct/7255b072836c4faab741aa2ba21507e3.png
4、 配置时钟速率
https://i-blog.csdnimg.cn/direct/406c3aba38774b058b8a49c0b2e0bb4c.png
5、 配置DS18b20引脚
https://i-blog.csdnimg.cn/direct/b13b35902a804b9d88c12c022804982f.png
6、配置串口
https://i-blog.csdnimg.cn/direct/e367016f7df548d9ae8db0668f3e2daf.png
7、输出工程文件
https://i-blog.csdnimg.cn/direct/cd46de795f784d76a2ba671c56c743e6.png
https://i-blog.csdnimg.cn/direct/577d602509144d50b463eb66a71eca8f.png
https://i-blog.csdnimg.cn/direct/81d822913fda4e1ca5a0cb39c86b83c6.png
四、Keil5编写代码

1、ds18b20.c 代码
/* 包含头文件 ----------------------------------------------------------------*/
#include "ds18b20.h"

/**
* 函数功能: DS18B20 初始化函数
* 返 回 值: 1为初始化失败,0为初始化成功
*/
uint8_t DS18B20_Init(void)
{
DS18B20_Mode_Out_PP();            //推挽输出模式
      
DS18B20_Dout_HIGH();                                                //输出高电平
      
DS18B20_Rst();                                                      //输出复位脉冲

return DS18B20_Presence ();                        //返回响应情况
}


/**
* 函数功能: 使DS18B20-DATA引脚变为上拉输入模式
*/
static void DS18B20_Mode_IPU(void)
{
GPIO_InitTypeDef GPIO_InitStruct;

/* 串口外设功能GPIO配置 */
GPIO_InitStruct.Pin   = DS18b20_Pin;
GPIO_InitStruct.Mode= GPIO_MODE_INPUT;
GPIO_InitStruct.Pull= GPIO_PULLUP;
HAL_GPIO_Init(DS18b20_GPIO_Port, &GPIO_InitStruct);
      
}

/**
* 函数功能: 使DS18B20-DATA引脚变为推挽输出模式
*/
static void DS18B20_Mode_Out_PP(void)
{
GPIO_InitTypeDef GPIO_InitStruct;

/* 串口外设功能GPIO配置 */
GPIO_InitStruct.Pin = DS18b20_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(DS18b20_GPIO_Port, &GPIO_InitStruct);         
}

/**
* 函数功能: 主机给从机发送复位脉冲
*/
static void DS18B20_Rst(void)
{
   DS18B20_Mode_Out_PP(); /* 主机设置为推挽输出 */
   DS18B20_Dout_LOW();    /* 主机输出低电平 */
   DS18B20_Delay(750);    /* 主机至少产生480us的低电平复位信号 */
   DS18B20_Dout_HIGH();   /* 主机在产生复位信号后,需将总线拉高 */
   DS18B20_Delay(15);   /* 从机接收到主机的复位信号后,会在15~60us后给主机发一个存在脉冲 */
}

/**
* 函数功能: 检测从机给主机返回的存在脉冲
* 返 回 值: 0:成功,1:失败
*/

static uint8_t DS18B20_Presence(void)
{
   uint8_t pulse_time = 0;
   /* 主机设置为上拉输入 */
   DS18B20_Mode_IPU();
   
   /* 等待存在脉冲的到来,存在脉冲为一个60~240us的低电平信号
    * 如果存在脉冲没有来则做超时处理,从机接收到主机的复位信号后,会在15~60us后给主机发一个存在脉冲
    */
   while( DS18B20_Data_IN() && pulse_time<100 )
   {
      pulse_time++;
      DS18B20_Delay(1);
   }      
   /* 经过100us后,存在脉冲都还没有到来*/
   if( pulse_time >=100 )
      return 1;
   else
      pulse_time = 0;
   
   /* 存在脉冲到来,且存在的时间不能超过240us */
   while( !DS18B20_Data_IN() && pulse_time<240 )
   {
       pulse_time++;
       DS18B20_Delay(1);
   }      
   if( pulse_time >=240 )
       return 1;
   else
       return 0;
}

/**
* 函数功能: 从DS18B20读取一个bit
* 返 回 值: 读取到的数据
*/
static uint8_t DS18B20_ReadBit(void)
{
   uint8_t dat;
   
   /* 读0和读1的时间至少要大于60us */      
   DS18B20_Mode_Out_PP();
   /* 读时间的起始:必须由主机产生 >1us <15us 的低电平信号 */
   DS18B20_Dout_LOW();
   DS18B20_Delay(10);
   
   /* 设置成输入,释放总线,由外部上拉电阻将总线拉高 */
   DS18B20_Mode_IPU();
   //Delay_us(2);
   
   if( DS18B20_Data_IN() == SET )
         dat = 1;
   else
         dat = 0;
   
   /* 这个延时参数请参考时序图 */
   DS18B20_Delay(45);
   
   return dat;
}

/**
* 函数功能: 从DS18B20读一个字节,低位先行
* 返 回 值: 读到的数据
*/
static uint8_t DS18B20_ReadByte(void)
{
   uint8_t i, j, dat = 0;      
   for(i=0; i<8; i++)
   {
      j = DS18B20_ReadBit();               
      dat = (dat) | (j<<i);
   }
   return dat;
}

/**
* 函数功能: 写一个字节到DS18B20,低位先行
* 输入参数: dat:待写入数据
*/
static void DS18B20_WriteByte(uint8_t dat)
{
   uint8_t i, testb;
   DS18B20_Mode_Out_PP();
   for( i=0; i<8; i++ )
   {
      testb = dat&0x01;
      dat = dat>>1;               
      /* 写0和写1的时间至少要大于60us */
      if (testb)
      {                        
         DS18B20_Dout_LOW();
         /* 1us < 这个延时 < 15us */
         DS18B20_Delay(8);
         
         DS18B20_Dout_HIGH();
         DS18B20_Delay(58);
      }         
      else
      {                  
         DS18B20_Dout_LOW();
         /* 60us < Tx 0 < 120us */
         DS18B20_Delay(70);
         
         DS18B20_Dout_HIGH();               
         /* 1us < Trec(恢复时间) < 无穷大*/
         DS18B20_Delay(2);
      }
   }
}

/**
* 函数功能: 跳过匹配 DS18B20 ROM
*/
static void DS18B20_SkipRom ( void )
{
   DS18B20_Rst();                  
   DS18B20_Presence();               
   DS18B20_WriteByte(0XCC);                /* 跳过 ROM */      
}

/**
* 函数功能: 获取 DS18B20 温度值
* 返 回 值: 浮点型温度值
*/
float DS18B20_GetTemp_SkipRom ( void )
{
   uint8_t tpmsb, tplsb;
   short s_tem;
   float f_tem;
   
   DS18B20_SkipRom ();
   DS18B20_WriteByte(0X44);                              /* 开始转换 */
   
   DS18B20_SkipRom ();
       DS18B20_WriteByte(0XBE);                              /* 读温度值 */
   
   tplsb = DS18B20_ReadByte();               
   tpmsb = DS18B20_ReadByte();
   
   s_tem = tpmsb<<8;
   s_tem = s_tem | tplsb;
   
   if( s_tem < 0 )                /* 负温度 */
   f_tem = (~s_tem+1) * 0.0625;      
   else
   f_tem = s_tem * 0.0625;
   
   return f_tem;         
}

/**
* 微妙延时函数
* 全系列通用,只需要将宏定义CPU_FREQUENCY_MHZ根据时钟主频修改即可。
* 系统滴答定时器是HAL库初始化的,且必须有HAL库初始化。
*/
#define CPU_FREQUENCY_MHZ   (int)(HAL_RCC_GetHCLKFreq()/1000000)                // 自动获取STM32时钟主频
void DS18B20_Delay(__IO uint32_t delay)
{
   int last, curr, val;
   int temp;

   while (delay != 0)
   {
      temp = delay > 900 ? 900 : delay;
      last = SysTick->VAL;
      curr = last - CPU_FREQUENCY_MHZ * temp;
      if (curr >= 0)
      {
         do
         {
             val = SysTick->VAL;
         }
         while ((val < last) && (val >= curr));
      }
      else
      {
         curr += CPU_FREQUENCY_MHZ * 1000;
         do
         {
             val = SysTick->VAL;
         }
         while ((val <= last) || (val > curr));
      }
      delay -= temp;
    }
}

2、ds18b20.h 代码
#ifndef __DS18B20_H
#define __DS18B20_H

/* 包含头文件 ----------------------------------------------------------------*/
#include "main.h"

/* 引脚操作函数宏定义 --------------------------------------------------------*/
#define DS18B20_Dout_LOW()               HAL_GPIO_WritePin(DS18b20_GPIO_Port,DS18b20_Pin,GPIO_PIN_RESET)
#define DS18B20_Dout_HIGH()            HAL_GPIO_WritePin(DS18b20_GPIO_Port,DS18b20_Pin,GPIO_PIN_SET)
#define DS18B20_Data_IN()                HAL_GPIO_ReadPin(DS18b20_GPIO_Port,DS18b20_Pin)

/* 函数声明 ------------------------------------------------------------------*/
void                 DS18B20_Rst(void);
void                 DS18B20_SkipRom(void);
void                 DS18B20_Mode_IPU(void);
void                 DS18B20_Mode_Out_PP(void);
void                 DS18B20_WriteByte(uint8_t dat);
void                 DS18B20_Delay(__IO uint32_t delay);
float   DS18B20_GetTemp_SkipRom(void);
uint8_t DS18B20_Init(void);
uint8_t DS18B20_ReadBit(void);
uint8_t DS18B20_Presence(void);
uint8_t DS18B20_ReadByte(void);

#endif 3、main.c 参考调用代码
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "ds18b20.h"
#include "stdio.h"
/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
charTx_Buf = {0};
float Temp = 0;
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

/**
* @briefThe application entry point.
* @retval int
*/
int main(void)
{

/* USER CODE BEGIN 1 */

/* USER CODE END 1 */

/* MCU Configuration--------------------------------------------------------*/

/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();

/* USER CODE BEGIN Init */

/* USER CODE END Init */

/* Configure the system clock */
SystemClock_Config();

/* USER CODE BEGIN SysInit */

/* USER CODE END SysInit */

/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
        while(DS18B20_Init())
        {
                HAL_UART_Transmit(&huart1,(uint8_t*)"DS18b20初始化失败\r\n",19,100);
                HAL_Delay(1000);
        }
        HAL_UART_Transmit(&huart1,(uint8_t*)"DS18b20初始化成功\r\n",19,100);
/* USER CODE END 2 */

/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
                Temp = DS18B20_GetTemp_SkipRom();
                sprintf(Tx_Buf,"温度:%0.3f \r\n",Temp);
                HAL_UART_Transmit(&huart1,(uint8_t*)Tx_Buf,15,100);
                HAL_Delay(1000);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
五、实验效果

        通过本驱动利用DS18b20丈量出来的环境温度,与米家温湿度计丈量的效果仅仅相差0.012摄氏度,丈量精度非常可观。
https://i-blog.csdnimg.cn/direct/6856464209e24687b2bde1276e9e2b3f.jpeg
 六、特别说明



[*]同学们在操作的过程中遇到的问题可在评论区留言,我看到后会第一时间回复。
[*]想看其他传感器的教程也可在评论区留言,我会按照大家的需求来修改教程内容。
[*]若您以为本教程对您有所帮助,请点赞、收藏,这是我持续更新的最大动力,感谢您!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: STM32-HAL库 驱动DS18B20温度传感器 -- 2024.10.8