STM32笔记_7(EXTI—外部中断)

EXTI是STM32中的外部中断/事件控制器,管理20个中断线,支持GPIO和特定外设事件。每个中断线可配置为中断或事件,检测上升沿和下降沿。中断线通过NVIC触发中断服务函数,事件则产生脉冲信号供硬件级使用。初始化涉及GPIO、EXTI和NVIC配置。

EXTI—外部中断/事件控制器

EXTI 简介

EXTI(External interrupt/event controller)—外部中断/事件控制器,管理了控制器的 20 个中断/事件线

每个中断/事件线都对应有一个边沿检测器,可以实现输入信号的上升沿检测和下降沿的检测

EXTI 可以实现对每个中断/事件线进行单独配置,可以单独配置为中断或者事件,以及触发事件的属性。

EXTI 功能框图

EXTI 可分为两大部分功能,一个是产生中断,另一个是产生事件。

红色虚线指示的电路流程。它是一个产生中断的线路,最终信号流入到 NVIC 控制器内

编号 1 是输入线, EXTI 控制器有 19 个中断/事件输入线,这些输入线可以通过寄存器设置为任意一个 GPIO,也可以是一些外设的事件,输入线一般是存在电平变化的信号

编号 2 是一个边沿检测电路,它会根据上升沿触发选择寄存器 (EXTI_RTSR) 和下降沿触发选择寄存器 (EXTI_FTSR) 对应位的设置来控制信号触发。边沿检测电路以输入线作为信号输入端,如果检测到有边沿跳变就输出有效信号 1 给编号 3 电路,否则输出无效信号 0。EXTI_RTSR 和EXTI_FTSR 两个寄存器可以控制器需要检测哪些类型的电平跳变过程,可以是只有上升沿触发、只有下降沿触发或者上升沿和下降沿都触发

编号 3 电路实际就是一个或门电路,它一个输入来自编号 2 电路,另外一个输入来自软件中断事件寄存器 (EXTI_SWIER)。EXTI_SWIER 允许我们通过程序控制就可以启动中断/事件线

编号 4 电路是一个与门电路,它一个输入是编号 3 电路,另外一个输入来自中断屏蔽寄存器(EXTI_IMR)。

编号 5 是将 EXTI_PR 寄存器内容输出到 NVIC 内,从而实现系统中断事件控制

绿色虚线指示的电路流程。它是一个产生事件的线路,最终输出一个脉冲信号

编号 6 电路是一个与门,它一个输入来自编号 3 电路,另外一个输入来自事件屏蔽寄存器 (EXTI_EMR)。

编号 7 是一个脉冲发生器电路,当它的输入端,即编号 6 电路的输出端,是一个有效信号 1 时就会产生一个脉冲;如果输入端是无效信号就不会输出脉冲。

编号 8 是一个脉冲信号,就是产生事件的线路最终的产物,这个脉冲信号可以给其他外设电路使用,比如定时器 TIM、模拟数字转换器 ADC 等等,这样的脉冲信号一般用来触发 TIM 或者 ADC开始转换

产生中断线路目的是把输入信号输入到 NVIC,进一步会运行中断服务函数,实现功能,这样是软件级的。而产生事件线路目的就是传输一个脉冲信号给其他外设使用,并且是电路级别的信号传输,属于硬件级的。

EXTI 是在 APB2 总线上的。

中断/事件线

EXTI 有 20 个中断/事件线,每个 GPIO 都可以被设置为输入线,占用 EXTI0 至 EXTI15,还有另外七根用于特定的外设事件。

EXTI0 至 EXTI15 用于 GPIO,通过编程控制可以实现任意一个 GPIO 作为 EXTI 的输入源

EXTI0 可以通过 AFIO 的外部中断配置寄存器 1(AFIO_EXTICR1) 的EXTI0[3:0] 位选择配置为 PA0、 PB0、 PC0、 PD0、 PE0、 PF0、 PG0、 PH0 或者 PI0。

EXTI 初始化结构体详解

1) EXTI_Line: EXTI 中断/事件线选择,可选 EXTI0 至 EXTI19,可参考表 EXTI 中断 _ 事件线选择。

2) EXTI_Mode: EXTI 模式选择,可选为产生中断 (EXTI_Mode_Interrupt) 或者产生事件(EXTI_Mode_Event)。

3) EXTI_Trigger: EXTI 边沿触发事件,可选上升沿触发 (EXTI_Trigger_Rising)、下降沿触发 (EXTI_Trigger_Falling) 或者上升沿和下降沿都触发 ( EXTI_Trigger_Rising_Falling)。

4) EXTI_LineCmd:控制是否使能 EXTI 线,可选使能 EXTI 线 (ENABLE) 或禁用 (DISABLE)。

外部中断控制实验

1) 初始化用来产生中断的 GPIO;

2) 初始化 EXTI;

3) 配置 NVIC;

4) 编写中断服务函数;

EXTI代码

exti.h

#ifndef _EXTI_H
#define _EXTI_H

#include "stm32f10x.h"

#define EXTI_KEY_RCC		RCC_APB2Periph_AFIO

#define EXTI_KEY_1_Line		EXTI_Line0
#define EXTI_KEY_2_Line		EXTI_Line13

#define EXTI_KEY_1_PortSource 	GPIO_PortSourceGPIOA
#define EXTI_KEY_2_PortSource 	GPIO_PortSourceGPIOC

#define EXTI_KEY_1_PinSource	GPIO_PinSource0
#define EXTI_KEY_2_PinSource	GPIO_PinSource13

#define EXTI_KEY_1_IRQn			EXTI0_IRQn
#define EXTI_KEY_2_IRQn			EXTI15_10_IRQn

#define EXTI_KEY_1_IRQHandler	EXTI0_IRQHandler
#define EXTI_KEY_2_IRQHandler	EXTI15_10_IRQHandler

void EXTI_Config(void);

#endif

exti.c

#include "exti.h"
#include "key.h"

static void NVIC_Config(void)
{
	NVIC_InitTypeDef NVIC_InitStruct;
	//配置中断优先级分组
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
	//NVIC中断控制器结构体配置
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
	//配置按键1中断控制器通道和初始化按键1中断控制器
	NVIC_InitStruct.NVIC_IRQChannel = EXTI_KEY_1_IRQn;
	NVIC_Init(&NVIC_InitStruct);
	//配置按键2中断控制器通道和初始化按键2中断控制器
	NVIC_InitStruct.NVIC_IRQChannel = EXTI_KEY_2_IRQn;
	NVIC_Init(&NVIC_InitStruct);
}

void EXTI_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	EXTI_InitTypeDef EXTI_InitStruct;
	//使能KEY1和KEY2以及EXTI中断时钟
	RCC_APB2PeriphClockCmd(KEY_1_RCC | KEY_2_RCC | EXTI_KEY_RCC,ENABLE);
	//KEY1和KEY2的GPIO结构体配置
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_InitStruct.GPIO_Pin = KEY_1_PIN | KEY_2_PIN;
	GPIO_Init(KEY_1_PORT,&GPIO_InitStruct);
	GPIO_Init(KEY_2_PORT,&GPIO_InitStruct);
	//EXTI结构体配置
	EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;
	EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Rising;
	EXTI_InitStruct.EXTI_LineCmd = ENABLE;
	//KEY1的EXTI结构体配置
	GPIO_EXTILineConfig(EXTI_KEY_1_PortSource,EXTI_KEY_1_PinSource);
	EXTI_InitStruct.EXTI_Line = EXTI_KEY_1_Line;
	EXTI_Init(&EXTI_InitStruct);
	//KEY2的EXTI结构体配置
	GPIO_EXTILineConfig(EXTI_KEY_2_PortSource,EXTI_KEY_2_PinSource);
	EXTI_InitStruct.EXTI_Line = EXTI_KEY_2_Line;	
	EXTI_Init(&EXTI_InitStruct);
	//开启中断服务
	NVIC_Config();
}

按键代码

key.h

#ifndef _KEY_H
#define _KEY_H

#include "stm32f10x.h"

#define KEY_1_RCC   RCC_APB2Periph_GPIOA
#define KEY_1_PIN   GPIO_Pin_0
#define KEY_1_PORT  GPIOA

#define KEY_2_RCC   RCC_APB2Periph_GPIOC
#define KEY_2_PIN   GPIO_Pin_13
#define KEY_2_PORT  GPIOC

#define PRESS   1
#define RELEASE 0

enum
{
    KEY_1,
    KEY_2
};

void KEY_Init(void);
uint8_t KEY_Scan(unsigned char key);

#endif

key.c

#include "key.h"

void KEY_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;

    RCC_APB2PeriphClockCmd(KEY_1_RCC | KEY_2_RCC,ENABLE);

    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_InitStruct.GPIO_Pin = KEY_1_PIN | KEY_2_PIN;

    GPIO_Init(KEY_1_PORT,&GPIO_InitStruct);
    GPIO_Init(KEY_2_PORT,&GPIO_InitStruct);
}

uint8_t KEY_Scan(unsigned char key)
{
    uint8_t key_state;
    switch (key)
    {
    case KEY_1:
        if(GPIO_ReadInputDataBit(KEY_1_PORT,KEY_1_PIN) == PRESS)
        {
            while(GPIO_ReadInputDataBit(KEY_1_PORT,KEY_1_PIN) == PRESS);
            key_state = PRESS;
        }
        else
            key_state = RELEASE;
        break;
    case KEY_2:
        if(GPIO_ReadInputDataBit(KEY_2_PORT,KEY_2_PIN) == PRESS)
        {
            while(GPIO_ReadInputDataBit(KEY_2_PORT,KEY_2_PIN) == PRESS);
            key_state = PRESS;
        }
        else
            key_state = RELEASE;
        break;
    }
    return key_state;
}

LED灯代码

led.h

#ifndef _LED_H
#define _LED_H

#include "stm32f10x.h"

#define LED_G_RCC   RCC_APB2Periph_GPIOB
#define LED_G_PIN   GPIO_Pin_0
#define LED_G_PORT  GPIOB

#define LED_R_RCC   RCC_APB2Periph_GPIOB
#define LED_R_PIN   GPIO_Pin_5
#define LED_R_PORT  GPIOB

#define LED_B_RCC   RCC_APB2Periph_GPIOB
#define LED_B_PIN   GPIO_Pin_1
#define LED_B_PORT  GPIOB

#define ON 1
#define OFF 0

enum 
{
    LED_G, /* LED_G*/
    LED_R, /* LED_R*/
    LED_B  /* LED_B*/
};

void LED_Init(void);
void LED_Config(unsigned char led,unsigned char state);
void LED_Toggle(unsigned char led);

#endif

led.c

#include "led.h"

/* 
    led初始化
*/
void LED_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    
    RCC_APB2PeriphClockCmd(LED_G_RCC | LED_R_RCC | LED_B_RCC,ENABLE);

    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStruct.GPIO_Pin = LED_G_PIN | LED_R_PIN | LED_B_PIN;

    GPIO_Init(LED_G_PORT,&GPIO_InitStruct);
    GPIO_Init(LED_R_PORT,&GPIO_InitStruct);
    GPIO_Init(LED_B_PORT,&GPIO_InitStruct);

    //默认关闭LED
    GPIO_SetBits(LED_G_PORT,LED_G_PIN);
    GPIO_SetBits(LED_R_PORT,LED_R_PIN);
    GPIO_SetBits(LED_B_PORT,LED_B_PIN);
}

/* 
    Fun:led设置(配置)
    Para1:led 选择(LED_G/LED_R/LED_B)
    Para2:led 状态(ON/OFF)
*/
void LED_Config(unsigned char led,unsigned char state)
{
    switch(led)
    {
        case LED_G:
            if(state == ON)
                GPIO_ResetBits(LED_G_PORT,LED_G_PIN);
            else 
                GPIO_SetBits(LED_G_PORT,LED_G_PIN);
        break;
        case LED_R:
            if(state == ON)
                GPIO_ResetBits(LED_R_PORT,LED_R_PIN);
            else 
                GPIO_SetBits(LED_R_PORT,LED_R_PIN);
        break;
        case LED_B:
            if(state == ON)
                GPIO_ResetBits(LED_B_PORT,LED_B_PIN);
            else 
                GPIO_SetBits(LED_B_PORT,LED_B_PIN);
        break;
    }
}

/* 
    Fun:led反转
    Para:led 选择(LED_G/LED_R/LED_B)
*/
void LED_Toggle(unsigned char led)
{ 
    switch (led)
    {
    case LED_G:
			LED_G_PORT->ODR ^= LED_G_PIN;
        break;
    
    case LED_R:
			LED_R_PORT->ODR ^= LED_R_PIN;
        break;

    case LED_B:
			LED_B_PORT->ODR ^= LED_B_PIN;
        break;
    }
}

中断服务函数代码

void EXTI_KEY_1_IRQHandler(void)
{
	if(EXTI_GetITStatus(EXTI_KEY_1_Line) == SET)
	{
		LED_Toggle(LED_G);
		EXTI_ClearITPendingBit(EXTI_KEY_1_Line);
	}
}

void EXTI_KEY_2_IRQHandler(void)
{
	if(EXTI_GetITStatus(EXTI_KEY_2_Line) == SET)
	{
		LED_Toggle(LED_G);
		EXTI_ClearITPendingBit(EXTI_KEY_2_Line);
	}
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

small陀螺

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值