STM32F103C8----外部中断探秘:解锁嵌入式实时响应的关键

STM32F103C8T6外部中断 外部中断是微控制器与外部世界交互的重要方式之一,它使得微控制器能够实时响应外部事件,提高了系统的实时性和效率。在实际开发中,需要根据具体需求进行配置和调试,以确保外部中断的正确性和可靠性。在嵌入式系统开发中,中断是一种非常重要的机制,它使得微控制器能够在执行主程序的同时,响应并处理外部或内部发生的事件。这种机制使得微控制器能够在执行主程序的同时,处理外部输入,提高了系统的实时性和响应速度。:在ISR执行完毕后,需要清除对应的中断标志位,以确保下一次相同的中断事件发生时能够再次触发中断。 阅读详情

​​​在这里插入图片描述
在这里插入图片描述

一、引言

在嵌入式系统的广袤世界里,中断就如同一位高效的调度员,发挥着举足轻重的作用。想象一下,一个嵌入式系统就像一个繁忙的工厂,CPU 如同工厂里的核心工人,负责执行各种任务。如果没有中断机制,CPU 就需要不断地检查各个设备的状态,就像工人要不断停下手中的工作去询问其他部门的工作进展,这无疑会浪费大量的时间和精力。而中断的出现,就像是给每个设备都配备了一个紧急呼叫按钮,当设备有紧急事情需要处理时,比如传感器检测到了异常数据、外部设备发送了重要信息,就可以通过中断信号通知 CPU。CPU 收到信号后,会暂停当前正在执行的任务,优先处理中断事件,处理完成后再返回原来的任务继续执行。这样一来,CPU 就可以更加高效地工作,系统的响应速度和实时性也得到了极大的提升。

今天我们要深入探讨的主角 ——STM32F103C8T6,它作为一款被广泛应用于各种嵌入式项目的微控制器,其外部中断功能更是为开发者们提供了强大的工具。无论是智能硬件开发中对外部信号的实时响应,还是工业控制领域里对设备状态的及时监测,STM32F103C8T6 的外部中断都能大显身手。接下来,就让我们一起揭开它神秘的面纱,深入了解其外部中断的原理、配置与应用。

二、中断基础概念

(一)中断定义

中断,简单来说,就是在主程序运行过程中,当出现特定的中断触发条件(即中断源)时,CPU 会暂停当前正在执行的程序,转而去执行中断服务程序。这个过程就好比你正在专心写作业,突然手机响了(中断源),你会暂停写作业(暂停主程序),去查看手机消息(执行中断服务程序),看完消息后再回来继续写作业(返回主程序继续执行) 。在 STM32F103C8T6 中,中断源可以是外部设备的信号变化,如按键按下、传感器数据更新,也可以是内部定时器溢出、串口数据接收等事件。中断的出现,使得系统能够及时响应各种异步事件,大大提高了系统的实时性和效率。

(二)中断优先级

当有多个中断源同时向 CPU 申请中断时,就需要有一个裁决机制来决定 CPU 先响应哪个中断。这就引入了中断优先级的概念。STM32F103C8T6 的中断优先级由 NVIC(Nested Vectored Interrupt Controller,嵌套向量中断控制器)进行管理。NVIC 为每个中断通道都分配了一个优先级,优先级数值越小,表示优先级越高。例如,假设同时有按键中断和定时器中断申请,而按键中断的优先级设置为 1,定时器中断的优先级设置为 2,那么 CPU 会优先响应按键中断,待按键中断处理完成后,才会去处理定时器中断。通过合理设置中断优先级,可以确保重要的中断事件能够得到及时处理,避免因低优先级中断的干扰而导致关键任务延迟。

(三)中断嵌套

中断嵌套是指在一个中断服务程序执行过程中,又有更高优先级的中断源申请中断,此时 CPU 会暂停当前正在执行的中断服务程序,转而去处理更高优先级的中断服务程序,待处理完成后,再返回到原来被中断的中断服务程序继续执行。这就像你在处理手机消息(执行中断服务程序)时,突然来了一个紧急电话(更高优先级的中断源),你会暂停处理消息(暂停当前中断服务程序),先去接电话(处理更高优先级的中断服务程序),接完电话后再回来继续处理消息(返回原来的中断服务程序继续执行)。在 STM32F103C8T6 中,要实现中断嵌套,需要正确配置 NVIC 的优先级分组,将抢占优先级设置为不同的值,使得高优先级的中断能够打断低优先级的中断。例如,将外部中断 0 的抢占优先级设置为 1,外部中断 1 的抢占优先级设置为 2,当外部中断 0 正在执行中断服务程序时,如果外部中断 1 产生中断请求,由于外部中断 0 的抢占优先级更高,所以不会被外部中断 1 打断;反之,如果外部中断 1 正在执行中断服务程序,外部中断 0 产生中断请求,那么外部中断 1 的中断服务程序会被暂停,优先执行外部中断 0 的中断服务程序。

(四)中断执行流程

中断请求:当某个中断源产生特定事件时,如按键按下、定时器溢出等,会向 CPU 发送中断请求信号。这个信号就像是一个紧急通知,告诉 CPU 有事情需要它立即处理。

中断响应:CPU 在每个指令周期结束时,会检查是否有中断请求。如果有,且中断允许位被设置(即中断未被屏蔽),CPU 会暂停当前正在执行的程序,将当前的程序计数器(PC)、程序状态寄存器(PSR)等重要寄存器的值压入堆栈进行保存,这一步就像是在离开之前记录好自己的位置和状态。然后,CPU 根据中断向量表找到对应的中断服务程序的入口地址,跳转到中断服务程序开始执行。中断向量表就像是一个索引表,记录了每个中断源对应的中断服务程序的入口地址。

中断服务:在中断服务程序中,首先会保护现场,即将其他需要用到的寄存器的值也压入堆栈保存,防止这些数据在中断处理过程中被破坏。然后,根据中断源的具体需求,执行相应的处理代码,比如读取传感器数据、处理按键事件等。处理完成后,再恢复现场,将之前压入堆栈的寄存器的值弹出,恢复到原来的状态。

中断返回:当中断服务程序执行完毕,最后会执行中断返回指令。这时候,CPU 会从堆栈中弹出之前保存的程序计数器(PC)和程序状态寄存器(PSR)的值,回到原来被中断的程序处继续执行,就像完成了紧急任务后,又回到原来的工作中。

三、STM32 中断系统

(一)STM32 中断资源

STM32F103C8T6 拥有丰富的中断资源,为嵌入式系统的多样化需求提供了有力支持。它包含多达 60 个可屏蔽中断通道 ,涵盖了众多关键的外设中断。

其中,EXTI(External Interrupt/Event Controller,外部中断 / 事件控制器)是其外部中断的核心。EXTI 可以监测指定 GPIO 口的电平信号,当指定 GPIO 口产生电平变化时,能立即向 NVIC 发出中断申请。例如,在智能安防系统中,我们可以将外部入侵检测传感器连接到 STM32F103C8T6 的某个 GPIO 口,并通过 EXTI 配置为上升沿触发中断。当传感器检测到有人入侵,输出电平发生变化时,就会触发中断,通知系统进行相应的处理,如启动报警装置、记录入侵时间等。

除了 EXTI,定时器中断(TIM)也是常用的中断资源之一。STM32F103C8T6 的定时器功能强大,有基本定时器(TIM6、TIM7)、通用定时器(TIM2、TIM3、TIM4、TIM5)和高级定时器(TIM1)。这些定时器可以用于精确计时、PWM 信号生成、事件触发等多种场景。以工业电机控制为例,通用定时器可以配置为 PWM 模式,生成不同占空比的 PWM 信号来控制电机的转速和转向。同时,通过定时器中断,可以实现周期性地读取电机的运行状态,如电流、温度等,以便及时调整控制策略,确保电机的稳定运行。

此外,ADC(Analog - to - Digital Converter,模数转换器)中断在数据采集领域发挥着重要作用。当 ADC 完成一次模数转换时,会触发中断,通知 CPU 读取转换后的数据。在环境监测项目中,通过 ADC 中断,可以实时采集温度、湿度、光照等传感器的模拟信号,并将其转换为数字信号进行处理和存储。

还有串口通信(USART)中断、SPI 通信中断、I2C 通信中断等,为 STM32F103C8T6 与外部设备的数据交互提供了高效的中断处理机制。在智能家居系统中,通过串口通信中断,STM32 可以与各类智能设备进行通信,接收设备的状态信息,发送控制指令,实现家居设备的智能化控制。

(二)NVIC(嵌套向量中断控制器)

1. 基本结构

NVIC 作为 Cortex - M3 内核的重要组成部分,就像是 CPU 的得力助手,负责管理中断的方方面面。它的结构设计精妙,与 CPU 和中断源之间有着紧密的连接 。从硬件层面来看,NVIC 一端连接着众多的中断源,这些中断源来自于 STM32F103C8T6 的各个外设,如前面提到的 EXTI、TIM、ADC 等;另一端则与 CPU 紧密相连,直接参与中断的裁决和处理流程。

当多个中断源同时向 CPU 申请中断时,NVIC 就发挥了关键的调度作用。它不会让 CPU 直接面对混乱的中断请求,而是像一个有序的调度员,先对中断请求进行收集和整理。NVIC 根据每个中断源预先设定的优先级,对这些中断请求进行排序,然后将优先级最高的中断请求传递给 CPU。这样一来,CPU 只需专注于处理 NVIC 筛选后的中断,大大提高了中断处理的效率和准确性。

例如,假设同时有定时器中断和串口中断申请,NVIC 会先查看它们的优先级设置。如果定时器中断的优先级高于串口中断,NVIC 就会将定时器中断请求传递给 CPU,让 CPU 优先处理定时器中断。在这个过程中,串口中断请求会被暂时挂起,等待 CPU 处理完当前的高优先级中断。

2. 优先级分组

在 NVIC 中,中断优先级分为抢占优先级和响应优先级,这两个概念对于理解中断的处理顺序至关重要。

抢占优先级:它决定了中断是否可以打断其他正在执行的中断,实现中断嵌套。简单来说,具有高抢占优先级的中断可以在低抢占优先级的中断处理过程中被响应。例如,在一个实时控制系统中,可能有一个紧急故障检测中断,其抢占优先级设置得很高。当系统正在处理普通的定时器中断时,如果紧急故障检测中断发生,由于其抢占优先级更高,就会立即打断定时器中断的处理,转而执行紧急故障检测中断服务程序。这样可以确保系统能够及时响应紧急事件,避免因处理普通中断而延误对关键问题的处理。

响应优先级:当两个中断源的抢占优先级相同时,响应优先级就发挥了作用。它决定了在抢占优先级相同的情况下,中断的响应顺序。也就是说,当两个抢占优先级相同的中断同时到达时,响应优先级高的中断会先被处理。例如,假设有两个串口中断,它们的抢占优先级都设置为相同的值,但其中一个串口中断的响应优先级设置为 1,另一个设置为 2。那么当这两个串口中断同时发生时,响应优先级为 1 的串口中断会先被处理,处理完成后才会处理响应优先级为 2 的串口中断。

STM32F103C8T6 通过对优先级寄存器的 4 位进行分组设置,来确定抢占优先级和响应优先级的具体位数。总共有 5 种分组模式:

第 0 组:所有 4 位用于指定响应优先级,此时没有抢占优先级的区分,所有中断按照响应优先级的高低顺序处理。

第 1 组:最高 1 位用于指定抢占优先级,最低 3 位用于指定响应优先级。这样可以有 2 个抢占优先级级别(0 和 1),8 个响应优先级级别(0 - 7)。

第 2 组:最高 2 位用于指定抢占优先级,最低 2 位用于指定响应优先级。有 4 个抢占优先级级别(0 - 3),4 个响应优先级级别(0 - 3)。

第 3 组:最高 3 位用于指定抢占优先级,最低 1 位用于指定响应优先级。有 8 个抢占优先级级别(0 - 7),2 个响应优先级级别(0 和 1)。

第 4 组:所有 4 位用于指定抢占优先级,没有响应优先级的区分,中断按照抢占优先级的高低顺序处理。

在实际应用中,我们可以根据项目的需求,使用固件库函数NVIC_PriorityGroupConfig()来选择合适的优先级分组模式。例如,如果我们的项目中需要较多的抢占优先级级别来处理不同紧急程度的中断,就可以选择第 3 组或第 4 组;如果项目中对响应优先级的区分要求较高,而抢占优先级的需求相对简单,就可以选择第 1 组或第 2 组。通过合理配置优先级分组和每个中断源的优先级,我们能够优化系统的中断处理机制,提高系统的性能和稳定性。

四、EXTI(外部中断)

(一)EXTI 介绍

工作原理:EXTI(External Interrupt/Event Controller)作为 STM32F103C8T6 中负责外部中断的关键部件,其工作原理精妙而高效。它就像一个时刻保持警惕的信号监测员,持续监测着指定 GPIO 口的电平信号 。当指定 GPIO 口的电平发生变化时,比如从低电平变为高电平(上升沿),或者从高电平变为低电平(下降沿),EXTI 会迅速捕捉到这个变化,并立即向 NVIC(Nested Vectored Interrupt Controller,嵌套向量中断控制器)发出中断申请。NVIC 在收到申请后,会根据预先设定的中断优先级进行裁决,决定是否中断当前正在运行的 CPU 主程序。如果裁决结果是允许中断,那么 CPU 就会暂停主程序的执行,转而执行 EXTI 对应的中断服务程序。在中断服务程序中,开发者可以编写相应的代码来处理这个中断事件,比如读取传感器数据、控制外部设备等。处理完成后,CPU 会返回原来被中断的主程序位置,继续执行主程序。

触发方式:

上升沿触发:当 GPIO 口的电平从低电平跳变为高电平时,触发中断。例如,在一个智能照明系统中,我们可以将人体红外传感器连接到 STM32F103C8T6 的某个 GPIO 口,并配置为上升沿触发中断。当人体红外传感器检测到有人靠近时,输出电平从低电平变为高电平,触发中断,通知系统打开灯光。

下降沿触发:当 GPIO 口的电平从高电平跳变为低电平时,触发中断。比如在一个电子门锁系统中,按键的按下动作会使 GPIO 口的电平从高电平变为低电平,通过配置下降沿触发中断,系统可以及时响应按键操作,进行开锁或其他相关处理。

双边沿触发:无论是上升沿还是下降沿,只要 GPIO 口的电平发生跳变,就会触发中断。在一些需要精确检测信号变化的场景中,如测量旋转编码器的脉冲信号,双边沿触发可以提高检测的精度和效率。因为旋转编码器在旋转过程中,其输出信号会在上升沿和下降沿都携带重要的位置信息,通过双边沿触发中断,系统能够更全面地获取这些信息,从而准确计算出旋转的角度和速度。

软件触发:即使 GPIO 口的电平没有发生实际变化,也可以通过编写代码来触发中断。这种触发方式在一些特殊的应用场景中非常有用,比如在系统初始化阶段,需要模拟一个外部中断事件来进行一些初始化操作;或者在调试过程中,方便开发者手动触发中断,检查中断服务程序的正确性。

支持 GPIO 口与通道数:STM32F103C8T6 的 EXTI 支持所有的 GPIO 口触发中断,这为开发者提供了极大的灵活性。然而,需要注意的是,相同编号的 Pin(引脚)不能同时触发中断。例如,GPIOA 的 Pin0 和 GPIOB 的 Pin0 虽然是不同端口的相同编号引脚,但它们不能同时被配置为触发中断,因为它们共用同一个中断线。EXTI 总共支持 16 个 GPIO_Pin 的中断触发,分别对应 PA0 - PA15、PB0 - PB15 等端口的引脚。此外,EXTI 还支持一些特殊的中断源,如 PVD(Power Voltage Detector,电源电压检测器)输出、RTC(Real - Time Clock,实时时钟)闹钟、USB 唤醒、以太网唤醒等,这些特殊中断源进一步丰富了 EXTI 的应用场景。以 RTC 闹钟为例,在一个定时提醒的应用中,通过配置 RTC 闹钟触发 EXTI 中断,系统可以在设定的时间点触发中断,执行相应的提醒操作,如发出声音、显示提示信息等。

触发响应方式:

中断响应:这是最常见的触发响应方式。当 EXTI 监测到指定 GPIO 口的电平变化并触发中断后,CPU 会暂停当前正在执行的主程序,保存当前的程序状态(如寄存器的值、程序计数器的值等),然后跳转到对应的中断服务程序执行。在中断服务程序中,完成对中断事件的处理后,再恢复之前保存的程序状态,返回主程序继续执行。中断响应方式适用于需要及时处理的异步事件,比如按键按下、传感器数据更新等,确保系统能够对这些事件做出快速响应。

事件响应:与中断响应不同,事件响应不会触发 CPU 执行中断服务程序,而是直接触发其他外设的操作,属于外设之间的联合工作。在事件响应过程中,当 EXTI 检测到满足条件的信号变化时,会通过硬件电路直接产生一个脉冲信号,这个脉冲信号可以被其他外设(如定时器 TIM、模拟数字转换器 ADC 等)接收并利用。例如,在一个数据采集系统中,当外部传感器产生一个触发信号时,EXTI 通过事件响应方式将这个信号直接传递给 ADC,触发 ADC 开始进行数据转换,而不需要 CPU 的干预。这种方式可以减少 CPU 的负担,提高系统的整体运行效率,尤其适用于那些对实时性要求较高、但不需要 CPU 进行复杂处理的场景。

(二)EXTI 基本结构与 AFIO 复用 IO 接口

基本结构:EXTI 的内部结构设计巧妙,各个部分协同工作,实现了高效的外部中断处理。

边沿检测电路:这是 EXTI 的信号感知部分,它就像一个敏锐的探测器,根据上升沿触发选择寄存器(EXTI_RTSR)和下降沿触发选择寄存器(EXTI_FTSR)对应位的设置来控制信号触发。当输入线的信号发生边沿跳变时,边沿检测电路会根据寄存器的设置来判断是否输出有效信号。如果设置为上升沿触发,那么只有当信号从低电平变为高电平时,边沿检测电路才会输出有效信号 1 给后续电路;如果设置为下降沿触发,则只有信号从高电平变为低电平时输出有效信号;若设置为双边沿触发,那么上升沿和下降沿都会使边沿检测电路输出有效信号。

或门电路:或门电路的作用是整合边沿检测电路和软件中断事件寄存器(EXTI_SWIER)的信号。它的一个输入来自边沿检测电路,另一个输入来自 EXTI_SWIER。由于或门的特性是只要有一个输入为 1,输出就为 1,所以当边沿检测电路检测到边沿跳变输出有效信号,或者通过软件设置 EXTI_SWIER 的相应位使其输出有效信号时,或门电路就会输出 1 给后面的与门电路。这就为中断的触发提供了两种途径,一种是硬件的边沿触发,另一种是软件的触发,增加了中断触发的灵活性。

与门电路:与门电路在中断控制中起到了关键的开关作用。它有两个输入,一个来自或门电路,另一个输入来自中断屏蔽寄存器(EXTI_IMR)。与门电路要求两个输入都为 1 时才输出 1,这就意味着只有当 EXTI_IMR 设置为 1(即允许中断),并且或门电路输出有效信号 1 时,与门电路才会输出 1。如果 EXTI_IMR 设置为 0(禁止中断),那么无论或门电路的输出如何,与门电路的输出都为 0,从而不会产生中断。这种设计使得开发者可以通过控制 EXTI_IMR 来灵活地开启或关闭中断,方便对中断进行管理。

挂起寄存器(EXTI_PR):上与门电路输出的信号会被保存到挂起寄存器(EXTI_PR)内。当确定上与门电路输出为 1 时,就会把 EXTI_PR 对应位置 1。这个位置 1 表示有中断事件发生且尚未被处理,CPU 可以通过读取 EXTI_PR 寄存器来判断是否有中断等待处理。在中断处理完成后,需要将 EXTI_PR 中相应的位清零,以表示该中断已经被处理。

AFIO 复用 IO 接口:AFIO(Alternate - Function I/O,复用功能 I/O)在 STM32F103C8T6 中扮演着重要的角色,它主要用于引脚复用功能的选择和重定义 。在 STM32 中,AFIO 主要完成两个关键任务:

复用功能引脚重映射:STM32 的一些外设功能(如 SPI、USART、I2C 等)需要使用特定的 GPIO 引脚作为复用功能引脚。通过 AFIO 的复用功能引脚重映射,开发者可以将这些外设的功能映射到不同的 GPIO 引脚上,增加了引脚使用的灵活性。例如,在一个项目中,原本 SPI 接口使用的是 PA5、PA6、PA7 引脚,但由于这些引脚在其他功能中也有重要用途,通过 AFIO 的重映射功能,可以将 SPI 接口的功能映射到 PB3、PB4、PB5 等引脚上,使得硬件设计更加灵活,避免了引脚资源的冲突。

中断引脚选择:AFIO 在 EXTI 的中断引脚选择中起着不可或缺的作用。前面提到,所有 GPIO 口都可以触发 EXTI 中断,但相同 Pin 不能同时触发中断。AFIO 负责将不同 GPIO 口的中断信号进行选择和映射,确保每个中断信号能够正确地传输到 EXTI 控制器。例如,当我们配置 PA0 引脚触发外部中断时,AFIO 会将 PA0 的中断信号连接到 EXTI 对应的中断线,使得 EXTI 能够监测到 PA0 的电平变化并触发中断。这种中断引脚选择功能使得 EXTI 能够有效地管理多个 GPIO 口的中断请求,提高了系统的中断处理能力。

(三)EXTI 框图解析

结合 EXTI 的框图,我们可以更加直观地理解其工作过程。

输入线:EXTI 控制器拥有 19 个中断 / 事件输入线,这些输入线是 EXTI 与外部世界沟通的桥梁。它们可以通过寄存器设置为任意一个 GPIO 口,也可以连接一些外设的事件输出。这些输入线负责接收外部的信号变化,无论是 GPIO 口的电平跳变,还是外设产生的特定事件信号,都通过这些输入线进入 EXTI 控制器。

边沿检测:输入线的信号首先进入边沿检测电路。如前文所述,边沿检测电路根据 EXTI_RTSR 和 EXTI_FTSR 的设置,对输入信号进行边沿检测。假设我们将某个输入线配置为上升沿触发,当该输入线的信号从低电平变为高电平时,边沿检测电路会捕捉到这个上升沿,输出有效信号 1 给或门电路;如果信号没有发生符合条件的边沿跳变,边沿检测电路则输出无效信号 0。

中断屏蔽:或门电路的输出信号会与中断屏蔽寄存器(EXTI_IMR)的对应位进行与运算。如果 EXTI_IMR 中对应位设置为 1,那么或门电路的输出信号能够顺利通过与门电路,进而触发中断;如果 EXTI_IMR 中对应位设置为 0,无论或门电路输出是 1 还是 0,与门电路的输出都为 0,即不会触发中断。这就好比一个开关,EXTI_IMR 控制着中断是否能够被触发。

挂起寄存器:当中断成功触发,上与门电路输出的信号会被保存到挂起寄存器(EXTI_PR)中。EXTI_PR 中对应位被置 1,表示有中断事件发生且处于挂起状态,等待 CPU 处理。CPU 在适当的时候读取 EXTI_PR 寄存器,判断是否有中断等待处理,并根据中断服务程序的设置进行相应的处理。在中断处理完成后,需要通过软件将 EXTI_PR 中对应的挂起位清零,以表示该中断已经被处理完毕,避免重复处理。

五、STM32F103C8T6 外部中断配置步骤

(一)初始化 GPIO 引脚

使能 GPIO 时钟:在使用 GPIO 引脚之前,首先要使能对应 GPIO 端口的时钟。以使用 GPIOA 端口的 PA0 引脚作为外部中断输入为例,通过 RCC(Reset and Clock Control,复位和时钟控制)寄存器来使能 GPIOA 的时钟。在标准库中,可以使用函数RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);来实现,其中RCC_APB2Periph_GPIOA表示 GPIOA 端口的时钟,ENABLE表示使能该时钟。

配置 GPIO 模式:将用于外部中断的 GPIO 引脚配置为输入模式。GPIO_InitTypeDef 结构体用于配置 GPIO 的各种参数,如引脚号、模式、速度等。对于 PA0 引脚,设置其模式为浮空输入或上拉 / 下拉输入。若采用上拉输入模式,代码如下:

GPIO_InitTypeDef GPIO_InitStructure;

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 设置引脚速度

GPIO_Init(GPIOA, &GPIO_InitStructure);

这里GPIO_Pin_0指定了 PA0 引脚,GPIO_Mode_IPU表示上拉输入模式,GPIO_Speed_50MHz设置了引脚的输出速度为 50MHz 。如果选择浮空输入模式,则将GPIO_Mode设置为GPIO_Mode_IN_FLOATING;若为下拉输入模式,设置为GPIO_Mode_IPD。不同的输入模式适用于不同的应用场景,例如,当外部信号源能够可靠地提供高电平和低电平时,可以使用浮空输入;而上拉输入适用于外部信号源默认处于低电平,需要通过上拉电阻使其在无信号输入时保持高电平的情况;下拉输入则相反,适用于外部信号源默认处于高电平,需要通过下拉电阻使其在无信号输入时保持低电平的情况。

(二)配置外部中断线路

使能 AFIO 时钟:AFIO(Alternate - Function I/O,复用功能 I/O)用于选择中断引脚,因此需要先使能 AFIO 的时钟。使用函数RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);来使能 AFIO 时钟。

选择中断引脚:通过GPIO_EXTILineConfig()函数将 GPIO 引脚映射到对应的外部中断线上。例如,将 PA0 引脚映射到 EXTI Line0 中断线,代码为GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);,其中GPIO_PortSourceGPIOA表示 GPIO 端口源为 GPIOA,GPIO_PinSource0表示引脚源为 PA0。

配置 EXTI 参数:使用 EXTI_InitTypeDef 结构体来配置外部中断的触发条件、模式和使能状态。

EXTI_InitTypeDef EXTI_InitStructure;

EXTI_InitStructure.EXTI_Line = EXTI_Line0; // 选择EXTI Line0

EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; // 配置为中断模式

EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; // 上升沿触发

EXTI_InitStructure.EXTI_LineCmd = ENABLE; // 使能中断线

EXTI_Init(&EXTI_InitStructure);

这里EXTI_Line0指定了中断线为 Line0,EXTI_Mode_Interrupt表示配置为中断模式,EXTI_Trigger_Rising表示上升沿触发中断,如果需要下降沿触发,将其设置为EXTI_Trigger_Falling;双边沿触发则设置为EXTI_Trigger_Rising_Falling 。EXTI_LineCmd = ENABLE表示使能该中断线,只有使能后,中断线才能正常工作。

  1. 配置中断优先级:使用 NVIC_InitTypeDef 结构体来配置中断优先级。首先要设置优先级分组,确定抢占优先级和响应优先级的位数。例如,设置为第 2 组,即 2 位抢占优先级和 2 位响应优先级,代码为NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 。然后配置 EXTI 中断的优先级,假设配置 EXTI0 中断的抢占优先级为 0,响应优先级为 0,代码如下:
NVIC_InitTypeDef NVIC_InitStructure;

NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; // 选择EXTI0中断通道

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // 抢占优先级为0

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; // 响应优先级为0

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 使能中断通道

NVIC_Init(&NVIC_InitStructure);

NVIC_IRQChannel = EXTI0_IRQn指定了中断通道为 EXTI0,NVIC_IRQChannelPreemptionPriority设置抢占优先级,NVIC_IRQChannelSubPriority设置响应优先级,NVIC_IRQChannelCmd = ENABLE使能该中断通道。通过合理设置优先级,可以确保在多个中断同时发生时,系统能够按照预定的顺序进行处理。

(三)编写中断服务程序(ISR)

当中断触发时,CPU 会自动跳转到对应的中断服务程序执行。中断服务程序的名称是固定的,例如,EXTI0 中断的服务程序名为EXTI0_IRQHandler 。在中断服务程序中,首先要检查中断标志位,以确保是当前中断线触发的中断。例如:

void EXTI0_IRQHandler(void)

{

   if (EXTI_GetITStatus(EXTI_Line0)!= RESET) // 检查EXTI Line0的中断标志位

   {

       // 在这里编写中断处理代码,例如读取传感器数据、控制设备等

       // 假设连接了一个温度传感器,读取温度数据并进行处理

       uint16_t temperature = ReadTemperatureSensor(); // 读取温度传感器数据的函数

       if (temperature > 30) // 假设温度阈值为30度

       {

           // 控制风扇启动,进行散热

           ControlFan(ENABLE);

       }

       else

       {

           // 控制风扇停止

           ControlFan(DISABLE);

       }

       // 清除中断标志位

       EXTI_ClearITPendingBit(EXTI_Line0);

   }

}

在上述代码中,EXTI_GetITStatus(EXTI_Line0)用于获取 EXTI Line0 的中断标志位状态,如果不为RESET,则表示该中断线触发了中断。在中断处理代码部分,可以根据实际需求编写相应的功能代码,如读取传感器数据、控制设备的开关、执行特定的算法等。这里假设连接了一个温度传感器,通过自定义函数ReadTemperatureSensor()读取温度数据,并根据温度值控制风扇的启动和停止。处理完成后,使用EXTI_ClearITPendingBit(EXTI_Line0)清除中断标志位,以便下一次中断能够正常触发。

(四)清除中断标志位

在中断服务程序执行完毕后,清除中断标志位是非常重要的一步。中断标志位用于表示中断事件的发生,如果不清除,当中断处理完成后,该标志位仍然会保持置位状态,导致 CPU 认为中断事件仍然存在,可能会再次进入中断服务程序,形成死循环,或者影响后续正常中断的触发。在 STM32F103C8T6 中,清除外部中断标志位可以使用EXTI_ClearITPendingBit()函数 。例如,对于 EXTI Line0 中断,使用EXTI_ClearITPendingBit(EXTI_Line0);来清除其对应的中断标志位。该函数会将 EXTI 挂起寄存器(EXTI_PR)中对应中断线的标志位清零,从而使系统能够正确识别下一次中断事件的发生。除了在中断服务程序中手动清除中断标志位外,在一些特殊情况下,如系统初始化阶段,也可能需要清除中断标志位,以确保系统的正常运行。

六、代码示例与实践

(一)完整代码展示

下面是一个使用 STM32F103C8T6 的 PA0 引脚作为外部中断输入,控制 LED 状态的完整代码示例:

#include "stm32f10x.h"

// 函数声明

void GPIO_Configuration(void);

void EXTI_Configuration(void);

void NVIC_Configuration(void);

void Delay(uint32_t nCount);

// 主函数

int main(void)

{

   // 配置GPIO

   GPIO_Configuration();

   // 配置外部中断

   EXTI_Configuration();

   // 配置中断优先级

   NVIC_Configuration();

   while (1)

   {

       // 主循环可以执行其他任务

   }

}

// 配置GPIO

void GPIO_Configuration(void)

{

   GPIO_InitTypeDef GPIO_InitStructure;

   // 使能GPIOA时钟

   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

   // 配置PA0为浮空输入

   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;

   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;

   GPIO_Init(GPIOA, &GPIO_InitStructure);

   // 配置PA1为推挽输出,用于控制LED

   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;

   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

   GPIO_Init(GPIOA, &GPIO_InitStructure);

}

// 配置外部中断

void EXTI_Configuration(void)

{

   EXTI_InitTypeDef EXTI_InitStructure;

   // 使能AFIO时钟

   RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);

   // 将PA0映射到EXTI Line0

   GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);

   // 配置EXTI Line0为上升沿触发中断

   EXTI_InitStructure.EXTI_Line = EXTI_Line0;

   EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;

   EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;

   EXTI_InitStructure.EXTI_LineCmd = ENABLE;

   EXTI_Init(&EXTI_InitStructure);

}

// 配置中断优先级

void NVIC_Configuration(void)

{

   NVIC_InitTypeDef NVIC_InitStructure;

   // 设置优先级分组为第2组

   NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

   // 配置EXTI0中断通道

   NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;

   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

   NVIC_Init(&NVIC_InitStructure);

}

// 简单的延时函数

void Delay(uint32_t nCount)

{

   for (; nCount!= 0; nCount--);

}

// 外部中断0服务函数

void EXTI0_IRQHandler(void)

{

   if (EXTI_GetITStatus(EXTI_Line0)!= RESET)

   {

       // 消抖处理

       Delay(0xFFFFF);

       // 切换LED状态

       GPIO_SetBits(GPIOA, GPIO_Pin_1);

       Delay(0xFFFFF);

       GPIO_ResetBits(GPIOA, GPIO_Pin_1);

       // 清除中断标志位

       EXTI_ClearITPendingBit(EXTI_Line0);

   }

}

(二)代码逐行解析

头文件包含:

#include "stm32f10x.h"

包含了 STM32F10x 系列微控制器的标准库头文件,该头文件中定义了所有的寄存器、结构体、宏等,是使用标准库函数的基础。

函数声明:

void GPIO_Configuration(void);

void EXTI_Configuration(void);

void NVIC_Configuration(void);

void Delay(uint32_t nCount);

声明了后续要使用的函数,包括 GPIO 配置函数、外部中断配置函数、中断优先级配置函数和一个简单的延时函数。

主函数:

int main(void)

{

   // 配置GPIO

   GPIO_Configuration();

   // 配置外部中断

   EXTI_Configuration();

   // 配置中断优先级

   NVIC_Configuration();

   while (1)

   {

       // 主循环可以执行其他任务

   }

}

首先调用GPIO_Configuration函数配置 GPIO 引脚。

接着调用EXTI_Configuration函数配置外部中断。

然后调用NVIC_Configuration函数配置中断优先级。

最后进入一个无限循环while(1),在这个循环中可以执行其他任务,由于本示例主要关注外部中断,所以循环中暂时为空。

GPIO 配置函数:

void GPIO_Configuration(void)

{

   GPIO_InitTypeDef GPIO_InitStructure;

   // 使能GPIOA时钟

   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

   // 配置PA0为浮空输入

   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;

   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;

   GPIO_Init(GPIOA, &GPIO_InitStructure);

   // 配置PA1为推挽输出,用于控制LED

   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;

   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

   GPIO_Init(GPIOA, &GPIO_InitStructure);

}

定义了一个GPIO_InitTypeDef类型的结构体变量GPIO_InitStructure,用于配置 GPIO 的参数。

使用RCC_APB2PeriphClockCmd函数使能 GPIOA 的时钟,只有使能时钟后,才能对 GPIOA 进行配置。

配置 PA0 为浮空输入模式:

设置GPIO_InitStructure.GPIO_Pin为GPIO_Pin_0,指定配置 PA0 引脚。

设置GPIO_InitStructure.GPIO_Mode为GPIO_Mode_IN_FLOATING,表示浮空输入模式。

调用GPIO_Init函数,将配置应用到 GPIOA 上。

配置 PA1 为推挽输出模式,用于控制 LED:

设置GPIO_InitStructure.GPIO_Pin为GPIO_Pin_1,指定配置 PA1 引脚。

设置GPIO_InitStructure.GPIO_Mode为GPIO_Mode_Out_PP,表示推挽输出模式。

设置GPIO_InitStructure.GPIO_Speed为GPIO_Speed_50MHz,设置引脚速度为 50MHz。

再次调用GPIO_Init函数,将配置应用到 GPIOA 上。

外部中断配置函数:

void EXTI_Configuration(void)

{

   EXTI_InitTypeDef EXTI_InitStructure;

   // 使能AFIO时钟

   RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);

   // 将PA0映射到EXTI Line0

   GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);

   // 配置EXTI Line0为上升沿触发中断

   EXTI_InitStructure.EXTI_Line = EXTI_Line0;

   EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;

   EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;

   EXTI_InitStructure.EXTI_LineCmd = ENABLE;

   EXTI_Init(&EXTI_InitStructure);

}

定义了一个EXTI_InitTypeDef类型的结构体变量EXTI_InitStructure,用于配置外部中断的参数。

使用RCC_APB2PeriphClockCmd函数使能 AFIO 的时钟,AFIO 用于选择中断引脚,所以需要先使能其时钟。

使用GPIO_EXTILineConfig函数将 PA0 引脚映射到 EXTI Line0 中断线上。

配置 EXTI Line0 为上升沿触发中断:

设置EXTI_InitStructure.EXTI_Line为EXTI_Line0,指定配置 EXTI Line0 中断线。

设置EXTI_InitStructure.EXTI_Mode为EXTI_Mode_Interrupt,表示配置为中断模式。

设置EXTI_InitStructure.EXTI_Trigger为EXTI_Trigger_Rising,表示上升沿触发中断。

设置EXTI_InitStructure.EXTI_LineCmd为ENABLE,使能该中断线。

调用EXTI_Init函数,将配置应用到外部中断控制器上。

中断优先级配置函数:

void NVIC_Configuration(void)

{

   NVIC_InitTypeDef NVIC_InitStructure;

   // 设置优先级分组为第2组

   NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

   // 配置EXTI0中断通道

   NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;

   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

   NVIC_Init(&NVIC_InitStructure);

}

定义了一个NVIC_InitTypeDef类型的结构体变量NVIC_InitStructure,用于配置中断优先级的参数。

使用NVIC_PriorityGroupConfig函数设置优先级分组为第 2 组,即 2 位抢占优先级和 2 位响应优先级。

配置 EXTI0 中断通道:

设置NVIC_InitStructure.NVIC_IRQChannel为EXTI0_IRQn,指定配置 EXTI0 中断通道。

设置NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority为 0,表示抢占优先级为 0。

设置NVIC_InitStructure.NVIC_IRQChannelSubPriority为 0,表示响应优先级为 0。

设置NVIC_InitStructure.NVIC_IRQChannelCmd为ENABLE,使能该中断通道。

调用NVIC_Init函数,将配置应用到 NVIC 上。

延时函数:

void Delay(uint32_t nCount)

{

   for (; nCount!= 0; nCount--);

}

这是一个简单的延时函数,通过循环nCount次来实现延时。在实际应用中,这种简单的延时函数精度较低,对于高精度的延时需求,可以使用定时器来实现。

外部中断 0 服务函数:

void EXTI0_IRQHandler(void)

{

   if (EXTI_GetITStatus(EXTI_Line0)!= RESET)

   {

       // 消抖处理

       Delay(0xFFFFF);

       // 切换LED状态

       GPIO_SetBits(GPIOA, GPIO_Pin_1);

       Delay(0xFFFFF);

       GPIO_ResetBits(GPIOA, GPIO_Pin_1);

       // 清除中断标志位

       EXTI_ClearITPendingBit(EXTI_Line0);

   }

}

当 EXTI0 中断触发时,CPU 会自动跳转到这个函数执行。

使用EXTI_GetITStatus函数检查 EXTI Line0 的中断标志位,如果不为RESET,表示该中断线触发了中断。

进行消抖处理,通过调用Delay函数延时一段时间,以消除按键抖动可能产生的误触发。

切换 LED 状态,先使用GPIO_SetBits函数将 PA1 引脚置高,点亮 LED,然后调用Delay函数延时,再使用GPIO_ResetBits函数将 PA1 引脚置低,熄灭 LED。

最后使用EXTI_ClearITPendingBit函数清除 EXTI Line0 的中断标志位,以便下一次中断能够正常触发。

(三)实践操作与调试技巧

硬件连接:

按键连接:将按键的一端连接到 STM32F103C8T6 的 PA0 引脚,另一端接地或接电源(根据按键的类型和配置的输入模式决定)。如果 PA0 配置为浮空输入,按键按下时会改变 PA0 的电平状态,从而触发外部中断。为了防止按键抖动对中断触发的影响,可以在按键两端并联一个 0.1uF 的电容进行硬件消抖。

LED 连接:将 LED 的阳极通过一个限流电阻(如 220Ω)连接到电源(如 3.3V),阴极连接到 STM32F103C8T6 的 PA1 引脚。这样,通过控制 PA1 引脚的电平,就可以控制 LED 的亮灭。在选择限流电阻时,需要根据 LED 的工作电流和电源电压进行计算,以确保 LED 能够正常工作且不会因为电流过大而损坏。

调试工具使用:

Keil MDK:在 Keil MDK 开发环境中,可以使用断点调试功能来逐步执行代码,观察变量的值和程序的执行流程。在代码中设置断点后,点击调试按钮进入调试模式,当程序执行到断点处时会暂停。此时,可以查看寄存器的值,如 GPIO 寄存器、EXTI 寄存器、NVIC 寄存器等,以检查硬件配置是否正确。例如,在外部中断服务函数中设置断点,当外部中断触发时,程序会停在断点处,此时可以查看 EXTI_PR 寄存器的值,确认中断标志位是否被正确置位,以及查看 GPIOA 寄存器的值,确认 LED 的控制引脚电平是否正确切换。

逻辑分析仪:逻辑分析仪可以用于监测 GPIO 引脚的电平变化,帮助分析外部中断的触发情况和按键的动作。将逻辑分析仪的探头连接到 PA0 和 PA1 引脚,在运行程序时,通过逻辑分析仪可以直观地看到 PA0 引脚的电平变化,判断按键是否正常触发中断,以及 PA1 引脚的电平变化,检查 LED 的控制是否正确。如果发现 PA0 引脚的电平变化异常,可能是按键硬件连接有问题,或者是 GPIO 配置不正确;如果 PA1 引脚的电平变化不符合预期,可能是中断服务程序中的 LED 控制代码有误。

常见问题及解决方法:

中断无法触发:

原因:可能是 GPIO 配置错误,如没有正确设置为输入模式,或者 AFIO 配置错误,导致中断引脚映射不正确;也可能是 EXTI 配置错误,如触发方式设置错误,或者中断线未使能;还可能是 NVIC 配置错误,如中断通道未使能,或者优先级设置不当。

解决方法:仔细检查 GPIO、AFIO、EXTI 和 NVIC 的配置代码,确保每一步配置都正确无误。可以使用调试工具查看相关寄存器的值,确认配置是否生效。例如,使用 Keil MDK 的寄存器查看窗口,查看 GPIOx_CRL、AFIO_EXTICR、EXTI_IMR、NVIC_ISER 等寄存器的值,检查引脚模式、中断映射、中断使能等设置是否正确。

中断误触发:

原因:可能是按键抖动导致的,按键在按下和松开的过程中,由于机械触点的弹跳,会产生多次电平变化,从而触发多次中断;也可能是外部干扰,如周围的电磁干扰,导致 GPIO 引脚的电平出现异常波动,触发中断。

解决方法:对于按键抖动问题,可以采用软件消抖或硬件消抖的方法。软件消抖如在中断服务程序中添加延时函数,等待按键稳定后再进行处理;硬件消抖如在按键两端并联电容。对于外部干扰问题,可以采取屏蔽措施,如使用屏蔽线连接按键和 STM32,或者在 GPIO 引脚上添加滤波电容,以减少干扰对电平的影响。

中断优先级混乱:

原因:可能是 NVIC 优先级分组设置错误,或者中断源的抢占优先级和响应优先级设置不合理,导致中断处理顺序不符合预期。

解决方法:重新检查 NVIC 优先级分组和每个中断源的优先级设置,根据项目的需求合理分配优先级。可以参考 NVIC 的优先级分组规则和中断处理机制,确保高优先级的中断能够及时响应,并且不会被低优先级的中断干扰。在设置优先级时,可以使用一些工具或方法来辅助理解和验证,如绘制中断优先级图表,直观地展示各个中断源的优先级关系。

七、应用案例

(一)按键控制 LED 灯

在许多嵌入式项目中,按键控制 LED 灯是一个常见且基础的应用场景,它充分展示了外部中断在实时响应外部事件方面的优势。利用 STM32F103C8T6 的外部中断实现按键控制 LED 灯的功能,具体步骤如下:

硬件连接:将按键的一端连接到 STM32F103C8T6 的某个 GPIO 引脚,如 PA0,另一端接地或接电源(根据按键类型和 GPIO 输入模式而定)。这里假设按键为低电平有效,即按下按键时,PA0 引脚电平被拉低。同时,将 LED 的阳极通过限流电阻连接到电源,阴极连接到另一个 GPIO 引脚,如 PA1。

软件配置:

初始化 GPIO:使能 GPIOA 时钟,将 PA0 配置为浮空输入或上拉 / 下拉输入模式,以检测按键状态;将 PA1 配置为推挽输出模式,用于控制 LED 的亮灭。例如:

GPIO_InitTypeDef GPIO_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

// 配置PA0为浮空输入

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;

GPIO_Init(GPIOA, &GPIO_InitStructure);

// 配置PA1为推挽输出

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOA, &GPIO_InitStructure);

配置外部中断:使能 AFIO 时钟,将 PA0 映射到对应的外部中断线(如 EXTI Line0),并配置 EXTI 为下降沿触发中断(因为按键按下时 PA0 电平从高到低变化)。同时,配置 NVIC 中断优先级,确保外部中断能够被及时响应。示例代码如下:

EXTI_InitTypeDef EXTI_InitStructure;

NVIC_InitTypeDef NVIC_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);

GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);

EXTI_InitStructure.EXTI_Line = EXTI_Line0;

EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;

EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;

EXTI_InitStructure.EXTI_LineCmd = ENABLE;

EXTI_Init(&EXTI_InitStructure);

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&NVIC_InitStructure);

编写中断服务程序:当中断触发时,在中断服务程序中切换 LED 的状态。为了消除按键抖动的影响,可以在中断服务程序中添加消抖处理,如延时一段时间后再次检测按键状态。代码如下:

void EXTI0_IRQHandler(void)

{

   if (EXTI_GetITStatus(EXTI_Line0)!= RESET)

   {

       // 消抖处理

       Delay(0xFFFFF);

       if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == Bit_RESET)

       {

           // 切换LED状态

           GPIO_SetBits(GPIOA, GPIO_Pin_1);

           Delay(0xFFFFF);

           GPIO_ResetBits(GPIOA, GPIO_Pin_1);

       }

       // 清除中断标志位

       EXTI_ClearITPendingBit(EXTI_Line0);

   }

}

在上述代码中,Delay函数用于简单的延时消抖,实际应用中可根据按键抖动情况调整延时时间。通过这种方式,当按键按下时,外部中断被触发,中断服务程序执行,实现 LED 状态的切换,从而达到按键控制 LED 灯的目的。

(二)传感器数据采集

在工业控制、智能家居、环境监测等众多领域,实时采集传感器数据是嵌入式系统的重要任务之一。STM32F103C8T6 的外部中断功能为高效采集传感器数据提供了有力支持,以下以红外传感器和旋转编码器为例进行说明。

1. 红外传感器数据采集

红外传感器常用于检测物体的存在、运动状态等。以对射式红外传感器为例,当有物体遮挡红外光线时,传感器的输出电平会发生变化,我们可以利用这个电平变化触发 STM32F103C8T6 的外部中断,从而实现对物体的检测和计数。

硬件连接上,将红外传感器的输出引脚连接到 STM32F103C8T6 的一个 GPIO 引脚,如 PB14。软件配置方面,与按键控制 LED 灯类似,先初始化 GPIO 和外部中断。假设红外传感器为低电平有效,即有物体遮挡时输出低电平,配置如下:

// 初始化GPIO

GPIO_InitTypeDef GPIO_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入

GPIO_Init(GPIOB, &GPIO_InitStructure);

// 配置外部中断

EXTI_InitTypeDef EXTI_InitStructure;

NVIC_InitTypeDef NVIC_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);

GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource14);

EXTI_InitStructure.EXTI_Line = EXTI_Line14;

EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;

EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;

EXTI_InitStructure.EXTI_LineCmd = ENABLE;

EXTI_Init(&EXTI_InitStructure);

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&NVIC_InitStructure);

在中断服务程序中,对检测到的遮挡事件进行计数或其他处理:

volatile int count = 0;

void EXTI15_10_IRQHandler(void)

{

   if (EXTI_GetITStatus(EXTI_Line14)!= RESET)

   {

       // 消抖处理

       Delay(10);

       if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_14) == Bit_RESET)

       {

           count++;

       }

       // 清除中断标志位

       EXTI_ClearITPendingBit(EXTI_Line14);

   }

}

通过上述配置,当红外传感器检测到物体遮挡时,会触发外部中断,在中断服务程序中对计数变量count进行累加,从而实现对物体通过次数的统计。

2. 旋转编码器数据采集

旋转编码器是一种用于测量旋转角度、速度和方向的传感器,常用于电机控制、机器人运动控制等领域。旋转编码器通常有 A、B 两相输出,通过检测 A、B 相脉冲的相位差可以判断旋转方向,通过计数脉冲个数可以计算旋转角度或速度。

硬件连接时,将旋转编码器的 A 相和 B 相分别连接到 STM32F103C8T6 的两个 GPIO 引脚,如 PB0 和 PB1。软件配置如下:

// 初始化GPIO

GPIO_InitTypeDef GPIO_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入

GPIO_Init(GPIOB, &GPIO_InitStructure);

// 配置外部中断

EXTI_InitTypeDef EXTI_InitStructure;

NVIC_InitTypeDef NVIC_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);

GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource0);

GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource1);

EXTI_InitStructure.EXTI_Line = EXTI_Line0 | EXTI_Line1;

EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;

EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising_Falling; // 双边沿触发

EXTI_InitStructure.EXTI_LineCmd = ENABLE;

EXTI_Init(&EXTI_InitStructure);

NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&NVIC_InitStructure);

NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&NVIC_InitStructure);

在中断服务程序中,根据 A、B 相的电平状态判断旋转方向,并进行计数:

volatile int encoder_count = 0;

void EXTI0_IRQHandler(void)

{

   if (EXTI_GetITStatus(EXTI_Line0)!= RESET)

   {

       if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == Bit_RESET)

       {

           if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == Bit_RESET)

           {

               encoder_count--; // 反转计数

           }

       }

       // 清除中断标志位

       EXTI_ClearITPendingBit(EXTI_Line0);

   }

}

void EXTI1_IRQHandler(void)

{

   if (EXTI_GetITStatus(EXTI_Line1)!= RESET)

   {

       if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1) == Bit_RESET)

       {

           if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0) == Bit_RESET)

           {

               encoder_count++; // 正转计数

           }

       }

       // 清除中断标志位

       EXTI_ClearITPendingBit(EXTI_Line1);

   }

}

通过上述配置,当旋转编码器旋转时,A、B 相的脉冲变化会触发外部中断,在中断服务程序中根据 A、B 相的电平关系判断旋转方向,并对encoder_count进行相应的累加或递减,从而实现对旋转编码器数据的采集和处理,为后续的电机控制、运动测量等应用提供数据支持。

八、总结与展望

(一)总结外部中断要点

在嵌入式系统的广阔天地中,STM32F103C8T6 的外部中断功能犹如一颗璀璨的明星,闪耀着独特的光芒。通过对其深入探究,我们清晰地认识到外部中断在系统中的关键作用。

从原理层面来看,中断作为一种特殊的机制,能够在主程序运行的过程中,当特定的中断源出现时,果断暂停主程序的执行,转而执行中断服务程序。这种机制的出现,极大地提高了系统的实时性和效率,使得系统能够及时响应各种异步事件。就像在一场繁忙的交响乐演奏中,中断就像是一个紧急信号,当它响起时,指挥会立即暂停当前的演奏,优先处理紧急情况,处理完毕后再继续进行演奏。

在 STM32F103C8T6 中,中断系统包含了丰富的中断资源,其中 EXTI(外部中断 / 事件控制器)更是外部中断的核心。EXTI 就像一个敏锐的观察者,时刻监测着指定 GPIO 口的电平信号。当这些信号发生变化时,EXTI 会迅速做出反应,向 NVIC(嵌套向量中断控制器)发出中断申请。NVIC 则如同一个公正的裁判,根据预先设定的优先级,对中断请求进行裁决,决定是否中断当前正在运行的 CPU 主程序。

在实际配置过程中,初始化 GPIO 引脚是第一步,这就像是为一场比赛准备好场地和器材。通过使能 GPIO 时钟,将引脚配置为合适的输入模式,为后续的外部中断配置奠定基础。接着,配置外部中断线路,使能 AFIO 时钟,选择中断引脚,并合理配置 EXTI 参数和中断优先级,这一系列操作就像是精心制定比赛规则,确保每个环节都能顺利进行。最后,编写中断服务程序,这是整个外部中断配置的核心部分,就像是比赛中的运动员,根据不同的中断事件,执行相应的处理代码,完成特定的任务。在中断服务程序执行完毕后,清除中断标志位是必不可少的一步,它就像是比赛结束后清理场地,为下一次的比赛做好准备。

在应用方面,STM32F103C8T6 的外部中断展现出了强大的实用性。以按键控制 LED 灯为例,通过将按键连接到特定的 GPIO 引脚,并配置为外部中断输入,当按键按下时,触发中断,在中断服务程序中实现 LED 灯状态的切换。这一简单的应用,充分体现了外部中断在实时响应外部事件方面的优势。在传感器数据采集中,无论是红外传感器还是旋转编码器,都可以利用外部中断来实现数据的高效采集。例如,红外传感器检测到物体遮挡时,触发中断,在中断服务程序中对遮挡事件进行计数;旋转编码器旋转时,其输出的脉冲信号触发外部中断,通过判断脉冲的相位差和个数,实现对旋转角度、速度和方向的测量。

(二)展望未来学习方向

随着嵌入式系统应用领域的不断拓展和技术的飞速发展,中断技术在其中的重要性愈发凸显。对于 STM32F103C8T6 外部中断的学习,只是我们踏入嵌入式中断世界的第一步。在未来的学习中,我们可以从以下几个方向深入探索。

在更复杂的嵌入式系统中,中断的应用场景将更加多样化。例如,在工业自动化控制系统中,可能会涉及多个传感器、执行器以及通信模块的协同工作,这就需要更精细地配置中断优先级和处理机制,以确保系统能够稳定、高效地运行。在智能家居系统中,大量的智能设备需要实时与中央控制器进行通信和交互,中断技术可以实现对各种设备状态变化的及时响应,提升用户体验。我们可以深入研究如何在这些复杂系统中,合理利用中断来优化系统性能,提高系统的可靠性和稳定性。

中断的优化也是未来学习的重要方向。随着系统复杂度的增加,中断响应时间、中断处理效率等问题变得尤为关键。我们可以探索如何通过优化中断服务程序的代码结构,减少不必要的计算和操作,提高中断处理的速度。还可以研究动态优先级调整策略,根据系统的实时状态和任务需求,动态地调整中断的优先级,使得系统能够更好地应对各种突发情况。

在实际项目开发中,还需要考虑中断与其他系统模块的协同工作。例如,中断与定时器、DMA(直接内存访问)等模块的配合,如何实现数据的快速传输和处理,以满足系统对实时性和数据处理能力的要求。同时,结合实时操作系统(RTOS)来管理中断,也是一个值得深入研究的方向。RTOS 可以提供更高效的任务调度和资源管理机制,与中断技术相结合,能够进一步提升嵌入式系统的性能和开发效率。

STM32F103C8T6 的外部中断为我们打开了嵌入式中断技术的大门,未来还有更多的知识和应用等待我们去探索和实践。希望读者能够在后续的学习和实践中,不断积累经验,提升自己在嵌入式系统开发领域的能力。

STM32F103C8T6的学习(4)——外部中断 EXTI介绍 阅读详情

相关推荐

STM32F103C8T6-中断

灰色为内核中断,中断地址是每次中断后跳转的地址,是固定的。相同的PIN不能同时触发中断,比如GPIOA1,GPIOB1.,可触发中断响应,也可以触发事件响应。

aloneboyooo的博客 1691

stm32f103c8t6的外部中断

/指定外部中断的模式 EXTI_Mode_Interrupt中断模式 EXTI_Mode_Event事件模式。//触发信号的有效边沿 EXTI_Trigger_Rising上升沿 EXTI_Trigger_Falling下降沿 EXTI_Trigger_Rising_Falling双边沿。if (EXTI_GetITStatus(EXTI_Line14) == SET) //中断标志位判断,因为EXTI_Line10-EXTI_Line15都能进来,判断是否14进来。//指定中断通道是使能还是失能。

weixin_75264509的博客 3150

用Arduino IDE玩转STM32F103C8T6:从点亮LED到驱动OLED屏的保姆级实战

本文详细介绍了如何使用Arduino IDE开发STM32F103C8T6微控制器,从基础LED闪烁到驱动OLED屏幕的完整实战教程。涵盖环境搭建、PWM调光、外部中断和I2C通信等关键技能,提供可立即验证的代码和常见问题解决方案,适合初学者快速上手STM32开发。

weixin_30907935的博客 561

1-3 STM32F103按键中断(代码复制即可使用)

STM32外部中断

weixin_65878567的博客 2591

用STM32F103C8T6和RC522模块DIY一个智能门禁(附完整代码和接线图)

本文详细介绍了如何使用STM32F103C8T6和RC522模块DIY一个智能门禁系统,包括硬件选型、接线图、代码实现和调试技巧。通过完整的实战指南,帮助电子爱好者和嵌入式初学者快速搭建功能完善的智能门禁,适合毕业设计或创客项目。

weixin_30443747的博客 345

别再只玩点灯了!用STM32F103C8T6实战智能门禁,RC522卡权限管理+OLED显示完整项目复盘

本文详细介绍了基于STM32F103C8T6的智能门禁系统开发全过程,涵盖RC522卡权限管理、舵机控制和OLED显示等关键技术。通过硬件选型、多任务软件架构设计和用户交互优化,实现了一个完整的工程化解决方案,为嵌入式开发者提供了宝贵的实战经验。

weixin_30298497的博客 441

STM32外部中断实战:用按键控制LED(基于STM32F103C8T6最小系统板)

本文以STM32F103C8T6最小系统板为例,详细讲解了STM32外部中断的配置与实战应用。通过对比轮询方式,阐述了外部中断在提升CPU效率与实时响应方面的优势,并提供了从GPIO配置、AFIO映射、EXTI触发到NVIC优先级设置的全流程代码解析,帮助开发者掌握使用按键控制LED的事件驱动编程方法。

weixin_29159441的博客 250

嵌入式系统STM32速成复习与环境搭建全流程指南

嵌入式系统是软硬件结合的核心技术,在期末考试、专升本及考研复试中备受关注,而STM32系列芯片更是课堂教学与工程实践的主流平台。学习难点往往不在知识点本身,而在于缺乏清晰的复习路径与可用的开发环境。从ARM Cortex-M架构、GPIO配置、中断机制到定时器与串口通信,掌握基础原理是构建知识骨架的关键。结合标准库与HAL库的工程实践,详解Keil MDK与STM32CubeMX环境搭建流程、ST-Link烧录调试技巧及常见报错排查方法,能够帮助初学者快速跑通LED流水灯等经典实验。基于“先全局、再实操、后

weixin_34384557的博客 373

基于STM32F103C8T6的智能门禁系统设计:从密码解锁到红外感应控制【附完整工程源码】

本文详细介绍基于STM32F103C8T6单片机的智能门禁系统设计,整合密码解锁与红外感应控制功能。通过硬件选型、电路设计、软件架构及关键功能实现,提供完整的工程源码和流程图解析,重点阐述步进电机控制、红外感应优化等核心技术,为嵌入式开发提供实用参考。

redis7keeper的博客 1132

双参数威布尔分布(Weibull分布)参数计算(根据故障数据,求双参数威布尔分布的参数详细步骤)

根据故障数据求威布尔分布参数步骤 根据众多文献研究,设备故障数据大多服从指数分布、威布尔分布或对数正态分布。其中威布尔分布较为常用,本文主要介绍威布尔分布的简单应用,并根据某设备故障数据为例简单介绍威布尔分布参数的计算方法。 参考文献11参考文献22 1.双参数威布尔分布的概率密度函数、概率分布函数、可靠度函数: 2.预处理故障数据 将故障数据按时间排序,假设设备分别在以下时间点失效:11.1 、23.5、58.4……则将此时间从小到大排序。并计算中位秩。中位秩的计算公式如下: 其中i表示第几个数据,n

biaochengxiaobai的博客 4万+

渗透测试自学日志之漏洞复现篇:漏洞列表

复现成功的漏洞列表,有复现方式,各位可以参考。 网络安全,人人有责,使用本文进行非法活动,与本人无关

maverickpig的博客 2176

中断优先级的艺术:用STM32F103C8T6解锁嵌入式系统的多任务协奏曲

本文深入探讨STM32F103C8T6中断优先级配置的艺术,通过代码示例解析NVIC优先级分组机制,提供实用的配置策略和实战权衡方案。帮助嵌入式工程师优化多任务系统响应,避免优先级反转和中断丢失,提升系统稳定性和实时性能。

code8的博客 185

Silvaco TCAD仿真例库——肖特基二极管反向击穿特性(案例)

本文详细解析了使用Silvaco TCAD仿真例库进行肖特基二极管反向击穿特性分析的完整案例。通过构建包含浮空P型保护环的平面结构,重点阐述了针对雪崩击穿仿真的关键步骤,包括高精度网格划分、碰撞电离模型(impact selb)的启用以及反向电压的精细扫描策略。文章深入探讨了漂移区掺杂浓度、保护环设计等参数对击穿电压的影响,并提供了实用的调试心得,旨在帮助工程师精准预测和优化功率肖特基二极管的反向耐压能力。

fire9的博客 724

解锁STM32的无限潜能:8个颠覆传统的嵌入式设计思维

在嵌入式开发领域,STM32系列微控制器以其强大的性能和丰富的外设资源,正重新定义智能控制的可能性。通过深入分析温控系统的核心实现,我们发现了一系列突破常规的设计理念,这些思维模式将彻底改变你对嵌入式系统的认知方式。🚀 ## 为什么传统温控方案正在被淘汰? **精度瓶颈的突破**:传统的温度控制方案往往受限于传感器的精度和控制算法的局限性。然而,基于STM32F103C8T6的智能温控系统实

gitblog_00505的博客 1107

用Docker-Compose三节点部署生产级Doris集群:从配置文件到故障转移

本文详细介绍了如何使用Docker-Compose部署一个生产级的三节点Apache Doris集群。内容涵盖从核心架构理解、配置文件编写到集群初始化验证的全过程,并重点讲解了如何实现高可用、数据持久化、健康检查以及故障转移等生产级运维关键点,为中小团队提供了一种在容器化便利性与系统稳定性间取得平衡的可靠部署方案。

kkk56的博客 858

人工智能入门系列之一: 鸢尾花(Iris)多分类的神经网络详解及代码实现

这是最好的时代,我们一起来打造属于自动驾驶汽车上路、无人机飞天、智能机器人管工厂的AI未来 人工智能领域分化为两个阵营:其一是规则式(rule-based)方法,在人工智能早期占主峰;其二是神经网络(neural network)方法,后起之秀。随着硬件水平的提高,算力的指数式增长;人工智能的重心已经从规则式的专家时代转移到神经网络的数据时代。 “神经网络”不选择把人脑熟稔的逻辑规则传授给计算机...

NLP家的码奴小荷的博客 2万+

单片机课程设计:基于STM32F103C8T6的简易自动门设计【含源码、流程图、报告(网盘自取)】

经过一坤年的忙碌且混乱的大学生活,深感本人所学知识寥寥、实力低微。本贴提供的代码为本人学了几天(1个星期不到)32单片机后花费数天完成的课程设计,代码臃肿且难免有错漏之处,仅供参考(程序经我简单测试暂时没发现啥问题),也欢迎大家提出代码的修改意见。

m0_73699268的博客 1292

【win10】win 10 电脑喇叭音频显示红叉的处理方法

目录 一、报错情况 二、“音频服务未运行”解决方法 三、“未插入扬声器或耳机”解决方法 一、报错情况 (1)当电脑的扬声器喇叭图标上带有红X符号,提示“音频服务未运行”时: (2)小喇叭上面有红叉,显示“未插入扬声器或耳机”时: 二、“音频服务未运行”解决方法 (1)开始菜单搜索“服务”: (2)没有启动的点击“启动”,已启动的点击“重新启动”: (3)继续,右...

顾三殇 —— 博客空间(软件测试) 17万+

蓝药丸STM32F103C8T6嵌入式开发实战:从最小系统到避坑指南

微控制器是嵌入式系统的核心,理解其最小系统、外设资源与开发方式,是硬件工程师和物联网开发者的基本功。以经典入门芯片为例,它采用Cortex-M3内核,主频72MHz,内置64KB Flash和20KB SRAM,提供丰富通信接口和GPIO,适合学习与原型验证。掌握时钟树配置、GPIO复用、HAL库与FreeRTOS移植等原理,能显著提升工程效率。典型应用涵盖密码锁、智能家居安防、电子秤及图形界面设计,同时在去耦电容、SWD调试、Flash模拟EEPROM等方面积累经验,可有效规避常见陷阱。本文围绕这颗高性价

weixin_33794672的博客 487

从 ABAP 后端到 AEX,Local Integration Engine 下的 Business System 配置全景

本文围绕SAP PI AEX配置中ABAP后端系统与AEX的连接问题,梳理了关键概念和技术脉络。重点指出基于ABAP 6.20及更高版本的业务系统内置了本地集成引擎(Local Integration Engine),负责与AEX的消息交互。配置要点包括:1)在SM59中创建HTTP类型RFC目标连接AEX;2)配置SAP_PROXY_ESR供设计时代理生成;3)通过SXMB_ADM设置业务系统角色为应用系统;4)确保SLD注册和SICF服务激活。文章特别强调运行时代理消息传递与设计时代理生成的区分,以及H

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 99

SAP 采购订单入库——移动类型

业务场景:采购入库,实物入库至仓库,然后系统同步过账。MIGO:收货、采购订单。 MVT:101 入库,---库存增加。 MVT:移动类型,就是代表业务场景,(比如入库、发货,成本中心发、工单发、报废、盘赢、盘亏等等) 移动类型 1、正向采购入库:101 2、反向冲销(MIGO)102:与101相反,用于错误操作的反向冲销。参考原凭证,全部进行一...

willieyuan的博客 7781

超越点灯:用HAL库解锁STM32的创意交互与可视化调试

本文探讨如何利用STM32的HAL库实现超越基础流水灯的创意交互设计,包括非阻塞式灯光模式、音频响应效果及可视化调试技巧。通过STM32CubeMX配置和Keil逻辑分析仪,开发者可构建智能灯光控制系统,提升嵌入式项目的用户体验和调试效率。

rainy的博客 1026

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

【STM32实战】基于STM32F103C8T6的多模态智能门禁系统设计与实现(附完整源码与PCB)

本文详细介绍了基于STM32F103C8T6的多模态智能门禁系统设计与实现,整合指纹识别、RFID刷卡、密码输入及蓝牙控制功能。提供了完整的硬件电路设计、软件架构解析、关键代码实现及PCB布局要点,并附源码与PCB文件,为开发者提供一站式解决方案。

o0p1q2r3的博客 370

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

STM32F103C8T6入门指南:从点灯到实战,摸透Cortex-M3内核开发

嵌入式开发入门绕不开单片机(MCU)的核心概念,而ARM Cortex-M3内核则是众多经典芯片的基石。理解时钟树与GPIO工作原理,是掌握任何MCU外设配置的关键。通过HAL库与CubeMX工具,开发者能高效搭建工程,实现点灯、串口通信、OLED显示等基础功能,并在此过程中理解寄存器、中断、总线等底层机制。这些技术不仅适用于学习验证,更可直接延伸到电机控制、传感器采集、物联网节点等真实应用场景。当开发者从基础概念走到项目实战,再逐步接触FreeRTOS、外设驱动移植时,STM32F103C8T6这颗经典型

weixin_30824479的博客 339

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

基于STM32F103C8T6从零手写抢占式调度器:PSP、PendSV与SysTick实战

在嵌入式开发中,任务调度是RTOS的核心机制,而Cortex-M3内核的PSP、PendSV和SysTick为任务切换提供了硬件基础。通过双堆栈机制实现任务与中断的栈隔离,利用PendSV异常在最低优先级下安全完成上下文切换,再以SysTick作为系统时间基准,即可构建一个支持优先级抢占的轻量级调度器。这种从底层寄存器出发的实现方式,不仅有助于深入理解RTOS原理,还能在资源受限的STM32F103C8T6上获得约2-3微秒的切换开销,适用于面试准备、教学实践或为项目添加轻量调度。

weixin_34210740的博客 409

探索STM32的奇妙世界:stm32_tutorial项目深度剖析

探索STM32的奇妙世界:stm32_tutorial项目深度剖析 项目介绍 在物联网和嵌入式开发的浩瀚宇宙中,STM32微控制器系列以其高性能、低功耗和灵活的外设配置占据了一席之地。对于初学者和经验丰富的开发者而言,stm32_tutorial项目犹如一盏明灯,照亮了探索STM32的路径。本项目特别针对使用STM32F429I-DISCO开发板的朋友们设计,不仅包括基础的外设实现教程,还特意增加...

gitblog_00043的博客 420
上一篇: 制作数学动画的软件
下一篇: 算法——用C语言解答汉诺塔问题
夏子曦
夏子曦 优质创作者: 产品设计技术领域 优质创作者: 产品设计技术领域
博客等级 码龄15年 8289粉丝 427原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值