目录
[1.count Sensor.c](#1.count Sensor.c)
[count Sensor.h](#count Sensor.h)
#中断系统和EXTI外部中断#
中断系统(管理和执行中断的逻辑结构)
- 中断:在主程序运行过程中,出现了特定的中断触发条件(中断源)(外部中断---引脚发生电平跳变,定时器---到达定时的时间,串口通信---接收数据),使得 CPU 暂停当前正在运行的程序,转而去处理中断程序,处理完成后又返回原来被暂停的位置继续运行
- 中断优先级:当有多个中断源同时申请中断时, CPU 会根据中断源的 轻重缓急 进行裁决,优先响应更加紧急的中断源
- 中断嵌套:当一个中断程序正在运行时,又有新的更高优先级的中断源申请中断, CPU 再次暂停当前中断程序,转而去处理新的中断程序,处理完成后依次进行返回
中断执行流程



STM32 中断
- 68 个可屏蔽中断通道(中断源),包含 EXTI 外部中断、 TIM定时器 、 ADC 模数 转换器 、 USART 串口、 SPI 通信、 I2C 通信、 RTC 实时时钟等多个外设
- 使用 NVIC (在 STM32 中管理中断分配优先级)统一管理中断, 每个中断通道都拥有 16 个可编程的优先等级 ,可对优先级进行分组,进一步 设置抢占优先级和响应优先级
内核中断:
①复位中断,当产生复位事件时,程序就会自动执行复位中断函数(复位后程序开始执行的位置)。
②NMI,不可屏蔽中断。
③硬件失效
④存储管理
⑤总线错误
⑥错误应用
......
外设中断:
①窗口看门狗,监测程序运行状态的中断(程序卡死没有及时喂狗,窗口看门狗就会申请中断)
② PVD 电源电压监测,如果供电电压不足就会申请中断。
③ EXTI0~ EXTI 4 ,EXTI 9_5 , EXTI15_10 外部中断对应的中断源
......
程序中的中断函数地址,由编译器分配,不固定,但是中段跳转由于硬件的限制,只能跳到固定的地址执行程序,所以为了能让硬件跳转到一个不固定的中段函数里,就需要在内存中定义一个地址的列表,在这个固定位置有编译器,再加上一条跳转到中断函数的代码,这样中断跳转跳到任意位置可行,中段地址的列表叫 中段向量表 。
NVIC 基本结构(嵌套中断向量控制器)
在 STM32 中,统一分配中断优先级和管理中断
NVIC 是一个内核外设,是 CPU 助手
NVIC 有许多输入口,可以接许多中断线路
NVIC 只有一个输出口,根据每个中断的优先级分配中断的先后顺序,通过一个输出口连接 CPU ,确定中断

NVIC 优先级分组
- NVIC 的中断优先级由优先级寄存器的 4 位( 0 最高 ~15 最低)决定,这 4 位可以进行切分,分为高 n 位的 抢占优先级 和低 4-n 位的 响应优先级
- 抢占优先级高的可以中断嵌套,响应优先级高的可以优先排队 ,抢占优先级和响应优先级均相同的按中断号排队(不存在先来后到排队方式)
- 分组方式在程序中是我们自己来选择的,再分配优先级的时候,要注意抢占优先级和响应优先级的取值范围
|----------------|-------------|-------------|
| 分组方式(抢占等级) | 抢占优先级 | 响应优先级 |
| 分组0 | 0位,取值为0 | 4位,取值为0~15 |
| 分组1 | 1位,取值为0~1 | 3位,取值为0~7 |
| 分组2 | 2位,取值为0~3 | 2位,取值为0~3 |
| 分组3 | 3位,取值为0~7 | 1位,取值为0~1 |
| 分组4 | 4位,取值为0~15 | 0位,取值为0 |
EXTI 简介(众多能产生中断的外设之一)
- EXTI(Extern Interrupt)外部中断
- EXTI可以监测指定GPIO口的电平信号,当其指定的GPIO口产生电平变化 时,EXTI将立即向NVIC发出中断申请,经过NVIC裁决后即可中断CPU主程序,使CPU执行EXTI对应的中断 程序
- 支持的触发方式:上升沿/下降沿/双边沿/软件触发
- 支持的GPIO口:所有GPIO口,但相同的Pin不能同时触发中断(PA0和PB0不能同时用)
- 通道数20个:16个GPIO_Pin(0~15),(外加PVD输出、RTC闹钟、USB唤醒、以太网唤醒)
(由于外部中断,可以从低功耗模式的停止模式下唤醒stm32,①pvd电源电压监测---电源从电压过低恢复时,PVD借助外部中断退出停止模式;②RTC闹钟---为了省电,RTC定闹钟后,stm32会进入停止模式,等到闹钟响的时候再唤醒,就需要借助外部中断;③USB唤醒和以太网唤醒都是类似作用)
- 触发响应方式:中断响应/事件响应
- (事件响应:Stm32对外部中断增加的一种额外功能,外部中断检测到引脚电平变化,正常流程是会选择触发中断,但也可以选择触发事件,那么外部中断的信号不会通向CPU,而是通向其他外设,触发其他外设的操作------触发ADC转换,触发DMA)
- 中断响应是正常流程引脚电平变化触发中断,事件响应不会触发中断,而是触发别的外设操作,属于外设之间的联合工作。
EXTI 基本结构

AFIO 复用 IO 口
- AFIO主要用于引脚复用功能的选择和重定义(选择器)
- 在STM32中,AFIO主要完成两个任务:复用功能引脚重映射(将默认复用功能引脚换到重定义模块)、中断引脚选择

EXTI 框图

配合外部中断原理模块
特征:想要获取信号是外部驱动的很快的突发信号(旋转编码器的输出信号 / 红外遥控接收头的输出)
旋转编码器简介
- 旋转编码器:用来测量位置、速度或旋转方向的装置,当其旋转轴旋转时,其输出端可以输出与旋转速度和方向对应的方波信号,读取方波信号的频率和相位信息即可得知旋转轴的速度和方向
- 类型:机械触点式/霍尔传感器式/光栅式
硬件电路

未旋转→(触点未导通,上拉电阻) A 端口高电平
旋转→(内部触点导通) A 端口低电平

外部中断流程:
//初始化
//配置外部中断流程
//看EXTI基本结构图,将外设配置好,线路串通即可
//GPIO------AFIO------EXTI------NVIC
//配置RCC,打开时钟------使外设能够工作
//配置GPIO,选择端口为输入模式(查看手册GPIO配置)

AFIO相关函数
//配置AFIO,库函数与GPIO同一个文件,选择我们用的一路GPIO,连接到后面的EXIT
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);
void GPIO_EventOutputCmd(FunctionalState NewState);
//俩个函数配置AFIO事件输出功能
void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState);
///进行引脚重映射,第一个参数:选择重映射的方式;第二个参数:新的状态
void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);
///外部中断需要的函数,配置AFIO的数据选择器,选择我们想要的中断引脚
void GPIO_ETH_MediaInterfaceConfig(uint32_t GPIO_ETH_MediaInterface);
//与以太网有关,芯片没有配置,用不到
EXIT相关函数
配置EXTI,选择边沿触发方式(上升沿/下降沿/双边沿),选择触发响应方式(中断响应/事件响应)
void EXTI_DeInit(void);
将EXTI配置清除,恢复上电默认状态
void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);
可根据结构体的参数配置EXTI外设,初始化EXTI 函数
cpp
EXIT在c文件中代码举例
EXTI_InitTypeDef EXTI_InitStructure;
EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;//中断模式
EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Falling //下降沿触发
EXTI_InitStructure.EXTI_Line=EXTI_Line14 ;//PB14
EXTI_InitStructure.EXTI_LineCmd=ENABLE;//开启中断
EXTI_Init(&EXTI_InitStructure);
EXTI_InitStructure.EXTI_Trigger=
EXTI_Trigger_Rising// 上升沿触发
EXTI_Trigger_Falling //下降沿触发
EXTI_Trigger_Rising_Falling //双沿触发
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);
//获取中断标志位是否被置1
//set为置1,程序跳转到中断函数
④void EXTI_ClearITPendingBit(uint32_t EXTI_Line);
//清除中断挂起标志位
若不清除标志位,程序会一直申请中断,会死机
在主程序查看和清除标志位,用①②函数
在中断函数查看和清除标志位,用③④函数
//配置NVIC,给中断选择一个何使的优先级,通过NVIC,外部中断信号就能进入CPU,CPU接收到中断信号,跳转到中断函数执行中断程序
NVIC为内核外设,库函数在杂项
在配置中断之前,先置定中断分组
再使用 NVIC_ Init初始化NVIC
void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);
//中断分组,参数使中断分组的方式
cpp
NVIC在c文件中代码举例
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
NVIC_InitStructure.NVIC_IRQChannel=EXTI15_10_IRQn;
NVIC_Init(&NVIC_InitStructure);
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);
//根据结构体里里面置定的参数初始化NVIC
void NVIC_SetVectorTable(uint32_t NVIC_VectTab, uint32_t Offset);
//设置中断向量表
void NVIC_SystemLPConfig(uint8_t LowPowerMode, FunctionalState NewState);
//系统低功耗配置
void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource);
对射式红外传感器计数
1.count Sensor.c
cpp
#include "stm32f10x.h" // Device header
uint16_t count;
//初始化
void CountSensor_Init(void)
{
//配置外部中断流程
//看EXTI基本结构图,将外设配置好,线路串通即可
//GPIO-AFIO------EXTI------NVIC
//1.配置RCC管理外设,打开时钟------使外设能够工作
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//PB12
//配置AFIO时钟,也是APB2外设
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//PB12
//EXTI和NVIC外设一直都是打开状态,不需要配置
//2.配置GPIO,选择端口为输入模式init初始化
GPIO_InitTypeDef GPIO_InitStructure;
//选择模式,对于外部中断来说,上拉输入,下拉输入,浮空输入
//不知道如何配置模式,在外设配置手册查看外设GPIO配置
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU;//上拉输入,默认高电平输入方式
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_12;//PB12
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;//常规
//********
GPIO_Init(GPIOB,&GPIO_InitStructure);
//3.配置AFIO,库函数与GPIO同一个文件,选择我们用的一路GPIO,连接到后面的EXIT
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource12);//PB12
//4.配置EXTI,选择边沿触发方式初始化(上升沿/下降沿/双边沿),选择触发响应方式(中断响应/事件响应)
EXTI_InitTypeDef EXTI_InitStructure;
EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt;//中断模式
EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Rising;//上升沿触发
EXTI_InitStructure.EXTI_Line=EXTI_Line12 ;//PB12
EXTI_InitStructure.EXTI_LineCmd=ENABLE;//开启中断
//*******
EXTI_Init(&EXTI_InitStructure);
//5.配置NVIC,给中断选择一个合适的优先级,通过NVIC,外部中断信号就能进入CPU,CPU接收到中断信号,跳转到中断函数执行中断程序
// 在配置中断之前,先置定中断分组
// 再使用NVIC_Init初始化NVIC
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//分组,整个工程执行一次
//配置NVIC为分组2
//即抢占优先级范围:0~3,响应优先级范围:0~3
//此分组配置在整个工程中仅需调用一次
//若有多个中断,可以把此代码放在main函数内,while循环之前
//若调用多次配置分组的代码,则后执行的配置会覆盖先执行的配置
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;//抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;//响应优先级
NVIC_InitStructure.NVIC_IRQChannel=EXTI15_10_IRQn;//选择配置NVIC的EXTI15_10线
// EXTI15_10_IRQn = 40, /*!< External Line[15:10] Interrupts */
//选择的是B12引脚,为外部中断12号线
NVIC_Init(&NVIC_InitStructure);
}
//中断程序
void EXTI15_10_IRQHandler(void)
{
//中断标志位判断,外部中断10~15都能进,判断是否是12
if(EXTI_GetITStatus(EXTI_Line12)==SET)
{
//执行中断程序
count++;
//清除中断标志位函数,只有中断标志位置1,程序就会跳到中断函数
EXTI_ClearITPendingBit(EXTI_Line12);
}
}
注意:
NVIC_InitStructure.NVIC_IRQChannel=EXTI15_10_IRQn;
F12跳转到stm32f10x.
根据芯片型号选择(芯片中8为64kflash)
|----|-------|----------|-------------------|
| MD | 中容量产品 | 64~128K | STM32F101/102/103 |
#ifdef STM32F10X_MD在这个模块里寻找相对应的 外部中断通道
EXTI15_10_IRQn = 40, /*!< External Line[15:10] Interrupts */
根据选择的引脚选择外部中断线通道
我选的是PB12,为12号线,而12号线在根10号线通用同一个外部中断线
每个终端通道都有对应的外部中断函数,参考启动文件,以IRQhander结尾的就是中断函数的名字
EXTI15_10_IRQHandler ; EXTI Line 15..10
这是中断线10~15的外部中断函数名字
外部中断函数无返回值,无参数
首先进行中断标志位判断,外部中断10~15都能进,判断是否是12
后执行中断程序
最后注意清除中断标志位函数,只有中断标志位置1,程序就会跳到中断函数
数值跳太快,可以在count++前面加延时函数
2.count Sensor.h
cpp
#ifndef __COUNTSENSOR_H_
#define __COUNTSENSOR_H_
void CountSensor_Init(void);
extern uint16_t count;
#endif
3.main.c
cpp
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "countSensor.h"
int main(void)
{
OLED_Init();
CountSensor_Init();
OLED_ShowString(1,1,"count");
while(1)
{
OLED_ShowNum(2,7,count,5);
}
}
旋转编码器计次
1.encounter.c
cpp
#include "stm32f10x.h" // Device header
int16_t count;
//B相下降沿和A相低电平,判断为正转
//A相下降沿和B相低电平,判断为正转
void Encoder_Init(void)
{
//RCC开启时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //开启GPIOB的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //开启AFIO的时钟,外部中断必须开启AFIO的时钟
//GPIO初始化
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;//PB0和PB1
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
//AFIO选择中断引脚
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource0);//将外部中断的0号线映射到GPIOB,即选择PB0为外部中断引脚
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource1);//将外部中断的1号线映射到GPIOB,即选择PB1为外部中断引脚
//EXTI初始化
EXTI_InitTypeDef EXTI_InitStructure; //定义结构体变量
EXTI_InitStructure.EXTI_Line = EXTI_Line0 | EXTI_Line1; //选择配置外部中断的0号线和1号线
EXTI_InitStructure.EXTI_LineCmd = ENABLE; //指定外部中断线使能
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //指定外部中断线为中断模式
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //指定外部中断线为下降沿触发
EXTI_Init(&EXTI_InitStructure); //将结构体变量交给EXTI_Init,配置EXTI外设
//NVIC中断分组
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //配置NVIC为分组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);
}
int16_t Encoder_Get(void)
{
int16_t Temp;
Temp = count;
count = 0;
return Temp;//返回count的变化值,用于外部加减变量
}
void EXTI0_IRQHandler(void)
{
//检查中断标志位
if (EXTI_GetITStatus(EXTI_Line0) == SET)
{
if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)//反转
//判断另一个引脚
{
count--;
}
EXTI_ClearITPendingBit(EXTI_Line0); //清除外部中断标志位
}
}
//在中断不要执行耗时的代码
//不要在主函数和制度函数调用同一个函数或操作同一个硬件,会显示错误
void EXTI1_IRQHandler(void)
{
//检查外部中断标志
if (EXTI_GetITStatus(EXTI_Line1) == SET)
{
/*如果出现数据乱跳的现象,可再次判断引脚电平,以避免抖动*/
if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0)//正转
{
count ++;
}
EXTI_ClearITPendingBit(EXTI_Line1); //清除外部标志位
}
}
2.encounter.h
cpp
#ifndef __ENCODER_H_
#define __ENCODER_H_
void Encoder_Init(void);
int16_t Encoder_Get(void);
#endif
3.main.c
cpp
#include "stm32f10x.h" // Device header
#include "OLED.h"
#include "encoder.h"
uint16_t number;
int main(void)
{
OLED_Init();
OLED_ShowString(1,1,"number");
Encoder_Init();
while(1)
{
number +=Encoder_Get();
OLED_ShowSignedNum(1,8,number,5);
}
}
#up俩个方法都有误差,数字都不稳定,就去搜寻消抖方法#
#江协科技STM32------旋转编码器计次(软件消抖)_旋转编码器消抖-CSDN博客,之前提的在中断函数内延时,占用内存#
这个是一位博主写的方法,我引用分享:
增加判断正、反转的条件,读取一个周期内的电平变化再进行判断。首先将最小系统板的PB0引脚与A相连接,触发方式选择上升/下降沿触发,用A相的输出信号来触发中断,然后在A相下降沿触发第一次中断后读取B相电平,紧接着A相上升沿触发第二次中断后读取B相电平,结合两次读取到的电平来判断是正转还是反转,从A相的下降沿触发到上升沿触发期间,若B相电平发生了变化,则判定编码器转动,反之未转动,波形抖动时B相的电平保持不变,能够实现消抖。
全部代码就放在下面了,注意要改的几个点:
①只需要写EXTI0的中断函数
②AFIO选择中断引脚只需要PB0作为中断引脚
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource0);
//将外部中断的0号线映射到GPIOB,即选择PB0为外部中断引脚
③EXTI初始化,只需选择配置外部中断的0号线
EXTI_InitStructure.EXTI_Line = EXTI_Line0 ;
④选择上升下降沿触发
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;
⑤NVIC通道只需选择PB0-中断0通道
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; //在启动项h文件中找到对应的
cpp
#include "stm32f10x.h" // Device header
#include "Delay.h"
int16_t count,B_level;
//B相下降沿和A相低电平,判断为正转
//A相下降沿和B相低电平,判断为正转
void Encoder_Init(void)
{
//RCC开启时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //开启GPIOB的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //开启AFIO的时钟,外部中断必须开启AFIO的时钟
//GPIO初始化
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;//PB0和PB1
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
//AFIO选择中断引脚
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource0);//将外部中断的0号线映射到GPIOB,即选择PB0为外部中断引脚
//EXTI初始化
EXTI_InitTypeDef EXTI_InitStructure;
EXTI_InitStructure.EXTI_Line = EXTI_Line0 ;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling;
EXTI_Init (&EXTI_InitStructure);
//NVIC中断分组
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //配置NVIC为分组2
//对俩个通道分别设置优先级
NVIC_InitTypeDef NVIC_InitStructure;
//定义结构体变量可以重复使用
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; //在启动项h文件中找到对应的
EXTI0_IRQn = 6, /*!< EXTI Line0 Interrupt */
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStructure);
对俩个通道分别设置优先级
NVIC_Init(&NVIC_InitStructure);
}
int16_t Encoder_Get(void)
{
int16_t Temp;
Temp = count;
count = 0;
return Temp;//返回count的变化值,用于外部加减变量
}
void EXTI0_IRQHandler(void)
{
if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0)//A相下降沿触发第一次中断
{
B_level=0;//读取B相电平,若为高电平则B_level置1,反之保持0
if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 1)
{
B_level=1;
}
}
if(GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 1)//A相上升沿触发第二次中断
{
if(B_level==1 && GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)
{
count++;//正转
}
if(B_level==0 && GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 1)
{
count--;//反转
}
}
EXTI_ClearITPendingBit(EXTI_Line0);
}
#所有现象均正确,之前的错误也全部解决,OLED显示屏没亮是RCC时钟初始化错误#