HAL库自学笔记(三)——中断

一、中断的概念

1.异常与中断

         异常

        异常是由操作系统和硬件实现的,是控制流中的突变,用来响应处理器状态的某些变化。异常分为中断(interrupt)、陷阱(trap)、故障(fault)和终止(abort)。

(1)陷阱(trap)

        陷阱是有意的异常,主要用来切换用户态和内核态,其提供的一个切换过程称为系统调用。用户希望调用系统资源的时候,可以执行syscall指令,这时会导致一个异常陷阱,从而进入内核态。

(2)故障(fault)

        故障由错误情况引起,它可能被故障处理程序修正,从而重新执行当前指令,也有可能无法被修正,即进入终止(abort),cpu会终止该应用程序。例:取数据时发生“缺页”,导致故障,操作系统通过将所需页面从磁盘调入内存,此时故障处理完毕,操作系统重新执行取数据指令。

(3)终止(abort)

        终止是不可恢复的致命错误导致的,通常是硬件错误,例如DRAM或SRAM损坏导致存储器校验错。此时会终止运行的应用程序。

        中断

        中断是处理来自处理器外部的I/O设备的信号的结果。硬件中断是异步的,硬件中断的异常处理程序被称为中断处理程序。

(1)硬中断与软中断

        硬中断是由硬件产生的,例如磁盘,定时器,键盘等。软中断是一组静态定义的下半部分接口,可以在所有处理器上同时执行。软中断不会抢占软中断,硬中断会抢占软中断。

(2)可屏蔽中断和不可屏蔽中断

        可屏蔽中断和不可屏蔽中断都属于外部中断,不可屏蔽中断源提出请求,CPU必须响应,而对可屏蔽中断源的请求,CPU可选择响应。

2.事件

        对于处理器的外设,是通过内部信号来协同工作的,这个信号则为事件。事件通常和中断绑定在一起,一个事件会引起一个中断或者引起另一个事件。例如:定时器计数完毕,通过计数完毕事件引起中断,或导致另一个事件开始。

二、外部中断/事件控制器(EXTI)

1.EXTI框图

        EXTI 可分为两大部分功能,一个是产生中断,另一个是产生事件,这两个功能从硬件上就有所 不同。

        对于事件:外部电路的I/O设备的高低电平变化通过输入线被边沿检测电路捕获(通过上升沿或下降沿触发),进入2(或门),并与软件中断做或运算,其中一个发生即可。接着进入4(与门)若事件屏蔽器允许则进入脉冲发生器,此时发出的脉冲可以被另一个事件或中断捕获。

        对于中断:1,2电路过程相同,此时中断信号被请求挂起寄存器挂起,与中断屏蔽寄存器作为3号与门的两个输入端,两者同时为1则触发NVIC中断。

三、中断实验

1.背景

        实验板:指南者STM32F103VET6

        配置环境:STM32CubeMX

        开发环境:Keil

        实现功能:利用按键进入中断,并在中断中控制LED的亮灭

2.配置环境

        参照按键和LED的原理图配置。

        对于按键,配置其为GPIO_EXIT,对于LED配置为GPIO_Output。

 

3.生成代码

        略,可看之前的文章。

4.代码解析

        (1)引脚的宏定义

        在main.h中,STM32帮我们定义了一些宏来增强程序可读性。

/* Private defines -----------------------------------------------------------*/
//按键的宏定义
#define KEY2_EXIT_Pin GPIO_PIN_13
#define KEY2_EXIT_GPIO_Port GPIOC
#define KEY2_EXIT_EXTI_IRQn EXTI15_10_IRQn
#define KEY1_EXIT_Pin GPIO_PIN_0
#define KEY1_EXIT_GPIO_Port GPIOA
#define KEY1_EXIT_EXTI_IRQn EXTI0_IRQn
//LED的宏定义
#define GREEN_Pin GPIO_PIN_0
#define GREEN_GPIO_Port GPIOB
#define BLUE_Pin GPIO_PIN_1
#define BLUE_GPIO_Port GPIOB
#define RED_Pin GPIO_PIN_5
#define RED_GPIO_Port GPIOB

(2)GPIO的初始化配置

        将按键1和按键2配置为中断源,同时配置LED初始为高电平,即灭的状态。此代码在gpio.c文件中配置。

void MX_GPIO_Init(void)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */   
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOB, GREEN_Pin|BLUE_Pin|RED_Pin, GPIO_PIN_SET);    //LED的默认电平为高电平

  /*Configure GPIO pin : PtPin */
  GPIO_InitStruct.Pin = KEY2_EXIT_Pin;       //按键2的引脚
  GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;   //KEY2设定为检测到上升沿触发中断
  GPIO_InitStruct.Pull = GPIO_NOPULL;           //设置为既不上拉也不下拉,即浮空输入
  HAL_GPIO_Init(KEY2_EXIT_GPIO_Port, &GPIO_InitStruct);  //结构体初始化按键

  /*Configure GPIO pin : PtPin */
  GPIO_InitStruct.Pin = KEY1_EXIT_Pin;      //按键1的引脚
  GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING;     //KEY1设定为检测到上升沿或下降沿触发中断,即按一次按键可触发两次
  GPIO_InitStruct.Pull = GPIO_NOPULL;       //设置为既不上拉也不下拉,即浮空输入
  HAL_GPIO_Init(KEY1_EXIT_GPIO_Port, &GPIO_InitStruct);   //结构体初始化按键

  /*Configure GPIO pins : PBPin PBPin PBPin */
  GPIO_InitStruct.Pin = GREEN_Pin|BLUE_Pin|RED_Pin;        //LED的引脚
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;         //模式为推挽输出
  GPIO_InitStruct.Pull = GPIO_NOPULL;                       //设置为既不上拉也不下拉    
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;       //速度设置为低速
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);            //结构体初始化LED
 
  /* EXTI interrupt init*/
  HAL_NVIC_SetPriority(EXTI0_IRQn, 4, 0);         //按键1的主优先级和次优先级分别为4和0
  HAL_NVIC_EnableIRQ(EXTI0_IRQn);

  HAL_NVIC_SetPriority(EXTI15_10_IRQn, 5, 0);        //按键2的主优先级和次优先级分别为5和0
  HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);

}

        除此之外,我们还可以在gpio.h中配置一些自己想要的宏定义。

/* USER CODE BEGIN Private defines */

#define	RED_ON  	 	HAL_GPIO_WritePin(GPIOB, RED_Pin, GPIO_PIN_RESET)    //低电平红灯亮
#define	RED_OFF 	 	HAL_GPIO_WritePin(GPIOB, RED_Pin, GPIO_PIN_SET)      //高电平红灯灭
#define RED_TOGGLE 	HAL_GPIO_TogglePin(GPIOB,RED_Pin)      //翻转

#define	GREEN_ON  	 	HAL_GPIO_WritePin(GPIOB, GREEN_Pin, GPIO_PIN_RESET)  //低电平绿灯亮
#define	GREEN_OFF 	 	HAL_GPIO_WritePin(GPIOB, GREEN_Pin, GPIO_PIN_SET)     //高电平绿灯灭
#define GREEN_TOGGLE 	HAL_GPIO_TogglePin(GPIOB,GREEN_Pin)        //翻转

#define	BLUE_ON  	 	HAL_GPIO_WritePin(GPIOB, BLUE_Pin, GPIO_PIN_RESET)    //低电平蓝灯亮
#define	BLUE_OFF 	 	HAL_GPIO_WritePin(GPIOB, BLUE_Pin, GPIO_PIN_SET)      //高电平蓝灯灭
#define BLUE_TOGGLE 	HAL_GPIO_TogglePin(GPIOB,BLUE_Pin)    //翻转


/* USER CODE END Private defines */

(3)中断服务程序

        我们将中断服务程序中对单片机的控制都放在stm32f1xx_it.c文件中,我们将在这里利用两个按键的中断来对LED进行亮灭控制。(注:在使用LED的宏时,不要忘记在stm32f1xx_it.c中添加头文件gpio.h)

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "stm32f1xx_it.h"
#include "gpio.h"   //此为LED和按键的头文件

         按键1配置的为上升沿和下降沿都触发中断,故按下按键时红灯亮,松开时红灯灭,而按键2则是按下时绿灯亮。

/**
  * @brief This function handles EXTI line0 interrupt.
  */
void EXTI0_IRQHandler(void)   //按键1的中断服务程序
{
  /* USER CODE BEGIN EXTI0_IRQn 0 */
  //确保是否产生了EXTI Line中断
	if(__HAL_GPIO_EXTI_GET_IT(KEY1_EXIT_Pin) != RESET) 
	{
		// 红灯 取反		
		RED_TOGGLE;
    //清除中断标志位
		__HAL_GPIO_EXTI_CLEAR_IT(KEY1_EXIT_Pin);     
	}  
  /* USER CODE END EXTI0_IRQn 0 */

}

/**
  * @brief This function handles EXTI line[15:10] interrupts.
  */
void EXTI15_10_IRQHandler(void)          //按键2的中断服务程序
{
  /* USER CODE BEGIN EXTI15_10_IRQn 0 */

	//确保是否产生了EXTI Line中断
	if(__HAL_GPIO_EXTI_GET_IT(KEY2_EXIT_Pin) != RESET) 
	{
		// 绿灯 取反		
		GREEN_TOGGLE;
    //清除中断标志位
		__HAL_GPIO_EXTI_CLEAR_IT(KEY2_EXIT_Pin);     
	}  
  /* USER CODE END EXTI15_10_IRQn 0 */
}

        此处的 __HAL_GPIO_EXTI_GET_IT()函数用来判断是否产生了中断,在这里即是否检测到按键的上升沿或下降沿。__HAL_GPIO_EXTI_CLEAR_IT()函数用于清除中断标志位,若不清除则会卡在当前中断,不会响应其他已经触发的新中断。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值