一、介紹
通用同步異步收發器(USART)提供了一種靈活的方法與使用工業標准NRZ異步串行數據格式的外部設備之間進行全雙工數據交換。USART利用分數波特率發生器提供寬范圍的波特率選擇。它支持同步單向通信和半雙工單線通信,也支持LIN(局部互連網),智能卡協議和IrDA(紅外數據組織)SIR ENDEC規范,以及調制解調器(CTS/RTS)操作。它還允許多處理器通信。使用多緩沖器配置的DMA方式,可以實現高速數據通信。
二、硬件連接
- 串口之間的接線方式

- TTL與RS232的電平標准

- STM32 USART框圖

三、通信協議
-
數據包
串口通訊的數據包由發送設備通過自身的TXD接口傳輸到接收設備得RXD接口,在協議層中規定了數據包的內容,具體包括起始位、主體數據(8位或9位)、校驗位以及停止位,通訊的雙方必須將數據包的格式約定一致才能正常收發數據。

-
波特率
由於異步通信中沒有時鍾信號,所以接收雙方要約定好波特率,常見的波特率有4800、9600、115200等。 -
起始和停止信號
數據包的首尾分別是起始位和停止位,數據包的起始信號由一個邏輯0的數據位表示,停止位信號可由0.5、1、1.5、2個邏輯1的數據位表示,雙方需約定一致。 -
有效數據
有效數據規定了主題數據的長度,一般為8或9位。 -
數據校驗
在有效數據之后,有一個可選的數據校驗位。由於數據通信相對更容易受到外部干擾導致傳輸數據出現偏差,可以在傳輸過程加上校驗位來解決這個問題。校驗方法有奇校驗(odd)、偶校驗(even)、 0 校驗(space)、 1 校驗(mark)以及無(noparity)。
4、STM32 USART的寄存器
- STM32 USART的配置的寄存器,庫函數中的結構體積是基於寄存器進行封裝的,還沒學會怎么看寄存器的小伙伴可以看我之前的筆記
| 寄存器 | 偏移 | 復位值 | 描述 |
|---|---|---|---|
| USART_SR | 0x00 | 0x00C0 | 狀態寄存器 |
| USART_DR | 0x04 | 不確定 | 數據寄存器 |
| USART_BRR | 0x08 | 0x0000 | 波特比率寄存器 |
| USART_CR1 | 0x0C | 0x0000 | 控制寄存器1 |
| USART_CR2 | 0x10 | 0x0000 | 控制寄存器2 |
| USART_CR3 | 0x14 | 0x0000 | 控制寄存器3 |
| USART_GTPR | 0x18 | 0x0000 | 保護時間和預分頻寄存器 |
- 寄存器的地址映象

四、代碼分析
- 配置串口的結構體
typedef struct
{
uint32_t USART_BaudRate; // 波特率設置
uint16_t USART_WordLength; //數據位數設置
uint16_t USART_StopBits; //停止位設置
uint16_t USART_Parity; //是否奇偶校驗
uint16_t USART_Mode; //接收與發送都使能
uint16_t USART_HardwareFlowControl; //硬件流控制模式設置
} USART_InitTypeDef;
- 中斷配置結構體
typedef struct
{
uint8_t NVIC_IRQChannel; // 配置USART為中斷源
uint8_t NVIC_IRQChannelPreemptionPriority; // 搶斷優先級
uint8_t NVIC_IRQChannelSubPriority; // 子優先級
FunctionalState NVIC_IRQChannelCmd; // 使能中斷
} NVIC_InitTypeDef;
- 配置USART 的 IO引腳
將Tx配置為復用推挽輸出,將Rx配置為浮空輸入
/* USART1 使用IO端口配置 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //復用推挽輸出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空輸入
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化GPIOA
- 配置USART 的工作模式配置
/* USART1 工作模式配置 */
USART_InitStructure.USART_BaudRate = 115200; //波特率設置:115200
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //數據位數設置:8位
USART_InitStructure.USART_StopBits = USART_StopBits_1; //停止位設置:1位
USART_InitStructure.USART_Parity = USART_Parity_No ; //是否奇偶校驗:無
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //硬件流控制模式設置:沒有使能
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//接收與發送都使能
- 將Rx讀取配置為中斷讀取模式
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 設置NVIC中斷分組2:2位搶占優先級,2位響應優先級
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; // 配置USART為中斷源
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; // 搶斷優先級
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; // 子優先級
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 使能中斷
NVIC_Init(&NVIC_InitStructure); // 初始化配置NVIC
}
- 中斷函數使用
當串口接收到數據后此中斷函數會被調用,調用次函數后,會將接收到的信息有通過串口發送獲取。這里的中斷函數名已經在啟動文件中已經定義好了的,建議不做更改。

注意:有的小伙伴編寫好程序后,發現串口無法收到發送的信息,可能是這里的中斷函數名寫錯了。
void USART1_IRQHandler(void)
{
uint16_t res;
/* 判斷是否收到中斷信號 */
if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
{
res = USART_ReceiveData(USART1);
USART_SendData(USART1, res);
}
//USART_SendData(USART1,(uint16_t)0xAC);
}
五、程序源碼
- usart1.c文件
/***************************************
* 文件名 :usart1.c
* 描述 :配置USART1
* 實驗平台:MINI STM32開發板 基於STM32F103C8T6
* 硬件連接:------------------------
* | PA9 - USART1(Tx) |
* | PA10 - USART1(Rx) |
* ------------------------
**********************************************************************************/
#include "usart1.h"
#include <stdarg.h>
#include "misc.h"
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // 設置NVIC中斷分組2:2位搶占優先級,2位響應優先級
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; // 配置USART為中斷源
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; // 搶斷優先級
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; // 子優先級
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 使能中斷
NVIC_Init(&NVIC_InitStructure); // 初始化配置NVIC
}
void USART1_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
/* 使能 USART1 時鍾*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
/* USART1 使用IO端口配置 */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //復用推挽輸出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空輸入
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化GPIOA
/* USART1 工作模式配置 */
USART_InitStructure.USART_BaudRate = 115200; //波特率設置:115200
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //數據位數設置:8位
USART_InitStructure.USART_StopBits = USART_StopBits_1; //停止位設置:1位
USART_InitStructure.USART_Parity = USART_Parity_No ; //是否奇偶校驗:無
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //硬件流控制模式設置:沒有使能
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//接收與發送都使能
USART_Init(USART1, &USART_InitStructure); //初始化USART1
USART_Cmd(USART1, ENABLE);// USART1使能
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); // 開啟串口接受中斷
NVIC_Configuration();// 串口中斷優先級配置
}
void USART1_IRQHandler(void)
{
uint16_t res;
/* 判斷是否收到中斷信號 */
if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET)
{
res = USART_ReceiveData(USART1);
USART_SendData(USART1, res);
}
//USART_SendData(USART1,(uint16_t)0xAC);
}
- main.c文件
#include "stm32f10x.h"
#include "usart1.h"
int main(void)
{
SystemInit(); //配置系統時鍾為 72M
USART1_Config(); //USART1 配置
while (1)
{
}
}
五、編譯運行
-
編譯

-
運行

六、常見問題
程序下載后運行后發送數據無反饋。
解決辦法:
- 檢查中斷函數名是否正確。
- 將STM32的引腳設置為運行模式,有不知道的怎么設置為運行模式的小伙伴可以參考STM32零基礎入門教程。
