问题——USART通信无反应 && 传输数据失败

文章讨论了USART通信中的常见问题,包括接线错误、串口线混淆、printf重定向导致的乱码以及在STM32上大批量数据传输失败的情况。作者分享了解决方案,如避免在同一接口连接仿真线和串口线,调整波特率,以及修改_sbrk函数实现以防止乱码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 USART通信无反应

1、拓展坞

        嗯这一点我是属实没想到,拓展坞只能接一根用于串口的线。细细想来,拓展坞虽有多个USB口接其他线,却是从上位机(PC)的一个USB口引来的,也就是说硬件上就决定上位机一个接口只能用于一个串口的通信?实测是,仿真线与串口线接在同一个上位机接口,会让串口线(CH340)在上位机中找不到

        总之,不要把串口通信的线仿真的线连接在同一个拓展坞(即上位机的同一个接口)。

2,接线接错了

        这一点我是最想吐槽的,查了好多资料是没有查出串口的线到底长什么样,又该怎么接。除非有人指导或是老师上课讲到这,发了相关资料,否则初学者单凭自己很容易混淆接线接口,比如把TTL、USART、COM之类的弄混了,也很容易认错线。

        这一点就属于不讲很容易错,会了又觉得太简单而没必要发讲╮ (╯_╰)╭ 

如果是做过数电设计(FPGA)或是使用J-Link烧录的话,想必对它一定不会陌生。

3,无法打印

        在GPIO引脚配好,USART初始化正确、串口助手配置也正确的情况下,仍然无法打印

        如果你不使用Keil,使用其他IDE的话,那么重定向printf时,要重写的是_write,因为arm-gnu-ebi交叉工具链和keil的工具链对应的printf不同。而这里重写的是_write里的_io_putchar

需要添加stdio.husart相应头文件

#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif
PUTCHAR_PROTOTYPE
{
  HAL_UART_Transmit(&huart3 , (uint8_t *)&ch, 1, 0xFFFF);// HAL,可自己换为标准外设库
  return ch;
}

4,配置正确_打印1个字符却输出一堆乱码

        这个问题相当诡异,情形是这样的:使用USART_SendData发送数据是正常的,但是一用printf就会发出一堆乱码。跟踪调试后发现,数组长度直接就1024,无论我发几个字母。

        查了许久网上资料,却仅仅了解到arm-gnu-ebi交叉编译工具链关于printf的重定向需要重写_write__io_putchar

        后来无意中想起来,从STM32CubeMX生成的代码中是没有_sbrk这个函数,当时就匆忙从网上摘抄了关于_sbrk的实现函数。于是现在嘛,开始怀疑_sbrk的实现有问题

 _sbrk是要添加到SysCall.c里的函数

下面是网上摘抄的

void *_sbrk(int incr) {
  (void) incr;
  return NULL;
}

仔细看一看的话,显然是有问题的,这与白板函数无异。于是就训练了一会AI

        我提供脚本、开发环境、设备芯片型号给它,让它生成实现函数,没想到还挺好用。至少不会打印乱码了。

#include <sys/types.h>

extern char _sdata; // 已初始化数据段的起始地址
extern char _edata; // 已初始化数据段的结束地址
extern char _end;   // 未初始化数据段(.bss)的结束地址

caddr_t _sbrk(int incr) {
  static char *heap_end = NULL;
  char *prev_heap_end;

  if (heap_end == NULL) {
    heap_end = &_end; // 堆的起始地址通常是未初始化数据段的结束地址
  }
  prev_heap_end = heap_end;

  // 检查是否有足够的内存来分配
  if (heap_end + incr > (char *)(((uintptr_t)&_sdata + (uintptr_t)&_edata) & ~(sizeof(uintptr_t) - 1))) {
      // 堆空间不足
      return (caddr_t) -1;
    }

  heap_end += incr;
  return (caddr_t) prev_heap_end;
}

(如果有条件的话,可以把Keil等其他非arm-gnu-ebi的IDE关于这个函数的实现代码扒过来)

下面是从一些工程的system.c里找到这个函数

void *_sbrk(ptrdiff_t incr)
{
  extern uint8_t _end; /* Symbol defined in the linker script */
  extern uint8_t _estack; /* Symbol defined in the linker script */
  extern uint32_t _Min_Stack_Size; /* Symbol defined in the linker script */
  const uint32_t stack_limit = (uint32_t)&_estack - (uint32_t)&_Min_Stack_Size;
  const uint8_t *max_heap = (uint8_t *)stack_limit;
  uint8_t *prev_heap_end;

  /* Initialize heap end at first call */
  if (NULL == __sbrk_heap_end)
  {
    __sbrk_heap_end = &_end;
  }

  /* Protect heap from growing into the reserved MSP stack */
  if (__sbrk_heap_end + incr > max_heap)
  {
    errno = ENOMEM;
    return (void *)-1;
  }

  prev_heap_end = __sbrk_heap_end;
  __sbrk_heap_end += incr;

  return (void *)prev_heap_end;
}

USART传输数据失败

1,问题描述

        在不使用DMA时,分批次使用USART从上位机向stm32传输少量数据(256字节)时,stm32可以正常接收,一旦单次传输四五百数据时,就进入USART的ErrorHandler。

        一开始使用的波特率是9600,后来下调至4800,但仍然出错,只不过上限拓展到700左右传输数据才失败。

2,原因

一般常说的USART串口通信,指的是异步串口通信,这种通信不适合大量数据的传输。

3,解决办法

把串口助手的传输文件由【连续传输】改为【……延时xxx ms】

然后把波特率改为115200(这个我也不知道原因,调高了反而可以正常传输了。要注意单片机也要设为相同的波特率)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值