文章目录
- 一、介绍部分
- 简介中断系统
- 中断执行流程
- 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){// 计数器+1Count++;}// 清除中断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 headeruint16_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);
中断函数可以在开始文件中寻找