CH2-EXIT

EXIT理论

EXTI

EXTI(Extern Interrupt)外部中断EXTI可以监测指定GPIO口的电平信号,当其指定的GPIO口产生电平变化时,EXTI将立即向NVIC发出中断申请,经过NVIC裁决后即可中断CPU主程序,使CPU执行EXTI对应的中断程序支持的触发方式:上升沿/下降沿/双边沿/软件触发支持的GPIO口:所有GPIO口,但相同的Pin不能同时触发中断通道数:16个GPIO_Pin,外加PVD输出、RTC闹钟、USB唤醒、以太网唤醒触发响应方式:中断响应/事件响应

中断:要进入NVIC,有相应的中断服务函数,需要CPU处理

事件:不进入NVIC,仅用于内部硬件自动控制的,如:TIM、DMA、ADC

image-20240112120322514
EXTI基本结构
image-20240116122717594
AFIO简介

中断触发流程

image-20240116112206826
中断触发流程

CubeMX配置

时钟配置

image-20240321222712016

时钟配置

下载配置

image-20240321222754003

下载线配置

中断配置

1.IO口先选择EXTI

image-20240321222911977

先选择一个IO口进行配置EXTI

2.GPIO配置触发方式

image-20240321223727466
GPIO触发方式配置

3.NVIC寄存器使能

image-20240321223938332
NVIC使能

代码编写

中断配置流程

image-20240116122949067
设置步骤

流程1-5

gpio.c文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
void MX_GPIO_Init(void)
{

GPIO_InitTypeDef GPIO_InitStruct = {0};//创建一个GPIO的结构体
/* 第一步:使能GPIO时钟 */
__HAL_RCC_GPIOC_CLK_ENABLE();//将RCC时钟的寄存器使能
__HAL_RCC_GPIOA_CLK_ENABLE();


HAL_GPIO_WritePin(GPIOA, RELAY1_Pin|RELAY2_Pin, GPIO_PIN_RESET);

/* 第二步:HAL_GPIO_Init()配置GPIO、AFIO(SYSCFG)、EXTI */
GPIO_InitStruct.Pin = USER_KEY_Pin;//设置USER按键为外部中断的输入口(引脚为PC14)
GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;//设置引脚为下降沿触发
GPIO_InitStruct.Pull = GPIO_PULLUP;//设置PC14IO口为上拉状态,可读取引脚电平,内部连接下拉电阻,悬空时默认低电平,这样下升沿到来时就可以很快被发现
HAL_GPIO_Init(USER_KEY_GPIO_Port, &GPIO_InitStruct);//初始化IO口


GPIO_InitStruct.Pin = RELAY1_Pin|RELAY2_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

/* 第三步:设置中断分组、设置中断优先级 */
HAL_NVIC_SetPriority(EXTI4_15_IRQn, 1, 0);//第一个参数为:设置中断优先级分组,为中断4-15;第二个参数为中断优先级,设置为1;第三个为子优先级,设置为0

/* 第四步:使能中断 */
HAL_NVIC_EnableIRQ(EXTI4_15_IRQn);//将中断2-15使能

}

中断逻辑

1.当外部中断触发的时候程序会判断优先级,当在前的优先级处理过后,程序会执行如下函数void EXTI4_15_IRQHandler(void)

image-20240321224405946

2.中断函数之后会运行HAL_GPIO_EXTI_IRQHandler(USER_KEY_Pin)中断公用函数中的变量为我们设置的IO口变量名称

image-20240321225945737

3.编写中断回调函数

image-20240321230039926

主函数编写

function.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include "function.h"
#include "gpio.h"


void RELAY(unsigned int flag_relay_p,unsigned int flag_relay_state)//继电器控制函数,第一个变量控制选择哪个继电器,第二个变量控制是否打开继电器
{
if(1 == flag_relay_p)//判断是否为选择继电器1
{
if(1==flag_relay_state)
HAL_GPIO_WritePin(GPIOA, RELAY1_Pin, GPIO_PIN_SET);//打开继电器1
if(0==flag_relay_state)
HAL_GPIO_WritePin(GPIOA, RELAY1_Pin, GPIO_PIN_RESET);//关闭继电器1

}
if(2 == flag_relay_p)//判断是否为选择继电器2
{
if(1==flag_relay_state)
HAL_GPIO_WritePin(GPIOA, RELAY2_Pin, GPIO_PIN_SET);//打开继电器2
if(0==flag_relay_state)
HAL_GPIO_WritePin(GPIOA, RELAY2_Pin, GPIO_PIN_RESET);//关闭继电器2

}
}

/*按键中断,在中断回调函数中编写,不用在.h文件中申明*/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
static int flag_user_key_num=0;//设置静态变量flag_user_key_num,变量仅当在函数中能使用,并且变量仅在函数中改变
if(GPIO_Pin == USER_KEY_Pin)//确定是哪个中断,如果是按键的中断,那么就进行判别
{
flag_user_key_num++;
}
if(1==flag_user_key_num)
RELAY(1,1);
if(2==flag_user_key_num)
RELAY(1,0);
if(3==flag_user_key_num)
RELAY(2,1);
if(4==flag_user_key_num)
RELAY(2,0);
if(flag_user_key_num>4)
flag_user_key_num=1;

}

function.h

1
2
3
4
5
6
#ifndef __FUNCTION_H__
#define __FUNCTION_H__

void RELAY(unsigned int flag_relay_p,unsigned int flag_relay_state);//继电器控制函数

#endif