文章目录
- 一、介绍部分
- 简介中断系统
- 中断执行流程
- STM32中断
- NVIC基本结构
- NVIC优先级分组
- 外部中断
- 外部中断简介
- 外部中断基本结构
- 外部中断的流程
- AFIO
- EXTI框图
- 相关外设介绍
- 旋转编码器介绍
- 硬件电路
- 对射式红外传感器
- 二、代码实现
- 对射式红外传感器计次
- 连接电路
- 封装红外传感器与中断函数
- 旋转编码器计数
- 连接电路
- 封装旋转编码器函数、外部中断函数
- 补充
一、介绍部分
简介中断系统
中断执行流程
STM32中断
此地址是用于编译器来跳转到中断函数的地址
NVIC基本结构
NVIC作用是为CPU分配各个中断优先级,然后直接告诉CPU先执行的中断函数。
NVIC优先级分组
外部中断
外部中断简介
外部中断基本结构
外部中断的流程
**
AFIO先从GPIOA、GPIOB、GPIOC中选择16个不同Pin值的引脚(如不能同时有GPIOA 的PIN_1或GPIOB的PIN_1),以此来选出16个中断通道,然后选择这些中断是否是跳转到其他外设,不是的话就会通过NVIC来配置要打开的中断通道、中断通道的优先级,最后按照优先级顺序依次交予CPU执行
**
AFIO
EXTI框图
相关外设介绍
旋转编码器介绍
硬件电路
对射式红外传感器
两个面板对射红外线,被遮挡恢复一次后就会产生一个电平变化。
二、代码实现
对射式红外传感器计次
让对射式红外传感器每被遮挡一次时,让OLED显示的数字+1
连接电路
封装红外传感器与中断函数
IRSensor.c
#include "stm32f10x.h" // Device header
// 初始化
void IRSensor_Init(void){
// 配置时钟(红外传感器与外部中断所需)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
// 初始化端口
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引脚选择
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource14);
EXTI_InitTypeDef EXTI_InitStructure;
// 选择中断线,14号端口对应14号线
EXTI_InitStructure.EXTI_Line = EXTI_Line14;
// 是否开启这条中断线
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
// 中断模式还是事件模式
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
// 触发方式,下降沿触发
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_Init(&EXTI_InitStructure);
// 设置中断优先级组
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStructure;
// 中断通道
NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;
// 是否打开通道
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
// 抢占优先级
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
// 相应优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStructure);
}
// 用于计数
uint16_t Count = 0;
// 获取计数器的值
uint16_t GetCount(void){
return Count;
}
// 中断函数
void EXTI15_10_IRQHandler(void){
// 获取中断线是否打开
if(EXTI_GetITStatus(EXTI_Line14) == SET){
// 如果出现数据乱跳的现象,可再次判断引脚电平,以避免抖动
if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_14) == 0){
// 计数器+1
Count++;
}
// 清除中断
EXTI_ClearITPendingBit(EXTI_Line14);
}
}
主函数main.c
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "IRSensor.h"
int main(void)
{
OLED_Init();
IRSensor_Init();
OLED_ShowString(1,1,"Count:");
while (1)
{
OLED_ShowNum(2,1,GetCount(),4);
}
}
旋转编码器计数
连接电路
封装旋转编码器函数、外部中断函数
有多条中断线时,要分别初始化,不能有相同的优先级,不过定义的初始化结构体可以重复使用。
Encoder.c内容
#include "stm32f10x.h" // Device header
uint16_t EncoderCount;
void Encoder_Init(void){
// 配置时钟(红外传感器与外部中断所需)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
// 初始化端口
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIO_InitStructure);
// 配置AFIO引脚选择
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource0);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource1);
EXTI_InitTypeDef EXTI_InitStructure;
// 选择中断线
EXTI_InitStructure.EXTI_Line = EXTI_Line0 | EXTI_Line1;
// 是否开启这条中断线
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
// 中断模式还是事件模式
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
// 触发方式,下降沿触发
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_Init(&EXTI_InitStructure);
// 设置中断优先级组
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
// 为两个通道分别初始化配置优先级
NVIC_InitTypeDef NVIC_InitStructure;
// 中断通道
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
// 是否打开通道
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
// 抢占优先级
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
// 相应优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStructure);
// 中断通道
NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;
// 是否打开通道
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
// 抢占优先级
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
// 相应优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_Init(&NVIC_InitStructure);
}
// 获取计数数据
uint16_t Encoder_Get(void){
uint16_t Temp;
Temp = EncoderCount;
EncoderCount = 0;
return Temp;
}
// 中断函数
void EXTI0_IRQHandler(void){
if(EXTI_GetITStatus(EXTI_Line0) == SET){
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1) == 0)
EncoderCount++;
// 清除此中断通道标志
EXTI_ClearITPendingBit(EXTI_Line0);
}
}
void EXTI1_IRQHandler(void){
if(EXTI_GetITStatus(EXTI_Line1) == SET){
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_0) == 0)
EncoderCount--;
// 清除此中断通道标志
EXTI_ClearITPendingBit(EXTI_Line1);
}
}
主函数main.c内容
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "Encoder.h"
int16_t Num;
int main(void)
{
OLED_Init();
Encoder_Init();
OLED_ShowString(1,1,"Num:");
while (1)
{
// 每次的数加旋转的数
Num += Encoder_Get();
OLED_ShowSignedNum(2,1,Num,5);
}
}
补充
两种获取中断标志与清除标志函数
前两中适用于普通函数执行
后两种适用于中断函数中执行
// 获取中断线标志
FlagStatus EXTI_GetFlagStatus(uint32_t EXTI_Line);
// 清除此中断线标志
void EXTI_ClearFlag(uint32_t EXTI_Line);
// 获取中断线标志
ITStatus EXTI_GetITStatus(uint32_t EXTI_Line);
// 清除此中断线标志
void EXTI_ClearITPendingBit(uint32_t EXTI_Line);
中断函数可以在开始文件中寻找