STM32 Uart中断发送打印乱码问题记录

print 和scanf 重定向

这里需要解决2个问题;

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

  2. 编译器兼容MDK和GCC

参考内容

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

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

cpp 复制代码
#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上面,都是用以下方式重定向的
cpp 复制代码
int fputc(int ch, FILE *f)
int fgetc(FILE *f)
  • gcc环境下,使用的是如下方式:
cpp 复制代码
int _write(int file, char *ptr, int len)
int _read(int file, char *ptr, int len)

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

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

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

cpp 复制代码
#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打印不全(或打印乱码问题)

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

cpp 复制代码
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博客

相关推荐
智者知已应修善业2 小时前
【51单片机用数码管显示流水灯的种类是按钮控制数码管加一和流水灯】2022-6-14
c语言·经验分享·笔记·单片机·嵌入式硬件·51单片机
智商偏低8 小时前
单片机之helloworld
单片机·嵌入式硬件
青牛科技-Allen9 小时前
GC3910S:一款高性能双通道直流电机驱动芯片
stm32·单片机·嵌入式硬件·机器人·医疗器械·水泵、
森焱森11 小时前
无人机三轴稳定控制(2)____根据目标俯仰角,实现俯仰稳定化控制,计算出升降舵输出
c语言·单片机·算法·架构·无人机
白鱼不小白11 小时前
stm32 USART串口协议与外设(程序)——江协教程踩坑经验分享
stm32·单片机·嵌入式硬件
S,D12 小时前
MCU引脚的漏电流、灌电流、拉电流区别是什么
驱动开发·stm32·单片机·嵌入式硬件·mcu·物联网·硬件工程
芯岭技术15 小时前
PY32F002A单片机 低成本控制器解决方案,提供多种封装
单片机·嵌入式硬件
youmdt15 小时前
Arduino IDE ESP8266连接0.96寸SSD1306 IIC单色屏显示北京时间
单片机·嵌入式硬件
嘿·嘘15 小时前
第七章 STM32内部FLASH读写
stm32·单片机·嵌入式硬件
Meraki.Zhang15 小时前
【STM32实践篇】:I2C驱动编写
stm32·单片机·iic·驱动·i2c