1、串口通信背景知識
1.1、 設備之間的通信方式
並行通信 串行通信
傳輸原理 數據各個位同時傳輸 數據按位順序傳輸
優點 速度快 佔用引腳資源少
缺點 佔用引腳資源多 速度相對較慢
1.2、 串行通信分類
1.2.1、按照通信方式,分為:
同步通信:帶時鐘同步信號傳輸。比如:SPI,I²C通信接口
異步通信:不帶時鐘同步信號。比如:UART(通用異步收發器),單總線
1.2.2、按照數據傳送方向,分為:
單工:數據傳輸只支持數據在一個方向上傳輸;
半雙工:允許數據在兩個方向上傳輸。但是,在某一時刻,只允許數據在一個方向上傳輸,它實際上是一種切換方向的單工通信;它不需要獨立的接收端和發送端,兩者可以合併一起使用一個埠。
全雙工:允許數據同時在兩個方向上傳輸。因此,全雙工通信是兩個單工通信方式的結合,需要獨立的接收端和發送端。
1.3、常見的串行通信接口
2、STM32的串口通信基礎
2.1、STM32的串口通信接口有兩種,分別是:
UART(通用異步收發器)、
USART(通用同步異步收發器)、
對於大容量STM32F10x系列晶片,分別有3個USART和2個UART。
2.2、UART引腳連接方法
① 單片機連接單片機
RXD:數據輸入引腳,數據接受
TXD"數據發送引腳,數據發送
對於兩個晶片之間的連接,兩個晶片GND共地,同時TXD和RXD交叉連接。這裡的交叉連接的意思就是,晶片1的RxD連接晶片2的TXD,晶片2的RXD連接晶片1的TXD。這樣,兩個晶片之間就可以進行TTL電平通信了
② 單片機連接PC
若是晶片與PC機(或上位機)相連,除了共地之外,就不能這樣直接交叉連接了。儘管PC機和晶片都有TXD和RXD引腳,但是通常PC機(或上位機)通常使用的都是RS232接口,因此不能直接交叉連接。RS232接口是9針(或引腳),通常是TxD和RxD經過電平轉換得到的。而單片機採用的是 TTL電平,所以需要 連接一個RS232轉換器 將TTL電平轉換成 PC可以識別的RS232電平,再交叉連接。
經過電平轉換後,晶片串口和rs232的電平標準是不一樣的:
單片機的電平標準(TTL電平):+5V表示1,0V表示0;
Rs232的電平標準:+15/+13 V表示1,-15/-13表示0。
RS-232通訊協議標準串口的設備間通訊結構圖如下:
所以單片機串口與PC串口通信就應該遵循下面的連接方式:
在單片機串口與上位機給出的rs232口之間,通過電平轉換電路(如下面圖中的Max232晶片) 實現TTL電平與RS232電平之間的轉換。
2.3、UART異步通信特點
全雙工異步通信;
分數波特率發生器系統,提供精確的波特率。發送和接受共用的可編程波特率,最高可達4.5Mbits/s;
可編程的數據字長度(8位或者9位);
可配置的停止位(支持1或者2位停止位);
可配置的使用DMA多緩衝器通信;
單獨的發送器和接收器使能位;
檢測標誌:① 接受緩衝器 ②發送緩衝器空 ③傳輸結束標誌;
多個帶標誌的中斷源,觸發中斷;
其他:校驗控制,四個錯誤檢測標誌。
2.4、STM32串口異步通信需要定義的參數
STM32異步通信參數:
①起始位
②數據位(8位或者9位)
③奇偶校驗位(第9位)
④停止位(1,15,2位)
⑤波特率設置
(奇偶校驗位分為奇校驗和偶校驗兩種,是一種簡單的數據誤碼校驗方法。奇校驗是指每幀數據中,包括數據位和奇偶校驗位的全部9個位中1的個數必須為奇數;偶校驗是指每幀數據中,包括數據位和奇偶校驗位的全部9個位中1的個數必須為偶數。
校驗方法除了奇校驗(odd)、偶校驗(even)之外,還可以有:0 校驗(space)、1 校驗(mark)以及無校驗(noparity)。 0/1校驗:不管有效數據中的內容是什麼,校驗位總為0或者1)
UART串口通信的數據包以幀為單位,常用的幀結構為:1位起始位+8位數據位+1位奇偶校驗位(可選)+1位停止位。如下圖所示
2.5、 UART(USART)框圖
任何USART雙向通信至少需要兩個腳:接收數據輸入(RX)和發送數據輸出(TX)。
RX:接收數據串行輸。通過過採樣技術來區別數據和噪音,從而恢復數據。
TX:發送數據輸出。當發送器被禁止時,輸出引腳恢復到它的I/O埠配置。當發送器被激活,並且不發送數據時,TX引腳處於高電平。在單線和智慧卡模式裡,此I/O口被同時用於數據的發送和接收。
● 總線在發送或接收前應處於空閒狀態
● 一個起始位
● 一個數據字(8或9位),最低有效位在前
● 0.5,1.5,2個的停止位,由此表明數據幀的結束
● 使用分數波特率發生器 —— 12位整數和4位小數的表示方法。
● 一個狀態寄存器(USART_SR)
● 數據寄存器(USART_DR)
● 一個波特率寄存器(USART_BRR),12位的整數和4位小數
● 一個智慧卡模式下的保護時間寄存器(USART_GTPR)
2.6、 串口通信過程
① 數據接收過程
外部設備將數據發送到 串行輸入移位寄存器,串行輸入移位寄存器在將數據傳送到輸入數據緩衝器,MCU在從輸入數據緩衝器中讀出數據
② 數據發送過程
MCU將要發送的數據寫入輸出數據緩衝器,輸出數據緩衝器在將數據寫入串行輸出移位寄存器,串行移位寄存器在將數據輸出到外部設備
3、 串行通信的編程
3.1、串口通信的相關寄存器
3.1.1、 USART_SR狀態寄存器
FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);
3.1.2、 USART_DR數據寄存器
void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);
uint16_t USART_ReceiveData(USART_TypeDef* USARTx);
3.1.3、 USART_BRR波特率寄存器
void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct);
波特率計算方法:
3.2、 串口操作相關庫函數(省略入口函數):
**void USART_Init();** //串口初始化:波特率,數據字長,奇偶校驗,硬體流控以及收發使能
**void USART_Cmd();**//使能串口
**void USART_ITConfig();**//使能相關中斷
**void USART_SendData();**//發送數據到串口,DR
**uint16_t USART_ReceiveData();**//接受數據,從DR讀取接受到的數據
**FlagStatus USART_GetFlagStatus();**//獲取狀態標誌位
**void USART_ClearFlag();**//清除狀態標誌位
**ITStatus USART_GetITStatus();**//獲取中斷狀態標誌位
**void USART_ClearITPendingBit();**//清除中斷狀態標誌位
3.3、 串口配置一般步驟:
串口時鐘使能,GPIO時鐘使能:RCC_APB2PeriphClockCmd();
串口復位:USART_DeInit(); 這一步不是必須的
GPIO埠模式設置:GPIO_Init(); 模式設置為GPIO_Mode_AF_PP
串口參數初始化:USART_Init();
開啟中斷並且初始化NVIC(如果需要開啟中斷才需要這個步驟) NVIC_Init();
USART_ITConfig();
使能串口:USART_Cmd();
編寫中斷處理函數:USARTx_IRQHandler();
串口數據收發:
void USART_SendData();//發送數據到串口,DR
uint16_t USART_ReceiveData();//接受數據,從DR讀取接受到的數據
串口傳輸狀態獲取:
FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);
void USART_ClearITPendingBit(USART_TypeDef* USARTx, uint16_t USART_IT);
4、 串口編程
(參照3.2、3.3的章節,其中有關於代碼配置的步驟)
usart.c
//串口1中斷服務程序
u8 USART_RX_BUF[USART_REC_LEN]; //接收緩衝,最大USART_REC_LEN個字節.
//接收狀態
//bit15, 接收完成標誌
//bit14, 接收到0x0d
//bit13~0, 接收到的有效字節數目
u16 USART_RX_STA=0; //接收狀態標記
void uart_init(u32 bound)
{
//GPIO埠設置
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USART1,GPIOA時鐘
//USART1_TX GPIOA.9
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //復用推輓輸出
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9
//USART1_RX GPIOA.10初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空輸入
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10
//Usart1 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//搶佔優先級3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子優先級3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根據指定的參數初始化VIC寄存器
//USART 初始化設置
USART_InitStructure.USART_BaudRate = bound;//串口波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字長為8位數據格式
USART_InitStructure.USART_StopBits = USART_StopBits_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); //初始化串口1
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//開啟串口接受中斷
USART_Cmd(USART1, ENABLE); //使能串口1
}
void USART1_IRQHandler(void) //串口1中斷服務程序
{
u8 Res;
#if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS為真,則需要支持OS.
OSIntEnter();
[
1] [
2]