HAL+M4学习记录_6

news2024/10/23 9:29:49

一、中断和事件

记录学习中断和事件的学习

1.1 NVIC(嵌套矢量中断控制器)

NVIC管理着所有中断,包括核心异常。中断分为内部中断(也称异常)和外部中断,根据core_cm4.h文件,NVIC寄存器映射如下

typedef struct
{
  __IOM uint32_t ISER[8U];               /* 中断使能寄存器 */
        uint32_t RESERVED0[24U];
  __IOM uint32_t ICER[8U];               /* 中断失能寄存器 */
        uint32_t RESERVED1[24U];
  __IOM uint32_t ISPR[8U];               /* 中断挂起使能寄存器 */
        uint32_t RESERVED2[24U];
  __IOM uint32_t ICPR[8U];               /* 中断挂起失能寄存器 */
        uint32_t RESERVED3[24U];
  __IOM uint32_t IABR[8U];               /* 中断激活寄存器 */
        uint32_t RESERVED4[56U];
  __IOM uint8_t  IP[240U];               /* 中断优先级寄存器 */
        uint32_t RESERVED5[644U];
  __OM  uint32_t STIR;                   /* 软件触发中断寄存器 */
}  NVIC_Type;

根据编程手册中NVIC寄存器映射图如下
NVIC寄存器映射图1
NVIC寄存器映射图2
由图可以看出,NVIC_ISER中断使能寄存器使用了8个,可完成240个中断的使能;NVIC_ICER中断失能寄存器使用了8个,可完成240个中断的失能;NVIC_ISPR中断挂起使能寄存器使用了8个,可完成240个中断挂起的使能;NVIC_ICPR中断挂起失能寄存器使用了8个,可完成240个中断挂起的失能;NVIC_IABR中断激活寄存器使用了8个,可完成240个中断的激活;NVIC_IPR中断优先级寄存器使用了60个,可完成240个中断的优先级配置;NVIC_STIP软件触发中断寄存器使用了1个,以触发软件生成中断,写入的值即为需要软件触发中断的ID,仅用了8位,可设置0-239范围。NVIC通过NVIC_IPRx寄存器用来配置中断优先级
IPR寄存器分布
由图可以看出,NVIC_IPR寄存器共使用了60个,每个NVIC_IPRx分为了4个用于配置优先级的字段,每个字段8位用于配置一个中断优先级
IPR寄存器
该寄存器为每一个中断提供了一个8位字段来设置优先级,理论上可设置256个优先级,在F407中只使用了高4位,因此可设置16个优先级。

1.2 优先级分组

这4位又分为高n位的抢占优先级和低4-n位的子优先级,抢占优先级高的可以中断嵌套,子优先级高的可以优先排队,抢占优先级和响应优先级均相同的按中断号排队,编号越小,优先级越高,在文件stm32f4xx_hal_cortex.c中给出了优先级分组

/**
  * @brief  Sets the priority grouping field (preemption priority and subpriority)
  *         using the required unlock sequence.
  * @param  PriorityGroup The priority grouping bits length. 
  *         This parameter can be one of the following values:
  *         @arg NVIC_PRIORITYGROUP_0: 0 bits for preemption priority
  *                                    4 bits for subpriority
  *         @arg NVIC_PRIORITYGROUP_1: 1 bits for preemption priority
  *                                    3 bits for subpriority
  *         @arg NVIC_PRIORITYGROUP_2: 2 bits for preemption priority
  *                                    2 bits for subpriority
  *         @arg NVIC_PRIORITYGROUP_3: 3 bits for preemption priority
  *                                    1 bits for subpriority
  *         @arg NVIC_PRIORITYGROUP_4: 4 bits for preemption priority
  *                                    0 bits for subpriority
  * @note   When the NVIC_PriorityGroup_0 is selected, IRQ preemption is no more possible. 
  *         The pending IRQ priority will be managed only by the subpriority. 
  * @retval None
  */
void HAL_NVIC_SetPriorityGrouping(uint32_t PriorityGroup)
{
  /* Check the parameters */
  assert_param(IS_NVIC_PRIORITY_GROUP(PriorityGroup));
  
  /* Set the PRIGROUP[10:8] bits according to the PriorityGroup parameter value */
  NVIC_SetPriorityGrouping(PriorityGroup);
}
优先级分组抢占优先级子优先级高4位使用情况
NVIC_PriorityGroup_00 级抢占优先级0-15 级子优先级0bit 用于抢占优先级 ,4bit 全用于子优先级
NVIC_PriorityGroup_10-1 级抢占优先级0-7 级子优先级1bit 用于抢占优先级 ,3bit 全用于子优先级
NVIC_PriorityGroup_20-3 级抢占优先级0-3 级抢占优先级2bit 用于抢占优先级 ,2bit 全用于子优先级
NVIC_PriorityGroup_30-7 级抢占优先级0-1 级抢占优先级3bit 用于抢占优先级 ,1bit 全用于子优先级
NVIC_PriorityGroup_40-15 级抢占优先级0 级抢占优先级4bit 用于抢占优先级 ,0bit 全用于子优先级

系统上电复位后默认使用的是优先级分组0,在F407中总共有82个中断可设置优先级。

1.3 常用NVIC API

stm32f4xx_hal_cortex.c文件中,给出了配置NVIC中断的函数

  • HAL_NVIC_SetPriorityGrouping(uint32_t PriorityGroup)函数配置中断优先级分组
  • HAL_NVIC_SetPriority(IRQn_Type IRQn, uint32_t PreemptPriority, uint32_t SubPriority)函数配置具体外设中断通道的抢占优先级和子优先级
  • HAL_NVIC_EnableIRQ(IRQn_Type IRQn)函数使能中断请求

在编程时,中断使能一般有两个门,外设使能相应的中断送入NVIC,NVIC使能后才能响应中断。
NVIC基本结构
stm32f407xx.h文件中列举了中断通道IRQn,具体如下

typedef enum
{
  /******  Cortex-M4 Processor Exceptions Numbers ****************************************************************/
  NonMaskableInt_IRQn         = -14,    /*!< 2 Non Maskable Interrupt                                          */
  MemoryManagement_IRQn       = -12,    /*!< 4 Cortex-M4 Memory Management Interrupt                           */
  BusFault_IRQn               = -11,    /*!< 5 Cortex-M4 Bus Fault Interrupt                                   */
  UsageFault_IRQn             = -10,    /*!< 6 Cortex-M4 Usage Fault Interrupt                                 */
  SVCall_IRQn                 = -5,     /*!< 11 Cortex-M4 SV Call Interrupt                                    */
  DebugMonitor_IRQn           = -4,     /*!< 12 Cortex-M4 Debug Monitor Interrupt                              */
  PendSV_IRQn                 = -2,     /*!< 14 Cortex-M4 Pend SV Interrupt                                    */
  SysTick_IRQn                = -1,     /*!< 15 Cortex-M4 System Tick Interrupt                                */
  /******  STM32 specific Interrupt Numbers **********************************************************************/
  WWDG_IRQn                   = 0,      /*!< Window WatchDog Interrupt                                         */
  PVD_IRQn                    = 1,      /*!< PVD through EXTI Line detection Interrupt                         */
  TAMP_STAMP_IRQn             = 2,      /*!< Tamper and TimeStamp interrupts through the EXTI line             */
  RTC_WKUP_IRQn               = 3,      /*!< RTC Wakeup interrupt through the EXTI line                        */
  FLASH_IRQn                  = 4,      /*!< FLASH global Interrupt                                            */
  RCC_IRQn                    = 5,      /*!< RCC global Interrupt                                              */
  EXTI0_IRQn                  = 6,      /*!< EXTI Line0 Interrupt                                              */
  EXTI1_IRQn                  = 7,      /*!< EXTI Line1 Interrupt                                              */
  EXTI2_IRQn                  = 8,      /*!< EXTI Line2 Interrupt                                              */
  EXTI3_IRQn                  = 9,      /*!< EXTI Line3 Interrupt                                              */
  EXTI4_IRQn                  = 10,     /*!< EXTI Line4 Interrupt                                              */
  DMA1_Stream0_IRQn           = 11,     /*!< DMA1 Stream 0 global Interrupt                                    */
  DMA1_Stream1_IRQn           = 12,     /*!< DMA1 Stream 1 global Interrupt                                    */
  DMA1_Stream2_IRQn           = 13,     /*!< DMA1 Stream 2 global Interrupt                                    */
  DMA1_Stream3_IRQn           = 14,     /*!< DMA1 Stream 3 global Interrupt                                    */
  DMA1_Stream4_IRQn           = 15,     /*!< DMA1 Stream 4 global Interrupt                                    */
  DMA1_Stream5_IRQn           = 16,     /*!< DMA1 Stream 5 global Interrupt                                    */
  DMA1_Stream6_IRQn           = 17,     /*!< DMA1 Stream 6 global Interrupt                                    */
  ADC_IRQn                    = 18,     /*!< ADC1, ADC2 and ADC3 global Interrupts                             */
  CAN1_TX_IRQn                = 19,     /*!< CAN1 TX Interrupt                                                 */
  CAN1_RX0_IRQn               = 20,     /*!< CAN1 RX0 Interrupt                                                */
  CAN1_RX1_IRQn               = 21,     /*!< CAN1 RX1 Interrupt                                                */
  CAN1_SCE_IRQn               = 22,     /*!< CAN1 SCE Interrupt                                                */
  EXTI9_5_IRQn                = 23,     /*!< External Line[9:5] Interrupts                                     */
  TIM1_BRK_TIM9_IRQn          = 24,     /*!< TIM1 Break interrupt and TIM9 global interrupt                    */
  TIM1_UP_TIM10_IRQn          = 25,     /*!< TIM1 Update Interrupt and TIM10 global interrupt                  */
  TIM1_TRG_COM_TIM11_IRQn     = 26,     /*!< TIM1 Trigger and Commutation Interrupt and TIM11 global interrupt */
  TIM1_CC_IRQn                = 27,     /*!< TIM1 Capture Compare Interrupt                                    */
  TIM2_IRQn                   = 28,     /*!< TIM2 global Interrupt                                             */
  TIM3_IRQn                   = 29,     /*!< TIM3 global Interrupt                                             */
  TIM4_IRQn                   = 30,     /*!< TIM4 global Interrupt                                             */
  I2C1_EV_IRQn                = 31,     /*!< I2C1 Event Interrupt                                              */
  I2C1_ER_IRQn                = 32,     /*!< I2C1 Error Interrupt                                              */
  I2C2_EV_IRQn                = 33,     /*!< I2C2 Event Interrupt                                              */
  I2C2_ER_IRQn                = 34,     /*!< I2C2 Error Interrupt                                              */
  SPI1_IRQn                   = 35,     /*!< SPI1 global Interrupt                                             */
  SPI2_IRQn                   = 36,     /*!< SPI2 global Interrupt                                             */
  USART1_IRQn                 = 37,     /*!< USART1 global Interrupt                                           */
  USART2_IRQn                 = 38,     /*!< USART2 global Interrupt                                           */
  USART3_IRQn                 = 39,     /*!< USART3 global Interrupt                                           */
  EXTI15_10_IRQn              = 40,     /*!< External Line[15:10] Interrupts                                   */
  RTC_Alarm_IRQn              = 41,     /*!< RTC Alarm (A and B) through EXTI Line Interrupt                   */
  OTG_FS_WKUP_IRQn            = 42,     /*!< USB OTG FS Wakeup through EXTI line interrupt                     */
  TIM8_BRK_TIM12_IRQn         = 43,     /*!< TIM8 Break Interrupt and TIM12 global interrupt                   */
  TIM8_UP_TIM13_IRQn          = 44,     /*!< TIM8 Update Interrupt and TIM13 global interrupt                  */
  TIM8_TRG_COM_TIM14_IRQn     = 45,     /*!< TIM8 Trigger and Commutation Interrupt and TIM14 global interrupt */
  TIM8_CC_IRQn                = 46,     /*!< TIM8 Capture Compare global interrupt                             */
  DMA1_Stream7_IRQn           = 47,     /*!< DMA1 Stream7 Interrupt                                            */
  FSMC_IRQn                   = 48,     /*!< FSMC global Interrupt                                             */
  SDIO_IRQn                   = 49,     /*!< SDIO global Interrupt                                             */
  TIM5_IRQn                   = 50,     /*!< TIM5 global Interrupt                                             */
  SPI3_IRQn                   = 51,     /*!< SPI3 global Interrupt                                             */
  UART4_IRQn                  = 52,     /*!< UART4 global Interrupt                                            */
  UART5_IRQn                  = 53,     /*!< UART5 global Interrupt                                            */
  TIM6_DAC_IRQn               = 54,     /*!< TIM6 global and DAC1&2 underrun error  interrupts                 */
  TIM7_IRQn                   = 55,     /*!< TIM7 global interrupt                                             */
  DMA2_Stream0_IRQn           = 56,     /*!< DMA2 Stream 0 global Interrupt                                    */
  DMA2_Stream1_IRQn           = 57,     /*!< DMA2 Stream 1 global Interrupt                                    */
  DMA2_Stream2_IRQn           = 58,     /*!< DMA2 Stream 2 global Interrupt                                    */
  DMA2_Stream3_IRQn           = 59,     /*!< DMA2 Stream 3 global Interrupt                                    */
  DMA2_Stream4_IRQn           = 60,     /*!< DMA2 Stream 4 global Interrupt                                    */
  ETH_IRQn                    = 61,     /*!< Ethernet global Interrupt                                         */
  ETH_WKUP_IRQn               = 62,     /*!< Ethernet Wakeup through EXTI line Interrupt                       */
  CAN2_TX_IRQn                = 63,     /*!< CAN2 TX Interrupt                                                 */
  CAN2_RX0_IRQn               = 64,     /*!< CAN2 RX0 Interrupt                                                */
  CAN2_RX1_IRQn               = 65,     /*!< CAN2 RX1 Interrupt                                                */
  CAN2_SCE_IRQn               = 66,     /*!< CAN2 SCE Interrupt                                                */
  OTG_FS_IRQn                 = 67,     /*!< USB OTG FS global Interrupt                                       */
  DMA2_Stream5_IRQn           = 68,     /*!< DMA2 Stream 5 global interrupt                                    */
  DMA2_Stream6_IRQn           = 69,     /*!< DMA2 Stream 6 global interrupt                                    */
  DMA2_Stream7_IRQn           = 70,     /*!< DMA2 Stream 7 global interrupt                                    */
  USART6_IRQn                 = 71,     /*!< USART6 global interrupt                                           */
  I2C3_EV_IRQn                = 72,     /*!< I2C3 event interrupt                                              */
  I2C3_ER_IRQn                = 73,     /*!< I2C3 error interrupt                                              */
  OTG_HS_EP1_OUT_IRQn         = 74,     /*!< USB OTG HS End Point 1 Out global interrupt                       */
  OTG_HS_EP1_IN_IRQn          = 75,     /*!< USB OTG HS End Point 1 In global interrupt                        */
  OTG_HS_WKUP_IRQn            = 76,     /*!< USB OTG HS Wakeup through EXTI interrupt                          */
  OTG_HS_IRQn                 = 77,     /*!< USB OTG HS global interrupt                                       */
  DCMI_IRQn                   = 78,     /*!< DCMI global interrupt                                             */
  RNG_IRQn                    = 80,     /*!< RNG global Interrupt                                              */
  FPU_IRQn                    = 81      /*!< FPU global interrupt                                               */
} IRQn_Type;

1.4 EXTI(外部中断/事件)

EXTI外部中断/事件控制器包含多达23个边缘检测器,用于产生事件/中断请求。每条输入线均可独立配置,以选择类型(中断或事件)以及相应的触发事件(上升沿、下降沿或两者)。每条线路也可单独屏蔽。挂起寄存器用于维护中断请求的状态线。EXTI可监测指定GPIO的电平信号,触发事件发生时会向NVIC发出中断请求,经NVIC裁决后即可MCU响应中断。EXTI框图如下
EXTI外部中断
由图知EXTI可分为两部分,一个是产生中断,一个是产生事件,具体分析如下

  • 中断
    中断是表示有某个事件发送产生中断并跳转到对应的中断处理程序中。外部信号经GPIO进入边沿监测器,触发事件发生后输出到一个或门;软件中断事件寄存器允许软件启动中断,输出到一个与门;中断屏蔽寄存器可决定中断的产生,然后进入挂起请求寄存器;最后由挂起请求寄存器决定将中断输送到NVIC。中断需要CPU参与

  • 事件
    事件是表示检测到某一动作(电平边沿)触发事件发生了。产生事件是在或门之后输出到另一个与门,该与门结果由事件屏蔽寄存器控制输出;产生有效输出后,脉冲发生器会输出一个脉冲信号。事件不CPU参与

这里给出事件中断之间的区别:中断可被更优先的中断屏蔽,事件不会;事件是一个触发信号(脉冲),中断则是一个固定电平信号;中断一定要有中断服务函数,必须有CPU参入,事件不需要。

1.5 外部中断/事件线映射

GPIO以以下方式连接16组外部中断/事件线
EXTI映射
剩下的7组外部中断/事件以以下方式连接
EXTI映射1
EXTI基本结构如下
EXTI基本结构
IO口外部中断分配了7个中断向量
外部中断向量
在启动文件中,给出了中断函数入口

EXTI0_IRQHandler                  ; EXTI Line0
EXTI1_IRQHandler                  ; EXTI Line1
EXTI2_IRQHandler                  ; EXTI Line2
EXTI3_IRQHandler                  ; EXTI Line3
EXTI4_IRQHandler                  ; EXTI Line4
EXTI9_5_IRQHandler                ; External Line[9:5]s
EXTI15_10_IRQHandler              ; External Line[15:10]s

由图和启动代码可以看出外部中断线5-9公用一个中断向量,共用一个服务函数;外部中断线10-15共用一个中断向量,共用一个服务函数。

1.6 EXTI寄存器

stm32f407xx.h文件中,给出了EXTI寄存器的定义

/**
  * @brief External Interrupt/Event Controller
  */

typedef struct
{
  __IO uint32_t IMR;    /*!< EXTI 中断屏蔽寄存器, Address offset: 0x00 */
  __IO uint32_t EMR;    /*!< EXTI 时间屏蔽寄存器, Address offset: 0x04 */
  __IO uint32_t RTSR;   /*!< EXTI 上升沿触发选择寄存器,  Address offset: 0x08 */
  __IO uint32_t FTSR;   /*!< EXTI 下降沿触发选择寄存器, Address offset: 0x0C */
  __IO uint32_t SWIER;  /*!< EXTI 软件中断事件寄存器,  Address offset: 0x10 */
  __IO uint32_t PR;     /*!< EXTI 挂起寄存器,  Address offset: 0x14 */
} EXTI_TypeDef;

二、HAL编程

这里设计使用外接的按键作为触发源,上升沿触发MCU产生中断并在中断服务函数中实现点亮LED的任务,编程步骤如下

  • 配置GPIO
  • 配置NVIC
  • 配置EXTI
  • 编写中断服务函数

在文件stm32f4xx_hal_gpio.c中存在两个有关EXTI中断的函数:void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)__weak void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin),前一个函数是在中断服务函数中对GPIO外部中断进行检测;然后调用后一个回调函数执行中断响应,需要进行重定义。

  • key.c文件
/*
*********************************************************************************************************
*	                                   Module Description
*
*	独立按键驱动模块,板载三个按键K_UP、K0和K1
*	按键K_UP(WK_UP可作为待机唤醒选项)按下为高电平,设置为下拉输入模式
*	按键K0和按键K1按下为低电平,设置为上拉输入模式
*	配置EXTI外部中断,按键按下实现LED翻转
*		优先级:K_UP > K_0 > K_1
*********************************************************************************************************
*/

#include "bsp.h"
									
/*
**********************************************************************************
*   @brief    按键硬件初始化,配置按键对应的GPIO
*   @param	  None
*   @return	  None
*   @note	  	
**********************************************************************************
*/
static void bsp_InitKeyHard()
{
	GPIO_InitTypeDef GPIO_InitStructure;
	/* 打开GPIO时钟 */
	GPIO_CLK_ENABLE_K_UP();
	GPIO_CLK_ENABLE_K0();
	GPIO_CLK_ENABLE_K1();
	/* 配置K_UP为下拉输入,K0和K1为上拉输入 */
	GPIO_InitStructure.Mode 	= GPIO_MODE_IT_RISING;			// 上升沿触发中断输入模式
	GPIO_InitStructure.Speed 	= GPIO_SPEED_FREQ_VERY_HIGH;	// GPIO速度
	GPIO_InitStructure.Pin 		= GPIO_PIN_K_UP;				// K_UP引脚
	GPIO_InitStructure.Pull 	= GPIO_PULLDOWN;				// 下拉模式
	HAL_GPIO_Init(GPIO_PORT_K_UP, &GPIO_InitStructure);
	HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);			// 第4优先级组
	HAL_NVIC_SetPriority(GPIO_IRQ_K_UP, 1, 0);					// 第1抢占优先级,第0子优先级
	HAL_NVIC_EnableIRQ(GPIO_IRQ_K_UP);							// 使能K_UP按键中断
	
	GPIO_InitStructure.Pin 		= GPIO_PIN_K0;					// K0引脚
	GPIO_InitStructure.Pull		= GPIO_PULLUP;					// 上拉模式
	HAL_GPIO_Init(GPIO_PORT_K0, &GPIO_InitStructure);
	HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);			// 第4优先级组
	HAL_NVIC_SetPriority(GPIO_IRQ_K0, 2, 0);					// 第2抢占优先级,第0子优先级
	HAL_NVIC_EnableIRQ(GPIO_IRQ_K0);							// 使能K0按键中断
	
	GPIO_InitStructure.Pin 		= GPIO_PIN_K1;					// K1引脚
	GPIO_InitStructure.Pull		= GPIO_PULLUP;					// 上拉模式
	HAL_GPIO_Init(GPIO_PORT_K1, &GPIO_InitStructure);
	HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_4);			// 第4优先级组
	HAL_NVIC_SetPriority(GPIO_IRQ_K1, 3, 0);					// 第3抢占优先级,第0子优先级
	HAL_NVIC_EnableIRQ(GPIO_IRQ_K1);							// 使能K1按键中断
}

/*
**********************************************************************************
*   @brief    初始化按键驱动
*   @param	  None
*   @return	  None
*   @note	  	
**********************************************************************************
*/
void bsp_InitKey()
{
	bsp_InitKeyHard();
}

/*
**********************************************************************************
*   @brief    阻塞式按键扫描函数
*   @param	  None
*   @return	  键值,如下
*				K_UP按下返回3
*				K0按下返回1
*				K1按下返回2
*   @note	  
**********************************************************************************
*/
uint8_t bsp_ScanKey()
{
	uint8_t key_value = 0;	// 键值
	// K_UP按键检测
	if(K_UP_NOW == 1)
	{
		bsp_DelayMs(20);
		while(K_UP_NOW == 1);
		bsp_DelayMs(20);
		key_value = 3;
	}
	// K0按键检测
	if(K0_NOW == 0)
	{
		bsp_DelayMs(20);
		while(K0_NOW == 0);
		bsp_DelayMs(20);
		key_value = 1;
	}
	// K1按键检测
	if(K1_NOW == 0)
	{
		bsp_DelayMs(20);
		while(K1_NOW == 0);
		bsp_DelayMs(20);
		key_value = 2;
	}
	return key_value;
}


/* Interrupt function */
/*
**********************************************************************************
*   @brief    EXTI0中断服务函数,按键K_UP触发EXTI0_IRQHandler函数
*   @param	  None
*   @return	  None
*   @note	  
**********************************************************************************
*/
void EXTI0_IRQHandler()
{
	HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_K_UP);	// 处理K_UP引脚中断请求
	__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_K_UP);	// HAL库默认先清除中断再处理回调,退出时再清除一次中断
}

/*
**********************************************************************************
*   @brief    EXTI4中断服务函数,按键K_0触发EXTI4_IRQHandler函数
*   @param	  None
*   @return	  None
*   @note	  
**********************************************************************************
*/
void EXTI4_IRQHandler()
{
	HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_K0);	// 处理K0引脚中断请求
	__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_K0);	// HAL库默认先清除中断再处理回调,退出时再清除一次中断
}

/*
**********************************************************************************
*   @brief    EXTI3中断服务函数,按键K_1触发EXTI3_IRQHandler函数
*   @param	  None
*   @return	  None
*   @note	  
**********************************************************************************
*/
void EXTI3_IRQHandler()
{
	HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_K1);	// 处理K_1引脚中断请求
	__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_K1);	// HAL库默认先清除中断再处理回调,退出时再清除一次中断
}

/*
**********************************************************************************
*   @brief    EXTI线检测回调函数,所有外部中断服务函数会调用此函数
*   @param	  GPIO_Pin:外部GPIO中断引脚号
*   @return	  None
*   @note	  
**********************************************************************************
*/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
	bsp_DelayMs(20);	// 去抖
	switch(GPIO_Pin)
	{
		case GPIO_PIN_K_UP:
		{
			bsp_LedToggle(1);
			bsp_LedToggle(2);
			printf("K_UP press!!");
			break;
		}
		case GPIO_PIN_K0:
		{
			bsp_LedToggle(1);
			printf("K_0 press!!");
			break;
		}
		case GPIO_PIN_K1:
		{
			bsp_LedToggle(2);
			printf("K_1 press!!");
			break;
		}
		default:
			break;
	}
}


  • key.h文件
#ifndef __BSP_KEYS_H
#define __BSP_KEYS_H

/* private define */
#define HARD_KEY_NUM			3											// 实体按键个数
// 按键引脚定义,板载三个按键K_UP、K0和K1,所接引脚分别是PA0、PE4和PE3
#define GPIO_CLK_ENABLE_K_UP()	do{__HAL_RCC_GPIOA_CLK_ENABLE();}while(0)
#define GPIO_PORT_K_UP			GPIOA
#define GPIO_PIN_K_UP			GPIO_PIN_0
#define GPIO_IRQ_K_UP			EXTI0_IRQn

#define GPIO_CLK_ENABLE_K0()	do{__HAL_RCC_GPIOE_CLK_ENABLE();}while(0)
#define GPIO_PORT_K0			GPIOE
#define GPIO_PIN_K0				GPIO_PIN_4
#define GPIO_IRQ_K0				EXTI4_IRQn

#define GPIO_CLK_ENABLE_K1()	do{__HAL_RCC_GPIOE_CLK_ENABLE();}while(0)
#define GPIO_PORT_K1			GPIOE
#define GPIO_PIN_K1				GPIO_PIN_3
#define GPIO_IRQ_K1				EXTI3_IRQn
// 按键引脚当前电平
#define K_UP_NOW				HAL_GPIO_ReadPin(GPIO_PORT_K_UP, GPIO_PIN_K_UP)
#define K0_NOW					HAL_GPIO_ReadPin(GPIO_PORT_K0, GPIO_PIN_K0)
#define K1_NOW					HAL_GPIO_ReadPin(GPIO_PORT_K1, GPIO_PIN_K1)
// 键值定义
#define PRES_K_UP				3
#define PRES_K0					1
#define PRES_K1					2

/* public statement */
void bsp_InitKey();
uint8_t bsp_ScanKey();
#endif

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2213308.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++ | set / map(详解)

前言 本篇博客讲解c中stl的set/map&#xff0c;本篇讲的如何使用 &#x1f493; 个人主页&#xff1a;普通young man-CSDN博客 ⏩ 文章专栏&#xff1a;C_普通young man的博客-CSDN博客 ⏩ 本人giee: 普通小青年 (pu-tong-young-man) - Gitee.com 若有问题 评论区见&#x1f…

R语言绘制Venn图(文氏图、温氏图、维恩图、范氏图、韦恩图)

Venn图&#xff0c;又称文氏图&#xff0c;标题中其他名字也是它的别称&#xff0c;由封闭圆形组成&#xff0c;代表不同集合。圆形重叠部分表示集合交集&#xff0c;非重叠处为独有元素。在生物学、统计学等领域广泛应用&#xff0c;可展示不同数据集相似性与差异&#xff0c;…

【hot100-java】LRU 缓存

链表篇 灵神题解 class LRUCache {private static class Node{int key,value;Node prev,next;Node (int k,int v){keyk;valuev;}}private final int capacity;//哨兵节点private final Node dummynew Node(0,0);private final Map<Integer,Node> keyToNode new HashMap&l…

【机器学习】并行计算(parallel computation)Part1

为什么我们在机器学习中需要用到并行计算呢&#xff0c;因为现在最流行的机器学习算法都是神经网络&#xff0c;神经网络模型的计算量、参数量都很大&#xff0c;比如ResNet-50参数量为25M。而我们在训练的时候使用的数据集也很大&#xff0c;比如ImageNet数据集含有14M张图片。…

【C++笔记】引用、inline关键字和nullptr

前言 各位读者朋友们大家好&#xff0c;上期我们讲了C的部分基础语法&#xff0c;这期我们继续对C语法进行深入的学习。 目录 前言一. 引用1. 引用的概念及定义2. 引用的特性3. 引用的使用4. const引用5. 指针和引用的关系 二. inline三. nullptr 一. 引用 1. 引用的概念及定…

ubuntu登录root用户相关配置与注意事项

在ubuntu系统中&#xff0c;部分文件的访问与操作需要在root权限的认证加持下才能顺利进行&#xff0c;以下对如何登录root权限用户进行记录。 学习目标&#xff1a;随心所欲地切换普通权限用户与root用户 首先&#xff1a;在Ubuntu系统中&#xff0c;出于安全考虑&#xff0c;…

项目验收 | 星云股份携手盘古信息加“数”前行,数字智慧提升生产效率

在位于福州市的现代化智能制造工厂内&#xff0c;一排排先进的储能变流器&#xff08;PCS&#xff09;和充电桩正在紧锣密鼓地生产中&#xff0c;从电池研发、工程应用的系列测试及自动化装备&#xff0c;再到应用于电动汽车、储能新基建的储能变流器及充电桩等&#xff0c;福建…

ajax php

文章目录 get请求postget和post的异同点ajax原生步骤jquery步骤优点 php安装&#xff0c;后台处理脚本语言。 后端开发语言不能直接允许&#xff0c;必须放在服务器对对应的文件夹下运行。 如&#xff1a;wamp的对应服务器的文件夹是www get请求 <!DOCTYPE html> &l…

手机摄影入门

感觉会摄影的人是能够从生活中发现美的人。 我不太会拍照&#xff0c;觉得拍好的照片比较浪费时间&#xff0c;而且缺乏审美也缺乏技巧&#xff0c;所以拍照的时候总是拍不好。但有时候还是需要拍一些好看的照片的。 心态和审美可能需要比较长时间提升&#xff0c;但一些基础…

Firefox火狐浏览器新建标签页的位置

文章目录 环境新建标签页的位置打开“与当前页面相关的”新标签页 环境 Windows 11家庭版Firefox浏览器 131.0.2 (64 位) 新建标签页的位置 比方说浏览器打开了两个标签页&#xff0c;当前浏览的是第一个标签页&#xff0c;如下图所示&#xff1a; 此时&#xff0c;如果新建…

国有特大型企业安全知识竞赛,赛制就是不一样

国家电力投资集团有限公司是中央直接管理的特大型国有重要骨干企业&#xff0c;肩负保障国家能源安全的重大责任&#xff0c;业务涵盖电力、热力、煤炭、铝业、物流、金融、环保、光伏、电站服务等领域, 拥有核电、火电、水电、风电、光伏发电等全部发电类型。 电投集团本次安…

星舰第五次发射解读:火箭「筷子」夹取技术的奥秘

SpaceX 的星舰&#xff08;Starship&#xff09;第五次发射成功&#xff0c;引发了全球航天领域的广泛关注。在这次发射中&#xff0c;最引人注目的是其一级助推器 Super Heavy 成功回收&#xff0c;并首次被发射塔上的「筷子」机械臂精准抓取。这标志着 SpaceX 朝着完全可重复…

dotjs学习使用

数据插入 {{ }} for interpolation //插入案例 <!DOCTYPE html> <html lang"zh"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>do…

无人机之三维航迹规划篇

一、基本原理 飞行环境建模&#xff1a;在三维航迹规划中&#xff0c;首先需要对飞行环境进行建模。这包括对地形、障碍物、气象等因素进行准确的测量和分析&#xff0c;以获得可行的飞行路径。 飞行任务需求分析&#xff1a;根据无人机的任务需求&#xff0c;确定航迹规划的…

电力电子技术(四)

单相可控整流电路&#xff1a;&#xff08;包括单相半波整流和单相桥式整流&#xff09; &#xff08;一&#xff09;单相半波整流&#xff1a; 1.1阻性负载&#xff1a; 晶闸管导通条件&#xff1a;1.阳极承受正向电压 2.门极具有触发信号 这里的触发延迟角的定义要注意记…

Go语言中的函数:简单有趣的代码块魔法(五)

Go语言中的函数&#xff1a;简单有趣的代码块魔法 Go语言中的函数不仅简单易用&#xff0c;还带有一些有趣的小魔法&#xff0c;让它在代码世界里游刃有余。本文将带你通俗易懂地理解Go函数的声明与调用、多返回值、命名返回值、可变参数、匿名函数与闭包&#xff0c;以及函数作…

mac地址漂移实验

MAC地址漂移是指交换机的MAC地址表中的内容被改变&#xff0c;导致网络中的数据包无法正确传输到目标设备。在正常情况下&#xff0c;网络中的MAC地址应该是稳定的&#xff0c;不会频繁发生变化。因此&#xff0c;如果在短时间内出现大量MAC地址漂移的情况&#xff0c;可能意味…

【Web——HTML 初阶】网页设计标题

♥HTML&#xff08;HyperText Markup Language&#xff0c;超文本标记语言&#xff09;是构建网页和Web应用的基础语言之一。它不是一种编程语言&#xff0c;而是一种标记语言&#xff0c;用于描述网页的结构和内容。HTML使用标签&#xff08;tags&#xff09;来标记不同类型的…

NFTScan | 10.07~10.13 NFT 市场热点汇总

欢迎来到由 NFT 基础设施 NFTScan 出品的 NFT 生态热点事件每周汇总。 周期&#xff1a;2024.10.07~ 2024.10.13 NFT Hot News ​01/ 数据&#xff1a;9 月份加密市场大多数指标均出现下降&#xff0c;链上总交易量下降 13% 10 月 7 日&#xff0c;据 The Block 研究总监 la…