【STM32】STM32中断体系

一、STM32的NVIC和起始代码中的ISP

1.NVIC(嵌套向量中断控制器)

(1)数据手册中相关部分浏览

(2)地址映射时0地址映射到Flash或SRAM

(3)中断向量表可以被人为重新映射,一般用来IAP中

(4)STM32采用一维的中断向量表

(5)中断优先级设置有点复杂,后面细说

1.特征

2.系统嘀嗒(SysTick)校准值寄存器

3.向量表

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

2、起始代码中的ISR

(1)其实代码中定义了一个Vector数组

(2)WEAK声明的默认ISR

(3)用户根据需要提供自己真正有用的ISR

(4)中断要配置使能,ISR中要清挂起等,这一点和其他CPU一样

二、STM32的外部中断(EXTI)

1.EXTI 控制器的主要特性如下:

2.外部中断/事件控制器框图

3.外部中断与I/O 映像(AFIO的的中断)

AFIO中与中断相关的寄存器有4个

记得再使用之前一定要使能时钟!!!!!

我们有4个AFIO的中断寄存器,则一个寄存器中应该可以处理16个引脚。

最好使用引脚时,设置PA0,PA1....

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

cpp 复制代码
/**
  * @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.外部中断配置寄存器 1(AFIO_EXTICR1)

2.外部中断配置寄存器 2(AFIO_EXTICR2)

4.如何实际编程使用外部中断

(1)时钟设置并打开相应GPIO模块时钟

(2)将相应GPIO配置为浮空输入

(3)NVIC设置

(4)将外部中断线和配套的GPIO进行连接映射

(5)外部中断线使能触发

(6)准备好ISR,并在ISR处等待执行中断程序即可

(7)记得!!!!!!!!!执行完ISR后记得将中断清除。

5.外部中断 VS 外部事件中断

外部中断:需要CPU,中断处理程序的参与

外部事件中断:不需要CPU参与

我们一般使用外部中断,不使用外部事件中断,因为我们不知道该器件是否接受脉冲信号。

6.相关寄存器

1. 上升沿触发选择寄存器(EXTI_RTSR)

2.下降沿触发选择寄存器(EXTI_FTSR)

3.中断屏蔽寄存器(EXTI_IMR)

4.挂起寄存器(EXTI_PR)

三、标准库中NVIC(中断优先级)模块分析

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

NVIC在【misc.c】中

1.抢占优先级 VS 次优先级

当抢占优先级的不同时,抢占优先级小的先执行,然后在执行优先级大的。

当抢占优先级相同时,次优先级小的不能抢占次优先级大的

当相同抢占优先级的程序进行中断时,次优先级小的可以抢先执行,在执行次优先级大的。

cpp 复制代码
//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 */

2.优先级组

cpp 复制代码
/**
	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 */

3.启动方式

RAM或者FLASH

cpp 复制代码
/**
	启动方式: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))

4.函数

1.NVIC_PriorityGroupConfig

在使用时一定设置使用哪一个优先级

cpp 复制代码
/**
  * @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;
}

2.NVIC_Init

cpp 复制代码
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);
  }
}

3.NVIC_SetVectorTable

设置中断向量表,看要设置到RAM还是FLASH

cpp 复制代码
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);
}

四、标准库中外部中断模块分析

1.EXTI_DeInit

cpp 复制代码
 //完全去始化
void EXTI_DeInit(void)
{
  EXTI->IMR = 0x00000000;
  EXTI->EMR = 0x00000000;
  EXTI->RTSR = 0x00000000; 
  EXTI->FTSR = 0x00000000; 
  EXTI->PR = 0x000FFFFF;
}

2.EXTI_Init

将我们设置好的结构体变量写入到寄存器中

cpp 复制代码
/**
  * @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;
  }
}

3.EXTI_StructInit

如果用户不想自己设置中断值,则可以调用这个函数,这个函数中有默认值可以使用

cpp 复制代码
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;
}

4.EXTI_GenerateSWInterrupt

软件中断,可以对寄存器中其中一位进行中断操作

cpp 复制代码
void EXTI_GenerateSWInterrupt(uint32_t EXTI_Line)
{
  /* Check the parameters */
  assert_param(IS_EXTI_LINE(EXTI_Line));
  
  EXTI->SWIER |= EXTI_Line;
}

5.EXTI_GetFlagStatus

共享中断:判断中断标志位是否真的置1了**(判断是哪一个标志进行中断的)**

cpp 复制代码
/**
  * @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;
}

6.EXTI_ClearITPendingBit(中断挂起)

中断进入后,就会有一个中断挂起

cpp 复制代码
/**
  * @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;
}

6.EXTI_ClearFlag

清除中断

cpp 复制代码
void EXTI_ClearFlag(uint32_t EXTI_Line)
{
  /* Check the parameters */
  assert_param(IS_EXTI_LINE(EXTI_Line));
  
  EXTI->PR = EXTI_Line;
}

五、GPIO外部中断程序的移植和调试

0.GPIO外部中断的配置步骤

使用HAL_GPIO_Init一步到位(步骤2-步骤5)

1.EXTI的HAL库设置步骤(GPIO外部中断)

2.通用外设驱动模型

3.HAL库中断回调处理机制介绍

1.建立工程模板

STM32项目工程的搭建-CSDN博客

2.查看官方示例代码

以ARM3.0的按键示例程序作为参考,移植到PZ6806L开发板上。

stm32f10x_it.c

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

startup_stm32f10x_md.s

这个文件中存放是有中断处理函数的定义

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

stm32f10x_it.h

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

main.c

RCC_Configuragtion

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

GPIO_Configuration
NVIC_Configuration

NVIC中断优先级的初始化

3.整个main函数的流程

1)初始化RCC

2)初始化GPIO

3)初始化NVIC

4)设置外部中断(将中断线和GPIO线连接起来)

5)外部中断线的模式选择**(我们一般选择外部中断,不使用外部事件中断)**

6)产生软件中断触发事件

4.开始移植

1.按键的接线问题

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

LED8-LED16的J34接到PA0-PA7

因为操作库函数的时候只能一位一位操作,所以我们只能选择其中一个引脚进行操作。

我们选择KEY1和LED16进行操作,分别对应PB0和PA7

2.关于中断几的选择

由上面可知我们KEY1对应的是PB0,由0可知应该选择EXIT0

确定好后,再stm32f10x.c和stm32f10x.h文件中进行重写和声明【我们可以再stm32f10x_md.c文件中查看应该调用哪一个函数】

3.EXTI0_IRQHandler的移植

注意点:本来我们应该再stm32f10x_it.c文件中去查找这个中断函数的初始化,但是普中科技的AMR3.0的官方代码将这个中断函数的初始化写再了exit.c文件中。

stm32f10x_it.c
cpp 复制代码
  */
void EXTI0_IRQHandler(void)
{
	//检测制定的EXTI线路触发
	if(EXTI_GetITStatus(EXTI_Line0)==1)
	{
		/*
		delay_ms(10);
		if(KEY1==0)
		{
			led2=0;
		}
		*/
	}
	//清除EXTI线路挂起位
	EXTI_ClearITPendingBit(EXTI_Line0);
}
stm32f10x_it.h
cpp 复制代码
//声明自己写的EXIT0
void EXTI0_IRQHandler(void);

4.RCC_Configuration的移植

1.RCC的使能
cpp 复制代码
//RCC的配置
void RCC_Configuration(void){
	
	//因为起始代码中已经调用SystemInit将主时钟设置为72MHZ
	//所以我们这里RCC直接使能时钟就可以
	
	//使能GPIO端口
	//因为我们使用到的是PB0和PB8,所以只使用到GPIOB
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|
												RCC_APB2Periph_AFIO,ENABLE);
	
}
2.GPIO_Configuration的移植
cpp 复制代码
//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亮

}
3.NVIC优先级的移植

NVIC_IRQChannel:在misc.h中定义

cpp 复制代码
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);//初始化中断
}
4.main函数
cpp 复制代码
//函数声明
//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;
}
5.中断函数的处理(stm32f10x_it.c)

因为我们要在中断函数中对LED进行点亮/熄灭,所以需要对LED进行读取和写入。

所以要使用到我们的【GPIO_ReadInputDataBit】和【GPIO_WriteBit】

cpp 复制代码
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);
}
6.对LED的初始化

在对GPIO初始化的时候一起将lED一起点亮

cpp 复制代码
	// 默认输出1让LED亮
  GPIO_WriteBit(GPIOA, GPIO_Pin_7, Bit_SET);	

3.完整代码

main.c

cpp 复制代码
#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);//初始化中断
}
stm32f10x_it.c
cpp 复制代码
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);
}
相关推荐
酷飞飞1 分钟前
RTC和看门狗基于GD32F407VE的天空星的配置
stm32·单片机·嵌入式硬件·mcu
qq_401700411 小时前
STM32的HardFault错误处理技巧
stm32
WD137298015572 小时前
WD5030A,24V降5V,15A 大电流,应用于手机、平板、笔记本充电器
stm32·单片机·嵌入式硬件·智能手机·汽车·电脑·51单片机
日更嵌入式的打工仔2 小时前
GPIO 中断通用配置指南
stm32·单片机·嵌入式硬件
平凡灵感码头2 小时前
基于 STM32 的智能门锁系统,系统界面设计
stm32·单片机·嵌入式硬件
Truffle7电子3 小时前
STM32理论 —— 存储、中断
stm32·嵌入式硬件·嵌入式·存储·中断
报错小能手3 小时前
linux学习笔记(32)网络编程——UDP
单片机·嵌入式硬件
XiangrongZ5 小时前
江协科技STM32课程笔记(四)—定时器TIM(输入捕获)
笔记·科技·stm32
xyx-3v5 小时前
SPI四种工作模式
stm32·单片机·嵌入式硬件·学习
qiuiuiu4136 小时前
正点原子RK3568学习日志6-驱动模块传参
linux·c语言·开发语言·单片机·学习