printf的封裝與實現


1 UART通信協議

1.1 UART通信的物理連接

    圖1 UART的物理連接

 

1.2 邏輯電平

用電平表示邏輯1和邏輯0,邏輯1和邏輯0用來組織計算機層面的數據。

 

1.3 電平標准

根據通訊使用的電平標准不同,串口通訊可分為 TTL標准及 RS-232 標准。

 

1.4 協議解析

通訊雙方需要約定波特率,並約定一致的數據包格式才能保證正常收發數據。

1.4.1 波特率(bps)

單位時間內,發送數據的位數。

 

1.4.2 數據格式

串口通信一般以起始位作為一幀數據傳輸的開始,以結束位表示一幀數據傳輸的結束。每一幀數據一般由起始位、數據位、停止位、校驗位組成。

起始位:由1個邏輯0的數據位表示;

停止位:由 0.5、1、1.5或 2個邏輯 1的數據位表示;

校驗位(奇校驗/偶校驗):當為奇校驗時,數據位和校驗位中,邏輯1的數據位的個數為奇數個;當為偶校驗時,數據位和校驗位中,邏輯1的數據位的個數為偶數個。

圖2 115200,8n1; send 0b01000001

 

如圖2所示,115200bps,則1/115200spb,即每傳輸一位需要1/115200秒,數據在(1/115200)/2處采樣。

 

2 printf的實現

2.1 標准庫中的printf

函數原型:

int printf(const char *format, ...)

返回值:

成功返回實際輸出字符數,失敗返回-1;

傳入參數說明:

format:     固定參數

...:       可變參數;參數的個數不確定,類型不確定;

 

2.2 可變參數的實現原理

調用子函數,函數的參數最終會以被壓入棧中,被函數使用;通過格式控制符,實現對棧中傳入參數的讀取和使用。

在標准庫中的實現:

typedef char* va_list;

#define _INTSIZEOF(n)    ((sizeof(n)+sizeof(int)-1) & ~(sizeof(int)-1))       //保證4字節對齊

#define va_start(ap, v)    (ap = (va_list)&v + _INTSIZEOF(v))               //獲取第一個變參在棧中的地址

#define va_arg(ap, t)    (*(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)))     //獲取ap所指向的數據,並把ap偏移至下一個變參的地址

#define va_end(ap)      (ap = (va_list)0)                          //使ap指向空,避免野指針

 

  

printf(format, arg1, arg2, arg3);參數在棧中的存放

 

2.3.1 對_INTSIZEOF(n)分析

棧指針總是4字節對齊的,因此使用_INTSIZEOF(n),使變量的大小是4的倍數(實際變量在棧中占據的空間)。

#define _INTSIZEOF(n) ((sizeof(n)+sizeof(int)-1) & ~(sizeof(int)-1)),對這個宏定義有一個形象的比喻:

  比方說有一個箱子可以裝4個瓶子,

  如果我有8個瓶子 ,那么我需要2個箱子;

  如果我有10個瓶子呢,我不能說我需要10除4,需要2.5個箱子吧,實際上我需要3個箱子;

  那怎么求我實際需要的箱子數呢?

   用一個容易理解的公式來求上述問題:

  設我的瓶子數為B,我需要的箱子數為C,一個箱子最多可以裝A個瓶子。

公式:C =(B+A-1)/ A (舍去余數)

  因此,((sizeof(n)+sizeof(int)-1) & ~(sizeof(int)-1))相當於C * A。

 

 

2.3.2 對va_arg(ap, t)分析

#define va_arg(ap, t)     (*(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)))

這個宏定義實現了兩個功能:

a、ap += _INTSIZEOF(t) —— 求下一個參數的指針

b、(*(t*)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t))) —— 取當前參數值,這個宏定義將返回的就是當前參數值

 

附錄:源代碼

uart.c —— 波特率:115200

 

debug_printf.c

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM