開發板的應用中,有一項重要的功能是通訊,常見的協定有 I2C、SPI 等,還有一個常用的協定是 UART 或 USART,也就是常見的 RSR-232、RS-422、RS-485 等這些介面,本篇文章就來探討一下這個協定。
USART 使用同步通訊時,比 UART 多一條時鐘線,當 USART 用於非同步通訊時,就跟 UART 一樣。所謂的同步是指發送方發送完一組數據後,需要等待接受方應答,才能再發下一組通訊。而非同步就是發送方發送一組數據後,不需等待接受方應答,就繼續發送下一組數據。傳送的時候是雙方約定一樣的傳送速度,就可以互傳資料。這個速度的設定稱做「鲍率」(Baud Rate或稱波特率),表示一秒鐘內傳輸多少位位元數,單位是 BPS(Byte Per Second)。
另一個要瞭解的知識是:「串列通訊」每次傳送一個位元,且連續傳送,「並列通訊」一次同時傳送兩個位元以上的數據,透過多條導線進行傳輸。傳輸的方式可以是以下三種模式:
以上這些是串列/並列通訊的基本常識,以下將探討 STM32 如何使用 USART/UART 進行通訊。
USART 透過 3 個引腳與其他設備連接在一起,任何 USART 雙向通信至少需要 2 個引腳:
使用 USART 接收資料時,有兩種方式:
還有另一種,是將要傳送的資料直接放到記憶體,透過 DMA(Direct Memory Access) 隨時讓 USART 取得資料傳送或接收。之後再來研究如何使用 DMA 的方法存取資料。
STM32 有三個 USART 及兩個 UART 串列通訊,其引腳如下表:
✈ void USART_DeInit(USART_TypeDef *USARTx)
將 USARTx 設定為預設值。
- 引數 USARTx,是 USART 的編號,x 可以是 1~5。
✈ void USART_Init(USART_TypeDef *USARTx, USART_InitTypeDef *USART_InitStruct)
對 USART 進行初始化,定義在標準函式庫的 stm32f10x_usart.h 文件中,需先定義並填入一個 USART_InitTypeDef 類型的結構體。
- 引數 USARTx,是 USART 的編號,x 可以是 1~5。
✈ void USART_Cmd(USART_TypeDef *USARTx, FunctionalState NewState)
設定 USART 外設啟用或停用。
- 引數 USARTx,是 USART 的編號,x 可以是 1~5,用來選擇 USART。
- 引數 NewState:設定 USARTx 中斷的啟用 ENABLE 或停用 DISABLE。
✈ void USART_SendData(USART_TypeDef *USARTx, uint16_t Data)
由 USARTx 傳送資料。
- 引數 USARTx,是 USART 的編號,x 可以是 1~5。
- 引數 Data 是傳送的資料。
✈ uint16_t USART_ReceiveData(USART_TypeDef *USARTx)
傳回 USART 接收到的最新的數據。
- 引數 USARTx,是 USART 的編號,x 可以是 1~5。
- 傳回值:接收的資料
✈ void USART_ITConfig(USART_TypeDef *USARTx, uint16_t USART_IT, FunctionalState NewState)
設定 USART 中斷型別的啟用或停用。
- 引數 USARTx,是 USART 的編號,x 可以是 1~5。
- 引數 USART_IT,可以是以下值。
USART_IT 串列埠中斷的型別很多種,需要依據不同的情境進行選擇,以串列埠接收資料時,產生中斷為例:
✈ ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT); - 引數 USARTx,是 USART 的編號,x 可以是 1~5。
- 引數 USART_IT 的值請參考 USART_ITConfig() 函式中的 USART_IT。
- 傳回值:USART_IT 的最新狀態:SET 或者 RESET。
✈ FlagStatus USART_GetFlagStatus(USART_TypeDef *USARTx, uint16_t USART_FLAG);
檢查指定的 USART 標誌位。
- 引數 USARTx,是 USART 的編號,x 可以是 1~5,用來選擇 USART。
- 引數 USART_FLAG:待檢查的 USART 標誌位,可以是以下值。
✈ void USART_ClearFlag(USART_TypeDef *USARTx, uint16_t USART_FLAG)
清除指定的 USARTx 標誌位。
- 引數 USARTx,是 USART 的編號,x 可以是 1~5。
- 引數 USART_FLAG,可以是以下幾種標誌位:
✈ void USART_ClearITPendingBit(USART_TypeDef *USARTx, uint16_t USART_IT) 清除 USARTx 的中斷位元狀態。 - 引數 USARTx,是 USART 的編號,x 可以是 1~5。
- 引數 USART_IT,可以是以下幾種標誌位:
以上這些是較為常用的函式,以下就來探討撰寫串列通訊的程序與方法:
(1) 開啟 USART 和 GPIO 時鐘
STM32F103C8 晶片中有 5 個 UART(3 個 USART, 2 個 UART) 通訊資源,其中 USART1 掛載在 APB1 匯流排上,USART2 ~ USART15 掛載在 APB2 匯流排上,使用 UART 時,需要分別對應匯流排上的 UART 以及 GPIO 的時鐘即可。
(2) 設定 GPIO
將 USART Tx 的 GPIO 設定為推輓復用模式(GPIO_Mode_AF_PP),將 Rx 的 GPIO 設定為浮空輸入模式(GPIO_Mode_IN_FLOATING),GPIO_Speed 切換速率設置為 GPIO_Speed_10MHz,使用 GPIO_InitTypeDef 定義 GPIO 結構體,最後使用 GPIO_Init() 啟用 I/O 口。
(3) 使用 USART_Init() 函式進行初始化,並啟用中斷
使用 USART_Init() 進行初始化。需先使用 USART_InitTypeDef 定義一個結構體型別:
(4) 設定 NVIC 中斷優先順序,並進行初始化
(5) 編寫串列埠中斷服務函數
使用串列埠開啟了中斷功能,就需要在中斷服務函數(USARTx_IRQHandler)判斷由串列埠產生的中斷是那種型別,然後實現相應的功能。判斷中斷型別,呼叫庫函數: 在 NVIC 的配置中,主要是 USART1_IRQChannel 的配置。
發送數據用 USART_SendData() 函數,接收數據用 USART_ReceiveData()函數。
(6) 使用終端軟體發送/接收數據
在電腦端要執行串列埠通訊程式,我用的免費軟體,名為:Serial Port Utility,可以到 這裡 下載程式。下載下來解壓縮放在一個目錄內就可使用。
這裡要注意編寫好的程式是透過 ST-Link 下載到 STM32,下載完成後要拔出 ST-Link,改插入 USB 轉 TTL 序列傳輸的 CP2102。每改一次程式,檢視結果就要差拔一次,有點麻煩。
下一篇:STM32(20):USART串列通訊(下)
- UART 通用非同步收發傳輸 (Universal Asynchronous Receiver/Transmitter)
- USART 通用同步/非同步接收/發送 (Universal Synchronous/Asynchronous Receiver/Transmitter)
USART 使用同步通訊時,比 UART 多一條時鐘線,當 USART 用於非同步通訊時,就跟 UART 一樣。所謂的同步是指發送方發送完一組數據後,需要等待接受方應答,才能再發下一組通訊。而非同步就是發送方發送一組數據後,不需等待接受方應答,就繼續發送下一組數據。傳送的時候是雙方約定一樣的傳送速度,就可以互傳資料。這個速度的設定稱做「鲍率」(Baud Rate或稱波特率),表示一秒鐘內傳輸多少位位元數,單位是 BPS(Byte Per Second)。
另一個要瞭解的知識是:「串列通訊」每次傳送一個位元,且連續傳送,「並列通訊」一次同時傳送兩個位元以上的數據,透過多條導線進行傳輸。傳輸的方式可以是以下三種模式:
- 單工(Simplex):只能單向傳送數據。
- 半雙工(Half duplex):某一個時刻只能發送或接收的雙向傳送數據。
- 全雙工(Full duplex):可以同時進行接收和發送數據。
以上這些是串列/並列通訊的基本常識,以下將探討 STM32 如何使用 USART/UART 進行通訊。
USART 透過 3 個引腳與其他設備連接在一起,任何 USART 雙向通信至少需要 2 個引腳:
- 接受數據輸入(RX): 接受數據串行輸入。
- 發送數據輸出(TX): 發送數據輸出。
使用 USART 接收資料時,有兩種方式:
- 輪詢(polling):是 CPU 一直問 UART 的 RXNE 旗標是否有新資料?這個方法效率太低且占用大量 CPU 運算資源,如果傳送資料量大,如未讀取 USART Data 暫存器的資料,又進來新資料時,會產生 Overrun 的錯誤。一般是用所謂的 Blocking mode (阻斷模式),就是傳送/接收資料時不被中斷,一直到傳送/接收完成為止。
- 中斷(interrupt):開啟 USART 的 RXNE 中斷,當接收到新資料時跳到中斷服務程式,這個方法比較不佔用 CPU 資源。使用所謂的 non-blocking mode 模式(非阻斷模式)。
還有另一種,是將要傳送的資料直接放到記憶體,透過 DMA(Direct Memory Access) 隨時讓 USART 取得資料傳送或接收。之後再來研究如何使用 DMA 的方法存取資料。
STM32 有三個 USART 及兩個 UART 串列通訊,其引腳如下表:
APB2總線 | APB1總線 | ||||
---|---|---|---|---|---|
引腳 | USART1 | USART2 | USART3 | UART4 | UART5 |
TX | PA9 | PA2 | PB10 | PC10 | PC12 |
RX | PA10 | PA3 | PB11 | PC11 | PD2 |
[常用的 USART 函式]
STM32F10x 要設定使用 USART 時 ,需要將 USART 函數庫 stm32f10x_usart.c 和 stm32f10x_usart.h 兩個檔案包含進來。常用到的幾個函式說明如下:✈ void USART_DeInit(USART_TypeDef *USARTx)
將 USARTx 設定為預設值。
- 引數 USARTx,是 USART 的編號,x 可以是 1~5。
✈ void USART_Init(USART_TypeDef *USARTx, USART_InitTypeDef *USART_InitStruct)
對 USART 進行初始化,定義在標準函式庫的 stm32f10x_usart.h 文件中,需先定義並填入一個 USART_InitTypeDef 類型的結構體。
- 引數 USARTx,是 USART 的編號,x 可以是 1~5。
USART_InitTypeDef USART_InitStructure;USART_InitStructure 這個結構體有以下 6 個引數:
引數名稱 | 說明 |
---|---|
USART_InitStructure.USART_BaudRate = xxx; | BuadRate 鲍率,xxx 可以是 9600、38400、115200...等。 |
USART_InitStructure.USART_WordLength = xxx; | 表示發送或接收到的數據位數。xxx 可以是: ▸USART_WordLength_8b:8位元 ▸USART_WordLength_9b:9位元 |
USART_InitStructure.USART_StopBits = xxx; | 定義發送的停止位數目。xxx 可以是以下之一: ▸USART_StopBits_1:在幀結尾傳輸 1 個停止位 ▸USART_StopBits_0.5 :在幀結尾傳輸 0.5 個停止位 ▸USART_StopBits_2:在幀結尾傳輸 2 個停止位 ▸USART_StopBits_1.5:在幀結尾傳輸 1.5 個停止位。 |
USART_InitStructure.USART_Parity = xxx; | ▸校驗位元,xxx 可以是以下之一: ▸USART_Parity_NO(奇偶模式) ▸USART_Parity_Even(偶模式) ▸USART_Parity_Odd(奇模式) |
USART_InitStructure.USART_Mode = xxx; | 使能或失能發送和接收模式。xxx 可以是以下之一: ▸USART_Mode_Rx 使用接收 ▸USART_Mode_Tx:使用發送 |
USART_InitStructure.USART_HardwareFlowControl = xxx; | 硬體流控制,只有在硬體流模式下有效。xxx 可以是以下模式之一: ▸USART_HardwareFlowControl_None:無硬件流控制 ▸USART_HardwareFlowControl_RTS:發送請求 RTS ▸USART_HardwareFlowControl_CTS:清除發送CTS ▸USART_HardwareFlowControl_RTS_CTS:使用 RTS 和 CTS |
✈ void USART_Cmd(USART_TypeDef *USARTx, FunctionalState NewState)
設定 USART 外設啟用或停用。
- 引數 USARTx,是 USART 的編號,x 可以是 1~5,用來選擇 USART。
- 引數 NewState:設定 USARTx 中斷的啟用 ENABLE 或停用 DISABLE。
✈ void USART_SendData(USART_TypeDef *USARTx, uint16_t Data)
由 USARTx 傳送資料。
- 引數 USARTx,是 USART 的編號,x 可以是 1~5。
- 引數 Data 是傳送的資料。
✈ uint16_t USART_ReceiveData(USART_TypeDef *USARTx)
傳回 USART 接收到的最新的數據。
- 引數 USARTx,是 USART 的編號,x 可以是 1~5。
- 傳回值:接收的資料
✈ void USART_ITConfig(USART_TypeDef *USARTx, uint16_t USART_IT, FunctionalState NewState)
設定 USART 中斷型別的啟用或停用。
- 引數 USARTx,是 USART 的編號,x 可以是 1~5。
- 引數 USART_IT,可以是以下值。
- USART_IT_CTS: CTS 變更的中斷 (不適用 UART4 及 UART5)
- USART_IT_LBD: LIN 停止偵測的中斷
- USART_IT_TXE: 傳送的資料暫存器已空的中斷
- USART_IT_TC: 傳輸完成的中斷
- USART_IT_RXNE: 接收資料暫存器不是空的中斷
- USART_IT_IDLE: 空閒總線偵測的中斷
- USART_IT_PE: 奇偶錯誤的中斷
- USART_IT_ERR: Frame、noise 及 overrun 錯誤的中斷。
USART_IT 串列埠中斷的型別很多種,需要依據不同的情境進行選擇,以串列埠接收資料時,產生中斷為例:
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);以串列埠傳送資料為例:
USART_ITConfig(USART1, USART_IT_TC, ENABLE);
✈ ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT); - 引數 USARTx,是 USART 的編號,x 可以是 1~5。
- 引數 USART_IT 的值請參考 USART_ITConfig() 函式中的 USART_IT。
- 傳回值:USART_IT 的最新狀態:SET 或者 RESET。
✈ FlagStatus USART_GetFlagStatus(USART_TypeDef *USARTx, uint16_t USART_FLAG);
檢查指定的 USART 標誌位。
- 引數 USARTx,是 USART 的編號,x 可以是 1~5,用來選擇 USART。
- 引數 USART_FLAG:待檢查的 USART 標誌位,可以是以下值。
- USART_FLAG_CTS: CTS 變更的標誌位(不適用 UART4 及 UART5)
- USART_FLAG_LBD: LIN 停止偵測的標誌位
- USART_FLAG_TXE: 傳送的資料暫存器已空的標誌位
- USART_FLAG_TC: 傳輸完成的標誌位
- USART_FLAG_RXNE: 接收資料暫存器不是空的標誌位
- USART_FLAG_IDLE: 空閒匯流排偵測的標誌位
- USART_FLAG_ORE: OverRun 錯誤的標誌位
- USART_FLAG_NE: noise 錯誤的標誌位
- USART_FLAG_FE: Framing 錯誤的標誌位
- USART_FLAG_PE: 奇偶錯誤的標誌位
✈ void USART_ClearFlag(USART_TypeDef *USARTx, uint16_t USART_FLAG)
清除指定的 USARTx 標誌位。
- 引數 USARTx,是 USART 的編號,x 可以是 1~5。
- 引數 USART_FLAG,可以是以下幾種標誌位:
- USART_FLAG_CTS: CTS 變更的標誌位(不適用 UART4 及 UART5)
- USART_FLAG_LBD: LIN 停止偵測的標誌位
- USART_FLAG_TC: 傳輸完成的標誌位
- USART_FLAG_RXNE: 接收資料暫存器不是空的標誌位
✈ void USART_ClearITPendingBit(USART_TypeDef *USARTx, uint16_t USART_IT) 清除 USARTx 的中斷位元狀態。 - 引數 USARTx,是 USART 的編號,x 可以是 1~5。
- 引數 USART_IT,可以是以下幾種標誌位:
- USART_IT_CTS: CTS 變更的中斷 (不適用 UART4 及 UART5)
- USART_IT_LBD: LIN 停止偵測的中斷
- USART_IT_TC: 傳輸完成的中斷
- USART_IT_RXNE: 接收資料暫存器不是空的中斷
以上這些是較為常用的函式,以下就來探討撰寫串列通訊的程序與方法:
[串列埠通訊設定步驟]
要編寫串列通訊程式,可按照如下步驟進行設定:(1) 開啟 USART 和 GPIO 時鐘
STM32F103C8 晶片中有 5 個 UART(3 個 USART, 2 個 UART) 通訊資源,其中 USART1 掛載在 APB1 匯流排上,USART2 ~ USART15 掛載在 APB2 匯流排上,使用 UART 時,需要分別對應匯流排上的 UART 以及 GPIO 的時鐘即可。
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
(2) 設定 GPIO
將 USART Tx 的 GPIO 設定為推輓復用模式(GPIO_Mode_AF_PP),將 Rx 的 GPIO 設定為浮空輸入模式(GPIO_Mode_IN_FLOATING),GPIO_Speed 切換速率設置為 GPIO_Speed_10MHz,使用 GPIO_InitTypeDef 定義 GPIO 結構體,最後使用 GPIO_Init() 啟用 I/O 口。
// GPIO 初始化 USART1_TX PA9 GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOA, &GPIO_InitStructure); // GPIO初始化USART1_RX PA10 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &GPIO_InitStructure);
(3) 使用 USART_Init() 函式進行初始化,並啟用中斷
使用 USART_Init() 進行初始化。需先使用 USART_InitTypeDef 定義一個結構體型別:
//USART 初始化設置 USART_InitStructure.USART_BaudRate = 115200; //一般設定爲 9600 或 115200; USART_InitStructure.USART_WordLength = USART_WordLength_8b; // 資料長度 = 8 Bits USART_InitStructure.USART_StopBits = USART_StopBits_1; // 1 個停止位 USART_InitStructure.USART_Parity = USART_Parity_No; //無奇偶校驗位 USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //無硬體流控(即禁止 RTS 和 CTS ) USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收發模式 USART_Init(USART1, &USART_InitStructure); //初始化串口啟用 USART1 中斷:
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //開啓 ENABLE 中斷 USART_Cmd(USART1, ENABLE); // Enable USART
(4) 設定 NVIC 中斷優先順序,並進行初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //設置NVIC中斷分組2 // USART1外設中斷配置 NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1 ; //主優先級1 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0 ; //次優先級0 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //啟用IRQ通道 NVIC_Init(& NVIC_InitStructure);
(5) 編寫串列埠中斷服務函數
使用串列埠開啟了中斷功能,就需要在中斷服務函數(USARTx_IRQHandler)判斷由串列埠產生的中斷是那種型別,然後實現相應的功能。判斷中斷型別,呼叫庫函數: 在 NVIC 的配置中,主要是 USART1_IRQChannel 的配置。
發送數據用 USART_SendData() 函數,接收數據用 USART_ReceiveData()函數。
void USART1_IRQHandler(void) { if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) { USART_SendData(USART1, USART_ReceiveData(USART1)); USART_ClearITPendingBit(USART1, USART_IT_RXNE); while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); } }
(6) 使用終端軟體發送/接收數據
在電腦端要執行串列埠通訊程式,我用的免費軟體,名為:Serial Port Utility,可以到 這裡 下載程式。下載下來解壓縮放在一個目錄內就可使用。
這裡要注意編寫好的程式是透過 ST-Link 下載到 STM32,下載完成後要拔出 ST-Link,改插入 USB 轉 TTL 序列傳輸的 CP2102。每改一次程式,檢視結果就要差拔一次,有點麻煩。
下一篇:STM32(20):USART串列通訊(下)
張貼留言