重定义/自定义printf到串口输出实现的三种方法(cubeide)

简介: 重定义/自定义printf到串口输出实现的三种方法(cubeide)

1.重写_write函数

注释掉syscalls.c文件中的_write函数

重写_write函数

__attribute__((weak)) int _write(int file, char *ptr, int len)
{
     if(HAL_UART_Transmit(&huart1,(uint8_t *)ptr,len,0xffff) != HAL_OK)
     {
         Error_Handler();
     }
     return len;
}

这段代码也是一个重定义的输出方法,用于重定向标准输出函数_write。通过使用__attribute__((weak))属性修饰,可以在用户自定义的函数中进行重定义。

具体分析如下:

函数的原型是int _write(int file, char *ptr, int len),表示重定义了标准输出函数_write。该函数接受三个参数,file表示文件描述符(在这里可以忽略),ptr表示要发送的数据指针,len表示要发送的数据长度。

在函数内部,使用HAL_UART_Transmit函数将数据指针ptr指向的内容通过UART进行传输。这里同样使用了名为huart1的UART句柄,您可能需要根据实际情况进行相应的修改。

如果UART传输过程中出现错误,通过调用Error_Handler函数进行错误处理。

最后,函数返回发送的数据长度len。

2.重定义PUTCHAR_PROTOTYPE宏

/* USER CODE BEGIN PFP */
#ifdef __GNUC__                                    //串口重定向
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif 
PUTCHAR_PROTOTYPE
{
    HAL_UART_Transmit(&huart1 , (uint8_t *)&ch, 1, 0xFFFF);
    return ch;
}
/* USER CODE END PFP */

这段代码是重定义了printf函数的输出方法,使用串口进行输出。它通过重定义PUTCHAR_PROTOTYPE宏来定义了一个名为__io_putchar(对于GCC编译器)或fputc(对于其他编译器)的函数。

首先,根据编译器类型,PUTCHAR_PROTOTYPE宏会被定义为__io_putchar或fputc。GCC编译器使用__io_putchar,而其他编译器使用fputc。

接下来,PUTCHAR_PROTOTYPE函数会被定义。它的返回类型是int,并接受一个字符参数ch。

在函数内部,使用HAL_UART_Transmit函数将字符ch通过UART进行传输。这里使用了名为huart1的UART句柄,你可能需要根据实际情况进行相应的修改。

最后,函数返回传输的字符ch。

3.va_list自定义printf

#define USART2_MAX_SEND_LEN        400
#pragma pack(8)
uint8_t USART1_TX_BUF[USART1_MAX_SEND_LEN];     //发送缓冲,最大USART2_MAX_SEND_LEN字节
#pragma pack()
void u1_printf(char* fmt,...)
{
    uint16_t i,j;
    va_list ap;
    va_start(ap,fmt);
    vsprintf((char*)USART1_TX_BUF,fmt,ap);
    va_end(ap);
    i=strlen((const char*)USART1_TX_BUF);//此次发送数据的长度
    for(j=0;j<i;j++)//循环发送数据
    {
        while((USART1->SR&0X40)==0);//循环发送,直到发送完毕
        USART1->DR=USART2_TX_BUF[j];
    }
}

这段代码是一个用于在串口1上实现重定义的printf函数的例子。

具体分析如下:

首先,定义了一个名为u1_printf的函数,用于重定义printf函数在串口2上的输出。

函数接受一个格式化字符串fmt作为参数,后面跟着可变参数列表…。

在函数内部,首先使用va_start宏和va_list类型的变量ap来初始化可变参数列表。

然后,使用vsprintf函数将格式化后的字符串保存到全局数组USART1_TX_BUF中。这里假设数组已经定义,并且长度足够容纳格式化后的字符串。vsprintf函数的使用类似于sprintf,但是可以处理可变参数列表。

使用va_end宏结束可变参数的处理。

接下来,计算格式化后的字符串的长度,并将其存储在变量i中。

然后,通过循环逐个发送数据。在每次发送之前,使用while循环等待串口2发送寄存器为空,即等待上一次发送完成。

最后,将字符逐个发送到串口2的数据寄存器USART1->DR中,以便通过串口进行发送。

如果文章对您有所帮助,点赞支持,感谢!!!

总结:

重写_write函数:通过重定义_write函数,将数据通过UART发送。在函数内部使用HAL_UART_Transmit函数将数据发送到UART。如果发送过程中出现错误,会调用Error_Handler函数进行错误处理。

重定义PUTCHAR_PROTOTYPE宏:通过重定义PUTCHAR_PROTOTYPE宏,定义了一个名为__io_putchar(对于GCC编译器)或fputc(对于其他编译器)的函数。这个函数将字符通过UART发送。

自定义printf函数:定义了一个名为u1_printf的函数,用于在串口1上实现重定义的printf函数。函数接受一个格式化字符串作为参数,使用vsprintf函数将格式化后的字符串保存到全局数组USART1_TX_BUF中。然后通过循环逐个发送数据到串口1的数据寄存器。

这些重定义的函数和宏都用于实现在特定的串口上进行输出,并使用UART进行数据传输。请确保在使用这些重定义函数之前已经正确初始化了相关的硬件资源(例如UART)以及引入了正确的头文件。


目录
相关文章
|
6月前
|
程序员 编译器 C语言
用printf函数输出数据
用printf函数输出数据
43 2
|
5月前
getchar()函数的格式和使用方法
【6月更文挑战第24天】getchar()函数的格式和使用方法。
102 2
|
6月前
|
编译器 C++
VS编译器对scanf函数不安全报错的解决办法(详细步骤)
VS编译器对scanf函数不安全报错的解决办法(详细步骤)
|
6月前
|
C语言
使用printf函数输出数据
在C语言中,printf函数是一个常用的标准库函数,用于在控制台输出格式化的字符串和数据。它允许我们按照指定的格式输出各种类型的数据,包括整数、浮点数、字符和字符串等。
71 0
|
6月前
|
存储 程序员 C语言
C语言的scanf的作用和屏幕需要输入类型
C语言的scanf的作用和屏幕需要输入类型
39 0
|
编译器 文件存储 C++
一劳永逸的方法解决函数scanf报错问题
一劳永逸的方法解决函数scanf报错问题
158 0
|
12月前
|
编译器
printf返回值的定义与举例
printf返回值的定义与举例
|
存储
如何编写一个可变参数函数?如何让所有单片机的所有串口实现printf函数?
如何编写一个可变参数函数?如何让所有单片机的所有串口实现printf函数?
187 0
|
编译器 C语言 C++
scanf返回值被忽略的原因及其解决方法(vs2019)
scanf返回值被忽略的原因及其解决方法(vs2019)
750 0