STM32之EXTI

Posted nwjlq

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了STM32之EXTI相关的知识,希望对你有一定的参考价值。

简介:

exti--外部中断/事件控制器,控制器由20个边沿检测器组成,每个检测器都连接了所有端口对应引脚,每个输入线都可以独立的配置输入类型可触发事件(上升沿/下降沿/双边沿触发)。

功能框图;

技术图片

图中黄色部分表示每个寄存器都有20个输入线与之相对应

如:中断屏蔽寄存器

技术图片

寄存器中有20个外部输入线的中断屏蔽标志位。

红色虚线部分为中断部分:边沿检测电路通过上升/下降沿边沿触发选择寄存器对输入线输入的信号进行检测,当检测条件满足时(如:设置上升沿触发,则信号线来了一个上升沿),边沿检测电路输出1给图中的3(或门),或门输出信号传给图中4(与门),如果设置了中断屏蔽寄存器的值为1(表示开发中断请求),则与门输出电平1,请求挂起寄存器对应位置1,图中的5从请求挂起寄存器中取出值给NVIC,从而实现中断控制。

绿色虚线部分为事件部分:图中1 2 3与产生中断一样。图3产生的信号此时电平为1与6(与门)另一个输入信号事件屏蔽寄存器值进行与操作,如果事件屏蔽寄存器的对应位也为1,则输出电平1给脉冲发生器,脉冲发生器接收到电平1后,产生脉冲从图中8输出出去。

技术图片

中断/事件线:

技术图片

 exti0~15可以对应多个io引脚,通过AFIO寄存器选择具体的引脚。

技术图片

技术图片

外部中断初始化结构体:

技术图片

EXTI_Line:中断线选择,可以选择EXTI0~EXTI19

EXTI_Mode:模式 是产生中断还是事件

EXTI_Trigger:触发类型 是上升沿 下降沿还是双边沿触发

EXTI_LineCmd:是 使能还是失能中断线

实验:

通过开发板上的四个按键对4个LED控制。按下按键LED亮,再按下,LED灭

原理图:

技术图片

编程思路:

1.初始化4个led端口 和4个按键其中key_up配置成下拉输入,其他按键配置成上拉输入

2.配置中断优先级

3.配置外部中断,在里面记得开启AFIO时钟

4.编写中断程序

exti头文件:

#ifndef _EXTI_H
#define _EXTI_H

#include "stm32f10x.h"
//上键宏定义
#define KEY_UP_CLK   RCC_APB2Periph_GPIOA
#define KEY_UP_PIN   GPIO_Pin_0
#define KEY_UP_PORT  GPIOA
//左键
#define KEY_LEFT_CLK RCC_APB2Periph_GPIOE
#define KEY_LEFT_PIN GPIO_Pin_2
#define KEY_LEFT_PORT GPIOE
//下键
#define KEY_DOWN_CLK RCC_APB2Periph_GPIOE
#define KEY_DOWN_PIN GPIO_Pin_3
#define KEY_DOWN_PORT GPIOE
//右键
#define KEY_RIGHT_CLK RCC_APB2Periph_GPIOE
#define KEY_RIGHT_PIN GPIO_Pin_4
#define KEY_RIGHT_PORT GPIOE

//LED
#define      LED_CLK    RCC_APB2Periph_GPIOC
#define   LED_PORT   GPIOC

#define   LED1_PIN    GPIO_Pin_0
#define   LED2_PIN    GPIO_Pin_1
#define   LED3_PIN    GPIO_Pin_2
#define   LED4_PIN    GPIO_Pin_3



void EXTI_Config(void);
#endif

exti源文件

#include "exti.h"
static void LED_GPIO_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    RCC_APB2PeriphClockCmd(LED_CLK,ENABLE);
    //LED1 LED2 LED3 LED4初始化
    GPIO_InitStruct.GPIO_Pin=LED1_PIN|LED2_PIN|LED3_PIN|LED4_PIN;
    GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;//推挽输出
    GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_Init(LED_PORT,&GPIO_InitStruct);
    //默认熄灭
    GPIO_SetBits(LED_PORT,LED1_PIN|LED2_PIN|LED3_PIN|LED4_PIN);
}
static void KEY_GPIO_Config(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    //开启四个键所对应io端口时钟
    RCC_APB2PeriphClockCmd(KEY_UP_CLK|KEY_LEFT_CLK|KEY_DOWN_CLK|KEY_RIGHT_CLK,ENABLE);
    //上键
    GPIO_InitStruct.GPIO_Pin=KEY_UP_PIN;
    GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPD;//下拉输入模式
    GPIO_Init(KEY_UP_PORT,&GPIO_InitStruct);
    //左键
    GPIO_InitStruct.GPIO_Pin=KEY_LEFT_PIN;
    GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU;//上拉输入模式
    GPIO_Init(KEY_LEFT_PORT,&GPIO_InitStruct);
    //下键
    GPIO_InitStruct.GPIO_Pin=KEY_DOWN_PIN;
    GPIO_Init(KEY_DOWN_PORT,&GPIO_InitStruct);
    //右键
    GPIO_InitStruct.GPIO_Pin=KEY_RIGHT_PIN;
    GPIO_Init(KEY_RIGHT_PORT,&GPIO_InitStruct);
}
static void KEY_EXTI_Config(void)
{
    EXTI_InitTypeDef   EXTI_InitStruct;
    //使用外部中断 端口复用 重映射需要开启AFIO时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
    //上键外部中断配置
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);//外部中断线配置
    EXTI_InitStruct.EXTI_Line=EXTI_Line0;//中断线
    EXTI_InitStruct.EXTI_LineCmd=ENABLE;
    EXTI_InitStruct.EXTI_Mode=EXTI_Mode_Interrupt;//中断模式
    EXTI_InitStruct.EXTI_Trigger=EXTI_Trigger_Rising;//上升沿检测
    EXTI_Init(&EXTI_InitStruct);
    //左键外部中断配置
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource2);//外部中断线配置
    EXTI_InitStruct.EXTI_Line=EXTI_Line2;//中断线
    EXTI_InitStruct.EXTI_Trigger=EXTI_Trigger_Falling;//下降沿检测
    EXTI_Init(&EXTI_InitStruct);
    //下键外部中断配置
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource3);//外部中断线配置
    EXTI_InitStruct.EXTI_Line=EXTI_Line3;//中断线
    EXTI_Init(&EXTI_InitStruct);
    //右键外部中断配置
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource4);//外部中断线配置
    EXTI_InitStruct.EXTI_Line=EXTI_Line4;//中断线
    EXTI_Init(&EXTI_InitStruct);
}

static void NVIC_Config(void)
{
    NVIC_InitTypeDef NVIC_InitStruct;
    
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断优先级分组
    //上键
    NVIC_InitStruct.NVIC_IRQChannel=EXTI0_IRQn;//中断源
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=1;
    NVIC_InitStruct.NVIC_IRQChannelSubPriority=1;
    NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
    NVIC_Init(&NVIC_InitStruct);
    //左键
    NVIC_InitStruct.NVIC_IRQChannel=EXTI2_IRQn;//中断源
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=1;
    NVIC_InitStruct.NVIC_IRQChannelSubPriority=2;
    NVIC_Init(&NVIC_InitStruct);
    //下键
    NVIC_InitStruct.NVIC_IRQChannel=EXTI3_IRQn;//中断源
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=1;
    NVIC_InitStruct.NVIC_IRQChannelSubPriority=2;
    NVIC_Init(&NVIC_InitStruct);
    //右键
    NVIC_InitStruct.NVIC_IRQChannel=EXTI4_IRQn;//中断源
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=1;
    NVIC_InitStruct.NVIC_IRQChannelSubPriority=3;
    NVIC_Init(&NVIC_InitStruct);
}
void EXTI_Config(void)
{
    LED_GPIO_Config();
    KEY_GPIO_Config();
    NVIC_Config();
    KEY_EXTI_Config();
}
//上键中断
void EXTI0_IRQHandler(void)
{
    if(EXTI_GetITStatus(EXTI_Line0)==SET)
    {
        if(GPIO_ReadOutputDataBit(LED_PORT,LED1_PIN))
            GPIO_ResetBits(LED_PORT,LED1_PIN);
        else
            GPIO_SetBits(LED_PORT,LED1_PIN);
        EXTI_ClearITPendingBit(EXTI_Line0);
    }
}
//左键中断
void EXTI2_IRQHandler(void)
{
    if(EXTI_GetITStatus(EXTI_Line2)==SET)
    {
        if(GPIO_ReadOutputDataBit(LED_PORT,LED2_PIN))
            GPIO_ResetBits(LED_PORT,LED2_PIN);
        else
            GPIO_SetBits(LED_PORT,LED2_PIN);
        EXTI_ClearITPendingBit(EXTI_Line2);
    }
}
//下键中断
void EXTI3_IRQHandler(void)
{
    if(EXTI_GetITStatus(EXTI_Line3)==SET)
    {
        if(GPIO_ReadOutputDataBit(LED_PORT,LED3_PIN))
            GPIO_ResetBits(LED_PORT,LED3_PIN);
        else
            GPIO_SetBits(LED_PORT,LED3_PIN);
        EXTI_ClearITPendingBit(EXTI_Line3);
    }
}
//右键中断
void EXTI4_IRQHandler(void)
{
    if(EXTI_GetITStatus(EXTI_Line4)==SET)
    {
        if(GPIO_ReadOutputDataBit(LED_PORT,LED4_PIN))
            GPIO_ResetBits(LED_PORT,LED4_PIN);
        else
            GPIO_SetBits(LED_PORT,LED4_PIN);
        EXTI_ClearITPendingBit(EXTI_Line4);
    }
}

main 文件:

#include "stm32f10x.h"
#include "exti.h"
int main(void)
{
    EXTI_Config();
    while(1);
}

 

以上是关于STM32之EXTI的主要内容,如果未能解决你的问题,请参考以下文章

嵌入式接口之EXTI与NVIC的STM32模板库函数的一些解释

STM32之外部中断

STM32外部中断EXTI简介

stm32如何在中断服务程序里关闭EXTI中断?

STM32中断函数

STM32 进入不了中断