STM32 - Retarget printf to usart

STM32printf 重定向至 串口或自定义 printf 函数.

  1. 实现串口发送字符串函数。

    /**
      * @brief USART1 send data
      * @param None
      * @retval None
      * @author shizj
      * @date  2019.07.10
      */
    inline void USART1_SendData(uint8_t data)
    {
      /* Loop until the end of transmission */
      while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET)
      {
        // __nop();
      }
     
      /* Write a character to the USART */
      USART_SendData(USART1, (uint16_t)data);  
    }
     
    /**
      * @brief USART1 send data
      * @param None
      * @retval None
      * @author shizj
      * @date  2019.07.10
      */
    void USART1_SendString(uint8_t* data, uint32_t size)
    {
      for(uint32_t i = 0; i < size; ++i)
      {
        USART1_SendData(*(data + i));
      }
    }
    
  2. 自定义 printf 函数[1]

    /**
      * @brief Overridden cstd 'vprint' function
      * @param None
      * @retval None
      * @author shizj
      * @date  2019.07.10
      */
    void vprint(const char *fmt, va_list argp)
    {
      char string[200];
      if(0 < vsprintf(string, fmt, argp)) // build string
      {
        USART1_SendString((uint8_t*)string, strlen(string)); // send message via UART
      }
    }
    
    /**
      * @brief Custom my own printf function
      * @param None
      * @retval None
      * @author shizj
      * @date  2019.07.10
      */
    void UsartPrintf(const char *fmt, ...)
    {
      va_list argp;
      va_start(argp, fmt);
      vprint(fmt, argp);
      va_end(argp);
     }
    

    该方法同样出现在 STM32's official demos,官方样例很重要啊!

  3. 使用原始 printf 函数,通过重载 putc 函数实现。

    #ifdef __GNUC__
      /* With GCC, 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
    {
      USART_SendData(USART1, (uint16_t)ch);
      return ch;
    }
    

    注意:该方法需要禁用 semihost

    #pragma import(__use_no_semihosting)
    
    void _sys_exit(int x)
    {
      x = x;
    }
    
    struct __FILE
    {
      int handle;
    };
     
    FILE __stdout;
    

    否则 printf 会触发进入主机模式并尝试使用主机的 I/O 而导致程序卡住[2]

    Semihosting is a mechanism that enables code running on an ARM target to communicate and use the Input/Output facilities on a host computer that is running a debugger.

    Examples of these facilities include keyboard input, screen output, and disk I/O. For example, you can use this mechanism to enable functions in the C library, such as printf() and scanf(), to use the screen and keyboard of the host instead of having a screen and keyboard on the target system

参考链接


  1. Bence Kaulics's answer - stackoverflow ↩

  2. What is semihosting? - arm ↩

你可能感兴趣的:(STM32 - Retarget printf to usart)