STM32中斷系統概述
-
中斷處理過程
-
進入中斷 :處理器自動保存現場到堆棧里 ---> 入棧結束,ISR寄存器開始執行指令 ---> 晚到的中斷會重新取ISR
-
退出中斷 :恢復現場 ---> 繼續執行被中斷打斷的指令
-
NVIC主要功能 ---> 內嵌向量中斷控制器( Nested Vectored Interrupt Controller (NVIC))
-
中斷管理(外部中斷使能或禁止,可設置掛起或者清除狀態)
-
支持異常及中斷向量化處理
-
支持嵌套處理
外部中斷控制器EXTI
-
EXTI控制器的主要特性如下:
-
每個中斷/事件都有獨立的觸發和屏蔽
-
每個中斷線都有專用的狀態位
-
支持多達19個中斷/事件請求
-
檢測脈沖寬度低於APB2時種寬度的外部信號。參見數據手冊中電氣特性部分的相關參數
-
框圖(紅藍虛線為輸入線,藍色為產生中斷,紅色為產生事件輸出脈沖信號)
-
STM32F103 的觸發來源有兩種(標號 1 的或門輸入):
-
軟件觸發中斷
-
外部邊沿觸發中斷
2. STM32F103 的輸出結果有兩種(綠色和藍色區域):
-
觸發外部中斷
-
產生事件脈沖
3. 結合上圖作者來講解一下:
-
當邊沿檢測電路檢測到引腳上產生用戶設置的觸發沿時邊沿檢測電路會輸出高電平給標號 1 部分,由於 1 是或門所以輸入有一個是 1 輸出就是 1, 此時 1 號或門的輸出給請求中斷掛起寄存器,並讓該寄存器對應中斷線掛起位為 1,如果此時中斷屏蔽寄存器使能,即該中斷線中斷使能位為 1 時, 2 號與門輸出 1,並傳給 NVIC,如果此時 NVIC 使能了該中斷線中斷,則外部中斷發生,外部中斷服務函數得以執行。 同時,如果事件屏蔽寄存器中的對應位設置為 1,即開放來自該中斷線的事件時, 3 號與門輸出 1,進而使得脈沖發生器產生脈沖給對應外設,對應外設在收到脈沖后執行相應的聯動觸發動作,如觸發 ADC 采集。
-
同理如果設置軟件中斷寄存器相應位為 1, 即通過軟件產生外部中斷時也會觸發上面所述動作
-
中斷屏蔽寄存器(EXTI_IMR)
-
當對應中斷屏蔽位為 1 時,如果此時掛起寄存器對應位也為 1,則產生 NVIC 中斷
-
事件屏蔽寄存器(EXTI_EMR)
-
當事件屏蔽寄存器對應位為 1 時, 一旦有觸發信號產生,就會生成事件脈沖給其他外設
-
上升沿觸發選擇寄存器(EXTI_RTSR)
-
設置觸發外部中斷/事件的信號為上升沿觸發。 上升下降沿寄存器可以同時配合使用來產生上升下降沿觸發
-
下降沿觸發選擇寄存器(EXTI_FTSR)
-
設置觸發外部中斷/事件的信號為下降沿觸發。上升下降沿寄存器可以同時配合使用來產生上升下降沿觸發
-
掛起寄存器(EXTI_PR)
-
當外部信號/或軟件產生了觸發請求(即 1 號或門的輸出為 1),則掛起寄存器對應位被設置為 1,通過寫 1 清零
-
外部中斷配置寄存器 1-4(AFIO_EXTICR1-4)
-
這里只列出 AFIO_EXTICR2,這樣的 32 位寄存器一種有 4 組,每組用於設置 4 個外部中斷,該寄存器用於指定外部中斷的輸入信號來自於那組 GPIO 的引腳,目的是將外部中斷線和某個對應引腳連接在一起
按鍵中斷實例
-
按鍵中斷編程步驟分析
-
使能相應的時鍾
-
配置GPIO管腳為中斷功能
-
設置中斷優先級
-
使能相應的中斷
-
實現中斷服務程序
-
中斷配置程序
-
1 void MX_GPIO_Init(void) 2 { 3 GPIO_InitTypeDef GPIO_InitStruct = {0}; 4 5 /* GPIO Ports Clock Enable */ 6 __HAL_RCC_GPIOA_CLK_ENABLE(); 7 8 /*Configure GPIO pin : PA8 */ 9 GPIO_InitStruct.Pin = GPIO_PIN_8; 10 GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;//上升沿觸發 11 GPIO_InitStruct.Pull = GPIO_NOPULL; 12 HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); 13 14 /* EXTI interrupt init*/ 15 HAL_NVIC_SetPriority(EXTI9_5_IRQn, 0, 0); 16 HAL_NVIC_EnableIRQ(EXTI9_5_IRQn); 17 }
串口中斷實例-
串口中斷編程步驟分析
-
使能相應的時鍾
-
配置GPIO管腳為串口功能
-
設置中斷優先級
-
使能相應的中斷
-
實現中斷服務程序
2. 程序- 更改printf函數為串口傳輸使用
int fputc(int ch, FILE *fp)//更改printf函數,使之可為串口傳輸使用 {
while(!(USART1->SR & (1<<7)));//判斷發送寄存器是否為空 USART1->DR = ch;//若不為空,則將數據傳輸到數據發送寄存器 return ch;} * 串口發送中斷程序 HAL_UART_Transmit_IT(&huart1, "Transmit INIT\n", 14);//main.c文件中編寫//調用此函數發送字符串,發送完成產生串口發送完成中斷,並調用HAL_UART_TxCpltCallback函數 void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)//usart.c文件中編寫 { if(huart->Instance == USART1) { printf("uart transmit end\n");//串口發送完成 }} * 串口接收中斷程序 uint8_t RX[10] = {0};//定義接收數組HAL_UART_Receive_IT(&huart1, RX, 1);//接收一個字符數據,編寫在main.c文件extern uint8_t RX[10];//聲明外部變量,編寫在usart.c文件 void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)//調用接收回調函數{ if(huart->Instance == USART1) { printf("RX: %x\n",RX[0]);//打印接收到的字符
HAL_UART_Receive_IT(&huart1, RX, 1);
}}
-
