00.EXTI基本结构
根据外部中断的结构图来进行外部中断的配置步骤如下
- 1.配置所涉及外设的系统时钟RCC
- 2.配置GPIO
- 3.配置AFIO,选择需要用的GPIO,连接到后面的EXTI
- 4.配置EXTI,选择 边沿触发方式,比如上升沿、下降沿或者双边沿,选择触发响应方式 中断响应 和事件响应
- 5.配置NVIC,设置中断的优先级,最后外部中断信号就能进入CPU了
下面将进行详细的说明
01.配置所涉及外设的系统时钟RCC
根据EXTI的基本结构从左到右
开启GPIO的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//开启GPIOB的时钟
注意:此句代码为 开启APB2总线GPIOB 外设的时钟。不同的APB总线 有不同的外设注意区分下面同理
开启AFIO的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//开启AFIO的时钟
开启EXTI和NVIC两个外设
由于这两个外设时钟是一直打开的所以不需要再额外开启,NVIC是内核外设,内核外设都不需要开启时钟。
02配置GPIO
步骤如下:
- 1.定义结构体
GPIO_InitTypeDef GPIO_InitStructure;
- 2.给结构体成员赋值
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;//对于外部中断 可选 浮空输入 上拉输入 下拉输入
GPIO_InitStructure.GPIO_Pin= GPIO_Pin_14;//GPIOB的引脚
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz ;
- 3.调用GPIO_Init函数 参数1 为使用的哪一个GPIO 外设,参数2 为结构体的地址
GPIO_Init(GPIOB,&GPIO_InitStructure);//初始化
03配置AFIO
AFIO相关函数说明
- void GPIO_AFIODeInit(void); 复位AFIO外设,调用后AFIO外设的配置就会清除
- void GPIO_PinLockConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);锁定GPIO配置,防止意外更改
- void GPIO_EventOutputConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);配置AFIO的事件输出功能
- void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);配置AFIO的数据选择器 选择想要的中断引脚
GPIO_EXTILineConfig( GPIO_PortSourceGPIOB,GPIO_PinSource14);
当执行完这个函数,AFIO的第14个数据选择器就配置好了,输入端是GPIOB外设,输出端连接的事EXTI的第14个中断线路。
04配置EXTI
EXTI相关函数
- void EXTI_DeInit(void); 清除配置 恢复成默认状态
- void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);根据结构体配置EXTI外设 初始化主要用
- void EXTI_StructInit(EXTI_InitTypeDef* EXTI_InitStruct);
- void EXTI_GenerateSWInterrupt(uint32_t EXTI_Line);软件触发外部中断,参数为指定中断线
- FlagStatus EXTI_GetFlagStatus(uint32_t EXTI_Line);获取指定标志位是否被置1
- void EXTI_ClearFlag(uint32_t EXTI_Line); 清除置1标志位
- ITStatus EXTI_GetITStatus(uint32_t EXTI_Line);中断函数里查看标志位
- void EXTI_ClearITPendingBit(uint32_t EXTI_Line);中断函数里清除标志位
配置EXTI
/*4.配置EXTI
*将EXTI的第14个线路配置为中断模式 下降沿触发 开启中断
*/
EXTI_InitTypeDef EXTI_InitStruct;
EXTI_InitStruct.EXTI_Line=EXTI_Line14;
EXTI_InitStruct.EXTI_LineCmd=ENABLE;
EXTI_InitStruct.EXTI_Mode=EXTI_Mode_Interrupt;
EXTI_InitStruct.EXTI_Trigger=EXTI_Trigger_Falling;
EXTI_Init( &EXTI_InitStruct);
05配置NVIC
NVIC相关函数
- void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);指定中断分组
- void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);初始化NVIC
配置NVIC
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//指定中断分组
NVIC_InitTypeDef NVIC_InitStruct;//定义结构体
NVIC_InitStruct.NVIC_IRQChannel=EXTI15_10_IRQn;//指定中断通道开启或关闭
NVIC_InitStruct.NVIC_IRQChannelCmd =ENABLE;//中断通道使能
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=1;//指定中断通道的抢占优先级
NVIC_InitStruct.NVIC_IRQChannelSubPriority=1;//指定中断通道的响应优先级
NVIC_Init(&NVIC_InitStruct);//传入结构体初始化NVIC
注: 指定中断分组的代码 整个工程只需要执行一次即可,如果把这行代码放到模块中 则需要保证每个模块的中断分组是相同的即可,要么放到主函数里面
优先级表如下
06定义中断函数
中断函数无参数无返回值 不需要调用
//中断函数 自动执行
void EXTI15_10_IRQHandler(void)
{
//中断标志位的判断
if(EXTI_GetITStatus(EXTI_Line14)==SET)//执行中断程序
{
CountSensor_Count++;
EXTI_ClearITPendingBit(EXTI_Line14);//清除中断标志位
}
}
07对射式红外传感器实例函数完整代码
接线图
下面贴出完整代码
硬件驱动CountSensor.c
#include "stm32f10x.h" // Device header
uint16_t CountSensor_Count;//统计中断执行次数的变量
void CountSensor_Init(void)
{
/*
*配置外部中断的流程
*1.配置RCC 打开时钟
*2.配置GPIO 选择输入的端口为输入模式
*3.配置AFIO,选择我们要用的这一路的GPIO,连接到后面的EXTI
*4.配置EXTI,选择 边沿触发方式,比如上升沿、下降沿或者双边沿,选择触发响应方式 中断响应 和事件响应
*5.配置NVIC,设置中断的优先级,最后外部中断信号就能进入CPU了
*/
//开启时钟 EXTI和NVIC 不需要开启时钟(NVIC是内核外设),RCC管理内核外的外设
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//开启GPIOB的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//开启AFIO的时钟
/*
*配置GPIO的流程
*1.定义结构体 GPIO_InitTypeDef GPIO_InitStructure;
*2.引出结构体的成员变量
*3.初始化GPIO
*
*/
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;//对于外部中断 可选 浮空输入 上拉输入 下拉输入
GPIO_InitStructure.GPIO_Pin= GPIO_Pin_14;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz ;
GPIO_Init(GPIOB,&GPIO_InitStructure);
/*
*配置AFIO
*void GPIO_AFIODeInit(void);复位AFIO外设,调用后AFIO外设的配置就会清除
*void GPIO_PinLockConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);锁定GPIO配置,防止意外更改
*void GPIO_EventOutputConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);配置AFIO的事件输出功能
*void GPIO_EventOutputCmd(FunctionalState NewState);
*
*
*void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState);用于引脚重映射,para1 选择重映射的方式 para2 新的状态
*void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);配置AFIO的数据选择器 选择想要的中断引脚
*void GPIO_ETH_MediaInterfaceConfig(uint32_t GPIO_ETH_MediaInterface);以太网相关函数
*/
GPIO_EXTILineConfig( GPIO_PortSourceGPIOB,GPIO_PinSource14);
/*4.配置EXTI
*将EXTI的第14个线路配置为中断模式 下降沿触发 开启中断
*/
EXTI_InitTypeDef EXTI_InitStruct;
EXTI_InitStruct.EXTI_Line=EXTI_Line14;
EXTI_InitStruct.EXTI_LineCmd=ENABLE;
EXTI_InitStruct.EXTI_Mode=EXTI_Mode_Interrupt;
EXTI_InitStruct.EXTI_Trigger=EXTI_Trigger_Falling;
EXTI_Init( &EXTI_InitStruct);
/*4.配置NVIC
*
*/
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//指定中断分组
NVIC_InitTypeDef NVIC_InitStruct;//定义结构体
NVIC_InitStruct.NVIC_IRQChannel=EXTI15_10_IRQn;
NVIC_InitStruct.NVIC_IRQChannelCmd =ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=1;
NVIC_InitStruct.NVIC_IRQChannelSubPriority=1;
NVIC_Init(&NVIC_InitStruct);//传入结构体初始化NVIC
}
uint16_t CountSensor_Get(void)
{
return CountSensor_Count;
}
//中断函数 自动执行
void EXTI15_10_IRQHandler(void)
{
//中断标志位的判断
if(EXTI_GetITStatus(EXTI_Line14)==SET)//执行中断程序
{
CountSensor_Count++;
EXTI_ClearITPendingBit(EXTI_Line14);//清除中断标志位
}
}
硬件驱动CountSensor.h
#ifndef __COUNT_SENSOR_H
#define __COUNT_SENSOR_H
void CountSensor_Init(void);
uint16_t CountSensor_Get(void);
#endif
主函数main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "CountSensor.h"
uint8_t KeyNum;
int main(void)
{
OLED_Init();
CountSensor_Init();
OLED_ShowString(1,1,"Count:");
while(1)
{
OLED_ShowNum(1,7,CountSensor_Get(),5);
}
}
08旋转编码器计次(双中断配置)
接线图
对于双中断配置只需要改变如下代码即可
//GPIO配置
GPIO_InitStructure.GPIO_Pin= GPIO_Pin_0 |GPIO_Pin_1;
//AFIO配置
GPIO_EXTILineConfig( GPIO_PortSourceGPIOB,GPIO_PinSource0);
GPIO_EXTILineConfig( GPIO_PortSourceGPIOB,GPIO_PinSource1);
//EXTI配置
EXTI_InitStruct.EXTI_Line=EXTI_Line0|EXTI_Line1;
//NVIC配置
NVIC_InitTypeDef NVIC_InitStruct;//中断优先级
NVIC_InitStruct.NVIC_IRQChannel=EXTI0_IRQn;
NVIC_InitStruct.NVIC_IRQChannelCmd =ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=1;
NVIC_InitStruct.NVIC_IRQChannelSubPriority=1;
NVIC_Init(&NVIC_InitStruct);
NVIC_InitStruct.NVIC_IRQChannel=EXTI1_IRQn;
NVIC_InitStruct.NVIC_IRQChannelCmd =ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=1;
NVIC_InitStruct.NVIC_IRQChannelSubPriority=2;
NVIC_Init(&NVIC_InitStruct);
//分别设置中断函数
void EXTI0_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line0)==SET)
{
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_0)==0)
{
Encoder_Count--;
}
EXTI_ClearITPendingBit(EXTI_Line0);
}
}
void EXTI1_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line1)==SET)
{
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)==0)
{
Encoder_Count++;
}
EXTI_ClearITPendingBit(EXTI_Line1);
}
}