解决STM32 UART中断发送打印乱码问题的记录

print 和scanf 重定向

这里需要解决2个问题;

1. print 和scanf重定向 编写对应的内部函数

2. 编译器兼容MDK和GCC

参考内容

基于 VsCode + GCC + STM32 环境下的串口输入输出重定向_gcc libc 重定向-CSDN博客

修改后的参考代码,亲自用VSCODE GCC和MDK测试 ok

#include "stdio.h"


// 条件编译
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#define GETCHAR_PROTOTYPE int __io_getchar(void)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#define GETCHAR_PROTOTYPE int fgetc(FILE *f)
#endif /* __GNUC__ */




/* 告知连接器不从C库链接使用半主机的函�???????? */
// 标准库需要的支持函数                 
struct __FILE 
{ 
    int handle; 
}; 
 
// 定义_sys_exit()以避免使用半主机模式    
void _sys_exit(int x) 
{ 
    x = x; 
} 
 
FILE __stdout;




/**
  * 函数功能: 重定�??? c库函�??? printf�??? DEBUG_USARTx
  * 输入参数: �???
  * �??? �??? �???: �???
  * �???    明:�???
  */
PUTCHAR_PROTOTYPE
{

  /***********等待上一次发送完成************/
	while(huart1.gState == HAL_UART_STATE_BUSY_TX);
  // HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFF); //阻塞式无限等�???
  HAL_UART_Transmit_IT(&huart1, (uint8_t *)&ch, 1); //中断方式
  // HAL_UART_Transmit_DMA(&huart1, (uint8_t *)&ch, 1); //DMA方式
  return ch;
}


/**
  * 函数功能: 重定�??? c库函�??? getchar,scanf�??? DEBUG_USARTx
  * 输入参数: �???
  * �??? �??? �???: �???
  * �???    明:�???
  */
GETCHAR_PROTOTYPE
{
  uint8_t ch = 0;

  // HAL_UART_Receive(&huart1, &ch, 1, 0x0FF);
  HAL_UART_Receive_IT(&huart1, &ch, 1);
  //  HAL_UART_Receive_DMA(&huart1, &ch, 1);
    
  return ch;
}


#ifdef __GNUC__
// 禁用半主机:
#pragma import(__use_no_semihosting)     //关闭半主机模式,只需要在任意�????????个C文件中加入即可�??
int _write(int file, char *ptr, int len)
{
    int DataIdx;
    for (DataIdx = 0; DataIdx < len; DataIdx++) 
    { 
        __io_putchar(*ptr++); 
    }
    return len;
}

int _read(int file, char *ptr, int len)
{
  int DataIdx;

  for (DataIdx = 0; DataIdx < len; DataIdx++)
  {
    *ptr++ = __io_getchar();
  }

  return len;
}
#endif

总结几个内容:

1.不同编译环境下的输入/输出重定向

在 gcc环境下,printf重定向跟以往的在 MDK上的重定向有点不同。

  • Keil、IAR等MDK上面,都是用以下方式重定向的 
  • int fputc(int ch, FILE *f)
    int fgetc(FILE *f)
    
  • gcc环境下,使用的是如下方式:
  • int _write(int file, char *ptr, int len)
    int _read(int file, char *ptr, int len)
    

    因此用条件编译兼容两种情况

    2. 禁用半主机也是在GCC下才使用,因此全部防止到了如下条件编译中

    注意,如下的_wirte和_read 也调用了前面的PUTCHAR_PROTOTYPE和GETCHAR_PROTOTYPE

    #ifdef __GNUC__
    // 禁用半主机:
    #pragma import(__use_no_semihosting)     //关闭半主机模式,只需要在任意�????????个C文件中加入即可�??
    int _write(int file, char *ptr, int len)
    {
        int DataIdx;
        for (DataIdx = 0; DataIdx < len; DataIdx++) 
        { 
            __io_putchar(*ptr++); 
        }
        return len;
    }
    
    int _read(int file, char *ptr, int len)
    {
      int DataIdx;
    
      for (DataIdx = 0; DataIdx < len; DataIdx++)
      {
        *ptr++ = __io_getchar();
      }
    
      return len;
    }
    #endif
    

    通过以上修改后已经完成了重定向

    2.printf打印不全(或打印乱码问题)

    最初参考代码如下,此处此时了三种方式,只有阻塞式可以完整打印

    PUTCHAR_PROTOTYPE
    {
    
    
      // HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFF); //阻塞式
      HAL_UART_Transmit_IT(&huart1, (uint8_t *)&ch, 1); //中断方式
      // HAL_UART_Transmit_DMA(&huart1, (uint8_t *)&ch, 1); //DMA方式
      return ch;
    }

    ,其它两种方式打印效果如下

    while1内容如下

    printf("Hello, uart printf simple!");

    HAL_Delay(1000);

     实际打印效果如下

     原因是没有发送完成又被新的中断打断了

    查找参考资料:【stm32使用CMSIS-Driver printf串口重映射打印不完整的问题】_cmsis 重写printf-CSDN博客

    修改增加等待不忙发送,即增加如下红色部分后测试中断方式正常,DMA应该也正常.

    PUTCHAR_PROTOTYPE

    {

      /***********等待上一次发送完成************/

      while(huart1.gState == HAL_UART_STATE_BUSY_TX);

      // HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFF); //阻塞式无限等�???

      HAL_UART_Transmit_IT(&huart1, (uint8_t *)&ch, 1); //中断方式

      // HAL_UART_Transmit_DMA(&huart1, (uint8_t *)&ch, 1); //DMA方式

      return ch;

    }

    发送修改后测试ok

    那么接收是否需要增加状态判断,判断不忙或者IDLE时再接收?

    最近简单使用了STM32,如上简单记录下.

    串口配置参考

    【STM32F4+CubeMX零基础快速入门】串口收发全攻略_哔哩哔哩_bilibili 

    printf重定向参考

    基于 VsCode + GCC + STM32 环境下的串口输入输出重定向_gcc libc 重定向-CSDN博客

    STM32 gcc与mdk下的printf重定向方式_gcc printf与keil printf-CSDN博客 

    物联沃分享整理
    物联沃-IOTWORD物联网 » 解决STM32 UART中断发送打印乱码问题的记录

    发表评论