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

树莓派Pico与4B基于C/C++的USB双向串口通信故障排查

树莓派Pico与4B USB串口双向通信问题修复

核心问题及解决思路

1. 自发送消息循环问题

问题成因:Pico默认USB stdio开启回显功能,导致printf输出的内容会被回送到自身输入缓冲区,触发无限确认循环。
修复:初始化时关闭USB stdio回显与CRLF自动转换:

stdio_set_echo(&stdio_usb, false);
stdio_set_translate_crlf(&stdio_usb, false);

2. 缓冲区溢出与乱码问题

原代码存在两个致命bug:

  • 未声明inputString缓冲区,导致写入随机内存,引发崩溃与乱码
  • 缓冲区边界判断错误,未预留字符串终止符空间

修复措施:

  • 显式声明全局缓冲区(避免栈溢出):char inputString[MAXLENGTH + 1];
  • 严格检查缓冲区边界,预留\0位置:if (i >= MAXLENGTH - 1)
  • 过滤无效非ASCII控制字符(可选,根据需求调整)
  • 添加字符串终止符,避免后续字符串操作出错

3. 输入残留数据处理

原代码处理完子串后直接清空整个缓冲区,导致未处理的残留数据丢失或引发后续乱码。修复后改为将未处理的剩余内容移到缓冲区开头,等待下一次处理。

修改后的完整代码

C代码

#include "pico/stdlib.h"
#include "hardware/pwm.h"
#include "hardware/clocks.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <tusb.h>

#define MAXLENGTH 128

const uint PROGRAM_SLEEP = 10;

uint inputLength = 0;
char inputString[MAXLENGTH + 1]; // 全局缓冲区,+1用于存储字符串终止符

void readUSB() {
  int c;
  uint i = inputLength;
  while (true) {
    c = getchar_timeout_us(0);
    if (c == PICO_ERROR_TIMEOUT) break;
    // 过滤无效控制字符,保留换行、分号与可打印ASCII
    if ((c < 32 && c != '\n' && c != '\r' && c != ';') || c > 126) {
      continue;
    }
    // 检查缓冲区剩余空间,预留终止符位置
    if (i >= MAXLENGTH - 1) {
      printf("overflow\n");
      inputLength = 0;
      memset(inputString, 0, MAXLENGTH);
      break;
    }
    inputString[i] = c;
    i++;
  }
  inputLength = i;
  inputString[inputLength] = '\0'; // 添加字符串终止符
}

void handleSubstr(char *substr, uint length) {
  // 示例处理逻辑:打印收到的子串
  printf("Received: %.*s\n", length, substr);
}

void processInput() {
  if (inputLength == 0) return;
  uint last = 0;
  for (uint i = 0; i < inputLength; i++) {
    // 跳过换行/回车符,重置子串起始位置
    if (inputString[i] == '\n' || inputString[i] == '\r') {
      last = i + 1;
      continue;
    }
    if (inputString[i] == ';') {
      uint length = i - last;
      if (length > 0) {
        inputString[i] = '\0'; // 临时终止子串
        handleSubstr(inputString + last, length);
      }
      last = i + 1;
    }
  }
  // 处理未分割的剩余内容,移到缓冲区开头
  if (last < inputLength) {
    memmove(inputString, inputString + last, inputLength - last);
    inputLength = inputLength - last;
    inputString[inputLength] = '\0';
  } else {
    inputLength = 0;
    memset(inputString, 0, MAXLENGTH);
  }
}

int main() {
    stdio_init_all();
    while(!stdio_usb_connected());
    // 关闭回显与CRLF转换,避免自读与多余换行
    stdio_set_echo(&stdio_usb, false);
    stdio_set_translate_crlf(&stdio_usb, false);
    
    memset(inputString, 0, MAXLENGTH);

    while(true) {
      readUSB();
      processInput();
      sleep_ms(PROGRAM_SLEEP);
    }
}

CMakeLists.txt(保持原配置即可)

add_executable(hello_pwm
        hello_pwm.c
        )

# pull in common dependencies and additional pwm hardware support
target_link_libraries(hello_pwm pico_stdlib hardware_pwm)

# create map/bin/hex file etc.
pico_add_extra_outputs(hello_pwm)

# enable usb serial
pico_enable_stdio_usb(hello_pwm 1)
pico_enable_stdio_uart(hello_pwm 0)

# add url via pico_set_program_url
example_auto_set_url(hello_pwm)

Linux端操作建议

  • 避免使用cat+echo的组合,改用screen或minicom进行串口通信,减少额外字符干扰:
    screen /dev/ttyUSB0 115200
    
  • 若使用echo发送消息,添加-n参数避免自动插入换行符:
    echo -n "test_msg;" > /dev/ttyUSB0
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 06:03:10