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重定向参考