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接收在后台通过中断处理,主循环可持续运行,不受输入等待影响。
初始化阶段开启UART接收中断:
在main函数初始化完成后(如MX_USART2_UART_Init()之后)添加:uint8_t input; // 将input定义为全局变量,或让中断回调可访问 HAL_UART_Receive_IT(&huart2, &input, 1);实现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); } }修改主循环,移除阻塞式接收:
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
相关产品推荐
相关产品推荐

