號(hào)稱(chēng)目前網(wǎng)上嵌入式最好的printf,用起來(lái)!
網(wǎng)上最好的printf?
今天分享的例程有stm32f4ZG和cc2530f256,這個(gè)兩款芯片的移植例程和移植教程!相信你看完后也可以移植到別的芯片去!- 使用的keil版本為:5.21a
- IAR for 8051 version 為 10.10.1
(f4)串口2:
下面這個(gè)是TI 的cc2530(就先跑著寄存器版本的吧,協(xié)議棧里頭配置差不太多!):
為啥要移植呢!相信學(xué)過(guò)實(shí)時(shí)操作系統(tǒng)的都有所了解有個(gè)叫信號(hào)互斥量的東西!就是為了防止同一時(shí)間內(nèi)有兩個(gè)寄存器(那十來(lái)個(gè)寄存器,不是指外設(shè)!)在訪問(wèn)同一塊內(nèi)存!這個(gè)很?chē)?yán)重的,可能會(huì)導(dǎo)致程序死機(jī),或者卡在了某個(gè)死循環(huán)里面!我們所使用的printf就是過(guò)首先vsprinf 通過(guò)對(duì)我們傳進(jìn)來(lái)的參數(shù)進(jìn)行格式化,我們傳進(jìn)去多少數(shù)據(jù)他按照我們傳進(jìn)來(lái)的格式,格式化就統(tǒng)統(tǒng)存放在一個(gè)buf里,如果我們定義了重定向,它就會(huì)把這個(gè)buf發(fā)送至你要發(fā)送的地方!想象一下如果在某個(gè)系統(tǒng)中有一個(gè)線(xiàn)程在vsprintf里面運(yùn)行,突然有一個(gè)任務(wù)級(jí)別比他高的任務(wù)把它運(yùn)行的時(shí)間搶了過(guò)去!而任務(wù)優(yōu)先級(jí)高的任務(wù)也在printf里面使用了那個(gè)buf,那就會(huì)產(chǎn)生上述的問(wèn)題!那就意味著我們所使用的printf不安全問(wèn)題!當(dāng)然我們?cè)谙到y(tǒng)中可以通過(guò)臨界保護(hù)區(qū)來(lái)處理,也可以通過(guò)信號(hào)量等等處理!但是目前有一個(gè)
線(xiàn)程安全
的函數(shù),擺在你面前,就問(wèn)你用不用?咳咳,那我們的上邊printf_u1它是怎么處理的呢?毫無(wú)疑問(wèn)的看代碼就能知道,它是直接發(fā)送的,也就是說(shuō)你傳進(jìn)來(lái)的每一個(gè)參數(shù)它都會(huì)順手就發(fā)送出去(當(dāng)然要看你配置),它的數(shù)據(jù)將不會(huì)存放在一個(gè)buf里邊,在發(fā)送。這就是他給力的地方了!keil移植printf
首先我們到文章的末尾獲取到源代碼后,打開(kāi)keil軟件, 點(diǎn)擊?project > Options for…
就能打開(kāi)一下頁(yè)面:點(diǎn)擊 C/C ,選擇c99標(biāo)準(zhǔn)。到此為止編譯器配置完畢!下面來(lái)配置代碼部分,打開(kāi)頭文件為printf.h:
代碼可在文末獲取。1,添加這個(gè)兩個(gè)文件的路徑還有頭文件,如果不懂可以搜搜!2,點(diǎn)擊圖片上面的printf_ 去它定義的地方,我們要做出一定的修改。
來(lái)到這里之后我們可以看到_vsprintf 這個(gè)代碼里面最復(fù)雜的就是這一串函數(shù)了!
//我們只需要關(guān)心第一個(gè)參數(shù)即可!它是一個(gè)函數(shù)指針
static?int?_vsnprintf(out_fct_type?out,?char*?buffer,?const?size_t?maxlen,?const?char*?format,?va_list?va)
//指向了一個(gè)參數(shù)為下圖的函數(shù),返回值為void
typedef?void?(*out_fct_type)(char?character,?void*?buffer,?size_t?idx,?size_t?maxlen);
putchar 里面的內(nèi)容即可。參數(shù)二是我加上去的為了區(qū)分不同的串口類(lèi)型,有多少個(gè)串口就的寫(xiě)多少個(gè)_out_char 這樣的函數(shù)(這個(gè)是我的方法):
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的。再來(lái)看看串口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第一參數(shù)
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 就是我們數(shù)據(jù)最終流向的地方了!我是這樣寫(xiě)的。
void?_putchar(char?character,char?sw)
{
??//?send?char?to?console?etc.
??if(sw?==?1)
??{
????while((USART1->SR