中斷接收簡介
回顧之前的代碼
之前的代碼是 等待標志位RXNE位為1才有數據 進而讀取數據存放在變量c中 再根據c變量的數據是為0還是為1進而編寫燈亮滅的代碼 if語句
但這樣的代碼明顯不符合裸機多任務的編程模型 因為在while中為進程 進程執行的時間不能大于5ms 但是while(RXNE==0)這條語句的執行時間是由發送數據的一方決定的 當發送方1s后發送數據 這條語句就執行1s 完全超出了裸機多任務模型的時間
右邊的代碼則是使用了中斷 數據通過RX引腳進入 當狀態寄存器SR 的RXNE標志位由0變為1就通過USART1觸發一次中斷 傳遞到NVIC進而執行中斷函數
配置中斷源
產生電平型的中斷源
USART產生的是電平型的中斷 當標志位由0變為1就產生中斷 在SR狀態寄存器中 每一個標志位都可以觸發中斷 都可以觸發7個電平型的中斷源
中斷共用
這七個標志位共用一個中斷源(節省中斷源) 在stm32中NVIC是管理中斷源的 當這七個標志位當中只要有一個為1通過這個或門就會觸發中斷源 傳遞到NVIC中 那如果產生了中斷 那到底是那個標志位為1觸發了中斷呢? 我們去查詢sr寄存器即可 if 語句判斷到底是那個標志位觸發了中斷 (可能是一個 也可能是多個)
中斷屏蔽
中斷傳輸到NVIC過程中有一個開關 閉合就能通過中斷 打開就屏蔽了中斷信號 那我們如何實現屏蔽一個標志位產生的中斷呢? 就是左下角的結構 將中斷標志位和中斷使能位通過一個與門相互連接 當中斷使能位為0不管中斷標志位為1還是為0都無法通過或門觸發中斷源 當中斷使能位為1就等于閉合了開關 中斷標志位即可正常工作 注意中斷標志位FE NE ORE都是共用了一個中斷使能位eie 當中斷使能位eie為0就屏蔽了這三個中斷標志位的中斷觸發請求 其他的中斷標志位都是各自有一個獨立的中斷使能位
編程接口
第一個編程接口(函數)就是通過配置藍色的中斷使能寄存器來屏蔽 使能中斷的 第二個接口就是查詢狀態寄存器的標志位 第三個接口是清除標志位 當觸發了中斷 如PE標志位觸發了中斷就為1 然后需要調用這個函數來手動清零
USART_ITConfig
USART_GetITStatus
USART_ClearITPendingBit
中斷接收數據的編程思路
數據處理能夠瞬間完成
套用裸機多任務的模型 就是初始化 然后進程函數 再到中斷服務函數 但是中斷函數中處理數據的速度要大于數據接收的速度(不然等到下一個數據發送過來還在處理上一個數據會造成數據的丟失和出錯) 那小于10us就看作瞬間完成 那么這里對數據的處理就是判斷if語句還有向對應的gpio模塊的ODR寄存器寫入對應的0或1 遠遠小于10us 視為瞬間完成 符合裸機多任務模型的時間需求
如第一幅圖 處理數據的時間遠遠小于數據傳來的時間(箭頭代表數據傳輸進來) 在兩個數據傳輸中數據已經處理完成
第二幅圖當箭頭傳入 (數據傳入) 當第一個箭頭(第一個數據)傳入開始處理數據 第二個箭頭(代表第二個數據傳入)傳入后還在處理第一個數據接著第三個數據傳入 導致了第二個數據的重載 (丟失了第二個數據) 導致數據傳輸的錯誤
但是數據處理的時間確實太長了怎么辦?
那我們就不在中斷服務函數中處理 就把數據傳到緩存區在傳入進程函數中延時處理
改進串口編程實驗
因為 這次數據處理的時間很短就只是個點燈 所以可以放在中斷服務函數中執行
usart初始化
編寫中斷響應函數
清除中斷的操作可以為第二步和第三步 因為標志位RXNE為1表示有數據接收
當讀取了數據RXNE標志位就會由1變為0 所以第三步讀取數據也相當于清除了中斷
#include "stm32f10x.h"
#include "stm32f10x_pal.h"static void USART_Recv_Init(void);int main(void)
{NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//NVIC的中斷優先級分組PAL_Init();USART_Recv_Init();while(1){}
}static void USART_Recv_Init(void)
{//1.初始化IO引腳//PB6 Tx PB7 Rx (經過了AFIO映射映射到了PB6和PB7引腳)RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//開啟GPIOB的時鐘//初始化PB6GPIO_InitTypeDef GPIOInitStruct;GPIOInitStruct.GPIO_Pin = GPIO_Pin_6;GPIOInitStruct.GPIO_Mode = GPIO_Mode_AF_PP;//PIN6為復用推挽模式GPIOInitStruct.GPIO_Speed = GPIO_Speed_10MHz;GPIO_Init(GPIOB,&GPIOInitStruct);//初始化PB7GPIOInitStruct.GPIO_Pin = GPIO_Pin_7;GPIOInitStruct.GPIO_Mode = GPIO_Mode_IPU;GPIO_Init(GPIOB,&GPIOInitStruct);//初始化PC13RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);//開啟GPIOC的時鐘GPIOInitStruct.GPIO_Pin = GPIO_Pin_13 ;GPIOInitStruct.GPIO_Mode = GPIO_Mode_Out_OD;GPIOInitStruct.GPIO_Speed = GPIO_Speed_2MHz;GPIO_Init(GPIOC,&GPIOInitStruct);//復用功能重映射RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);GPIO_PinRemapConfig(GPIO_Remap_USART1 ,ENABLE);//使能USART1的時鐘RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//配置USART的參數//9600 8為數據有效位 無奇偶校驗 1停止位為1位 Tx|RxUSART_InitTypeDef USART1InitStruct;USART1InitStruct.USART_BaudRate = 9600;USART1InitStruct.USART_WordLength = USART_WordLength_8b ;USART1InitStruct.USART_StopBits = USART_StopBits_1;USART1InitStruct.USART_Parity = USART_Parity_No;USART1InitStruct.USART_Mode = USART_Mode_Rx|USART_Mode_Tx;USART1InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None ;//硬件流控USART_Init(USART1,&USART1InitStruct);//配置中斷源USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//標志位RXNE的使能//NVIC的參數設置NVIC_InitTypeDef NVICInitStruct;NVICInitStruct.NVIC_IRQChannel = USART1_IRQn;NVICInitStruct.NVIC_IRQChannelPreemptionPriority = 0;//搶占優先級NVICInitStruct.NVIC_IRQChannelSubPriority =0;//子優先級NVICInitStruct.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVICInitStruct);//閉合總開關USART_Cmd(USART1,ENABLE);
}void USART1_IRQHandler(void)
{uint8_t c;if(USART_GetITStatus(USART1,USART_IT_RXNE) == SET){c = USART_ReceiveData(USART1); //清除了中斷也讀取了數據if(c == '0'){GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_SET);}if(c == '1'){GPIO_WriteBit(GPIOC,GPIO_Pin_13,Bit_RESET);}}}