You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

STM32H7平台DS18B20温度传感器读数异常求助

问题

在STM32H7开发板上使用DS18B20温度传感器,需求为:正确读取温度并通过Putty显示,当温度超过45℃时输出"Heat Warning"提示。

当前代码如下:

#include "main.h"
#include "string.h"

/* Private variables ---------------------------------------------------------*/
ADC_HandleTypeDef hadc1;
ADC_HandleTypeDef hadc2;
ADC_HandleTypeDef hadc3;

FDCAN_HandleTypeDef hfdcan1;
FDCAN_HandleTypeDef hfdcan2;

I2C_HandleTypeDef hi2c4;

LTDC_HandleTypeDef hltdc;

QSPI_HandleTypeDef hqspi;

RTC_HandleTypeDef hrtc;

SAI_HandleTypeDef hsai_BlockA2;
SAI_HandleTypeDef hsai_BlockB2;

MMC_HandleTypeDef hmmc1;

SPI_HandleTypeDef hspi2;

UART_HandleTypeDef huart3;

PCD_HandleTypeDef hpcd_USB_OTG_FS;

SDRAM_HandleTypeDef hsdram1;

/* USER CODE BEGIN PV */
#define     BUFSIZE 256
#define DS18B20_PORT GPIOA
#define DS18B20_PIN GPIO_PIN_1
uint8_t SendBuffer[BUFSIZE];
int Counter;
int KeyState=0;
int TouchX, TouchY;
uint8_t dataBuffer[10];

uint8_t VendorID, DeviceMode, Gesture, Status, Touchxh, Touchxl, Touchyh, Touchyl;
//uint8_t temp_lsb, temp_msb;
//int16_t temp_raw;
//float temperature;
uint8_t Temp_byte1, Temp_byte2;
uint16_t SUM, TEMP;

float Temperature = 0;
float Humidity = 0;
uint8_t Presence = 0;// Store temperature value

HAL_StatusTypeDef retval;
uint8_t Answer;
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void Display_Temp (float Temp);
void Set_Pin_Output (GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin);
void Set_Pin_Input (GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin);
uint8_t DS18B20_Start (void);
void DS18B20_Write (uint8_t data);
uint8_t DS18B20_Read (void);


void SystemClock_Config(void);
void PeriphCommonClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_ADC1_Init(void);
static void MX_ADC2_Init(void);
static void MX_ADC3_Init(void);
static void MX_FDCAN1_Init(void);
static void MX_FDCAN2_Init(void);
static void MX_FMC_Init(void);
static void MX_LTDC_Init(void);
static void MX_QUADSPI_Init(void);
static void MX_RTC_Init(void);
static void MX_SAI2_Init(void);
static void MX_SDMMC1_MMC_Init(void);
static void MX_SPI2_Init(void);
static void MX_USART3_UART_Init(void);
static void MX_USB_OTG_FS_PCD_Init(void);
static void MX_I2C4_Init(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

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

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  HAL_Init();
  SystemClock_Config();
  PeriphCommonClock_Config();
  MX_GPIO_Init();
  MX_ADC1_Init();
  MX_ADC2_Init();
  MX_ADC3_Init();
  MX_FDCAN1_Init();
  MX_FDCAN2_Init();
  MX_FMC_Init();
  MX_LTDC_Init();
  MX_QUADSPI_Init();
  MX_RTC_Init();
  MX_SAI2_Init();
  MX_SPI2_Init();
  MX_USART3_UART_Init();
  MX_USB_OTG_FS_PCD_Init();
  MX_I2C4_Init();
  HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12, 1);

  DS18B20_Init();

  while (1)
    {
       Presence = DS18B20_Start ();
       DS18B20_Write (0xCC);  // skip ROM
       DS18B20_Write (0x44);  // convert t

       Presence = DS18B20_Start ();
       DS18B20_Write (0xCC);  // skip ROM
       DS18B20_Write (0xBE);  // Read Scratch-pad

       Temp_byte1 = DS18B20_Read();
       Temp_byte2 = DS18B20_Read();
       printf("Raw Temp_byte1: %u, Temp_byte2: %u\n", Temp_byte1, Temp_byte2);
       TEMP = ((Temp_byte2<<8))|Temp_byte1;
       Temperature = (float)TEMP/16.0;  // resolution is 0.0625

       HAL_Delay(3000);
       Display_Temp(Temperature);
    }
  /* USER CODE END 3 */
}
uint8_t DS18B20_Start (void)
{
    uint8_t Response = 0;
    Set_Pin_Output(DS18B20_PORT, DS18B20_PIN);   // set the pin as output
    HAL_GPIO_WritePin (DS18B20_PORT, DS18B20_PIN, 0);  // pull the pin low
    HAL_Delay(480);   // delay according to datasheet

    Set_Pin_Input(DS18B20_PORT, DS18B20_PIN);
        HAL_Delay(80);    // delay according to datasheet
    if (!(HAL_GPIO_ReadPin (DS18B20_PORT, DS18B20_PIN))) Response = 1;    // if the pin is low i.e the presence pulse is detected
    else Response = -1;

    HAL_Delay (400); // 480 us delay totally.

    return Response;
}
void DS18B20_Write (uint8_t data)
{
    Set_Pin_Output(DS18B20_PORT, DS18B20_PIN);  // set as output

    for (int i=0; i<8; i++)
    {
        if ((data & (1<<i))!=0)  // if the bit is high
        {
            // write 1
            Set_Pin_Output(DS18B20_PORT, DS18B20_PIN);  // set as output
            HAL_GPIO_WritePin (DS18B20_PORT, DS18B20_PIN, 0);  // pull the pin LOW
            HAL_Delay (1);  // wait for 1 us

            Set_Pin_Input(DS18B20_PORT, DS18B20_PIN);  // set as input
            HAL_Delay (50);  // wait for 60 us
        }

        else  // if the bit is low
        {
            // write 0
            Set_Pin_Output(DS18B20_PORT, DS18B20_PIN);
            HAL_GPIO_WritePin (DS18B20_PORT, DS18B20_PIN, 0);  // pull the pin LOW
            HAL_Delay (50);  // wait for 60 us

            Set_Pin_Input(DS18B20_PORT, DS18B20_PIN);
        }
    }
}
uint8_t DS18B20_Read (void)
{
    uint8_t value=0;
    Set_Pin_Input (DS18B20_PORT, DS18B20_PIN);

    for (int i=0;i<8;i++)
    {
        Set_Pin_Output(DS18B20_PORT, DS18B20_PIN);   // set as output
        HAL_GPIO_WritePin (GPIOA, GPIO_PIN_1, 0);  // pull the data pin LOW
        HAL_Delay (2);  // wait for 2 us
        Set_Pin_Input(DS18B20_PORT, DS18B20_PIN);  // set as input
        if (HAL_GPIO_ReadPin (GPIOA, GPIO_PIN_1))  // if the pin is HIGH
        {
            value |= 1<<i;  // read = 1
        }
        HAL_Delay (60);  // wait for 60 us
    }
    return value;
}

void Set_Pin_Output (GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = GPIO_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOx, &GPIO_InitStruct);
}

void Set_Pin_Input (GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = GPIO_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    HAL_GPIO_Init(GPIOx, &GPIO_InitStruct);
}
void Display_Temp (float Temp)
{
//    char str[20] = {0};
//    lcd_put_cur(0, 0);
//
//    sprintf (str, "TEMP:- %.2f ", Temp);
//    lcd_send_string(str);
//    lcd_send_data('C');
    // Display temperature and check for heat warning
              if (Temp > 40.0) {
                 snprintf(SendBuffer, BUFSIZE, "Heat Warning! Current Temperature: %.2f°C\n\r", Temp);
             } else {
                 snprintf(SendBuffer, BUFSIZE, "Current Temperature: %.2f°C\n\r", Temp);
             }
             HAL_UART_Transmit(&huart3, SendBuffer, strlen(SendBuffer), 100);
}
/**
  * @brief System Clock Configuration
  * @retval None
  */

尝试将引脚改为模拟模式(替代输入输出模式)后,出现异常读数:

Heat Warning! Current Temperature: 2272.25°C
Heat Warning! Current Temperature: 1055.44°C
Heat Warning! Current Temperature: 2231.31°C

问题排查与解决方法

1. 核心问题:错误使用模拟模式引脚

DS18B20采用单总线通信协议,需要引脚在输入/输出模式之间切换,实现电平的读写控制。模拟模式下,引脚被配置为ADC采样用,无法进行GPIO的电平输出和输入检测,导致读取的Temp_byte1、Temp_byte2为随机无效值,计算出的温度自然异常。

解决:
立即恢复引脚的输入/输出模式配置,删除所有将该引脚设置为模拟模式的代码,保留原代码中Set_Pin_Input和Set_Pin_Output的逻辑。

2. 修复时序问题:替换毫秒级延时而为微秒级

DS18B20对通信时序要求极高(比如写1需要拉低引脚1us,读操作需要拉低2us后释放),但当前代码使用的HAL_Delay()是毫秒级延时(最小延时1ms),远大于协议要求的微秒级时长,会导致通信时序混乱,读取错误数据。

解决:
实现微秒级延时函数,比如利用定时器实现精确延时:

// 初始化TIM6,配置时钟为1MHz(1us计数一次)
void delay_us(uint16_t us)
{
    __HAL_TIM_SET_COUNTER(&htim6, 0);
    while(__HAL_TIM_GET_COUNTER(&htim6) < us);
}

然后将代码中所有HAL_Delay(1)、HAL_Delay(2)、HAL_Delay(50)等替换为对应的微秒延时,比如:

  • HAL_Delay(480) → delay_us(480)
  • HAL_Delay(1) → delay_us(1)
  • HAL_Delay(2) → delay_us(2)

3. 修正引脚硬编码问题

在DS18B20_Read()函数中,硬编码使用了GPIOA, GPIO_PIN_1,而不是宏定义的DS18B20_PORT和DS18B20_PIN,后续修改引脚时会导致逻辑不一致。

解决:
修改DS18B20_Read()中的对应代码:

HAL_GPIO_WritePin (DS18B20_PORT, DS18B20_PIN, 0);  // 替换原硬编码引脚
// ...
if (HAL_GPIO_ReadPin (DS18B20_PORT, DS18B20_PIN))  // 替换原硬编码引脚

4. 增加传感器应答检测

当前代码未判断DS18B20_Start()的返回值,如果传感器未正常应答(Presence≠1),仍会继续读取并计算温度,导致无效数据输出。

解决:
在主循环中增加应答判断:

while (1)
{
   Presence = DS18B20_Start ();
   if (Presence != 1) {
       snprintf(SendBuffer, BUFSIZE, "DS18B20 No Response!\n\r");
       HAL_UART_Transmit(&huart3, SendBuffer, strlen(SendBuffer), 100);
       HAL_Delay(3000);
       continue;
   }
   DS18B20_Write (0xCC);  // skip ROM
   DS18B20_Write (0x44);  // convert t

   HAL_Delay(750); // 等待温度转换完成(最长750ms,根据分辨率调整)

   Presence = DS18B20_Start ();
   if (Presence != 1) {
       snprintf(SendBuffer, BUFSIZE, "DS18B20 No Response!\n\r");
       HAL_UART_Transmit(&huart3, SendBuffer, strlen(SendBuffer), 100);
       HAL_Delay(3000);
       continue;
   }
   DS18B20_Write (0xCC);  // skip ROM
   DS18B20_Write (0xBE);  // Read Scratch-pad

   Temp_byte1 = DS18B20_Read();
   Temp_byte2 = DS18B20_Read();
   printf("Raw Temp_byte1: %u, Temp_byte2: %u\n", Temp_byte1, Temp_byte2);
   TEMP = ((Temp_byte2<<8))|Temp_byte1;
   Temperature = (float)TEMP/16.0;  // resolution is 0.0625

   Display_Temp(Temperature);
   HAL_Delay(3000);
}

5. 修正温度阈值

需求是温度超过45℃时提示,但当前Display_Temp()函数中判断的是Temp > 40.0,不符合需求。

解决:
修改阈值判断:

if (Temp > 45.0) {
   snprintf(SendBuffer, BUFSIZE, "Heat Warning! Current Temperature: %.2f°C\n\r", Temp);
} else {
   snprintf(SendBuffer, BUFSIZE, "Current Temperature: %.2f°C\n\r", Temp);
}

内容的提问来源于stack exchange,提问作者Red Smurf

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 19:40:54