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

STM32中atoi()转换UART接收字符串返回乱码问题求助

STM32 UART中断接收转整数及TIM占空比设置问题解决

问题核心

在STM32平台使用C语言开发时,通过HAL_UART_Receive_IT中断接收数据,尝试用atoi()将接收内容转为整数后回传终端出现乱码,且用该整数设置TIM占空比的功能完全失效。

现有代码的问题分析

  1. 单字节接收无法满足atoi()要求:UART_Rx_Data是单个uint8_t变量,每次中断仅接收1个字节,但atoi()需要带'\0'结束符的完整字符串,单字节无法构成有效输入,转换结果必然错误。
  2. 回传方式错误:HAL_UART_Transmit_IT(&huart2, (uint8_t *)i, sizeof(i))直接将整数的二进制内存值作为字节发送,终端无法解析为可读字符,因此显示乱码。
  3. 冗余循环无意义:遍历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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.07 07:23:19