關於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__ */

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章