news 2026/4/18 13:11:28

STM32F103C8T6中断配置和实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
STM32F103C8T6中断配置和实践

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. 配置GPIOGPIO_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;// 输入模式可忽略SpeedGPIO_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. 配置EXTIEXTI_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. 配置NVICNVIC_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会认为中断还在触发,一直进入服务函数,导致程序卡死!

// 中断服务函数定义voidEXTI1_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);elseGPIO_SetBits(GPIOB,GPIO_Pin_0);}EXTI_ClearITPendingBit(EXTI_Line1);// 必须清除中断标志}}

步骤7:整合main函数

把上面的代码整合到main函数里,死循环里啥都不用做,等待中断即可:

#include"stm32f10x.h"// STM32标准外设库头文件// 中断服务函数声明voidEXTI1_IRQHandler(void);/** * @brief 主函数 * @param 无 * @retval int 程序返回值(通常不会返回) */intmain(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;// 选择引脚1GPIO_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;// 选择引脚0GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;// 推挽输出模式GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;// 输出速度50MHzGPIO_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;// 选择外部中断线1EXTI_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线1NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;// 抢占优先级为2NVIC_InitStructure.NVIC_IRQChannelSubPriority=2;// 响应优先级为2NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;// 使能该中断通道NVIC_Init(&NVIC_InitStructure);// 应用配置/******************** 第六步:主循环 ********************/while(1){// 主循环可以添加其他后台任务// 中断处理会在中断服务函数中进行,不会影响主循环运行// 可以在这里添加低功耗模式、系统状态监测等代码}}/** * @brief EXTI线1中断服务函数 * @param 无 * @retval 无 * @note 当PA1引脚检测到下降沿时,此函数会被自动调用 */voidEXTI1_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);}}

五、容易踩的坑

  1. 忘记开启AFIO时钟:这是我当初最致命的坑,配置完所有步骤,按键按烂了LED都不亮,后来查手册才发现外部中断映射需要AFIO支持。
  2. 没清中断标志位:第一次成功触发中断后,LED闪了一下就卡住了,原因是没清标志位,MCU一直重复进入中断。
  3. GPIO模式配错:比如把PA0配成浮空输入,又没外接上拉电阻,导致引脚电平不稳定,中断乱触发。
  4. 优先级分组调用多次NVIC_PriorityGroupConfig只能调用一次,否则会导致优先级配置混乱。

六、总结:中断配置的核心逻辑

其实不管是外部中断、定时器中断还是串口中断,配置流程都大同小异:
开时钟 → 配外设 → 配中断源(EXTI/外设自身) → 配NVIC → 写服务函数(清标志位)

新手只要把这个流程刻在脑子里,再结合实际外设的特点稍作调整,就能搞定大部分中断配置了。

最后说句心里话:学习STM32,光看教程没用,一定要动手。遇到问题别慌,查手册、单步调试、逐行排查,那些踩过的坑,最后都会变成你的经验。

江协科技中断学习笔记

对射式传感器的应用

main.c 代码如下:

#include"stm32f10x.h"// Device header#include"Delay.h"#include"OLED.h"#include"CountSensor.h"intmain(){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 headeruint16_tCountSensor_Count;voidCountSensor_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线路的抢占优先级为1NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;//指定NVIC线路的响应优先级为1NVIC_Init(&NVIC_InitStructure);//将结构体变量交给NVIC_Init,配置NVIC外设}/** * 函 数:获取计数传感器的计数值 * 参 数:无 * 返 回 值:计数值,范围:0~65535 */uint16_tCountSensor_Get(void){returnCountSensor_Count;}voidEXTI15_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_HvoidCountSensor_Init(void);uint16_tCountSensor_Get(void);#endif

旋转编码器计数

main.c 代码如下:

#include"stm32f10x.h"// Device header#include"Delay.h"#include"OLED.h"#include"Encoder.h"int16_tNum;intmain(){/*模块初始化*/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 headerint16_tEncoder_Count;voidEncoder_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线路的抢占优先级为1NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;//指定NVIC线路的响应优先级为1NVIC_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线路的抢占优先级为1NVIC_InitStructure.NVIC_IRQChannelSubPriority=2;//指定NVIC线路的响应优先级为2NVIC_Init(&NVIC_InitStructure);//将结构体变量交给NVIC_Init,配置NVIC外设}int16_tEncoder_Get(void){/*使用Temp变量作为中继,目的是返回Encoder_Count后将其清零*//*在这里,也可以直接返回Encoder_Count 但这样就不是获取增量值的操作方法了 也可以实现功能,只是思路不一样*/int16_tTemp;Temp=Encoder_Count;Encoder_Count=0;returnTemp;}/** * 函 数:EXTI0外部中断函数 * 参 数:无 * 返 回 值:无 * 注意事项:此函数为中断函数,无需调用,中断触发后自动执行 * 函数名为预留的指定名称,可以从启动文件复制 * 请确保函数名正确,不能有任何差异,否则中断函数将不能进入 */voidEXTI0_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外部中断函数 * 参 数:无 * 返 回 值:无 * 注意事项:此函数为中断函数,无需调用,中断触发后自动执行 * 函数名为预留的指定名称,可以从启动文件复制 * 请确保函数名正确,不能有任何差异,否则中断函数将不能进入 */voidEXTI1_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_HvoidEncoder_Init(void);int16_tEncoder_Get(void);#endif
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/16 12:16:46

7.2 深度研究:利用大模型高级检索与分析能力

7.2 深度研究:利用大模型高级检索与分析能力 在上一节课中,我们学习了如何整合NotebookLM、大语言模型和Cursor等工具,构建完整的AI辅助开发工作流。本节课我们将深入探讨如何利用大模型的高级检索与分析能力,提升技术研究和方案设计的效率与质量。 大模型检索能力概述 …

作者头像 李华
网站建设 2026/4/16 13:08:59

restTemplate发送POST

HttpHeaders headers new HttpHeaders();headers.setContentType(MediaType.APPLICATION_JSON);// 2. 构建请求参数&#xff08;与文档示例完全一致&#xff09;Map<String, Object> requestBody new HashMap<>();requestBody.put("grant_type", "…

作者头像 李华
网站建设 2026/4/18 18:33:40

4、深入现实世界:包过滤网关配置指南

深入现实世界:包过滤网关配置指南 1. 从单机到网关 在之前的基础上,我们现在要进入更常规的领域——包过滤网关的设置。虽然本章的很多内容在单机设置中也可能有用,但我们现在的主要重点是搭建一个能处理常见网络服务的网关。 2. 简单网关与NAT 我们开始构建通常所说的防…

作者头像 李华
网站建设 2026/4/16 21:55:18

springboot宠物用品商城领养系统之家小程序_dsc9dqa7

文章目录具体实现截图主要技术与实现手段关于我本系统开发思路java类核心代码部分展示结论源码lw获取/同行可拿货,招校园代理 &#xff1a;文章底部获取博主联系方式&#xff01;具体实现截图 同行可拿货,招校园代理 springboot_dsc9dqa7 宠物用品商城领养系统之家小程序…

作者头像 李华
网站建设 2026/4/18 14:25:51

高效测试的利器:Pairwise组合测试工具深度解析与应用实践

一、测试效率的瓶颈与Pairwise的价值 在软件测试领域&#xff0c;随着系统复杂度呈指数级增长&#xff0c;测试用例的组合爆炸问题已成为团队面临的主要挑战之一。以某电商平台的用户注册模块为例&#xff0c;即使仅有10个参数&#xff08;如用户名格式、密码强度、邮箱验证、…

作者头像 李华