关于printf重定向打印日志方便调试的博客总结

说明:该博客为汇总性质,内容皆为转载

一、STM32在IAR中调用printf函数的一个方法
在串口都配置好的情况下,在工程的其中一个c文件中加入如下代码:
注:直接在main.c文件前面加入这段代码也行,只是这样的代码习惯不太好,代码显得太杂乱,个人不推荐。
本人习惯性的新建一个redefineprintf.c文件,在该文件中加入此段代码,注意不要忘了将该文件添加到工程中。

#include <stdio.h>
#ifdef __GNUC__

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

PUTCHAR_PROTOTYPE
{

  USART_SendData(USART1, (u16) ch);

  while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET)
  {}
  return ch;
}
  •  

之后如若编译出现identifier “FILE” is undefined,即将Options->GeneralOptions->Library Configuation中的Library选为full即可。

二、IAR中使用printf的几种方法

1、修改库文件

2、

1、option->C/C++ compiler--->defined symbols 下添加一行_DLIB_FILE_DESCRIPTOR

3、

错误 : FILE is undefined

FILE 是stdio.h 里的,所以查看这个文件

#if _DLIB_FILE_DESCRIPTOR
  typedef _Filet FILE;
#endif /* _DLIB_FILE_DESCRIPTOR */

要用FILE先要开 _DLIB_FILE_DESCRIPTOR

查了一下

stdio.h中

/* Module consistency. */
#pragma rtmodel="__dlib_file_descriptor",_STRINGIFY(_DLIB_FILE_DESCRIPTOR)

再查到DLib_Defaults.h

#ifndef _DLIB_FILE_DESCRIPTOR
#define _DLIB_FILE_DESCRIPTOR 0
#endif

把0  改为1 就可以了,先去除只读属性。

三、 搜索互联网上,关于此类问题的解决文章资料也比较丰富,不过按照其思路还是遇到了不少问题。

  首先,贴代码,大部分代码都是类似的方案,重写putchar或者fputc函数。

#ifdef  USE_IAR
#define PUTCHAR_PROTOTYPE int putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch,FILE *f)   
#endif

PUTCHAR_PROTOTYPE{
  HAL_UART_Transmit(&huart1, (char *)(&(ch)), 1, 10);
  return ch;
} 

  实际程序我定义了宏 USE_IAR,也就是实现了putchar()函数,不过实际调试,printf()函数会依次调用putchar()及fputs(),所以实际中实现其中任一一个函数即可。也就是上述的代码,即使我不定义USE_IAR,仍然是可用的。

  需要注意的一点是重写的putchar()函数必须要返回ch变量,否则只会打印首个字符一次。

  使用STM32的串口发送是阻塞的,也就是发送完一个字符程序才会继续运行发送下一个字符。

  记得配置IAR的环境 Options->General Options->Library Configuation的Library为Full。

  加入printf()函数在未使用IAR的优化功能前提下,会增加8.5KBytes左右的readonly  code memory,30Bytes的readonly  data memory,及2.4KBytes左右的readwrite data memory。

四、

今天看到这样一段代码,值摘取其中宏定义的部分,如下:

#define DEBUG(fmt,args...) printf("%s(%d)-%s -> " #fmt "\n", __FILE__, __LINE__, __FUNCTION__, ##args);

相信很多初入编程界的新人朋友们(我也是新人,汗。。。),看到这就会有疑问:

1.fmt及#fmt是什么?  2.##args是什么?

在此对这些问题做一个容易理解的解释:

1.fmt就是宏定义的第一个参数,在代码中展开时直接代入,需注意的是#fmt的意思为把fmt传进来的内容以字符串形式输出。

2.args..代表一个可变化的参数表,##args如果前面的可变参数被忽略或为空,“##”操作将使预处理器去除掉它前面的那个逗号。如果你在宏调用时,确实提供了一些可变参数,它会把这些可变参数放到逗号后面。

#include <stdio.h>
#include <stdlib.h>


#define DEBUG_PRINT(fmt,args...) printf("%s(%d)-%s -> " #fmt "\n", __FILE__, __LINE__, __FUNCTION__, ##args);


void main(void)
{
    char a = 'T', b = 'e', c = 's', d = 't';
    DEBUG_PRINT(%c%c%c%c,a,b,c,d);
}

五、标准C只支持可变参数的函数,意味着函数的参数是不固定的,例如printf()函数
的原型为:
int printf( const char *format [, argument]... );
而在GNU C中,宏也可以接受可变数目的参数,例如:
#define pr_debug(fmt,arg...) \
printk(fmt,##arg)
这里arg 表示其余的参数可以是零个或多个,这些参数以及参数之间的逗号构成
arg 的值,在宏扩展时替换arg,例如下列代码:
pr_debug("%s:%d",filename,line)
会被扩展为:
printk("%s:%d", filename, line)

六.本人的IAR工程中用的重定向的printf配置,iar for arm,华大136平台

#define CONFIG_RELASE  0

#if (CONFIG_RELASE == 0)
  #define Debug(fmt,arg...) printf(fmt,##arg)
#else
  #define Debug(fmt,arg...)
#endif
 

PUTCHAR_PROTOTYPE
{
  /* Place your implementation of fputc here */
  /* e.g. write a character to the USART */
    
    //USART_SendData(USART3, (uint8_t) ch);
    Uart_SendData(UARTCH0, (uint8_t) ch);
    
    /* Loop until transmit data register is empty */
    while (Uart_GetStatus(UARTCH0, UartTxe) == 0)//注意这里用的Txe而不是TC,TC在Uart_SendData函数中用的
    {

    }

    return ch;
}

#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__ */

猜你喜欢

转载自blog.csdn.net/shanshenyuyou/article/details/85275181
今日推荐