STM32串口通信學習總結
1.概述
1.1學習目的
通過基於AWA5812平臺,學習STM32F767芯片的串口通信程序開發。本人學習串口通信比較曲折,一開始使用的芯片時STM32新開發出來的一塊STM32L496ZG的板子,這塊板子的優點時低功耗,性能在M4系列中也比較強大,滿足了公司對現有產品升級的需求,而對於我這個新入手不到一個月的職場小白來說,這塊板子時相對的不友好了,所先從資料來說除了其芯片手冊,參考手冊,數據手冊,STM32官網包括論壇就幾乎沒有其他資料,而且全是英文,曾看到論壇的人在喊說大家一起來翻譯中文版吧,一人一段,看似很令人興奮的事,可這也說明現在是別想指望由中文版的了,所以只有硬着頭皮上吧;其次STM32官方給的例程在板子上沒跑通,這就奇了怪了,例程能錯嘛?堅持了2周我果斷實現了從入門到放棄的過程。可工作要求實在沒辦法,煎熬了一週,果斷向正點原子爸爸靠攏,花了千元買了塊阿波羅F767開發板,毫無疑問,正點原子爸爸給視頻給例程還給中文參考手冊,手把手教你編程,百度以下所遇到的問題,只應證了一點,你經歷的別人都經歷過。好的話不多說,來講講我的STM32串口通信的學習歷程吧。
1.2.學習過程
接下來我將從以下幾個方面介紹我學習過程
1、物理層
2、通用同步異步收發器
3、STM32串口通信過程
4、串口配置的一般步驟及代碼分析
5、問題總結
1.3參考文檔
《STM32F767xx數據手冊》
《STM32F4開發指南 v1.1 HAL庫版本》
《RM0385參考手冊》
2.1通訊標準說明
串口通訊(Serial Communication)是一種設備間非常常用的串行通訊方式,因爲它簡單便捷,大部分電子設備都支持該通訊方式,我們在調試設備時也經常使用該通訊方式輸出調試信息。
串口通信的物理層主要在兩設備間,主要用的標準是RS-232標準,它規定了信號的用途、通訊接口及信號的電平水平。
2.2 DB9接口中的公頭及母頭的各引腳示意圖
2.3 ST-Link/v2接口說明
2.3.1 LED狀態說明:
閃爍紅色:ST-LINK/V2連接到計算機後,第一次USB枚舉過程
紅色:ST-LINK/V2與計算機已建立連接
閃爍綠色/紅色:目標板和計算機在進行數據交換
綠色:通訊完成
橙色(紅色+綠色):通訊失敗
2.3.2 STM8接口定義
仿真端口 |
連接目標板 |
功能 |
1、VDD |
MCU VCC |
連接STM8目標板的電源VCC |
2、DATA |
MCU SWIM |
連接STM8目標板的SWIM PIN |
3、GND |
GND |
連接STM8目標板的電源GND |
4、RESET |
MCU RESET PIN |
連接STM8目標板的RESET PIN |
排列示意圖如下
2.3.3 STM32接口定義
仿真器端口 |
連接目標板 |
功能 |
1. TVCC |
MCU電源VCC |
連接STM32目標板的電源VCC |
2. TVCC |
MCU電源VCC |
連接STM32目標板的電源VCC |
3. TRST |
GND |
GROUND |
4. UART-RX |
GND |
GROUND |
5. TDI |
TDI |
連接STM32的JTAG TDI |
6. UART-TX |
GND |
GROUND |
7. TMS, SWIO |
TMS, SWIO |
連接STM32的JTAG的TMS, SWD的SW IO |
8. BOOT0 |
GND |
GROUND |
9. TCK, SWCLK |
TCK, SWCLK |
連接STM32的JTAG的TCK, SWD的SW CLK |
10. SWIM |
GND |
GROUND |
11. NC |
NC |
Unused |
12. GND |
GND |
GROUND |
13. TDO |
TDO |
連接STM32的JTAG TDO |
14. SWIM-RST |
GND |
GROUND |
15. STM32-RESET |
RESET |
連接STM32目標板的RESET端口 |
16. KEY |
NC |
GROUND |
17. NC |
NC |
Unused |
18. GND |
GND |
GROUND |
19. VDD |
NC |
VDD (3.3V) |
20. GND |
GND |
GROUN |
排列示意圖
通用同步異步收發器是一個串行通信設備,可以靈活的與外部設備進行全雙工數據交換。有別與USART,還有一個UART,它在USART基礎上裁剪掉了同步通信功能,只有異步通信。簡單區分同步和異步就是看通信時需不需要對外提供時鐘輸出,我們平時用的串口通信基本都是 UART,因此在不考慮同步通信時,USART與UART沒有太大差別。
串口通信一般是以幀格式傳輸數據,即一幀一幀傳輸,每幀包含有起始信號、數據信息、停止信息,可能還有校驗信息。
USART滿足外部設備對工業標準 NRZ 異步串行數據格式的要求,並且使用了小數波特率發生器,可以提供多種波特率,使得它的應用更加廣泛。USART 支持同步單向通信和半雙工單線通信;還支持局域互連網絡 LIN、智能卡(SmartCard)協議與 lrDA(紅外線數據協會) SIR ENDEC規範。
USART支持使用 DMA,可實現高速數據通信。
以下時USART的框圖:
注:fCK 可以是 fLSE、fHSI、fPCLK、fSYS.
由框圖我將其分爲四部分來學習:
3.1 功能引腳
引腳 |
功能 |
TX |
發送數據輸出引腳。 |
RX |
接收數據輸出引腳 |
nRTS |
請求以發送,n表示低電平有效。如果使能 RTS 流控制,當USART接收器準備好接收新數據時就會將nRTS變成低電平;當接收寄存器已滿時,nRTS將被設置爲高電平。該引腳只適用於硬件流控制。 |
nCTS |
清除以發送(Clear To Send),n表示低電平有效。如果使能 CTS流控制,發送器在發送下一幀數據之前會檢測 nCTS 引腳,如果爲低電平,表示可以發送數據,如果爲高電平則在發送完當前數據幀之後停止發送。該引腳只適用於硬件流控制 |
SCLK |
發送器時鐘輸出引腳。這個引腳僅適用於同步模式。 |
3.2數據寄存器
USART說數據寄存器(USART_DR)只有低 9 位有效,並且第 9 位數據是否有效要取決於USART 控制寄存器 1(USART_CR1)的 M 位設置,當 M 位爲 0 時表示 8 位數據字長,當 M位爲 1 表示 9 位數據字長,我們一般使用 8位數據字長。
USART_DR包含了已發送的數據或者接收到的數據。USART_DR實際是包含了兩個寄存器,一個專門用於發送的可寫 TDR,一個專門用於接收的可讀 RDR。當進行發送操作時,往 USART_DR寫入數據會自動存儲在 TDR內;當進行讀取操作時,向 USART_DR讀取數據會自動提取 RDR 數據。
TDR和RDR都是介於系統總線和移位寄存器之間。串行通信是一個位一個位傳輸的,發送時把 TDR 內容轉移到發送移位寄存器,然後把移位寄存器數據每一位發送出去,接時把接收到的每一位順序保存在接收移位寄存器內然後才轉移到 RDR。
USART 支持 DMA 傳輸,可以實現高速數據傳輸。
3.3 控制器
USART有專門控制發送的發送器、控制接收的接收器,還有喚醒單元、中斷控制等。
使用USART之前需要向USART_CR1寄存器的UE位置1使能USART,UE位用於開啓供給串口的時鐘。發送或者接收數據字長可選8或9位,由USARTT_CR1的M位控制。
3.3.1發送器
當USART_CR1寄存器的發送使能位TE置1時,啓動數據發送,發送移位寄存器的數據會在TX引腳輸出,低位在前,高位在後。如果是同步模式SCLK也輸出時鐘信號。
一個字符幀發送需要3部分:起始位、數據幀、停止位。起始位是一個位週期的低電平,位週期就是每一位佔用的時間;數據幀就是我們要發送的7或8或9位數據,數據是最低位開始傳輸的;停止位是一定時間週期的高電平。
停止位的時間長短可以通過USART控制寄存器2(USART_CR2)的STOP[1:0]位控制,可選0.5個、1個、1.5個、2個停止位。默認使用1個停止位。2個停止位適用於正常USART模式、單線模式和調制解調器模式。0.5和1.5個停止位用於智能卡模式。
當發使能位TE置1之後,發送器開始會發送一個空閒幀(一個數據幀長度的高電平),接下來就可以往USART_DR寄存器寫入要發送的數據。在寫入最後一個數據後,需等待USART狀態寄存器(USART_SR)的TC位爲1,表示數據傳輸完成。USART_CR1寄存器的TCIE位置1,則產生中斷。
發送數據時,幾個重要的標誌位如下:
TE:發送使能。
TXE:發送寄存器爲空,發送單個字節時使用。
TC:發送完成,發送多個字節數據時候使用。
TXIE:發送完成中斷使能。
3.3.2 接收器
將CR1寄存器的RE位置1,使能USART接收,使得接收器在RX線開始搜索起始位。在確定起始位後,就根據RX線電平狀態把數據存放在接收移位寄存器內。接收完成後就把接收移位寄存器的數據移到PDR內,並把USART_SR寄存器的RXNE位置。如果USART_CR2寄存器的RXNEIE置1可以產生中斷。
接收數據時,幾個重要的標誌位如下:
RE: 接收使能。
RXNE:讀數據寄存器非空。
RXNEIE:發送完成中斷使能。
3.4 波特率生產
接收器和發送器(Rx和Tx)的波特率設置爲USARTx_BRR寄存器中編程的相同值。
公式1;適用於標準USART(包括SPI模式)的波特率(OVER8=0或1)
16倍過採樣時的公式爲;
8倍過採樣時的公式爲:
如何從USARTx_BRR寄存器中獲取USARTDIV呢?
如本次實驗的要通過獲取115200波特率。
16倍過採樣時:
USARTDIV=8000000/115200
BRR=USARTDIV=69d=0x45
16倍過採樣時:
USARTDIV=2*8000000/115200
USARTDIV=138.89(139d=8Bh)
BRR[3:0]=Bh>>1=1h
BRR=0x8B
3.5 總結
UART異步通信方式特點:
4、STM32串口通信過程
USAT異步通信方式引腳(STM32F767IGT6)
串口號 |
USART_RX |
USART_TX |
USART1 |
PA10(PB7) |
PA9(PB6) |
USART2 |
PA3(PD6) |
PA2(PD5) |
USART3 |
PB11(PC11)(PD9) |
PB10(PC10)(PD8) |
UART4 |
PA1(PC11) |
PA0(PC10) |
UART5 |
PD2 |
PC12 |
USART6 |
PC7(PG9) |
PC6(PG14) |
5、串口配置的一般步驟及代碼分析
步驟 |
使用代碼 |
|
RCC_APBxPeriphClockCmd(); |
GPIO時鐘使能 |
RCC_AHB1PeriphClockCmd(); |
|
GPIO_PinAFConfig(); |
|
GPIO_Init();模式設置爲GPIO_MoDe_AF |
|
USART_Init(); |
|
NVIC_Init(); |
|
USART_ITConfig(); |
|
USART_Cmd; |
|
USARTx_IRQHandler(); |
|
Void USART SentDate();//發送數據到串口 |
|
Uint16_t USART_ReceiveDate();//接收數據 |
|
FlagStatus USART_GetFlagStatus(); |
|
Void USART_ClearITPendingBit(); |
5.1代碼分析
5.1.1 USART初始化結構體
初始化結構體的定義在stm32f7xx_hal_uart.h中,初始化庫函數定義在stm32f7xx_hal_uart.c中。
5.1.2 UART底層初始化,時鐘使能,引腳配置,中斷配置
HAL_UART_MspInit()函數會被HAL_UART_Init()函數調用,在stm32f7xx_hal_uart.c中可看見一個__weak void HAL_UART_MspInit(UART_HandleTypeDef *huart)函數,weak即爲弱定義,如果其他地方定義了,則執行定義的,不會出現重定義錯誤,如果其他地方未定義,只有這個弱定義,則執行此弱定義。
5.1.3 接收器
HAL_UART_RxCpltCallback(huart)函數在使用時,就調用HAL_UART_RxCpltCallback函數進行數據的接收。數據從串口接收端接收,並在使能情況下,自動寫入接收數據寄存器。在定義中已定義USART_RX_STA標誌位,bit15位爲接收完成標誌,即接收到0x0a,bit14位爲接收到0x0d,bit13~bit0位接收到的有效字節數目,因此,本代碼主要判斷數據結尾是否到0x0d0a.
5.1.4中斷服務程序
本中斷服務程序主要處理超時處理
5.1.5 發送器
發送器位於主循環中,主要是判斷已接收到標誌位0x0a0d後,將接收寄存器的值賦給發送寄存器,而發送寄存器向串口發送數據。
4.1.6 實驗結果
6、問題總結
6.1 調試中遇到的問題
1.無論PC發什麼,stm32都沒有迴應?
調試過程:把初始化的程序與網上衆多程序員寫的初始化程序做了比較,沒有發現不一樣的地方。覺得可能是是程序的問題,因此dubug了一下,發現在我設置的接收數組中,是有值寫入的,也就是接收寄存器能夠接收到PC端發送的值,按程序的運行,接下來應該是將接收數組賦值給發送寄存器,可問題就在於發送寄存器中沒有收到賦值。檢查程序後發現賦值處是有問題的,於是進行修改
調試過程:在確定了軟件上能過接收到PC端發來的信號,並且能發送出去的前提下,
PC窗口卻出現亂碼現象,判斷軟件上是沒有問題的,於是用示波器去測量硬件數據,發現PC接收端與STM32F767芯片之間的一塊控壓芯片存在虛焊。發現問題不要一味認爲是軟件問題,需要軟硬件兼顧的區考慮。
3.stm32發回來的內容與PC發送的不一致?
調試過程:用示波器觀測數據,發現收發的數據都是正確的,但電平寬度不一致,由此得知兩者的波特率不一致,進一步計算得知是stm32的串口波特率不對,後發現程序默認時鐘用的MSI內部時鐘,而波特率固定的四個時鐘中沒有MSI,因此修改使用外部高速時鐘HSE,其時鐘頻率爲8MHz。
需說明的是,配置時鐘需要了解時鐘樹如何區配置,建議利用STM32CubeMX來學習,如果不會編寫其時鐘代碼,可用其生成程序。