当前位置:网站首页>STM32cubeMX之 uart问题汇总

STM32cubeMX之 uart问题汇总

2022-06-21 11:58:00 夏沫の浅雨

写在前面:
本文章旨在总结备份、方便以后查询,由于是个人总结,如有不对,欢迎指正;另外,内容大部分来自网络、书籍、和各类手册,如若侵权请告知,马上删帖致歉。


一、gcc环境下输入输出重定向问题

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

在以往的 Keil、IAR等 IDE上面,都是用以下方式重定向的:

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)

现在明确了 gcc环境下输入输出重定向问题,那么就可以编写对应的函数了。一般地,我们会参考官方的 demo来进行修改编写,很幸运的是官方提供了示例工程,在固件库的 ...\STM32Cube_FW_F1_V1.8.0\Projects\STM32F103RB-Nucleo\Examples\UART\UART_Printf 目录中可以找到它;然,我们真正需要的是 syscalls.c 文件,syscalls翻译过来是系统调用的意思,从里面可以找得到 _write函数和 _read函数的实现方式:

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

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

return len;
}

__attribute__((weak)) int _write(int file, char *ptr, int len)
{
    
	int DataIdx;

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

于是乎我们直接把整个 syscalls.c 文件移植过来就好了;
_write函数和 _read函数里面,我们可以看到它是留有接口的,即:__io_putchar__io_getchar ,所以我们真正要实现的是 __io_putchar__io_getchar ;当然,你也可以直接重新实现 _write函数和 _read函数。

然后为了对不同编译环境的使用处理,往往我们利用宏来进行选择,而在 gcc环境中 __GNUC__ 是默认定义了的,因此得到了以下实现方式:

#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库函数 printf到 DEBUG_USARTx * 输入参数: 无 * 返 回 值: 无 * 说 明:无 */
PUTCHAR_PROTOTYPE
{
    
  HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);

  return ch;
}

/** * 函数功能: 重定向 c库函数 getchar,scanf到 DEBUG_USARTx * 输入参数: 无 * 返 回 值: 无 * 说 明:无 */
GETCHAR_PROTOTYPE
{
    
  uint8_t ch = 0;
  HAL_UART_Receive(&huart1, &ch, 1, 0xFFFF);
    
  return ch;
}

然后,在这里值得注意的是:

syscalls.c 文件移植到自己的工程后,记得在 Makefile中添加对它的进行编译的操作。

参考:

https://electronics.stackexchange.com/questions/206113/how-do-i-use-the-printf-function-on-stm32/279945#279945

https://www.openstm32.org/forumthread1055


二、gcc环境下的输出流刷新

在 gcc环境下,使用 printf()输出,如果输出数据中没有附带 \n 换行符,那么,在遇到 \n 之前或着缓冲区溢出,是不会在屏幕上输出任何数据;除此之外,还有一种方法可以刷新输出数据,那就是在发完数据之后,运行一次 fflush(stdout) 强制刷新一次输出流,这样数据就能发出去了。


三、HAL库上的一些函数理解

1、在中断处理上,STM32cubeMX初始化生成代码后,要靠 HAL_UART_Transmit_IT 来打开发送或 HAL_UART_Receive_IT 来打开接收等完成剩下的中断配置并打开?。。而且,第三个参数值 Size 决定了触发进入中断的参数;eg:HAL_UART_Receive_IT(&huart1, (uint8_t *)aRxBuffer, 8); 那就表示着只有接收的数据大于或等于 8的时候才出发接收中断,并且大于 8的时候会进入多次,视情况而定。

2、在使用非中断处理的函数 HAL_UART_TransmitHAL_UART_Receive 处理收发数据时,第四个参数 Timeout 超时机制,使用的是 STM32cubeMX配置的 Timebase Source时钟(一般为 systick)来进行超时判定的:

在这里插入图片描述


四、未完待续。。。

原网站

版权声明
本文为[夏沫の浅雨]所创,转载请带上原文链接,感谢
https://blog.csdn.net/qq_42992084/article/details/109481990