在嵌入式中printf 這種功能強大的函數可謂是c語言庫函數的中的一股清流!也就是太好用了吧!今天分享的例程有 stm32f4ZG 和 cc2530f256,這個兩款芯片的移植例程和移植教程!相信你看完后也可以移植到別的芯片去!
可能會因為有些版本不同配置就略有所不同!
(f4)串口1:
(f4)串口2:
下面這個是TI 的cc2530(就先跑著寄存器版本的吧,協議棧里頭配置差不太多!):
為啥要移植呢!相信學過實時操作系統的都有所了解,有個叫互斥信號量的東西!就是為了防止同一時間內有兩個寄存器(那十來個寄存器,不是指外設!)在訪問同一塊內存!這個很嚴重的,可能會導致程序死機,或者卡在了某個死循環里面!
我們所使用的 printf 就是首先通過 vsprinf 對我們傳進來的參數進行格式化,我們傳進去多少數據,他按照我們傳進來的格式,格式化后統統存放在一個buf里,如果我們定義了重定向,它就會把這個buf發送至你要發送的地方!
想象一下,如果在某個系統中有一個線程在vsprintf里面運行,突然有一個任務級別比他高的任務把它運行的時間搶了過去!而任務優先級高的任務也在printf里面使用了那個buf,那就會產生上述的問題!
那就意味著我們所使用的 printf 存在不安全問題!當然我們在系統中可以通過臨界保護區來處理,也可以通過信號量等等處理!
但是目前有一個線程安全
的函數,擺在你面前,就問你用不用?
那我們的上邊 printf_u1 它是怎么處理的呢?毫無疑問,看代碼就能知道,它是直接發送的,也就是說你傳進來的每一個參數它都會順手就發送出去(當然要看你配置),它的數據將不會存放在一個 buf 里邊,在發送。這就是他給力的地方了!
keil移植printf
首先,我們到文章的末尾獲取到源代碼后,打開 keil 軟件, 點擊 project > Options for…
就能打開一下頁面:
點擊 C/C++,選擇c99標準。到此為止編譯器配置完畢!
下面來配置代碼部分,打開頭文件為printf.h:
1,添加這個兩個文件的路徑還有頭文件,如果不懂可以搜搜!
2,點擊圖片上面的printf_ 去它定義的地方,我們要做出一定的修改。
來到這里之后我們可以看到_vsprintf 這個代碼里面最復雜的就是這一串函數了!
//我們只需要關心第一個參數即可!它是一個函數指針
static int _vsnprintf(out_fct_type out, char* buffer, const size_t maxlen, const char* format, va_list va)
//指向了一個參數為下圖的函數,返回值為void
typedef void (*out_fct_type)(char character, void* buffer, size_t idx, size_t maxlen);
我們只要修改這_putchar 里面的內容即可。參數二是我加上去的為了區分不同的串口類型,有多少個串口就的寫多少個_out_char 這樣的函數(這個是我的方法):
static inline void _out_char(char character, void* buffer, size_t idx, size_t maxlen)
{
(void)buffer; (void)idx; (void)maxlen;
if (character)
{
_putchar(character,1);
}
}
上圖是串口1的。再來看看串口2的:
int printf_u2(const char* format, ...)
{
va_list va;
va_start(va, format);
char buffer[1];
const int ret = _vsnprintf(u2_out_char, buffer, (size_t)-1, format, va);
va_end(va);
return ret;
}
//注意vsprintf第一參數
static inline void u2_out_char(char character, void* buffer, size_t idx, size_t maxlen)
{
(void)buffer; (void)idx; (void)maxlen;
if (character) {
_putchar(character,2);
}
}
而_putchar 就是我們數據最終流向的地方了!我是這樣寫的。
void _putchar(char character,char sw)
{
// send char to console etc.
if(sw == 1)
{
while((USART1- >SR&0X40)==0);//循環發送,直到發送完畢
USART1- >DR = (u8) character;
}
if(sw == 2)
{
while((USART2- >SR&0X40)==0);//循環發送,直到發送完畢
USART2- >DR = (u8) character;
}
if(sw == 3)
{
while((USART3- >SR&0X40)==0);//循環發送,直到發送完畢
USART3- >DR = (u8) character;
}
}
這個 USART3->DR 為stm32串口的寄存器!讀者可參照自己的芯片來配置!
簡單就完了!
IAR 配置方法
首先添加文件:
我在這里起名字為 C_Library。然后在添加文件:
選擇 printf.c (反正就是添加這個文件,放到哪里看你自己):
接著就是添加編譯器頭文件路徑:
在選擇第一個大框框右邊的那個:
點擊Click to add。選擇頭文件路徑所在的文件夾后 select,接著就會回到這里:
上面是配置頭文件路徑的,第一個是絕對路徑,也就是說你工程文件移動了,就回到不到了,第二個是相對路徑!選第二個吧!
接著編譯就會發現報錯了!??!
不要慌!我們首先選擇Options > General Options:
此時在編譯一次,就會發現也還是錯了!說什么沒定義。
經研究,哦,原來是stdint.h這個頭文件在for 8051 這款工具上,沒有定義64為的無符號整形,那個怎么辦??!
經發現,哦 ,原來注釋這個宏就行!
程序編譯通過!printf_u0 和stm32 配置類型,無非就是修改一下數據的流向!讀者自己研究一下吧!!
-
STM32
+關注
關注
2272文章
10923瀏覽量
357570 -
移植
+關注
關注
1文章
383瀏覽量
28193 -
函數
+關注
關注
3文章
4346瀏覽量
62971
發布評論請先 登錄
相關推薦
評論