一、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.0ProjectsSTM32F103RB-NucleoExamplesUARTUART_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中添加对它的进行编译的操作。
二、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_Transmit 和 HAL_UART_Receive 处理收发数据时,第四个参数 Timeout 超时机制,使用的是 STM32cubeMX配置的 Timebase Source时钟(一般为 systick)来进行超时判定的:
四、未完待续。。。