
注意:
我这里是标准库和HAL都混合一起使用,所以可能会有点混乱!!!!!!!!!!
NVIC:https://blog.51cto.com/wangjunlv/6021164?articleABtest=1

- /**
- * 函 数:计数传感器初始化
- * 参 数:无
- * 返 回 值:无
- */
- void CountSensor_Init(void)
- {
- /*开启时钟*/
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //开启GPIOB的时钟
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //开启AFIO的时钟,外部中断必须开启AFIO的时钟
-
- /*GPIO初始化*/
- GPIO_InitTypeDef GPIO_InitStructure;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Init(GPIOB, &GPIO_InitStructure); //将PB14引脚初始化为上拉输入
-
- /*AFIO选择中断引脚*/
- GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource14);//将外部中断的14号线映射到GPIOB,即选择PB14为外部中断引脚
-
- /*EXTI初始化*/
- EXTI_InitTypeDef EXTI_InitStructure; //定义结构体变量
- EXTI_InitStructure.EXTI_Line = EXTI_Line14; //选择配置外部中断的14号线
- EXTI_InitStructure.EXTI_LineCmd = ENABLE; //指定外部中断线使能
- EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //指定外部中断线为中断模式
- EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //指定外部中断线为下降沿触发
- EXTI_Init(&EXTI_InitStructure); //将结构体变量交给EXTI_Init,配置EXTI外设
-
- /*NVIC中断分组*/
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //配置NVIC为分组2
- //即抢占优先级范围:0~3,响应优先级范围:0~3
- //此分组配置在整个工程中仅需调用一次
- //若有多个中断,可以把此代码放在main函数内,while循环之前
- //若调用多次配置分组的代码,则后执行的配置会覆盖先执行的配置
-
- /*NVIC配置*/
- NVIC_InitTypeDef NVIC_InitStructure; //定义结构体变量
- NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn; //选择配置NVIC的EXTI15_10线
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //指定NVIC线路使能
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //指定NVIC线路的抢占优先级为1
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //指定NVIC线路的响应优先级为1
- NVIC_Init(&NVIC_InitStructure); //将结构体变量交给NVIC_Init,配置NVIC外设
- }



(1)数据手册中相关部分浏览
(2)地址映射时0地址映射到Flash或SRAM
(3)中断向量表可以被人为重新映射,一般用来IAP中
(4)STM32采用一维的中断向量表
(5)中断优先级设置有点复杂,后面细说




在每一个中断函数在startup_stm32f10x_md.s中都有进行定义






(1)其实代码中定义了一个Vector数组
(2)WEAK声明的默认ISR
(3)用户根据需要提供自己真正有用的ISR
(4)中断要配置使能,ISR中要清挂起等,这一点和其他CPU一样



EXIT处理和唤醒外部或者内部的设备中断
EXTI是属于边沿触发。所以要指定是上升沿触发还是下降沿触发。










AFIO中与中断相关的寄存器有4个
记得再使用之前一定要使能时钟!!!!!
我们有4个AFIO的中断寄存器,则一个寄存器中应该可以处理16个引脚。

最好使用引脚时,设置PA0,PA1....
PA1和PB1和PC1不能同时使用



使用AFIO中的EXTICRx寄存器进行操作


- /**
- * @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)));
- }



(1)时钟设置并打开相应GPIO模块时钟
(2)将相应GPIO配置为浮空输入
(3)NVIC设置
(4)将外部中断线和配套的GPIO进行连接映射
(5)外部中断线使能触发
(6)准备好ISR,并在ISR处等待执行中断程序即可(7)记得!!!!!!!!!执行完ISR后记得将中断清除。
外部中断:需要CPU,中断处理程序的参与---》使用NVIC
外部事件中断:不需要CPU参与---》不使用NVIC
我们一般使用外部中断,不使用外部事件中断,因为我们不知道该器件是否接受脉冲信号。











因为中断处理是在CPU内部进行的,所以没有单独的.c和.h文件
NVIC在【misc.c】中


当抢占优先级的不同时,抢占优先级小的先执行,然后在执行优先级大的。
当抢占优先级相同时,次优先级小的不能抢占次优先级大的
当相同抢占优先级的程序进行中断时,次优先级小的可以抢先执行,在执行次优先级大的。
- //PreemptionPriority:抢优先级
- uint8_t NVIC_IRQChannelPreemptionPriority; /*!< Specifies the pre-emption priority for the IRQ channel
- specified in NVIC_IRQChannel. This parameter can be a value
- between 0 and 15 as described in the table @ref NVIC_Priority_Table */
- //次优先级【同一个抢占级别中进行判断的】
- uint8_t NVIC_IRQChannelSubPriority; /*!< Specifies the subpriority level for the IRQ channel specified
- in NVIC_IRQChannel. This parameter can be a value
- between 0 and 15 as described in the table @ref NVIC_Priority_Table */




- /**
- pre-emption:抢占优先级
- subpriority:次优先级
- */
- #define NVIC_PriorityGroup_0 ((uint32_t)0x700) /*!< 0 bits for pre-emption priority
- 4 bits for subpriority=》2的4次方*/
- #define NVIC_PriorityGroup_1 ((uint32_t)0x600) /*!< 1 bits for pre-emption priority
- 3 bits for subpriority=>2的3次方*/
- #define NVIC_PriorityGroup_2 ((uint32_t)0x500) /*!< 2 bits for pre-emption priority
- 2 bits for subpriority */
- #define NVIC_PriorityGroup_3 ((uint32_t)0x400) /*!< 3 bits for pre-emption priority
- 1 bits for subpriority */
- #define NVIC_PriorityGroup_4 ((uint32_t)0x300) /*!< 4 bits for pre-emption priority
- 0 bits for subpriority */
RAM或者FLASH
- /**
- 启动方式:RAM或者FLASH
- 从0x0000 0000到0x080 0000之间的地址是用来设置映射关系
- 因为我们使用FLASH启动,所以将其映射到0x0800 0000
-
- */
- #define NVIC_VectTab_RAM ((uint32_t)0x20000000)
- #define NVIC_VectTab_FLASH ((uint32_t)0x08000000)
- #define IS_NVIC_VECTTAB(VECTTAB) (((VECTTAB) == NVIC_VectTab_RAM) || \
- ((VECTTAB) == NVIC_VectTab_FLASH))
注意点:
再HAL库中,我们中断分组已经再HAL_Init()函数中设置了分组为2【因为分组2中,有4个抢占优先级,有4个响应优先级】

下面这些函数都定义再stm32f1xx_hal_cortex中
因为NVIC属于内核部分的内容,所以如果我们要查看相应的寄存器,只能去Cortex-M数据手册中进行查看。

设置优先级分组字段(抢占优先级和子优先级)
- /**
- * @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;
- }




对抢占优先级和响应优先级的相关设置
- void HAL_NVIC_SetPriority(IRQn_Type IRQn, uint32_t PreemptPriority, uint32_t SubPriority)
- {
- uint32_t prioritygroup = 0x00U;
-
- /* Check the parameters */
- assert_param(IS_NVIC_SUB_PRIORITY(SubPriority));
- assert_param(IS_NVIC_PREEMPTION_PRIORITY(PreemptPriority));
-
- prioritygroup = NVIC_GetPriorityGrouping();
-
- NVIC_SetPriority(IRQn, NVIC_EncodePriority(prioritygroup, PreemptPriority, SubPriority));
- }

- 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);
- }
- }
设置中断向量表,看要设置到RAM还是FLASH
- void NVIC_SetVectorTable(uint32_t NVIC_VectTab, uint32_t Offset)
- {
- /* Check the parameters */
- assert_param(IS_NVIC_VECTTAB(NVIC_VectTab));
- assert_param(IS_NVIC_OFFSET(Offset));
-
- SCB->VTOR = NVIC_VectTab | (Offset & (uint32_t)0x1FFFFF80);
- }
使能NVIC
- void HAL_NVIC_EnableIRQ(IRQn_Type IRQn)
- {
- /* Check the parameters */
- assert_param(IS_NVIC_DEVICE_IRQ(IRQn));
-
- /* Enable interrupt */
- NVIC_EnableIRQ(IRQn);
- }

- //完全去始化
- void EXTI_DeInit(void)
- {
- EXTI->IMR = 0x00000000;
- EXTI->EMR = 0x00000000;
- EXTI->RTSR = 0x00000000;
- EXTI->FTSR = 0x00000000;
- EXTI->PR = 0x000FFFFF;
- }
将我们设置好的结构体变量写入到寄存器中
- /**
- * @brief Initializes the EXTI peripheral according to the specified
- * parameters in the EXTI_InitStruct.
- * @param EXTI_InitStruct: pointer to a EXTI_InitTypeDef structure
- * that contains the configuration information for the EXTI peripheral.
- * @retval None
- */
- void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct)
- {
- uint32_t tmp = 0;
-
- /* Check the parameters */
- assert_param(IS_EXTI_MODE(EXTI_InitStruct->EXTI_Mode));
- assert_param(IS_EXTI_TRIGGER(EXTI_InitStruct->EXTI_Trigger));
- assert_param(IS_EXTI_LINE(EXTI_InitStruct->EXTI_Line));
- assert_param(IS_FUNCTIONAL_STATE(EXTI_InitStruct->EXTI_LineCmd));
-
- tmp = (uint32_t)EXTI_BASE;
-
- if (EXTI_InitStruct->EXTI_LineCmd != DISABLE)//表示要使能
- {
- /* Clear EXTI line configuration */
- EXTI->IMR &= ~EXTI_InitStruct->EXTI_Line;
- EXTI->EMR &= ~EXTI_InitStruct->EXTI_Line;
-
- tmp += EXTI_InitStruct->EXTI_Mode;
-
- *(__IO uint32_t *) tmp |= EXTI_InitStruct->EXTI_Line;
-
- /* Clear Rising Falling edge configuration */
- EXTI->RTSR &= ~EXTI_InitStruct->EXTI_Line;
- EXTI->FTSR &= ~EXTI_InitStruct->EXTI_Line;
-
- /* Select the trigger for the selected external interrupts */
- if (EXTI_InitStruct->EXTI_Trigger == EXTI_Trigger_Rising_Falling)
- {
- /* Rising Falling edge */
- EXTI->RTSR |= EXTI_InitStruct->EXTI_Line;
- EXTI->FTSR |= EXTI_InitStruct->EXTI_Line;
- }
- else
- {
- tmp = (uint32_t)EXTI_BASE;
- tmp += EXTI_InitStruct->EXTI_Trigger;
-
- *(__IO uint32_t *) tmp |= EXTI_InitStruct->EXTI_Line;
- }
- }
- else
- {
- tmp += EXTI_InitStruct->EXTI_Mode;
-
- /* Disable the selected external lines */
- *(__IO uint32_t *) tmp &= ~EXTI_InitStruct->EXTI_Line;
- }
- }
如果用户不想自己设置中断值,则可以调用这个函数,这个函数中有默认值可以使用
- void EXTI_StructInit(EXTI_InitTypeDef* EXTI_InitStruct)
- {
- EXTI_InitStruct->EXTI_Line = EXTI_LINENONE;
- EXTI_InitStruct->EXTI_Mode = EXTI_Mode_Interrupt;
- EXTI_InitStruct->EXTI_Trigger = EXTI_Trigger_Falling;
- EXTI_InitStruct->EXTI_LineCmd = DISABLE;
- }
软件中断,可以对寄存器中其中一位进行中断操作
- void EXTI_GenerateSWInterrupt(uint32_t EXTI_Line)
- {
- /* Check the parameters */
- assert_param(IS_EXTI_LINE(EXTI_Line));
-
- EXTI->SWIER |= EXTI_Line;
- }
共享中断:判断中断标志位是否真的置1了(判断是哪一个标志进行中断的)
- /**
- * @brief Checks whether the specified EXTI line flag is set or not.
- * @param EXTI_Line: specifies the EXTI line flag to check.
- * This parameter can be:
- * @arg EXTI_Linex: External interrupt line x where x(0..19)
- * @retval The new state of EXTI_Line (SET or RESET).
- */
- FlagStatus EXTI_GetFlagStatus(uint32_t EXTI_Line)
- {
- FlagStatus bitstatus = RESET;
- /* Check the parameters */
- assert_param(IS_GET_EXTI_LINE(EXTI_Line));
-
- if ((EXTI->PR & EXTI_Line) != (uint32_t)RESET)
- {
- bitstatus = SET;
- }
- else
- {
- bitstatus = RESET;
- }
- return bitstatus;
- }
中断进入后,就会有一个中断挂起
- /**
- * @brief Clears the EXTI's line pending bits.
- * @param EXTI_Line: specifies the EXTI lines to clear.
- * This parameter can be any combination of EXTI_Linex where x can be (0..19).
- * @retval None
- */
- void EXTI_ClearITPendingBit(uint32_t EXTI_Line)
- {
- /* Check the parameters */
- assert_param(IS_EXTI_LINE(EXTI_Line));
-
- EXTI->PR = EXTI_Line;
- }
清除中断
- void EXTI_ClearFlag(uint32_t EXTI_Line)
- {
- /* Check the parameters */
- assert_param(IS_EXTI_LINE(EXTI_Line));
-
- EXTI->PR = EXTI_Line;
- }
以ARM3.0的按键示例程序作为参考,移植到PZ6806L开发板上。

将我们在初始化文件(STM32F10x_md.c)中的中断函数进行覆盖重写。


这个文件中存放是有中断处理函数的定义
我们如果想要执行(使用)这个中断,则将在md文件中将函数名字复制出来,然后再stm32f10x_it.c文件中使用

我们上面再stm32f10x_it.c中重写了一个函数,则要再这个.h文件中进行声明


作用:将时钟设置为72MHZ,将相关的开关打开。



NVIC中断优先级的初始化

1)初始化RCC
2)初始化GPIO
3)初始化NVIC
4)设置外部中断(将中断线和GPIO线连接起来)
5)外部中断线的模式选择(我们一般选择外部中断,不使用外部事件中断)
6)产生软件中断触发事件

这个程序的执行结果是:按下按键一(KEY1),使得LED16(也就是4*4矩阵显示屏上最后一排灯亮起)
独立按键的JP1接到PB0-PB7


LED8-LED16的J34接到PA0-PA7


因为操作库函数的时候只能一位一位操作,所以我们只能选择其中一个引脚进行操作。
我们选择KEY1和LED16进行操作,分别对应PB0和PA7

由上面可知我们KEY1对应的是PB0,由0可知应该选择EXIT0
确定好后,再stm32f10x.c和stm32f10x.h文件中进行重写和声明【我们可以再stm32f10x_md.c文件中查看应该调用哪一个函数】
注意点:本来我们应该再stm32f10x_it.c文件中去查找这个中断函数的初始化,但是普中科技的AMR3.0的官方代码将这个中断函数的初始化写再了exit.c文件中。

- */
- void EXTI0_IRQHandler(void)
- {
- //检测制定的EXTI线路触发
- if(EXTI_GetITStatus(EXTI_Line0)==1)
- {
- /*
- delay_ms(10);
- if(KEY1==0)
- {
- led2=0;
- }
- */
- }
- //清除EXTI线路挂起位
- EXTI_ClearITPendingBit(EXTI_Line0);
- }
- //声明自己写的EXIT0
- void EXTI0_IRQHandler(void);
- //RCC的配置
- void RCC_Configuration(void){
-
- //因为起始代码中已经调用SystemInit将主时钟设置为72MHZ
- //所以我们这里RCC直接使能时钟就可以
-
- //使能GPIO端口
- //因为我们使用到的是PB0和PB8,所以只使用到GPIOB
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|
- RCC_APB2Periph_AFIO,ENABLE);
-
- }
- //GPIO初始化
- void CPIO_Configuration(void){
-
- GPIO_InitTypeDef GPIO_InitStructure;
-
- //PB0 -- Key1 -- EXIT2 PA7 ---LED16
- //PB0 -- Key1 -- EXIT2【按键是输入获取】
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //配置浮空输入
- GPIO_Init(GPIOB, &GPIO_InitStructure);
-
- //PA7 ---LED16【LED的显示输出】
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
- GPIO_Init(GPIOA, &GPIO_InitStructure);
- GPIO_WriteBit(GPIOA, GPIO_Pin_7, Bit_RESET); // 默认输出0让LED亮
-
- }
NVIC_IRQChannel:在misc.h中定义
- void NVIC_Configuration(void)
- {
- NVIC_InitTypeDef NVIC_InitStructure;
-
- #ifdef VECT_TAB_RAM
- /* Set the Vector Table base location at 0x20000000 */
- NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0); //分配中断向量表
- #else /* VECT_TAB_FLASH */
- //表示从FLASH中启动
- /* Set the Vector Table base location at 0x08000000 */
- NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
- #endif
-
- /* Configure one bit for preemption priority */
- // NVIC_PriorityGroup_1:2个抢占优先级,8个次优先级
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); //设置中断优先级
-
- /* Enable the EXTI2 Interrupt */
- NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; //中断通道
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //强占优先级
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;//次优先级
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //通道中断使能
- NVIC_Init(&NVIC_InitStructure);//初始化中断
- }
- //函数声明
- //RCC的配置
- void RCC_Configuration(void);
- //GPIO初始化
- void GPIO_Configuration(void);
- void NVIC_Configuration(void);
-
- //全局变量定义
- EXTI_InitTypeDef EXTI_InitStructure;
- ErrorStatus HSEStatartUpStatus;
-
- int main(){
-
- //系统时钟配置
- RCC_Configuration();
- //NVIC配置
- NVIC_Configuration();
- //配置GPIO
- GPIO_Configuration();
-
- //将EXTI线0连接到PB0【处理按键中断】
- GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource0);
-
- /* Configure Key Button EXTI Line to generate an interrupt on falling edge */
- //配置按钮中断线触发方式
- EXTI_InitStructure.EXTI_Line = EXTI_Line0;
- EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
- EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //下降沿触发
- EXTI_InitStructure.EXTI_LineCmd = ENABLE; //中断线使能
- EXTI_Init(&EXTI_InitStructure); //初始化中断
-
- /* Generate software interrupt: simulate a falling edge applied on Key Button EXTI line */
- // EXTI_GenerateSWInterrupt(EXTI_Line0); //EXTI_Line2中断允许 到此中断配置完成,可以写中断处理函数。
-
- while (1);
-
-
- return 0;
- }
因为我们要在中断函数中对LED进行点亮/熄灭,所以需要对LED进行读取和写入。
所以要使用到我们的【GPIO_ReadInputDataBit】和【GPIO_WriteBit】
- void EXTI0_IRQHandler(void)
- {
- //检测制定的EXTI线路触发
- if(EXTI_GetITStatus(EXTI_Line0)==1)
- {
- //此时控制的是LED,LED对应的是PA0
- //我们想要对LED进行点亮/熄灭
- //则应该先将此时LED的状态位读取出来,然后在取反写进去
- GPIO_WriteBit(GPIOA,GPIO_Pin_0,(BitAction)((1-GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0))));
- }
- //清除EXTI线路挂起位
- EXTI_ClearITPendingBit(EXTI_Line0);
- }
在对GPIO初始化的时候一起将lED一起点亮


- // 默认输出1让LED亮
- GPIO_WriteBit(GPIOA, GPIO_Pin_7, Bit_SET);
- #include "stm32f10x.h" // Device header
-
- /**
- 使用库函数对STM32进行GPIO的外部中断
- 按下KEY1对LED16进行点亮/熄灭
- */
-
-
- //函数声明
- //RCC的配置
- void RCC_Configuration(void);
- //GPIO初始化
- void GPIO_Configuration(void);
- void NVIC_Configuration(void);
-
- //全局变量定义
- EXTI_InitTypeDef EXTI_InitStructure;
- ErrorStatus HSEStatartUpStatus;
-
- int main(){
-
- //系统时钟配置
- RCC_Configuration();
- //NVIC配置
- NVIC_Configuration();
- //配置GPIO
- GPIO_Configuration();
-
- //将EXTI线0连接到PB0【处理按键中断】
- GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource0);
-
- /* Configure Key Button EXTI Line to generate an interrupt on falling edge */
- //配置按钮中断线触发方式
- EXTI_InitStructure.EXTI_Line = EXTI_Line0;
- EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
- EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //下降沿触发
- EXTI_InitStructure.EXTI_LineCmd = ENABLE; //中断线使能
- EXTI_Init(&EXTI_InitStructure); //初始化中断
-
- /* Generate software interrupt: simulate a falling edge applied on Key Button EXTI line */
- //人为产生中断
- //如果不想要一进来就产生中断,则应该注释掉
- //EXTI_Line0中断允许 到此中断配置完成,可以写中断处理函数。
- EXTI_GenerateSWInterrupt(EXTI_Line0);
-
- while (1);
-
-
- return 0;
- }
-
-
- //RCC的配置
- void RCC_Configuration(void){
-
- //因为起始代码中已经调用SystemInit将主时钟设置为72MHZ
- //所以我们这里RCC直接使能时钟就可以
-
- //使能GPIO端口
- //因为我们使用到的是PB0和PB8,所以只使用到GPIOB
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|
- RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO,ENABLE);
-
- }
-
- //GPIO初始化
- void CPIO_Gonfiguration(void){
-
- GPIO_InitTypeDef GPIO_InitStructure;
-
- //PB0 -- Key1 -- EXIT2 PA7 ---LED16
- //PB0 -- Key1 -- EXIT2【按键是输入获取】
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //配置浮空输入
- GPIO_Init(GPIOB, &GPIO_InitStructure);
-
-
- //PA7 ---LED16【LED的显示输出】
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
- GPIO_Init(GPIOA, &GPIO_InitStructure);
- // 默认输出1让LED亮
- GPIO_WriteBit(GPIOA, GPIO_Pin_7, Bit_SET);
-
- }
-
- void NVIC_Configuration(void)
- {
- NVIC_InitTypeDef NVIC_InitStructure;
-
- #ifdef VECT_TAB_RAM
- /* Set the Vector Table base location at 0x20000000 */
- NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0); //分配中断向量表
- #else /* VECT_TAB_FLASH */
- //表示从FLASH中启动
- /* Set the Vector Table base location at 0x08000000 */
- NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
- #endif
-
- /* Configure one bit for preemption priority */
- // NVIC_PriorityGroup_1:2个抢占优先级,8个次优先级
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); //设置中断优先级
-
- /* Enable the EXTI2 Interrupt */
- NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; //中断通道
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //强占优先级
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;//次优先级
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //通道中断使能
- NVIC_Init(&NVIC_InitStructure);//初始化中断
- }
-
-
-
- void EXTI0_IRQHandler(void)
- {
- //检测制定的EXTI线路触发
- if(EXTI_GetITStatus(EXTI_Line0)==1)
- {
- //此时控制的是LED,LED对应的是PA0
- //我们想要对LED进行点亮/熄灭
- //则应该先将此时LED的状态位读取出来,然后在取反写进去
- GPIO_WriteBit(GPIOA,GPIO_Pin_0,(BitAction)((1-GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0))));
- }
- //清除EXTI线路挂起位
- EXTI_ClearITPendingBit(EXTI_Line0);
- }
因为EXTI是边沿触发,所以如果想要EXTI则只能设置上升沿/下降沿触发。

因为平时key处于低电平,如果我们想要控制,则需要给其高电平【上拉】


因为中断的触发点:就是通过引脚传入进入---》上升沿触发(高电平),下降沿触发(低电平)
上升沿触发(从低电平到高电平)--》下拉输入
下降沿触发(从高电平到低电平)--》上拉输入


设置
1)是输入???输出
2)是什么输入(上拉输入/下拉输入/浮动输入/模拟输入)/输出(开漏输出/推挽输出)

我们设置了哪一个EXTIx,就要中断相对应的Extix interupt


在stm32f1xx_it.c中有我们声明的EXTI3


- int main(void)
- {
- HAL_Init();
- SystemClock_Config();
- MX_GPIO_Init();
- while (1)
- {
- //先判断key是否被按下-->PA3
- if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_3)==GPIO_PIN_SET){//此时表示可能被按下
- //先进行软件消抖:延时一段时间再进行一次查看是否真的被按下
- HAL_Delay(5);
- if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_3)==GPIO_PIN_SET){//如果再一次进入说明是真的按键按下
- //下面这个while加上则表示按一次就亮,再按一次就灭
- while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_3)==GPIO_PIN_SET);
- //则我们调整led的亮灭--->PB0
- HAL_GPIO_WritePin(GPIOB,GPIO_PIN_6,!HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_6));
- }
- }
- }
- }
中断-NVIC与EXTI外设详解(超全面)-腾讯云开发者社区-腾讯云
1)NVIC其实本质就是中断的优先级。分为【抢占优先级】和【响应优先级】。
2)NVIC(嵌套向量中断):NVIC是Cortex-M3核心的一部分,关于它的资料不在《STM32的技术参考手册》中,应查阅ARM公司的《Cortex-M3技术参考手册》Cortex-M3的向量中断统一由NVIC管理。
3)NVIC是内部外设(Cortex-M中的外设)

1)NVIC是中断(EXTI)的主管。当我们使用到了外部或者内部的中断,都会使用到 NVIC来进行处理优先级。
2)类似于ExTI,TIM,串口的中断都是要经过NVIC才可以对CPU产生中断。只有其他内核中断,才可以不经过NVIC。

Cortex-M3 内核的外设也比较多,但STM32并没有用到这么多内核外设对其进行了裁剪,STM32重要的内核外设用到的库函数放在了misc.c文件之中所以core_cm3.c文件用的较少。
core_cm3.c:内核外设的驱动固件库
core_cm3.h:实现了内核(CPU)里面的外设的寄存器映射,还有很多关于内核外设的库函数。
misc.h:NVIC_InitTypeDef结构体,以及库函数的参数和声明
misc.c:NVIC(嵌套向量中断控制器)、SysTick(系统滴答定时器)相关函数
这个表存放在我们所使用的startup_stm32f103xb.s文件中【初始化文件】

STM32 将中断分为 5 个组,组 0-4。该分组的设置是由 SCB->AIRCR 寄存器的 bit10~8 来定义的。
数值越小,优先级越高

这里我们使用到的函数:

IRQn_Type IRQn:设置中断源不同的中断中断源不一样,且不可写错,即使写错了程序也不会报错,只会导致不响应中断。

具体的值要根据优先级分组来确定。
具体的值要根据优先级分组来确定

中断-NVIC与EXTI外设详解(超全面)-腾讯云开发者社区-腾讯云
对于互联型产品(F107),外部中断/事件控制器由20个产生事件/中断请求的边沿检测器组成,对于其它产品(我们这里是F103),则有19个能产生事件/中断请求的边沿检测器。
1)由外部条件触发例如按键触发(GPIO),触发产生上升沿、下降沿、双边沿【EXTI主要用于处理外部引脚状态变化引起的中断。】
2)每个输入线可以独立地配置输入类型(脉冲或挂起)和对应的触发事件(上升沿或下降沿或者双边沿都触发)。每个输入线都可以独立地被屏蔽。挂起寄存器保持着状态线的中断请求


16个中断线的不是每个中断都有独立的中断服务函数,IO口外部中断在中断向量表中只分配了7个中断向量,也就是只能使用7个中断服务函数
PA0--》EXTI0
PA2--》EXTI2

从表中可以看出,外部中断线5~9分配一个中断向量,共用一个服务函数。 外部中断线10~15分配一个中断向量,共用一个中断服务函数。
对应的中断服务函数,直接去启动文件里面找以防写错。【startup_stm32f103xb.s】


https://www.cnblogs.com/engraver-lxw/p/7518958.html
- 中断:需要CPU参与,需要调用软件的中断服务函数才能完成中断后产生的结果
- 事件:靠脉冲发生器产生一个脉冲,进而由硬件自动完成这个事件产生的结果,当然相应的联动部件需要先设置好,触发TIM计时,AD转换等,事件不要软件的参与,降低了CPU的负荷,而且硬件速度快于软件速度
- 选择需要作为外部中断触发引脚的GPIO引脚。
- 配置引脚为输入模式,选择上拉或下拉电阻。
- // 例如,配置引脚 PA0 作为外部中断触发引脚
- GPIO_InitTypeDef GPIO_InitStruct = {0};
-
- __HAL_RCC_GPIOA_CLK_ENABLE();
-
- GPIO_InitStruct.Pin = GPIO_PIN_0;
- GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
- GPIO_InitStruct.Pull = GPIO_PULLDOWN;
- HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
- 选择并配置外部中断线,将其连接到对应的GPIO引脚。
- 配置中断触发条件,例如上升沿、下降沿、或者是双边沿触发。
- // 例如,配置 EXTI0 与 PA0 相连,并设置为上升沿触发
- HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0);
- HAL_NVIC_EnableIRQ(EXTI0_IRQn);
-
- HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET);
-
- HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
- HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0);
- HAL_NVIC_EnableIRQ(EXTI0_IRQn);
-
- HAL_EXTI_GetHandle(&hexti0, EXTI_LINE_0);
- HAL_EXTI_RegisterCallback(&hexti0, HAL_EXTI_COMMON_CB_ID, UserButton_Callback);
- __HAL_GPIO_EXTI_GET_IT(GPIO_PIN_0);
- 中断服务函数是中断触发时执行的代码,处理实际的中断事件。【在it.c文件中写】
- 在中断服务函数中,可能需要清除中断标志。
- // 例如,编写 EXTI0 中断服务函数
- void EXTI0_IRQHandler(void)
- {
- HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
- }
-
- void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
- {
- if (GPIO_Pin == GPIO_PIN_0)
- {
- // 处理中断事件
- }
- }
在主程序中,启用外部中断
- // 启用中断
- HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);
- HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0);
- HAL_NVIC_EnableIRQ(EXTI0_IRQn);