前言:平時我們進行c語言編程的時候會經常用到printf函數進行打印輸出,來調試代碼。可是這個printf函數C庫已經幫我們實現好了,通常只需要直接調用即可,但是如果在一個新的開發平臺,如果庫沒有幫我們實現好,比如STM32開發板,那么我們怎么實現printf打印輸出呢?
首先我們來了解一下串口通信!
1、什么是串口通信?
串口通信(Serial Communication),是指外設和計算機間,通過數據信號線、地線等,按位進行傳輸數據的一種通訊方式。
串口是一種接口標準,它規定了接口的電氣標準,沒有規定接口插件電纜以及使用的協議。
2、串口通信協議
在串口通信中,常用的協議包括RS-232、RS-422和RS-485。
?RS-232:標準串口,最常用的一種串行通訊接口。有三種類型(A,B和C),它們分別采用不同的電壓來表示on和off。最被廣泛使用的是RS-232C,它將mark(on)比特的電壓定義為-3V到-12V之間,而將space(off)的電壓定義到+3V到+12V之間。傳送距離最大為約15米,最高速率為20kb/s。RS-232是為點對點(即只用一對收、發設備)通訊而設計的,其驅動器負載為3~7kΩ。所以RS-232適合本地設備之間的通信。
?RS-422:最大傳輸距離為1219米,最大傳輸速率為10Mb/s。其平衡雙絞線的長度與傳輸速率成反比,在100kb/s速率以下,才可能達到最大傳輸距離。只有在很短的距離下才能獲得最高速率傳輸。一般100米長的雙絞線上所能獲得的最大傳輸速率僅為1Mb/s。
?RS-485:從RS-422基礎上發展而來的,最大傳輸距離約為1219米,最大傳輸速率為10Mb/s。平衡雙絞線的長度與傳輸速率成反比,在100kb/s速率以下,才可能使用規定最長的電纜長度。只有在很短的距離下才能獲得最高速率傳輸。一般100米長雙絞線最大傳輸速率僅為1Mb/s。
3、同步通信?異步通信?
同步通信:是一種比特同步通信技術,要求發收雙方具有同頻同相的同步時鐘信號,只需在傳送報文的最前面附加特定的同步字符,使發收雙方建立同步,此后便在同步時鐘的控制下逐位發送/接收。如:SPI總線,I2C總線。
異步通信:指兩個互不同步的設備通過計時機制或其他技術進行數據傳輸。也就是說,雙方不需要共同的時鐘。發送方可以隨時傳輸數據,而接收方必須在信息到達時準備好接收。如:串口(USART)
4、通信方式
?單工模式(Simplex Communication):單向的數據傳輸。通信雙方中,一方為發送端,一方則為接收端。信息只能沿一個方向傳輸,使用一根傳輸線。雙方是固定的。
?半雙工模式(Half Duplex):通信使用同一根傳輸線,既可以發送數據又可以接收數據,但不能同時進行發送和接收。數據傳輸允許數據在兩個方向上傳輸,但是,在任何時刻只能由其中的一方發送數據,另一方接收數據。
?全雙工模式(Full Duplex)通信允許數據同時在兩個方向上傳輸。因此,全雙工通信是兩個單工通信方式的結合,它要求發送設備和接收設備都有獨立的接收和發送能力。在全雙工模式中,每一端都有發送器和接收器,有兩條傳輸線,信息傳輸效率高。
5、數據格式
(1)起始位:起始位必須是持續一個比特時間的“0”,標志傳輸一個字符的開始。
(2)數據位:數據位緊跟在起始位之后,是通信中的真正有效信息。數據位的位數可以由通信雙方共同約定,一般可以是5位、7位或8位。傳輸數據時先傳送字符的低位,后傳送字符的高位。
(3)奇偶校驗位:奇偶校驗位僅占一位,用于進行奇校驗或偶校驗,奇偶檢驗位不是必須有的。如果是奇校驗,需要保證傳輸的數據總共有奇數個“1”;如果是偶校驗,需要保證傳輸的數據總共有偶數個“1”
(4)停止位:停止位可以是是1位、1.5位或2位,可以由軟件設定。它一定是“1”,標志著傳輸一個字符的結束。
(5)空閑位:空閑位是指從一個字符的停止位結束到下一個字符的起始位開始,表示線路處于空閑狀態,必須由高電平來填充。
了解了串口通信的基礎知識之后,我們再來看看STM32開發板上是如何實現串口通信的,我以實現printf重定向為例來進行分析!
先看代碼:
main.c:
printf.c:
printf.h:
代碼分析:
1.串口初始化配置
學了STM串口通信之后,我們知道配置串口通信至少要配置:字長(一次傳送的數據長度),波特率(每秒傳輸的數據位數),奇偶校驗位,還有停止位。當然我在
配置過程中把他們分別設為8,115200,No ,1。
串口的配置主要與USART_InitTypeDef這個結構體有關,里面存放了控制參數成員:
其實在學習32的時候,一般如果要用到32的內設或者外設,都要進行相應的初始化,也就是相應的結構體成員進行配置,而我們本次要實現的printf重定向,也
就用到了串口,所以也要對串口進行初始化!而我是用的USART2,所以要對其進行相應的配置。
查看STM32硬件原理圖:
由原理圖可知,這個串口是支持TTL電平的,接收數據RX是接在PA3管腳上的,發送數據是接在PA2上的。由于我是要輸出到PC上的串口終端,所以PA2要
設為復用推挽輸出模式,PA3設為復用開漏輸入模式。
查看stm32f10x_it.c這個代碼可知USART2是掛接在APB1總線上的,GPIO是掛在APB2總線上的,如下所示:
所以我們在進行時鐘初始化的時候要特別注意。
2.printf重定向
其實printf重定向就是我們將printf重新定向到串口,也就是我們可以自己重寫C的庫函數,當連接器檢查到用戶編寫了與C庫函數相同的名字,優先采用
用戶編寫的函數這樣用戶就可以實現對庫的修改了。
printf函數實際是一個宏,最終調用的是 fputc(int ch,FILE *f)這個函數,所以我們需要修改這個函數。
下面我們著重分析一下fputc函數:
這個庫函數調用了兩個ST庫函數,分別是:USART_GetFlagStatus()與USART_SendData(),形參ch表示串口將要發送的數據,也就是說。當使用printf()時,它先調用fpuc()函數,然后使用ST庫的串口發送函數USART_SendData(),把數據轉移到發送數據寄存器TDR.觸發我們的串口向PC發送一個相應的數據,調用完USART_SendData()之后,
使用 while(USART_GetFlagStatus(USART2,USART_FLAG_TC) != SET)語句不停的檢查串口的數據是否發送完成的標志位TC,一直檢查到標志為“完成”,才進行下一步操作,
要注意的是USART_SendData()每次只發送一個字節的數據!
注意:由于fputc()函數的形參調用了C庫的FILE,所以在程序中加入stdio.h這個頭文件,便且在keil的編譯器的設置中勾選Use MicroLIB(使用微庫)
3.硬件連接
首先硬件上我們將USB轉串口線的TXD,RXD,GND,分別接在32開發板USART2上的RXD,TXD,GND。
由于USART2是TTL電平,所以我們用的usb轉串口線一定要是支持TTL電平的,否則串口通信不上!
4.效果圖
串口調試助手顯示:
評論
查看更多