STM32F103C8T6中断配置
作为一个STM32新手,当初第一次接触中断配置的时候,真的是一头雾水。拿着STM32F103C8T6的最小系统板,想做个按键外部中断翻转LED的小实验,结果折腾了大半天,LED就是纹丝不动。后来一点点排查,才发现是自己漏了关键的步骤。今天就把STM32F103C8T6的中断配置经验分享出来,希望能帮到和我当初一样的新手。
一、STM32中断的分类
在STM32中,中断是指CPU在执行当前任务时,由于某种事件(外部或内部)发生,暂停当前任务,转而执行中断服务程序(ISR),完成后再返回原任务。STM32的中断主要分为以下几种类型:
硬中断 硬中断是由外部硬件设备触发的中断信号,例如GPIO外部中断、定时器中断等。硬中断可以进一步分为以下两类:
不可屏蔽中断(NMI):用于处理紧急情况,例如RAM奇偶校验错误。NMI无法被屏蔽,CPU必须立即响应。可屏蔽中断(INTR):用于一般外设的中断请求,例如网卡或串口通信。CPU可以选择响应或忽略。
软中断 软中断是由软件触发的中断,通常用于系统调用或访问受保护的资源。软中断的主要作用是将复杂的任务分为两部分:一部分在硬中断中快速处理,另一部分在软中断中完成,以提高系统实时性。
异常 异常是CPU在运行过程中由于错误或特殊指令触发的中断,例如:
Fault:如除零错误或无效操作码。
Trap:如调试断点或溢出。
Abort:如总线错误或内存访问错误。
外部中断(EXTI) 外部中断是由GPIO引脚的电平变化触发的中断。STM32支持多达23条外部中断线,包括GPIO中断、RTC闹钟事件、USB唤醒等。每条中断线可以独立配置触发方式(上升沿、下降沿或双边沿)。
系统中断 系统中断是由内核触发的特殊中断,例如SysTick定时器中断、PendSV中断等。这些中断通常用于操作系统的任务调度或系统管理。
中断优先级 STM32的中断优先级分为抢占优先级和响应优先级。抢占优先级决定中断是否可以打断其他中断,而响应优先级用于决定同级抢占优先级的中断处理顺序。
通过合理配置中断优先级和触发条件,可以实现高效的实时控制和资源管理。
二、先聊点基础:STM32中断的核心概念
在动手之前,先简单提两个核心玩意儿,不用死记硬背,知道是干啥的就行:
- NVIC(嵌套向量中断控制器):相当于STM32的“中断管家”,负责管理所有中断的优先级、开启/关闭中断通道,所有外设的中断最终都要经过它的调度。
- EXTI(外部中断/事件控制器):专门管外部引脚的中断,比如按键触发的中断,它能把GPIO引脚和NVIC连接起来,还能设置触发方式(上升沿、下降沿、双边沿)。
STM32F103C8T6的中断配置本质上就是:让外设(比如GPIO)产生中断请求,通过EXTI(外部中断)或外设自身的中断源,告诉NVIC,最后由NVIC触发对应的中断服务函数。
三、实战环境准备
先交代下我的实验环境,新手可以直接照搬:
- 硬件:STM32F103C8T6最小系统板、LED灯(接PB0)、按键(接PA0)
- 软件:Keil MDK5.36、STM32标准外设库3.5.0(F1系列,别用HAL库,新手先从标准库入手更易理解)
实验目标很简单:按下PA0的按键,触发外部中断,翻转PB0的LED灯状态。
四、库函数配置外部中断
我推荐新手先用库函数,不用跟寄存器死磕,先把流程跑通再说。
步骤1:开启相关时钟(最容易漏的一步!)
STM32的外设要工作,必须先开时钟,这是铁律。这里需要开三个时钟:
- GPIOA(PA1按键)、GPIOB(PB0 LED)的时钟(APB2总线)
- AFIO(复用功能IO)的时钟(重点! 外部中断的引脚映射必须靠AFIO,不开这个时钟,中断绝对触发不了)
代码如下:
// 1. 开启时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
步骤2:配置GPIO引脚模式
PA1作为按键输入,我选上拉输入(这样按键没按下时是高电平,按下是低电平);PB0作为LED输出,选推挽输出。
代码:
// 2. 配置GPIO
GPIO_InitTypeDef GPIO_InitStructure;
// PA1配置(根据实际电路选择模式)
// 如果按键接在PA0和GND之间,使用上拉输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 输入模式可忽略Speed
GPIO_Init(GPIOA, &GPIO_InitStructure);
// PB0配置
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_SetBits(GPIOB, GPIO_Pin_0); // 初始高电平GPIO_InitTypeDef GPIO_InitStructure;
步骤3:配置AFIO的外部中断引脚映射
STM32的EXTI线和GPIO引脚是“一对多”的关系,比如EXTI0线可以对应GPIOA0、GPIOB0、GPIOC0等,但需要通过AFIO指定具体用哪个GPIO的引脚。
我们要把PA1和EXTI1线绑定,用库函数GPIO_EXTILineConfig就行:
// 3. 配置AFIO映射
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource1);
步骤4:配置EXTI中断参数
这里要设置中断的触发方式、开启中断线:
// 4. 配置EXTI
EXTI_InitTypeDef EXTI_InitStructure;
EXTI_InitStructure.EXTI_Line = EXTI_Line1;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; // 下降沿触发
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
步骤5:配置NVIC中断优先级
NVIC是“中断管家”,必须告诉它:哪个中断通道要开启?优先级是多少?
首先要配置优先级分组(整个程序只能调用一次!),我选分组2(2位抢占优先级,2位响应优先级),然后配置EXTI0的优先级:
// 5. 配置NVIC
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
步骤6:编写中断服务函数(必须清标志位!)
中断服务函数的名字是固定的,要和启动文件(startup_stm32f10x_md.s)里的中断向量表一致,比如EXTI0的服务函数名就是EXTI0_IRQHandler。
重点中的重点:执行完中断操作后,必须清除中断标志位,否则MCU会认为中断还在触发,一直进入服务函数,导致程序卡死!
// 中断服务函数定义
void EXTI1_IRQHandler(void)
{
if (EXTI_GetITStatus(EXTI_Line1) != RESET)
{
// 简单延时消抖(可选,根据需求)
// for(int i = 0; i < 10000; i++);
// 读取按键状态
if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_1) == 0)
{
// 翻转LED状态
if (GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_0))
GPIO_ResetBits(GPIOB, GPIO_Pin_0);
else
GPIO_SetBits(GPIOB, GPIO_Pin_0);
}
EXTI_ClearITPendingBit(EXTI_Line1); // 必须清除中断标志
}
}
步骤7:整合main函数
把上面的代码整合到main函数里,死循环里啥都不用做,等待中断即可:
#include "stm32f10x.h" // STM32标准外设库头文件
// 中断服务函数声明
void EXTI1_IRQHandler(void);
/**
* @brief 主函数
* @param 无
* @retval int 程序返回值(通常不会返回)
*/
int main(void)
{
// 系统初始化(配置系统时钟、Flash延迟等)
SystemInit();
/******************** 第一步:开启外设时钟 ********************/
// 使能GPIOA、GPIOB和AFIO(复用功能IO)的时钟
// 注意:STM32外设使用前必须开启对应的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
/******************** 第二步:配置GPIO引脚 ********************/
GPIO_InitTypeDef GPIO_InitStructure; // GPIO初始化结构体
// 配置PA1为输入模式(连接按键)
// 假设按键一端接PA1,另一端接GND,使用内部上拉电阻
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; // 选择引脚1
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 输入模式下此参数可忽略
GPIO_Init(GPIOA, &GPIO_InitStructure); // 应用配置到GPIOA
// 配置PB0为输出模式(连接LED)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; // 选择引脚0
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // 推挽输出模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 输出速度50MHz
GPIO_Init(GPIOB, &GPIO_InitStructure); // 应用配置到GPIOB
// 设置PB0初始状态为高电平(LED灭,假设低电平点亮LED)
GPIO_SetBits(GPIOB, GPIO_Pin_0);
/******************** 第三步:配置AFIO映射 ********************/
// 将GPIOA的Pin1映射到外部中断线1
// 注意:每个外部中断线可以映射到多个GPIO引脚,需通过AFIO选择具体引脚
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource1);
/******************** 第四步:配置外部中断(EXTI) ********************/
EXTI_InitTypeDef EXTI_InitStructure; // EXTI初始化结构体
EXTI_InitStructure.EXTI_Line = EXTI_Line1; // 选择外部中断线1
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; // 中断模式(非事件模式)
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; // 下降沿触发(按键按下时产生下降沿)
EXTI_InitStructure.EXTI_LineCmd = ENABLE; // 使能该中断线
EXTI_Init(&EXTI_InitStructure); // 应用配置
/******************** 第五步:配置嵌套向量中断控制器(NVIC) ********************/
NVIC_InitTypeDef NVIC_InitStructure; // NVIC初始化结构体
// 配置中断优先级分组(2位抢占优先级,2位响应优先级)
// 注意:整个系统只能调用一次优先级分组函数
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
// 配置EXTI1中断通道
NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn; // 中断通道:EXTI线1
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; // 抢占优先级为2
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; // 响应优先级为2
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 使能该中断通道
NVIC_Init(&NVIC_InitStructure); // 应用配置
/******************** 第六步:主循环 ********************/
while(1)
{
// 主循环可以添加其他后台任务
// 中断处理会在中断服务函数中进行,不会影响主循环运行
// 可以在这里添加低功耗模式、系统状态监测等代码
}
}
/**
* @brief EXTI线1中断服务函数
* @param 无
* @retval 无
* @note 当PA1引脚检测到下降沿时,此函数会被自动调用
*/
void EXTI1_IRQHandler(void)
{
// 检查是否发生了EXTI线1中断(中断标志位是否置位)
if (EXTI_GetITStatus(EXTI_Line1) != RESET)
{
// ---------- 可选:按键消抖处理 ----------
// 机械按键在按下/释放时会产生抖动,可能导致多次触发
// 简单的软件消抖方法:延时后再次检测引脚状态
// for(int i = 0; i < 10000; i++); // 简单延时
// ---------- 确认按键状态 ----------
// 再次读取PA1引脚状态,确保是有效的按键按下
// 上拉模式下,按键按下时引脚为低电平(0)
if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_1) == 0)
{
// ---------- 执行中断处理逻辑 ----------
// 读取PB0当前输出状态并翻转
if (GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_0))
{
// 当前为高电平,设置为低电平(点亮LED)
GPIO_ResetBits(GPIOB, GPIO_Pin_0);
}
else
{
// 当前为低电平,设置为高电平(熄灭LED)
GPIO_SetBits(GPIOB, GPIO_Pin_0);
}
// 可选:添加按键释放等待,避免单次按下触发多次
// while(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_1) == 0);
}
// ---------- 清除中断标志位 ----------
// 非常重要!如果不清除标志位,会连续触发中断
EXTI_ClearITPendingBit(EXTI_Line1);
}
}
五、容易踩的坑
- 忘记开启AFIO时钟:这是我当初最致命的坑,配置完所有步骤,按键按烂了LED都不亮,后来查手册才发现外部中断映射需要AFIO支持。
- 没清中断标志位:第一次成功触发中断后,LED闪了一下就卡住了,原因是没清标志位,MCU一直重复进入中断。
- GPIO模式配错:比如把PA0配成浮空输入,又没外接上拉电阻,导致引脚电平不稳定,中断乱触发。
- 优先级分组调用多次:
NVIC_PriorityGroupConfig只能调用一次,否则会导致优先级配置混乱。
六、总结:中断配置的核心逻辑
其实不管是外部中断、定时器中断还是串口中断,配置流程都大同小异:
开时钟 → 配外设 → 配中断源(EXTI/外设自身) → 配NVIC → 写服务函数(清标志位)
新手只要把这个流程刻在脑子里,再结合实际外设的特点稍作调整,就能搞定大部分中断配置了。
最后说句心里话:学习STM32,光看教程没用,一定要动手。遇到问题别慌,查手册、单步调试、逐行排查,那些踩过的坑,最后都会变成你的经验。
江协科技中断学习笔记











对射式传感器的应用

main.c 代码如下:
#include "stm32f10x.h" // Device header
#include "Delay.h"
#include "OLED.h"
#include "CountSensor.h"
int main()
{
OLED_Init();
CountSensor_Init();
OLED_ShowCHinese(0, 0, 0); //计
OLED_ShowCHinese(0, 16, 1); //次
OLED_ShowString(1,5,":");
while(1)
{
OLED_ShowNum(1,6,CountSensor_Get(),5);
}
}
CountSensor.c 代码如下:
#include "stm32f10x.h" // Device header
uint16_t CountSensor_Count;
void CountSensor_Init(void)
{
/*开启时钟*/
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_14;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure); //将PB14引脚初始化为上拉输入
/*AFIO选择中断引脚*/
//将外部中断的14号线映射到GPIOB,即选择PB14为外部中断引脚
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource14);
/*EXTI初始化*/
EXTI_InitTypeDef EXTI_InitStructure; //定义结构体变量
EXTI_InitStructure.EXTI_Line = EXTI_Line14; //选择配置外部中断的14号线
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
//即抢占优先级范围:0~3,响应优先级范围:0~3
//此分组配置在整个工程中仅需调用一次
//若有多个中断,可以把此代码放在main函数内,while循环之前
//若调用多次配置分组的代码,则后执行的配置会覆盖先执行的配置
/*NVIC配置*/
NVIC_InitTypeDef NVIC_InitStructure; //定义结构体变量
NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn; //选择配置NVIC的EXTI15_10线
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //指定NVIC线路使能
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //指定NVIC线路的抢占优先级为1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //指定NVIC线路的响应优先级为1
NVIC_Init(&NVIC_InitStructure); //将结构体变量交给NVIC_Init,配置NVIC外设
}
/**
* 函 数:获取计数传感器的计数值
* 参 数:无
* 返 回 值:计数值,范围:0~65535
*/
uint16_t CountSensor_Get(void)
{
return CountSensor_Count;
}
void EXTI15_10_IRQHandler(void)
{
if(EXTI_GetFlagStatus(EXTI_Line14) == SET)
{
/*如果出现数据乱跳的现象,可再次判断引脚电平,以避免抖动*/
if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_14) == 0) //判断是否是外部中断14号线触发的中断
{
CountSensor_Count ++; //计数值自增一次
}
EXTI_ClearITPendingBit(EXTI_Line14); //清除外部中断14号线的中断标志位
//中断标志位必须清除
//否则中断将连续不断地触发,导致主程序卡死
}
}
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 "Encoder.h"
int16_t Num;
int main()
{
/*模块初始化*/
OLED_Init(); //OLED初始化
Encoder_Init(); //旋转编码器初始化
OLED_ShowCHinese(0, 0, 0); //计
OLED_ShowCHinese(0, 16, 1); //次
OLED_ShowString(1,5,":");
while(1)
{
Num += Encoder_Get();
OLED_ShowSignedNum(1,6,Num,5);
}
}
Encoder.c 代码如下:
#include "stm32f10x.h" // Device header
int16_t Encoder_Count;
void Encoder_Init(void)
{
/*开启时钟*/
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;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure); //将PB14引脚初始化为上拉输入
/*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; //选择配置外部中断的14号线
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
//即抢占优先级范围:0~3,响应优先级范围:0~3
//此分组配置在整个工程中仅需调用一次
//若有多个中断,可以把此代码放在main函数内,while循环之前
//若调用多次配置分组的代码,则后执行的配置会覆盖先执行的配置
/*NVIC配置*/
NVIC_InitTypeDef NVIC_InitStructure; //定义结构体变量
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; //选择配置NVIC的EXTI0线
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //指定NVIC线路使能
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //指定NVIC线路的抢占优先级为1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //指定NVIC线路的响应优先级为1
NVIC_Init(&NVIC_InitStructure); //将结构体变量交给NVIC_Init,配置NVIC外设
NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn; //选择配置NVIC的EXTI1线
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //指定NVIC线路使能
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //指定NVIC线路的抢占优先级为1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //指定NVIC线路的响应优先级为2
NVIC_Init(&NVIC_InitStructure); //将结构体变量交给NVIC_Init,配置NVIC外设
}
int16_t Encoder_Get(void)
{
/*使用Temp变量作为中继,目的是返回Encoder_Count后将其清零*/
/*在这里,也可以直接返回Encoder_Count
但这样就不是获取增量值的操作方法了
也可以实现功能,只是思路不一样*/
int16_t Temp;
Temp = Encoder_Count;
Encoder_Count = 0;
return Temp;
}
/**
* 函 数:EXTI0外部中断函数
* 参 数:无
* 返 回 值:无
* 注意事项:此函数为中断函数,无需调用,中断触发后自动执行
* 函数名为预留的指定名称,可以从启动文件复制
* 请确保函数名正确,不能有任何差异,否则中断函数将不能进入
*/
void EXTI0_IRQHandler(void)
{
if (EXTI_GetITStatus(EXTI_Line0) == SET) //判断是否是外部中断0号线触发的中断
{
/*如果出现数据乱跳的现象,可再次判断引脚电平,以避免抖动*/
if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0)
{
//PB0的下降沿触发中断,此时检测另一相PB1的电平,目的是判断旋转方向
if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)
{
Encoder_Count --; //此方向定义为反转,计数变量自减
}
}
EXTI_ClearITPendingBit(EXTI_Line0); //清除外部中断0号线的中断标志位
//中断标志位必须清除
//否则中断将连续不断地触发,导致主程序卡死
}
}
/**
* 函 数:EXTI1外部中断函数
* 参 数:无
* 返 回 值:无
* 注意事项:此函数为中断函数,无需调用,中断触发后自动执行
* 函数名为预留的指定名称,可以从启动文件复制
* 请确保函数名正确,不能有任何差异,否则中断函数将不能进入
*/
void EXTI1_IRQHandler(void)
{
if (EXTI_GetITStatus(EXTI_Line1) == SET) //判断是否是外部中断1号线触发的中断
{
/*如果出现数据乱跳的现象,可再次判断引脚电平,以避免抖动*/
if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == 0)
{
//PB1的下降沿触发中断,此时检测另一相PB0的电平,目的是判断旋转方向
if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == 0)
{
Encoder_Count ++; //此方向定义为正转,计数变量自增
}
}
EXTI_ClearITPendingBit(EXTI_Line1); //清除外部中断1号线的中断标志位
//中断标志位必须清除
//否则中断将连续不断地触发,导致主程序卡死
}
}
Encoder.h 代码如下:
#ifndef __ENCODER_H
#define __ENCODER_H
void Encoder_Init(void);
int16_t Encoder_Get(void);
#endif
18万+

被折叠的 条评论
为什么被折叠?



