說明:該博客爲彙總性質,內容皆爲轉載
一、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__ */