STM32中atoi()转换UART接收字符串返回乱码问题求助
STM32 UART中断接收转整数及TIM占空比设置问题解决
问题核心
在STM32平台使用C语言开发时,通过HAL_UART_Receive_IT中断接收数据,尝试用atoi()将接收内容转为整数后回传终端出现乱码,且用该整数设置TIM占空比的功能完全失效。
现有代码的问题分析
- 单字节接收无法满足
atoi()要求:UART_Rx_Data是单个uint8_t变量,每次中断仅接收1个字节,但atoi()需要带'\0'结束符的完整字符串,单字节无法构成有效输入,转换结果必然错误。 - 回传方式错误:
HAL_UART_Transmit_IT(&huart2, (uint8_t *)i, sizeof(i))直接将整数的二进制内存值作为字节发送,终端无法解析为可读字符,因此显示乱码。 - 冗余循环无意义:遍历
0~4095寻找与Left_El相等值的循环完全多余,直接使用Left_El计算即可,且未对输入值做范围校验,非法值会导致占空比设置异常。
正确解决方案
1. 定义接收缓冲区与状态变量
需要一个缓冲区存储多字节输入,同时用变量记录接收长度和完成状态:
#define UART_RX_BUF_SIZE 16 // 根据输入需求调整缓冲区大小 uint8_t uart_rx_buf[UART_RX_BUF_SIZE]; uint8_t uart_rx_len = 0; volatile uint8_t uart_rx_complete = 0; // 接收完成标志(回车/换行触发)
2. 修改主循环与中断回调函数
- 主循环仅在接收完成时处理数据,避免反复调用
HAL_UART_Receive_IT; - 中断回调逐字节接收,直到收到结束符(回车
'\r'或换行'\n')再触发数据处理:
// 初始化阶段启动第一次中断接收 HAL_UART_Receive_IT(&huart2, &uart_rx_buf[uart_rx_len], 1); while (1) { if (uart_rx_complete) { // 添加字符串结束符,供atoi()解析 uart_rx_buf[uart_rx_len] = '\0'; int input_num = atoi((char*)uart_rx_buf); // 将整数转为字符串回传终端 char send_buf[32]; sprintf(send_buf, "Received value: %d\r\n", input_num); HAL_UART_Transmit(&huart2, (uint8_t*)send_buf, strlen(send_buf), HAL_MAX_DELAY); // 校验输入范围后设置TIM占空比 if (input_num >= 0 && input_num <= 4095) { uint32_t duty_cycle = round((input_num * (100.0 / 4095.0)) + 25); __HAL_TIM_SET_COMPARE(&htim21, TIM_CHANNEL_1, duty_cycle); } else { // 非法输入提示 char err_msg[] = "Input out of range (0~4095)\r\n"; HAL_UART_Transmit(&huart2, (uint8_t*)err_msg, strlen(err_msg), HAL_MAX_DELAY); } // 重置接收状态,准备下一次接收 uart_rx_len = 0; uart_rx_complete = 0; HAL_UART_Receive_IT(&huart2, &uart_rx_buf[uart_rx_len], 1); } } void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if (huart == &huart2) { // 判断是否收到输入结束符 if (uart_rx_buf[uart_rx_len] == '\r' || uart_rx_buf[uart_rx_len] == '\n') { uart_rx_complete = 1; } else { // 未到结束符,继续接收下一个字节 uart_rx_len++; // 防止缓冲区溢出,超出范围则重置 if (uart_rx_len >= UART_RX_BUF_SIZE - 1) { uart_rx_len = 0; } HAL_UART_Receive_IT(&huart2, &uart_rx_buf[uart_rx_len], 1); } } }
关键说明
- 字符串结束符:必须在接收完成后给缓冲区添加
'\0',确保atoi()能正确解析整数; - 整数转字符串回传:使用
sprintf()将整数转为可读字符串后发送,终端才能正常显示; - 输入范围校验:限制输入值在
0~4095之间,避免非法值导致TIM占空比设置错误; - 中断接收逻辑:每次中断接收1字节,直到收到结束符再触发处理,避免单字节解析的问题。
内容的提问来源于stack exchange,提问作者Serhii
相关产品推荐
相关产品推荐

