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

STM32半双工USART模式下带中断驱动DS18B20的实现求助

STM32半双工USART中断+状态机驱动DS18B20改造方案

现有基于STM32半双工USART驱动DS18B20的代码采用轮询方式实现,不符合项目要求的中断驱动需求,需要改为状态机+中断的非阻塞模式。以下是原代码及改造方案:

原轮询模式代码

void setBaudrate (uint32_t baud)
{
      huart1.Instance = USART1;
      huart1.Init.BaudRate = baud;
      huart1.Init.WordLength = UART_WORDLENGTH_8B;
      huart1.Init.StopBits = UART_STOPBITS_1;
      huart1.Init.Parity = UART_PARITY_NONE;
      huart1.Init.Mode = UART_MODE_TX_RX;
      huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
      huart1.Init.OverSampling = UART_OVERSAMPLING_16;
      if (HAL_HalfDuplex_Init(&huart1) != HAL_OK)
      {
        Error_Handler();
      }
}

int DS18B20_start()
{
    uint8_t data = 0xF0;
    setBaudrate(9600);
    HAL_UART_Transmit(&huart1, &data, 1, 100);
    if (HAL_UART_Receive(&huart1, &data, 1, 1000) != HAL_OK) return -1;
    setBaudrate(115200);
    if (data == 0xf0) return -2;
    return 1;
}

void DS18B20_write (uint8_t data)
{
    uint8_t buffer[8];
    for (int i=0; i<8; i++)
    {
        if ((data & (1<<i)) != 0)
        {
            buffer[i] = 0xFF;
        }
        else
        {
            buffer[i] = 0x00;
        }
    }

    HAL_UART_Transmit(&huart1, buffer, 8, 1000);
}

uint8_t DS18B20_read (void)
{
    uint8_t buffer[8];
    uint8_t value = 0;
    for (int i=0; i<8; i++)
    {
        buffer[i] = 0xFF;
    }

    HAL_UART_Transmit_DMA(&huart1, buffer, 8);
    HAL_UART_Receive_DMA(&huart1, RxData, 8);

    while (isRxed == 0);

    for (int i=0; i<8; i++)
    {
        if (RxData[i] == 0xFF)
        {
            value |= 1<<i;
        }
    }

    isRxed = 0;
    return value;
}

void measureTemp(){
    static uint32_t lastMeasurementTime = 0;
    uint32_t currentTime = HAL_GetTick();

    if((currentTime - lastMeasurementTime >= measurementInterval) || currentTime == 0){
        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 Scratchpad

        Temp_LSB = DS18B20_read();
        Temp_MSB = DS18B20_read();
        Temp = (Temp_MSB<<8) | Temp_LSB;
        Temperature = (float)Temp/16.0;

        lastMeasurementTime = currentTime;//更新测量时间
    }

}

改造方案:状态机+中断驱动

1. 定义状态枚举与全局变量

typedef enum {
    DS18B20_STATE_IDLE,
    DS18B20_STATE_SEND_RESET,
    DS18B20_STATE_WAIT_PRESENCE,
    DS18B20_STATE_SEND_SKIP_ROM,
    DS18B20_STATE_SEND_CONVERT_CMD,
    DS18B20_STATE_WAIT_CONVERT_DONE,
    DS18B20_STATE_SEND_READ_SCRATCHPAD,
    DS18B20_STATE_READ_LSB,
    DS18B20_STATE_READ_MSB,
    DS18B20_STATE_CALC_TEMP
} DS18B20_StateTypeDef;

DS18B20_StateTypeDef ds18b20_state = DS18B20_STATE_IDLE;
uint8_t rx_buffer[8];
uint8_t tx_buffer[8];
uint8_t presence_flag = 0;
uint16_t raw_temp = 0;
float temperature = 0.0f;
uint32_t measure_tick = 0;
#define MEASURE_INTERVAL 1000  //1秒测量一次

2. 重写UART中断回调函数

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) {
    if(huart->Instance == USART1) {
        switch(ds18b20_state) {
            case DS18B20_STATE_SEND_RESET:
                //发送复位后切换到等待存在信号状态
                ds18b20_state = DS18B20_STATE_WAIT_PRESENCE;
                HAL_UART_Receive_IT(&huart1, rx_buffer, 1);
                break;
            case DS18B20_STATE_SEND_SKIP_ROM:
                //发送Skip ROM后,根据流程阶段切换状态
                if(measure_tick == 0) {
                    ds18b20_state = DS18B20_STATE_SEND_CONVERT_CMD;
                    tx_buffer[0] = 0x44; //转换温度指令
                    HAL_UART_Transmit_IT(&huart1, tx_buffer, 1);
                } else {
                    ds18b20_state = DS18B20_STATE_SEND_READ_SCRATCHPAD;
                    tx_buffer[0] = 0xBE; //读取暂存器指令
                    HAL_UART_Transmit_IT(&huart1, tx_buffer, 1);
                }
                break;
            case DS18B20_STATE_SEND_CONVERT_CMD:
                //转换指令发送完成,进入等待转换阶段
                ds18b20_state = DS18B20_STATE_WAIT_CONVERT_DONE;
                measure_tick = HAL_GetTick();
                break;
            case DS18B20_STATE_SEND_READ_SCRATCHPAD:
                //读取指令发送完成,切换到读取LSB状态
                ds18b20_state = DS18B20_STATE_READ_LSB;
                //准备读取时序的高电平信号
                for(int i=0; i<8; i++) tx_buffer[i] = 0xFF;
                HAL_UART_Transmit_IT(&huart1, tx_buffer, 8);
                break;
            case DS18B20_STATE_READ_LSB:
                //LSB发送完成,启动接收并切换到读取MSB状态
                ds18b20_state = DS18B20_STATE_READ_MSB;
                for(int i=0; i<8; i++) tx_buffer[i] = 0xFF;
                HAL_UART_Transmit_IT(&huart1, tx_buffer, 8);
                break;
            case DS18B20_STATE_READ_MSB:
                //MSB发送完成,进入温度计算阶段
                ds18b20_state = DS18B20_STATE_CALC_TEMP;
                break;
            default:
                break;
        }
    }
}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
    if(huart->Instance == USART1) {
        switch(ds18b20_state) {
            case DS18B20_STATE_WAIT_PRESENCE:
                //检查传感器存在信号
                presence_flag = (rx_buffer[0] != 0xF0) ? 1 : 0;
                if(presence_flag) {
                    //存在信号正常,发送Skip ROM指令
                    ds18b20_state = DS18B20_STATE_SEND_SKIP_ROM;
                    tx_buffer[0] = 0xCC;
                    HAL_UART_Transmit_IT(&huart1, tx_buffer, 1);
                } else {
                    //传感器不存在,回到空闲状态
                    ds18b20_state = DS18B20_STATE_IDLE;
                }
                //恢复波特率到115200
                setBaudrate(115200);
                break;
            case DS18B20_STATE_READ_LSB:
                //存储LSB数据并启动接收
                raw_temp &= 0xFF00;
                raw_temp |= rx_buffer[0];
                HAL_UART_Receive_IT(&huart1, rx_buffer, 8);
                break;
            case DS18B20_STATE_READ_MSB:
                //存储MSB数据
                raw_temp &= 0x00FF;
                raw_temp |= (rx_buffer[0] << 8);
                HAL_UART_Receive_IT(&huart1, rx_buffer, 8);
                break;
            default:
                break;
        }
    }
}

3. 改造核心函数

void setBaudrate (uint32_t baud)
{
      huart1.Instance = USART1;
      huart1.Init.BaudRate = baud;
      huart1.Init.WordLength = UART_WORDLENGTH_8B;
      huart1.Init.StopBits = UART_STOPBITS_1;
      huart1.Init.Parity = UART_PARITY_NONE;
      huart1.Init.Mode = UART_MODE_TX_RX;
      huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
      huart1.Init.OverSampling = UART_OVERSAMPLING_16;
      if (HAL_HalfDuplex_Init(&huart1) != HAL_OK)
      {
        Error_Handler();
      }
}

//启动一次温度测量流程
void DS18B20_StartMeasure(void) {
    if(ds18b20_state == DS18B20_STATE_IDLE) {
        setBaudrate(9600);
        tx_buffer[0] = 0xF0;
        ds18b20_state = DS18B20_STATE_SEND_RESET;
        HAL_UART_Transmit_IT(&huart1, tx_buffer, 1);
    }
}

//状态机处理函数,放在主循环中调用
void DS18B20_StateMachineHandler(void) {
    switch(ds18b20_state) {
        case DS18B20_STATE_WAIT_CONVERT_DONE:
            //等待温度转换完成(最长750ms)
            if(HAL_GetTick() - measure_tick >= 750) {
                //转换完成,重新发送复位启动读取流程
                setBaudrate(9600);
                tx_buffer[0] = 0xF0;
                ds18b20_state = DS18B20_STATE_SEND_RESET;
                measure_tick = 1; //标记进入读取流程
                HAL_UART_Transmit_IT(&huart1, tx_buffer, 1);
            }
            break;
        case DS18B20_STATE_CALC_TEMP:
            //计算最终温度值
            temperature = (float)raw_temp / 16.0f;
            ds18b20_state = DS18B20_STATE_IDLE;
            measure_tick = 0;
            break;
        default:
            break;
    }
}

4. 主循环中的调用

int main(void) {
    //系统初始化代码...
    HAL_UART_Receive_IT(&huart1, rx_buffer, 1); //提前开启UART接收中断

    while (1) {
        //定时触发温度测量
        static uint32_t last_measure_time = 0;
        if(HAL_GetTick() - last_measure_time >= MEASURE_INTERVAL) {
            DS18B20_StartMeasure();
            last_measure_time = HAL_GetTick();
        }

        //处理DS18B20状态机流转
        DS18B20_StateMachineHandler();

        //其他业务逻辑代码...
    }
}

关键说明

  • 所有UART操作均采用中断触发方式,避免阻塞主循环
  • 状态机负责管理DS18B20的工作流程,每个阶段完成后通过中断回调自动切换到下一阶段
  • 温度转换等待逻辑放在主循环的状态机处理中,不占用额外阻塞时间
  • 波特率在复位阶段自动切换为9600,后续指令阶段恢复为115200

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 14:57:03