目錄
1,NVIC
2,中斷和事件的區(qū)別
3,優(yōu)先級的概念?
4,如何實際編程使用外部中斷
5,STM32開發(fā)板通過按鍵控制LED?
5.1,打開相應GPIO模塊時鐘
5.2,NVIC設置
5.3,外部中斷線和配套的GPIO進行連接映射
5.4,代碼文件?
6,FSMC
1,NVIC
NVIC: Nested Vector Interrupt Control,嵌套向量中斷控制器;
68個可屏蔽中斷通道。
數據手冊得向量表結合起始代碼查看:?
可以理解為數組里(__Vectors?)定義了數據類型為DCD的許多個元素。
下邊圖中可理解為復位時調用Reset_Handler函數,先執(zhí)行SystemInit,然后執(zhí)行__main:?
本章節(jié)我們關注的是外部中斷相關的內容:?
起始代碼中為我們提供了中斷函數默認的執(zhí)行程序,即下圖中的 B? ? . ,其含義即是C中的while(1)。
起始文件中的這些函數屬性是[WEAK],即弱函數。?
始代碼文件是用匯編語言編寫,[WEAK]標志代表該函數是弱函數,如果在其它地方定義這些函數則以定義的函數執(zhí)行,也就是不再執(zhí)行默認的while(1)函數,如果沒有在其它地方定義則以起始文件中的函數為準。
起始代碼的作用可以認為是建立了中斷向量表,中斷向量表是軟件實現的,但是是由硬件決定的。
即下圖中的地址是硬件設計時就決定了的。
中斷要配置使能,中斷處理程序要清中斷掛起。
2,中斷和事件的區(qū)別
中斷需要CPU參與,事件不需要CPU參與,中斷使用CPU處理程序比較靈活,事件不需要CPU參與通過產生脈沖直接與外設交互,可以節(jié)省CPU資源。
3,優(yōu)先級的概念?
搶占優(yōu)先級?NVIC_IRQChannelPreemptionPriority
子優(yōu)先級?NVIC_IRQChannelSubPriority
級別的數字越小,優(yōu)先級越高。
搶占優(yōu)先級內部劃分子優(yōu)先級,同一搶占優(yōu)先級內的中斷子優(yōu)先級必須不同。
優(yōu)先級為0的搶占優(yōu)先級可以打斷優(yōu)先級為1的搶占優(yōu)先級。
同一搶占優(yōu)先級內等級為0的子優(yōu)先級中斷不能打斷等級為1的子優(yōu)先級中斷,只有兩個不同子優(yōu)先級的中斷同時發(fā)生時,子優(yōu)先級高的中斷才會處于優(yōu)先地位。
4,如何實際編程使用外部中斷
?
(1)時鐘設置并打開相應GPIO模塊時鐘
(2)將相應GPIO配置為浮空輸入
(3)NVIC設置
(4)將外部中斷線和配套的GPIO進行連接映射
(5)外部中斷線使能觸發(fā)
(6)準備好ISR,并在ISR處等待執(zhí)行中斷程序即可
在下一節(jié)中通過相應的代碼對應對上述步驟。
5,STM32開發(fā)板通過按鍵控制LED?
中斷相關標準庫代碼在misc.c中,misc是miscellaneous(雜項)的縮寫。?
在51單片機中已經通過使用中斷,通過識別外部按鍵操作來控制LED燈。本節(jié)在STM32開發(fā)板上,通過使用標準庫中的中斷函數來控制LED燈,達到的效果為:按一個按鍵打開LED燈,按另一個按鍵關閉這個LED燈,主程序中控制另外一個LED燈閃爍。
5.1,打開相應GPIO模塊時鐘
本例中按鍵使用PIN角為PB8和PB9連接按鍵,所以要使能GPIOB端口所在的APB2總線時鐘,LED燈使用PA0和PA。
對應的標準庫函數是stm32f10x_rcc.c文件中的RCC_APB2PeriphClockCmd(),要使能該總線時鐘,對應的命令如下:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
5.2,NVIC設置
第一步,優(yōu)先級組設置,設置有幾個搶占優(yōu)先級,以及有幾個子優(yōu)先級
對于搶占優(yōu)先級和子優(yōu)先級,因為本例中通過按鍵控制LED燈只需要識別一個中斷,因此搶占優(yōu)先級和子優(yōu)先級可以隨意設置,即NVIC_PriorityGroupConfig()函數的輸入參數可以設置下列代碼中的任意值,對于具體的項目可以根據中斷個數和優(yōu)先級進行設置。?
/**
* @brief Configures the priority grouping: pre-emption priority and subpriority.
* @param NVIC_PriorityGroup: specifies the priority grouping bits length.
* This parameter can be one of the following values:
* @arg NVIC_PriorityGroup_0: 0 bits for pre-emption priority
* 4 bits for subpriority
* @arg NVIC_PriorityGroup_1: 1 bits for pre-emption priority
* 3 bits for subpriority
* @arg NVIC_PriorityGroup_2: 2 bits for pre-emption priority
* 2 bits for subpriority
* @arg NVIC_PriorityGroup_3: 3 bits for pre-emption priority
* 1 bits for subpriority
* @arg NVIC_PriorityGroup_4: 4 bits for pre-emption priority
* 0 bits for subpriority
* @retval None
*/
void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)
{
/* Check the parameters */
assert_param(IS_NVIC_PRIORITY_GROUP(NVIC_PriorityGroup));
/* Set the PRIGROUP[10:8] bits according to NVIC_PriorityGroup value */
SCB->AIRCR = AIRCR_VECTKEY_MASK | NVIC_PriorityGroup;
}
第二步,NVIC初始化
標準庫misc.c中的NVIC_Init()函數
/**
* @brief Initializes the NVIC peripheral according to the specified
* parameters in the NVIC_InitStruct.
* @param NVIC_InitStruct: pointer to a NVIC_InitTypeDef structure that contains
* the configuration information for the specified NVIC peripheral.
* @retval None
*/
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct)
{
uint32_t tmppriority = 0x00, tmppre = 0x00, tmpsub = 0x0F;
/* Check the parameters */
assert_param(IS_FUNCTIONAL_STATE(NVIC_InitStruct->NVIC_IRQChannelCmd));
assert_param(IS_NVIC_PREEMPTION_PRIORITY(NVIC_InitStruct->NVIC_IRQChannelPreemptionPriority));
assert_param(IS_NVIC_SUB_PRIORITY(NVIC_InitStruct->NVIC_IRQChannelSubPriority));
if (NVIC_InitStruct->NVIC_IRQChannelCmd != DISABLE)
{
/* Compute the Corresponding IRQ Priority --------------------------------*/
tmppriority = (0x700 - ((SCB->AIRCR) & (uint32_t)0x700))>> 0x08;
tmppre = (0x4 - tmppriority);
tmpsub = tmpsub >> tmppriority;
tmppriority = (uint32_t)NVIC_InitStruct->NVIC_IRQChannelPreemptionPriority << tmppre;
tmppriority |= NVIC_InitStruct->NVIC_IRQChannelSubPriority & tmpsub;
tmppriority = tmppriority << 0x04;
NVIC->IP[NVIC_InitStruct->NVIC_IRQChannel] = tmppriority;
/* Enable the Selected IRQ Channels --------------------------------------*/
NVIC->ISER[NVIC_InitStruct->NVIC_IRQChannel >> 0x05] =
(uint32_t)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (uint8_t)0x1F);
}
else
{
/* Disable the Selected IRQ Channels -------------------------------------*/
NVIC->ICER[NVIC_InitStruct->NVIC_IRQChannel >> 0x05] =
(uint32_t)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (uint8_t)0x1F);
}
}
5.3,外部中斷線和配套的GPIO進行連接映射
首先,確定按鍵和LED對應的PIN端口。通用I/O端口以下圖的方式連接到16個外部中斷/事件線上,若按鍵確定連接到PA0上,則對應的中斷線為EXTI0。
在外部中斷配置寄存器(AFIO_EXTICRX,X = 1,2,3,4)中設置中斷線與哪個PIN角對應。
對應的設置函數是標準庫GPIO.c文件中的GPIO_EXTILineConfig()函數:
/**
* @brief Selects the GPIO pin used as EXTI Line.
* @param GPIO_PortSource: selects the GPIO port to be used as source for EXTI lines.
* This parameter can be GPIO_PortSourceGPIOx where x can be (A..G).
* @param GPIO_PinSource: specifies the EXTI line to be configured.
* This parameter can be GPIO_PinSourcex where x can be (0..15).
* @retval None
*/
void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource)
{
uint32_t tmp = 0x00;
/* Check the parameters */
assert_param(IS_GPIO_EXTI_PORT_SOURCE(GPIO_PortSource));
assert_param(IS_GPIO_PIN_SOURCE(GPIO_PinSource));
tmp = ((uint32_t)0x0F) << (0x04 * (GPIO_PinSource & (uint8_t)0x03));
AFIO->EXTICR[GPIO_PinSource >> 0x02] &= ~tmp;
AFIO->EXTICR[GPIO_PinSource >> 0x02] |= (((uint32_t)GPIO_PortSource) << (0x04 * (GPIO_PinSource & (uint8_t)0x03)));
}
如果要設置PIN角PA0能夠檢測中斷,調用此函數:
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);
確定模式是中斷還是事件;
typedef enum
{
EXTI_Mode_Interrupt = 0x00,
EXTI_Mode_Event = 0x04
}EXTIMode_TypeDef;
配置上升沿/下降沿觸發(fā)選擇寄存器;
因開發(fā)板上的按鍵接通時是接地的,因此需要將中斷設置為下降沿觸發(fā),設置下降沿觸發(fā)選擇寄存器(EXTI_FTSR)
對應的標準庫中代碼:
typedef enum
{
EXTI_Trigger_Rising = 0x08,
EXTI_Trigger_Falling = 0x0C,
EXTI_Trigger_Rising_Falling = 0x10
}EXTITrigger_TypeDef;
重寫中斷函數ISR:
注意中斷函數的名稱要使用起始代碼中的對應中斷函數名稱,也就是對這個弱函數重寫。
注意要在ISR中清除中斷掛起寄存器(EXTI_PR),如果不在ISR中清除中斷就會反復進入中斷:
對應的標準庫函數在stm32f10x_exti.c中的EXTI_ClearFlag(),
/**
* @brief Clears the EXTI's line pending flags.
* @param EXTI_Line: specifies the EXTI lines flags to clear.
* This parameter can be any combination of EXTI_Linex where x can be (0..19).
* @retval None
*/
void EXTI_ClearFlag(uint32_t EXTI_Line)
{
/* Check the parameters */
assert_param(IS_EXTI_LINE(EXTI_Line));
EXTI->PR = EXTI_Line;
}
5.4,代碼文件?
中斷相關.c和.h文件:
#ifndef _exti_H
#define _exti_H
#include "system.h"
void My_EXTI_Init(void);
#endif
注意:需將AFIO使能,因為中斷線和端口的對應配置是在AFIO相關寄存器:外部中斷配置寄存器(AFIO_EXTICR)
#include "exti.h"
#include "led.h"
#include "SysTick.h"
#include "key.h"
void My_EXTI_Init(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); //注意需將AFIO使能
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource8);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource9);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
EXTI_InitStructure.EXTI_Line=EXTI_Line8|EXTI_Line9;
EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling;
EXTI_InitStructure.EXTI_LineCmd=ENABLE;
EXTI_Init(&EXTI_InitStructure);
}
void EXTI9_5_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line8)==1)
{
delay_ms(10);
if(KEY1==0)
{
led2=0;
}
}
else if(EXTI_GetITStatus(EXTI_Line9)==1)
{
delay_ms(10);
if(KEY2==0)
{
led2=1;
}
}
EXTI_ClearITPendingBit(EXTI_Line8|EXTI_Line9);
}
?main.c函數:文章來源:http://www.zghlxwxcb.cn/news/detail-799577.html
#include "system.h"
#include "SysTick.h"
#include "led.h"
#include "key.h"
#include "exti.h"
int main()
{
u8 i;
SysTick_Init(72);
LED_Init();
KEY_Init();
My_EXTI_Init();
while(1)
{
i++;
if(i%20==0)
{
led1=!led1;
}
delay_ms(10);
}
}
6,FSMC
Flexible static memory controller(FSMC)靈活的靜態(tài)存儲控制器文章來源地址http://www.zghlxwxcb.cn/news/detail-799577.html
到了這里,關于單片機第三季-第七課:STM32中斷體系的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!