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

STM32 Nucleo板NTC热敏电阻UART连续输出异常排查

问题分析与解决方案

问题根源:阻塞式UART接收导致主循环停滞

你的问题完全由代码逻辑导致。核心缺陷在主循环的第一行:

HAL_UART_Receive(&huart2, &input, sizeof(input), HAL_MAX_DELAY);

HAL_UART_Receive的HAL_MAX_DELAY参数会让程序一直阻塞在此处,必须等到UART收到输入字节后,才会继续执行后续代码。

即便你设置了system=1,每次主循环都要等待一次输入(比如再次按下'1'),才会触发一次温度采集和输出。这就是为什么无法实现一次输入'1'就持续输出的原因——主循环被卡在等待输入的步骤上,无法自主循环执行采集逻辑。

带标志位完全可以实现连续传输

通过system标志位控制连续采集是完全可行的,只需修改UART接收逻辑,避免其阻塞主循环运行。以下是两种可靠的修改方案:

方案1:使用UART中断接收(推荐,不占用主循环资源)

让UART接收在后台通过中断处理,主循环可持续运行,不受输入等待影响。

  1. 初始化阶段开启UART接收中断:
    在main函数初始化完成后(如MX_USART2_UART_Init()之后)添加:

    uint8_t input; // 将input定义为全局变量,或让中断回调可访问
    HAL_UART_Receive_IT(&huart2, &input, 1);
    
  2. 实现UART接收完成的中断回调函数:

    void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
    {
        if (huart->Instance == USART2)
        {
            if (input == '1' && system == 0)
            {
                system = 1;
                HAL_UART_Transmit(&huart2, (uint8_t*)"Temperature measurement started.\r\n", 35, HAL_MAX_DELAY);
            }
            else if (input == '2' && system == 1)
            {
                system = 0;
                HAL_UART_Transmit(&huart2, (uint8_t*)"Temperature measurement stopped.\r\n", 35, HAL_MAX_DELAY);
                HAL_GPIO_WritePin(GPIOA, GREEN_LED, GPIO_PIN_RESET);
                HAL_GPIO_WritePin(GPIOA, RED_LED, GPIO_PIN_RESET);
            }
            // 重新开启中断接收,保证持续监听输入
            HAL_UART_Receive_IT(&huart2, &input, 1);
        }
    }
    
  3. 修改主循环,移除阻塞式接收:

    while (1)
    {
        if(system == 1)
        {
            // 原有温度采集、计算、输出逻辑保持不变
            float V_ref= 3.3;
            char buffer[100];
            // 采集第一个NTC数据
            ADC_Select_CH0();
            HAL_ADC_Start(&hadc1);
            HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY);
            adc_value1 = HAL_ADC_GetValue(&hadc1);
            HAL_ADC_Stop(&hadc1);
            
            float voltage1= (adc_value1 / 4095.0)* V_ref;
            resistance1 = (refResistance1*voltage1)/(V_ref - voltage1);
            temperature_ntc1 = findTemp1(resistance1);
            
            // 采集第二个NTC数据
            ADC_Select_CH1();
            HAL_ADC_Start(&hadc1);
            HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY);
            adc_value2 = HAL_ADC_GetValue(&hadc1);
            HAL_ADC_Stop(&hadc1);
            
            float voltage2= (adc_value2 / 4095.0)* V_ref;
            resistance2 = (refResistance2*voltage2)/(V_ref- voltage2);
            temperature_ntc2 = findTemp2(resistance2);
            
            // LED控制逻辑
            if (fabs(temperature_ntc1 - temperature_ntc2) > 1.0)
            {
                HAL_GPIO_WritePin(GPIOA, RED_LED, GPIO_PIN_SET);
                HAL_GPIO_WritePin(GPIOA, GREEN_LED, GPIO_PIN_RESET);
            }
            else
            {
                HAL_GPIO_WritePin(GPIOA, GREEN_LED, GPIO_PIN_SET);
                HAL_GPIO_WritePin(GPIOA, RED_LED, GPIO_PIN_RESET);
            }
            
            // 发送温度数据
            sprintf(buffer, "Temperature_NTC1: %.2f °C \r\n", temperature_ntc1);
            HAL_UART_Transmit(&huart2, (uint8_t*)buffer, strlen(buffer), HAL_MAX_DELAY);
            sprintf(buffer, "Temperature_NTC2: %.2f °C \r\n\r\n", temperature_ntc2);
            HAL_UART_Transmit(&huart2, (uint8_t*)buffer, strlen(buffer), HAL_MAX_DELAY);
            
            oldtemp1 = temperature_ntc1;
            oldtemp2= temperature_ntc2;
            
            // 添加延时控制输出频率,避免刷屏
            HAL_Delay(1000);
        }
    }
    

方案2:使用非阻塞式UART接收(轮询方式)

若不想使用中断,可将HAL_UART_Receive的超时时间设为较短值,让主循环每次快速检查输入,无输入则直接执行采集逻辑。

修改后的主循环:

uint8_t input; // 将input移至循环外,避免重复定义
while (1)
{
    // 非阻塞接收,超时10ms,无输入则跳过
    if (HAL_UART_Receive(&huart2, &input, sizeof(input), 10) == HAL_OK)
    {
        if (input == '1' && system == 0)
        {
            system = 1;
            HAL_UART_Transmit(&huart2, (uint8_t*)"Temperature measurement started.\r\n", 35, HAL_MAX_DELAY);
        }
        else if (input == '2' && system == 1)
        {
            system = 0;
            HAL_UART_Transmit(&huart2, (uint8_t*)"Temperature measurement stopped.\r\n", 35, HAL_MAX_DELAY);
            HAL_GPIO_WritePin(GPIOA, GREEN_LED, GPIO_PIN_RESET);
            HAL_GPIO_WritePin(GPIOA, RED_LED, GPIO_PIN_RESET);
        }
    }

    if(system == 1)
    {
        // 原有温度采集、计算、输出逻辑保持不变
        float V_ref= 3.3;
        char buffer[100];
        // 采集第一个NTC数据
        ADC_Select_CH0();
        HAL_ADC_Start(&hadc1);
        HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY);
        adc_value1 = HAL_ADC_GetValue(&hadc1);
        HAL_ADC_Stop(&hadc1);
        
        float voltage1= (adc_value1 / 4095.0)* V_ref;
        resistance1 = (refResistance1*voltage1)/(V_ref - voltage1);
        temperature_ntc1 = findTemp1(resistance1);
        
        // 采集第二个NTC数据
        ADC_Select_CH1();
        HAL_ADC_Start(&hadc1);
        HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY);
        adc_value2 = HAL_ADC_GetValue(&hadc1);
        HAL_ADC_Stop(&hadc1);
        
        float voltage2= (adc_value2 / 4095.0)* V_ref;
        resistance2 = (refResistance2*voltage2)/(V_ref- voltage2);
        temperature_ntc2 = findTemp2(resistance2);
        
        // LED控制逻辑
        if (fabs(temperature_ntc1 - temperature_ntc2) > 1.0)
        {
            HAL_GPIO_WritePin(GPIOA, RED_LED, GPIO_PIN_SET);
            HAL_GPIO_WritePin(GPIOA, GREEN_LED, GPIO_PIN_RESET);
        }
        else
        {
            HAL_GPIO_WritePin(GPIOA, GREEN_LED, GPIO_PIN_SET);
            HAL_GPIO_WritePin(GPIOA, RED_LED, GPIO_PIN_RESET);
        }
        
        // 发送温度数据
        sprintf(buffer, "Temperature_NTC1: %.2f °C \r\n", temperature_ntc1);
        HAL_UART_Transmit(&huart2, (uint8_t*)buffer, strlen(buffer), HAL_MAX_DELAY);
        sprintf(buffer, "Temperature_NTC2: %.2f °C \r\n\r\n", temperature_ntc2);
        HAL_UART_Transmit(&huart2, (uint8_t*)buffer, strlen(buffer), HAL_MAX_DELAY);
        
        oldtemp1 = temperature_ntc1;
        oldtemp2= temperature_ntc2;
        
        // 添加延时控制输出频率
        HAL_Delay(1000);
    }
}

补充说明

  • 两种方案均能实现一次输入'1'持续输出、输入'2'停止的需求。中断方案效率更高,适合多任务场景;轮询方案更简单,适合小型项目。
  • 建议在采集循环中添加HAL_Delay控制输出频率,避免PuTTY控制台被快速刷屏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 16:15:55