【STM32】串口收发主要程序代码分析
文章目錄
- 數據發送與接收
- 串口狀態
- 開啟串口響應中斷
- 獲取相應中斷狀態
- main.c
- usart.c
- usart.h
串口設置的一般步驟可以總結為如下幾個步驟:
下表為幾個與串口基本配置直接相關的幾個固件庫函數,這些函數和定義主要分布在 stm32f10x_usart.h 和 stm32f10x_usart.c 文件中。
| 1. 串口時鐘使能 | RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1) |
| 2. 串口復位 | void USART_DeInit(USART_TypeDef* USARTx); // 串口復位 |
| USART_DeInit(USART1); // 復位串口 1 | |
| 3. 串口參數初始化 | void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct); |
| 4. 數據發送與接收(發送) | void USART_SendData(USART_TypeDef* USARTx, uint16_t Data); |
| 4. 數據發送與接收(接收) | uint16_t USART_ReceiveData(USART_TypeDef* USARTx); |
| 5. 串口狀態 | FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG); |
| USART_GetFlagStatus(USART1, USART_FLAG_RXNE); | |
| USART_GetFlagStatus(USART1, USART_FLAG_TC); | |
| 6. 串口使能 | USART_Cmd(USART1, ENABLE); //使能串口 |
| 7. 開啟串口響應中斷 | void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState) |
| USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //開啟中斷,接收到數據中斷 | |
| USART_ITConfig(USART1,USART_IT_TC,ENABLE); | |
| 8. 獲取相應中斷狀態 | ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT) |
| USART_GetITStatus(USART1, USART_IT_TC) |
數據發送與接收
STM32 的發送與接收是通過數據寄存器 USART_DR 來實現的,這是一個雙寄存器,包含了 TDR 和 RDR。當向該寄存器寫數據的時候,串口就會自動發送,當收到數據的時候,也是存在該寄存器內。
STM32 庫函數操作 USART_DR 寄存器發送數據的函數是:void USART_SendData(USART_TypeDef* USARTx, uint16_t Data); 通過該函數向串口寄存器 USART_DR 寫入一個數據。
STM32 庫函數操作 USART_DR 寄存器讀取串口接收到的數據的函數是:uint16_t USART_ReceiveData(USART_TypeDef* USARTx); 通過該函數可以讀取串口接收到的數據。
串口狀態
串口的狀態可以通過狀態寄存器 USART_SR 讀取。狀態寄存器 USART_SR 的各位描述如下圖:
RXNE(讀數據寄存器非空)。當該位被置 1 的時候,就是提示已經有數據被接收到了,并且可以讀出來了。這時候我們要做的就是盡快去讀取 USART_DR,通過讀 USART_DR 可以將該位清零,也可以向該位寫 0,直接清除。
TC(發送完成)。當該位被置位的時候,表示 USART_DR 內的數據已經被發送完成了。如果設置了這個位的中斷, 則會產生中斷。 該位也有兩種清零方式: 1 )讀 USART_SR , 寫USART_DR。2)直接向該位寫 0。
在我們固件庫函數里面,讀取串口狀態的函數是FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG); 這里第二個入口參數非常關鍵,它是標示我們要查看串口的哪種狀態。
例如我們要判斷讀寄存器是否非空(RXNE),操作庫函數的方法為:
USART_GetFlagStatus(USART1, USART_FLAG_RXNE);
判斷發送是否完成(TC),操作庫函數的方法為:
USART_GetFlagStatus(USART1, USART_FLAG_TC);
開啟串口響應中斷
有時候我們還需要開啟串口中斷,那么我們還需要使能串口中斷,使能串口中斷的函數是:void USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState); 這個函數的第二個入口參數是標示使能串口的類型,也就是使能哪種中斷,因為串口的中斷類型有很多種。
比如我們在接收到數據的時候(RXNE讀數據寄存器非空),我們要產生中斷,那么我們開啟中斷的方法是:USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); // 開啟中斷,接收到數據中斷
要在發送數據結束的時候(TC,發送完成)產生中斷的方法是:USART_ITConfig(USART1, USART_IT_TC, ENABLE);
獲取相應中斷狀態
當我們使能了某個中斷的時候,當改中斷發生了,就會設置狀態寄存器中的某個標志位。經常我們在中斷處理函數中,要判斷該中斷是哪種中斷,使用的函數是:ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT);
比如我們使能了串口發送完成中斷,那么當中斷發生了,我們便可以在中斷處理函數中調用這個函數來判斷到底是否是串口發送完成中斷,方法是:USART_GetITStatus(USART1, USART_IT_TC); 返回值是 SET,說明是串口發送完成中斷發生。
main.c
#include "sys.h" #include "usart.h" #include "delay.h" #include "led.h" int main(void) {u8 t; u8 len;u16 times=0;delay_init(); //延時函數初始化NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //設置中斷分組uart_init(9600); //串口初始化為 9600LED_Init(); //初始化與 LED 連接的硬件接口while(1){if(USART_RX_STA&0x8000){len=USART_RX_STA&0x3fff; //得到此次接收到的數據長度printf("\r\n 您發送的消息為:\r\n");for(t=0;t<len;t++){USART1->DR=USART_RX_BUF[t];while((USART1->SR&0X40)==0); //等待發送結束}printf("\r\n\r\n");//插入換行USART_RX_STA=0;}else{times++;if(times%5000==0){printf("\r\nALIENTEK MiniSTM32 開發板 串口實驗\r\n");printf("正點原子@ALIENTEK\r\n\r\n\r\n");}if(times%200==0)printf("請輸入數據,以回車鍵結束\r\n");if(times%30==0)LED0=!LED0; //閃爍 LED,提示系統正在運行.delay_ms(10);}} }usart.c
#include "sys.h" #include "usart.h" #if EN_USART1_RX //如果使能了接收 //串口1中斷服務程序 //注意,讀取USARTx->SR能避免莫名其妙的錯誤 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.9GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9GPIO_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; //PA10GPIO_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 ;//搶占優先級3NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子優先級3NVIC_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); //初始化串口1USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //開啟串口接受中斷USART_Cmd(USART1, ENABLE); //使能串口1 }void USART1_IRQHandler(void) //串口1中斷服務程序{u8 Res;if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中斷(接收到的數據必須是0x0d 0x0a結尾){Res = USART_ReceiveData(USART1); //讀取接收到的數據if((USART_RX_STA&0x8000)==0) //接收未完成{if(USART_RX_STA&0x4000) //接收到了0x0d{if(Res!=0x0a)USART_RX_STA=0; //接收錯誤,重新開始else USART_RX_STA|=0x8000; //接收完成了 }else //還沒收到0X0D{ if(Res==0x0d)USART_RX_STA|=0x4000;else{USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;USART_RX_STA++;if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收數據錯誤,重新開始接收 } }} } } #endif查看手冊得知,配置全雙工的串口 1,那么 TX(PA9) 管腳需要配置為推挽復用輸出,RX(PA10)管腳配置為浮空輸入或者帶上拉輸入。
這里需要注意一點, 因為我們使用到了串口的中斷接收, 必須在 usart.h 里面設置 EN_USART1_RX 為 1(默認設置就是 1 的) 。該函數才會配置中斷使能,以及開啟串口 1 的 NVIC 中斷。
我們之前進行了開啟串口響應中斷,接下來還要編寫中斷服務函數。
串口 1 的中斷服務函數為 USART1_IRQHandler。之前已講過,在【STM32】SYSTEM文件夾介紹,delay,sys,usart。從之前的代碼可以看出,其初始化串口的過程,先計算得到 USART1->BRR 的內容,然后開始初始化串口引腳,接著把 USART1 復位,之后設置波特率和奇偶校驗等。
重點看一下兩句函數:
USART_SendData(USART1, USART_RX_BUF[t]); // 向串口 1 發送數據 while(USART_GetFlagStatus(USART1, USART_FLAG_TC)!=SET);第一句,其實就是發送一個字節到串口。
第二句,就是我們在發送一個數據到串口之后,要檢測這個數據是否已經被發送完成了。
USART_FLAG_TC 是宏定義的數據發送完成標識符。
usart.h
#ifndef __USART_H #define __USART_H #include "stdio.h" #include "sys.h" #define EN_USART1_RX 1 //使能(1)/禁止(0)串口1接收 #define USART_REC_LEN 200 //定義最大接收字節數 200extern u8 USART_RX_BUF[USART_REC_LEN]; //接收緩沖,最大USART_REC_LEN個字節.末字節為換行符 extern u16 USART_RX_STA; //接收狀態標記 //如果想串口中斷接收,請不要注釋以下宏定義 void uart_init(u32 bound); #endif總結
以上是生活随笔為你收集整理的【STM32】串口收发主要程序代码分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【STM32】按键检测实验主要程序代码分
- 下一篇: 【Paper】2018_Nonlinea