MDK printf 、scanf 实现

9 篇文章 0 订阅

在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_semihostin g) 
//标准库需要的支持函数
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);  
}
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值