MDK printf 、scanf 實現

在MDK中使用printf,需要同時重定義fputc函數和避免使用semihosting(半主機模式),標準庫函數的默認輸出設備是顯示器,要實現在串口或LCD輸出,必須重定義標準庫函數裏調用的與輸出設備相關的函數。所以需要將printf需要調用的fputc裏面的輸出指向串口(重定向)。

方法1--使用微庫:( 使用微庫的話,不會使用半主機模式。)

選擇use Microlib   https://blog.csdn.net/graduation201209/article/details/79028792

1、使用微庫(平臺式keil-MDK),點擊“魔術棒” Target標籤下有個Use MicroLIB---勾選。

2、包含頭文件:#include "stdio.h"

3、Printf重定向,修改fputc()函數的內容

#include "main.h"

#include "stm32f4xx_hal.h" // 添加的代碼如下,進行函數重構

 /* With GCC/RAISONANCE,

small printf(option LD Linker->Libraries->Small printf set to 'Yes') calls __io_putchar() */

#ifdef __GNUC__ //gcc編譯器宏定義

#define PUTCHAR_PROTOTYPE int __io_putchar(int ch) 

#else #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f) 

#endif /* __GNUC__ */ /*上面的意思是: 如果定義了宏__GNUC__,即使用GCC編譯器,則定義宏#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)

如果沒有定義宏__GNUC__,即不使用GCC編譯器,則定義宏#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f) */ //添加printf重構函數的實現部分 

PUTCHAR_PROTOTYPE {

    HAL_UART_Transmit(&huart1 , (uint8_t *)&ch, 1, 0xFFFF); 

    return ch;

}

方法2 --使用標準庫(__use_no_semihosting):   

#pragma import(__use_no_semihosting) 
//標準庫需要的支持函數
struct __FILE 
{ 
        int handle; 
}; 
FILE __stdout;    
//定義_sys_exit()以避免使用半主機模式   
_sys_exit(int x) 
{ 
        x = x; 
} 
int fputc(int ch, FILE *f)
{      
        while((USART1->SR&0X40)==0);//Ñ»··¢ËÍ,Ö±µ½·¢ËÍÍê±Ï   
                USART1->DR = (u8) ch;      
        return ch;
}

 

方法3 --完全代碼實現: 

void simp_printf(S8P fmt, ...)
{
    if (g_PanelPara.bitUartPrtEn)
    {
        U8P str;
        S32 d;
        U32 u32d;
        U8 buf[32];
        U8 u8Len = 0x00;
        U8 u8precision = 0;
        va_list ap;
        va_start(ap, fmt);

        while (*fmt)
        {
            if (*fmt != '%' && (!u8Len))
            {
                #if PS_OS == WIN
                if (*fmt == 0x0a) //enter ,newline
                {
                    UartSendByte(0x0d);
                }
                #endif
                UartSendByte(*fmt++);
                continue;
            }
            switch (*++fmt)
            {
                case '1':
                case '2':
                case '3':
                case '4':
                case '5':
                case '6':
                case '7':
                case '8':
                case '9':
                    u8Len = (*fmt) - 0x30;
                    continue;
                case '.':
                    u8precision = (*(++fmt)) - 0x30;
                    continue;
                case 'd':
                case 'D':
                    d = va_arg(ap, int);
                    itoa(d, buf, 10, u8Len, u8precision);
                    u8Len = 0;
                    for (str = buf; *str; str++)
                    {
                        UartSendByte(*str);
                    }
                    break;
                case 'x':
                case 'X':
                    u32d = va_arg(ap, unsigned int);
                    itoa(u32d, buf, 16, u8Len, u8precision);
                    u8Len = 0;
                    for (str = buf; *str; str++)
                    {
                        UartSendByte(*str);
                    }
                    break;
                /* Add other specifiers here... */
                default:
                    UartSendByte(*fmt);
                    u8Len = 0;
                    break;
            }
            fmt++;
        }
        va_end(ap);
    }
    return;   /* Dummy return value */
}
 

方法4 --標準 C 庫 實現: ( vsprintf   該函數會引入一些CodeSize的損耗 ) 

#include <stdio.h>  
#include <stdarg.h>  
void  UART_PrintStr (const uint8_t * str)  
{
   while ((*str) != 0) {  
      if (*str == '\n') {  
         UART_PrintChar(*str++);  
         UART_PrintChar('\r');  
      } else {  
         UART_PrintChar(*str++);  
      }      
   }  
}  
 
void  UART_Printf (const  void *format, ...)  
{  
    static  uint8_t  buffer[0x100];  // 設置最大緩存區大小(
    va_list vArgs;  
    va_start(vArgs, format);  
    vsprintf((char *)buffer, (char const *)format, vArgs);  
    va_end(vArgs); 
 
    UART_PrintStr((uint8_t *) buffer);  
}
發佈了58 篇原創文章 · 獲贊 31 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章