如何在 STM32F10x 上重定向 printf()?

Posted

技术标签:

【中文标题】如何在 STM32F10x 上重定向 printf()?【英文标题】:How to retarget printf() on an STM32F10x? 【发布时间】:2017-02-10 10:20:35 【问题描述】:

我使用此代码重定向printf(),但它不起作用

#ifdef __GNUC__
/* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
   set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */

PUTCHAR_PROTOTYPE

    /* Place your implementation of fputc here */
      /* e.g. write a character to the LCD */
    lcd_Data_Write((u8)ch);

      return ch;

我用的是STM32F103RBT6

编译器:带有 emBitz 编辑器的 GCC

【问题讨论】:

可能与***.com/questions/39664071/…重复 可能有用:electronics.stackexchange.com/questions/206113/… 【参考方案1】:

作为替代方案,您可以使用 Variable Argument Functions (va_list) 编写自己的 printf() 函数。

使用va_list,自定义打印函数如下所示:

#include <stdio.h>
#include <stdarg.h>
#include <string.h>

void vprint(const char *fmt, va_list argp)

    char string[200];
    if(0 < vsprintf(string,fmt,argp)) // build string
    
        HAL_UART_Transmit(&huart1, (uint8_t*)string, strlen(string), 0xffffff); // send message via UART
    


void my_printf(const char *fmt, ...) // custom printf() function

    va_list argp;
    va_start(argp, fmt);
    vprint(target, fmt, argp);
    va_end(argp);

使用示例:

uint16_t year = 2016;
uint8_t month = 10;
uint8_t day   = 02;
char* date = "date";

// "Today's date: 2015-12-18"
my_printf("Today's %s: %d-%d-%d\r\n", date, year, month, day);

请注意,虽然此解决方案为您提供了方便使用的功能,但它比发送原始数据甚至使用sprintf() 都慢。我在 AVR 和 STM32 微控制器上都使用过这个解决方案。

您可以像这样进一步修改vprint,其中periphery_t 是一个简单的enum 类型:

void vprint(periphery_t target, const char *fmt, va_list argp)

    char string[200];
    if(0 < vsprintf(string,fmt,argp))
    
        switch(target)
        
            case PC: PC_send_str(string);
                break;
            case GSM: GSM_send_str(string);
                break;
            case LCD: LCD_print_str(string);
                break;
            default: LCD_print_str(string);
                break;
        
    

【讨论】:

【参考方案2】:

感谢本斯·考利克斯

我使用 tinyprintf 库,它运行良好:github link

【讨论】:

【参考方案3】:

尝试像这样劫持 _write 函数:

#define STDOUT_FILENO   1
#define STDERR_FILENO   2

int _write(int file, char *ptr, int len)

    switch (file)
    
    case STDOUT_FILENO: /*stdout*/
        // Send the string somewhere
        break;
    case STDERR_FILENO: /* stderr */
        // Send the string somewhere
        break;
    default:
        return -1;
    
    return len;

【讨论】:

我在 STM32F072 上使用这种方法。详情在这里。 electronics.stackexchange.com/questions/206113/…【参考方案4】:

只需确保在初始化代码中添加以下内容:

// Turn off buffers, so I/O occurs immediately
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
setvbuf(stderr, NULL, _IONBF, 0);

【讨论】:

它没有被缓冲。这些函数在这个实现中什么都不做。 嗯,我刚刚使用了 ST 最新的 MXCube 用于 STM32L0,我不得不添加这个。所以这可能会帮助其他人。 :-)

以上是关于如何在 STM32F10x 上重定向 printf()?的主要内容,如果未能解决你的问题,请参考以下文章

stm32f10x串口通信的写法

stm32f10x串口通信的写法

在 STM32f10x 中使用 EEPROM

STM32WB55 或 STM32F10 上的裸机编程

基于keil5新建STM32F10x寄存器版本工程

STM32F10x随笔(keil mdk)