STM32 的 GPIO和中断

news2025/4/26 5:08:48

GPIO的简单介绍

内部结构

  • 施密特触发器(TTL肖特基触发器) 的工作原理:

        施密特触发电路(简称)是一种波形整形电路,当任何波形的信号进入电路时,输出在正、负饱和之间跳动,产生方波或脉波输出。

        不同于比较器,施密特触发电路有两个临界电压且形成一个滞后区,可以防止在滞后范围内之噪声干扰电路的正常工作。**如遥控接收线路,传感器输入电路都会用到它整形。

GPIO的工作模式 (八种)

(十分重要,面试会考!!!)

模式类型模式介绍
浮空输入数字输入
浮空输入状态下, IO 的电平状态是不确定的,完全由外部输入决定,如果在该引脚悬空的情况下,读取该端口的电平是不确定的
上拉输入数字输入
IO 口在无输入的情况下,保持高电平
下拉输入数字输入
IO 口在无输入的情况下,保持低电平
模拟输入模拟输入
输入信号不经施密特触发器直接接入,输入信号为模拟量而非数字量,其余输入方式输入数字量
开漏输出数字输出
只能输出低电平
推挽输出数字输出
可以输出高、低电平
复用开漏输出数字输出参考复用推挽
复用推挽输出数字输出
此时 IO 受内部外设控制,比如定时器的 PWM ,比如 SPI MOSI MISO 等。
而普通的推挽输出,则 IO ODR 控制
  •  上拉/下拉/浮空输入

  •  推挽/开漏/复用推挽/复用开漏输出

推挽和开漏的区别
推挽输出开漏输出
既能输出高电平,又能输出低电平。只能输出低电平,若要输出高电平则外接上拉电阻。
  • 复用功能的配置:

 GPIO的寄存器

 常用的是前五种寄存器:

  • GPIOx_CRL:

CNFy[1:0]
位:
31:30
27:26
23:22
19:18
15:14
11:10
7:6
3:2

CNFy[1:0]:端口x配置位(y = 0…7) (Port x configuration bits)

软件通过这些位配置相应的I/O端口,请参考表17端口位配置表。

  • 输入模式(MODE[1:0]=00)

00:模拟输入模式

01:浮空输入模式(复位后的状态)

10:上拉/下拉输入模式

11:保留

  • 输出模式(MODE[1:0]>00)

00:通用推挽输出模式

01:通用开漏输出模式

10:复用功能推挽输出模式

11:复用功能开漏输出模式

MODEy[1:0]
位:
29:28
25:24
21:20
17:16
13:12
9:8,
5:4
1:0

MODEy[1:0]:(输出的频率)端口x的模式位(y = 0…7) (Port x mode bits)软件通过这些位配置相应的I/O端口,请参考表17端口位配置表。

00:输入模式(复位后的状态)

01:输出模式,最大速度10MHz

10:输出模式,最大速度20MHz

11:输出模式,最大速度50MHz

 说明:这个寄存器有32位,其中一个GPIOA口,例如:GPIOA1需要 4位进行控制,因此,这个寄存器可以控制 8 个 GPIOA的口。但是一个单片机中GPIOA外设最多可以有16个口,因此还需要一个寄存器:GPIOx_CRH。

  • GPIOx_CRH:(与GPIOx_CRL同理)

  • GPIOx_IDR:

 说明:表示的是GPIO的16的端口,写1输入高电平,写0输入低电平。

  • GPIOx_ODR:

  说明:表示的是GPIO的16的端口,写1输出高电平,写0输出低电平。

 GPIOx_BSRR(位设置/清除寄存器):

 说明:置1清除位置0,设置位置1。置0保留。

 GPIO口的库函数

模块:LED灯 

LED的介绍

定义:LED是发光二极体(Light Emitting Diode, LED)的简称,也被称作发光二极管,正向通电点亮,反向通电不亮。

分类:引脚二极管 和 贴边二极管

判断正负级:

引脚二极管贴片二极管
方式1:引脚长为正极,短引脚为负极有记号的是负极
方式2:灯里面宽的是负极,窄的是正极“T”字形:一横的一边是正极,另一边是负极;三角形符号:“边”靠近的是正极,“角”靠近的是负极。

接线方式:

 在上官二号开发板上的LED的原理图:

接到上官二号芯片上的端口:

小实验1:点亮一颗LED灯

  • led.c文件中代码
#include "led.h"
#include "stm32f1xx.h"                  // 外设的驱动函数


//初始化GPIO口

void led_init(void){
    
    //打开时钟
    __HAL_RCC_GPIOB_CLK_ENABLE();
    //调用GPIO的初始化函数
    GPIO_InitTypeDef GPIO_Initstruct;
    GPIO_Initstruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_Initstruct.Pin = GPIO_PIN_8;
    GPIO_Initstruct.Pull = GPIO_PULLUP;
    GPIO_Initstruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOB, &GPIO_Initstruct);
    //关闭LED
    led1_off();
    
}
//点亮LED1的函数
void led1_on(void){   
    
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_RESET);   
}

//反转LED1状态的函数
void led1_toggle(void){
    HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_8);
}

//熄灭LED1状态的函数
void led1_off(void){
    
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_SET);
    
}
  • main.c文件中 
#include "sys.h"
#include "led.h"
#include "delay.h"


void led_init(void);                       /* LED初始化函数声明 */

int main(void)
{
    HAL_Init();                         /* 初始化HAL库 */
    stm32_clock_init(RCC_PLL_MUL9);     /* 设置时钟, 72Mhz */
    led_init();                         /* LED初始化 */
    
    while(1)
    { 
       led1_on();
       delay_ms(500);
       led1_off();
       delay_ms(500);
    }
}

小实验2:流水灯

  • led.c文件中的代码:
#include "led.h"
#include "stm32f1xx.h"                  // 外设的驱动函数


//初始化GPIO口

void led_init(void){
    
    //打开时钟
    __HAL_RCC_GPIOB_CLK_ENABLE();
    //调用GPIO的初始化函数
    GPIO_InitTypeDef GPIO_Initstruct;
    GPIO_Initstruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_Initstruct.Pin = GPIO_PIN_8|GPIO_PIN_9;
    GPIO_Initstruct.Pull = GPIO_PULLUP;
    GPIO_Initstruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOB, &GPIO_Initstruct);
    //关闭LED
    led1_off();
    led2_off();
    
}
//点亮LED1的函数
void led1_on(void){   
    
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_RESET);   
}

//反转LED1状态的函数
void led1_toggle(void){
    HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_8);
}

//熄灭LED1状态的函数
void led1_off(void){
    
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_SET);
    
}


//点亮LED2的函数
void led2_on(void){   
    
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_RESET);   
}

//反转LED2状态的函数
void led2_toggle(void){
    HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_9);
}

//熄灭LED2状态的函数
void led2_off(void){
    
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_9,GPIO_PIN_SET);
    
}
  • mian.c中的文件 
#include "sys.h"
#include "led.h"
#include "delay.h"


int main(void)
{
    HAL_Init();                         /* 初始化HAL库 */
    stm32_clock_init(RCC_PLL_MUL9);     /* 设置时钟, 72Mhz */
    led_init();                         /* LED初始化 */
    
    while(1)
    { 
        led1_on();
        led2_off();
        delay_ms(500);
        led1_off();
        led2_on();
        delay_ms(500);
    }
}

模块:蜂鸣器

蜂鸣器的介绍

实物图:

低电平触发驱动电路:

  • 工作电压:3.3v
  • 电平:I/O引脚拉低

有源蜂鸣器和无源蜂鸣器的区别
有源蜂鸣器无源蜂鸣器
内部带有震荡源,只要给它通电,它就会发出声音,但是声音音调是单一的,频率是固定的。
        内部没有震荡源,需要用一定频率的方波(常见的频率范围在2K到5K之间)去驱动它才可以发声。 由于可以通过不同频率的方波驱动,其声音频率是可控的,可以模拟出多种声音效果,甚至达到唱歌的
效果。

小实验:让蜂鸣器响起来

  • beep.c文件
#include "stm32f1xx.h"
#include "beep.h"

//初始化GPIO口
void GPIO_Init(void){
    //打开时钟
    __HAL_RCC_GPIOB_CLK_ENABLE();
    //打开GPIO口
    GPIO_InitTypeDef GPIO_Initstruct;
    GPIO_Initstruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_Initstruct.Pin = GPIO_PIN_8;
    GPIO_Initstruct.Pull = GPIO_NOPULL;
    GPIO_Initstruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOB,&GPIO_Initstruct);
    //关闭蜂鸣器
    beep_off();
}
//打开蜂鸣器函数
void beep_on(void){
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_RESET);
}
//关闭蜂鸣器
void beep_off(void){
    HAL_GPIO_WritePin(GPIOB,GPIO_PIN_8,GPIO_PIN_SET);
}
//反转蜂鸣器
void beep_toggle(void){
    HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_8);  
}
  • mian.c文件
#include "sys.h"
#include "delay.h"
#include "beep.h"

int main(void)
{
    HAL_Init();                          /* 初始化HAL库 */
    stm32_clock_init(RCC_PLL_MUL9);     /* 设置时钟, 72Mhz */
    GPIO_Init();                       /*GPIO口初始化 */
    
    while(1)
    { 
       beep_on();
       delay_ms(500);
       beep_off();
       delay_ms(500);
    }
}

模块:按键

按键的介绍

实物图:

按键抖动:

定义:按键抖动是指在按键开关被按下或释放的瞬间,由于机械触点的弹性作用或电信号的短暂波动,导致开关状态不稳定,出现短暂的抖动现象。这种抖动现象会影响按键的识别和处理,可能导致按一次键而输入多次,影响设备的正常运行和用户的使用体验。 

软件消除:通过延时跳过抖动的时间段,再判断IO输入电平。

上官二号按键的电路图:

接到上官二号板的PA0和PA1口上:

小实验:按键控制LED灯

  • led.文件和点亮led的代码相同。
  • key.c文件
#include "key.h"
#include "stm32f1xx.h"
#include "Delay.h"

//初始化GPIO口
void key_init(void){
    //打开时钟
    __HAL_RCC_GPIOA_CLK_ENABLE();
    //调用GPIO初始化函数
    GPIO_InitTypeDef GPIO_Initstruct;
    GPIO_Initstruct.Mode = GPIO_MODE_INPUT;
    GPIO_Initstruct.Pin = GPIO_PIN_0|GPIO_PIN_1;
    GPIO_Initstruct.Pull = GPIO_PULLUP;
    GPIO_Initstruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOA,&GPIO_Initstruct);
}


//按键检测函数
uint8_t key_scan(void){
    //检测按键是否按下,消除抖动
    if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == GPIO_PIN_RESET){
        delay_ms(15);//消除抖动
        //再次判断按键是否按下
        if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == GPIO_PIN_RESET){
            //如果按键按下,等待按键松开
            while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == GPIO_PIN_RESET);
            //返回按键的值
            return 1;
        }
    }
        
        
        //检测按键是否按下,消除抖动
    if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) == GPIO_PIN_RESET){
        delay_ms(15);//消除抖动
        //再次判断按键是否按下
        if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) == GPIO_PIN_RESET){
            //如果按键按下,等待按键松开
            while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_1) == GPIO_PIN_RESET);
            //返回按键的值
            return 2;
        }
    }
    
    //返回默认值
    return 0;
}

  • main.c文件
#include "sys.h"
#include "led.h"
#include "delay.h"
#include "key.h"


int main(void)
{
    HAL_Init();                         /* 初始化HAL库 */
    stm32_clock_init(RCC_PLL_MUL9);     /* 设置时钟, 72Mhz */
    led_init();                         /* LED初始化 */
    key_init();                         /* KEY初始化 */
    
    uint8_t key_num = 0;
    while(1)
    { 
        key_num = key_scan();
        
        if(key_num == 1){
            led1_toggle();
        }
         if(key_num == 2){
            led2_toggle();
        }
       
    }
}

中断

中断的相关概念

什么是中断?

答:中断是单片机正在执行程序时,由于内部或外部事件的触发,打断当前程序,转而去处理这一事件,当处理完成后再回到原来被打断的地方继续执行原程序的过程。

产生中断的来源:

        在ARM体系结构中,中断通常由外设或外部输入产生,有时也可以由软件触发。中断是单片机系统处理紧急或突发事件的重要方式,如定时器溢出、按键输入、串口数据到达等

中断的意义:

        中断的主要意义在于提高CPU的效率,而不会一直占用CPU,实现对突发事件的实时处理,以及实现程序的并行化和嵌入式系统进程之间的切换。相较于轮询方式(即按照一定的频率和周期不断地检测某些事件的发生)中断在处理一些偶然发生的事情时效率更高

中断嵌套:

        如果一个高优先级的中断发生,它会立即打断当前正在处理的中断(如果其优先级较低),并首先处理这个高优先级的中断,这就是所谓的中断嵌套。

 中断的执行流程:

        当中断发生时,STM32的执行流程如下首先,由外设发出中断请求;然后,处理器暂停当前执行的任务,保护现场(如将当前位置的PC地址压栈);接着,程序跳转到对应的中断服务程序(ISR)并执行;中断服务程序执行完毕后,恢复现场(如将栈顶的值送回PC);最后,处理器返回到被中断的位置,继续执行下一个指令。

STM32中断 

STM32F103C8T6中断数量

  • STM32F103C8T6 支持的中断共有 70 ,其中包括 10 个内核中断 60 个外部中断
  • 外部中断包含 :EXTI、TIM、USARTADCI2CSPI
  • 内核中断包含:

中断向量表

定义:STM32的中断向量表是一个存储中断处理函数地址的数组,位于Flash区的起始位置。每个数组元素对应一个中断源,其地址指向相应的中断服务程序。当中断发生时,处理器会根据中断号查找向量表,然后跳转到对应的中断服务程序执行。

 中断向量表的作用:解决中断函数地址不固定中断必须跳转到固定地方执行程序之间的矛盾。由于编译器每次编译都会为中断函数随机分配地址,但硬件要求 :中断必须跳转到固定的位置,因此,中断向量表就作为这样一个固定的地址列表,其中包含了中断函数的地址以及跳转到这些地址的程序。当中断发生时,处理器会跳转到这个固定的中断向量表,然后根据其中的信息跳转到相应的中断处理函数,从而执行中断。

STM32中断框图

 NVIC

NVIC介绍

  • NVIC,即Nested Vectored Interrupt Controller(嵌套向量中断控制器),是STM32中的中断控制器。它负责管理和协调处理器的中断请求,是STM32中处理异步事件的重要机制。
  •  NVIC 支持:256个中断16内核+240外部)。每个 ISER 寄存器处理 32 个中断,如果有 8 个 ISER 寄存器,就能处理 256 个中断。因此,也支持:256个优先级,允许裁剪。(STM32F103C8T6有10个内核和60个外部中断)。

NVIC的工作原理

        NVIC提供了灵活、高效、可扩展的中断处理机制,支持 多级优先级、多向中断、嵌套向量中断 等特性。当一个中断请求到达时,NVIC会确定其优先级并决定是否应该中断当前执行的程序,以便及时响应和处理该中断请求。这种设计有助于提高系统的响应速度和可靠性,特别是在需要处理大量中断请求的实时应用程序中。

由上面的流程图可知NVIC的的作用: 

  1. 中断使能/失能控制;
  2. 中断优先级控制;
  3. 优先级分组控制。

 中断优先级(抢占、响应和自然优先级)

抢占优先级

响应优先级

(抢占优先级相同)

自然优先级

(抢占和响应优先级相同)

如果一个中断的抢占优先级高于当前正在执行的中断,那么它可以打断当前中断,优先得到执行。 数值越小,优先级越高
如果两个中断同时到达,且它们的抢占优先级相同,那么响应优先级高的中断将首先得到响应。 数值越小,优先级越高
自然优先级是由硬件固定并预先设定的,用户无法更改。当抢占优先级和响应优先级都相同时,自然优先级将决定哪个中断先得到处理。

 优先级的执行顺序:

多个中断同时发生时

  • 执行顺序首先由 抢占优先级决定 。如果抢占优先级相同,则进一步由响应优先级决定。如果响应优先级也相同,则最终由自然优先级决定。

中断嵌套的情况下

  • 高抢占优先级的中断可以打断低抢占优先级的中断;(图例如下)

  • 但高响应优先级的中断不能打断低响应优先级的中断(当它们具有相同的抢占优先级时)。(图例如下)

 优先级分组(对抢占和响应优先级分组)

优先级寄存器(IPR):8位。但实际上只用到高4位(由AIRCR寄存器控制)如下面表格所示用于决定抢占优先级、响应优先级的等级。

优先级分组AIRCR[10:8]抢占优先级响应优先级
0111
0 位,取值为 0
4 位,取值为 0~15
1110
1 位,取值为 0~1
3 位,取值为 0~7
2101
2 位,取值为 0~3
2 位,取值为 0~3
3100
3 位,取值为 0~7
1 位,取值为 0~1
4011
4 位,取值为 0~15
0 位,取值为 0

NVIC寄存器 

 NVIC相关函数介绍

  •  void HAL_NVIC_DisableIRQ(IRQn_Type IRQn)

 ICER:外设中断使能寄存器

  • void HAL_NVIC_EnableIRQ(IRQn_Type IRQn)

 ISER:外设中断失能寄存器

  • void HAL_NVIC_SetPriority()

 IPR:外设优先级寄存器

SHPR:内核外设优先级寄存器 

  •  void HAL_NVIC_SetPriorityGrouping(uint32_t PriorityGroup)

AIRCR :优先级分组寄存器

 NVIC配置方法

  • 设置中断分组 设置中断优先级 使能中断
  • 设置中断分组一般在 HAL_Init 函数中进行

EXTI 

EXIT介绍

定义:EXTI 是 External Interrupt 的缩写,表示外部 中断 事件控制器。EXTI 可以监测指定 GPIO 口的电平信号变化,并在检测到指定条件时,向内核的中断控制器 NVIC 发出中断申请。NVIC 在裁决后,如果满足条件,会中断CPU的主程序,使 CPU 转而执行 EXTI 对应的中断服务程序。

EXTI触发方式
上升沿下降沿双边沿软件触发

----------

 注意事项:

  • EXTI 支持所有的 GPIO 口,但需要注意的是,相同的 Pin 不能同时触发中断。例如,PA0 和 PB0 不能同时被配置为中断源
  • EXTI 提供了 16 GPIO_Pin 的中断线,以及额外的中断线如 PVD 输出 RTC 闹钟 USB 唤醒以太网唤醒(互联型芯片才具备)

中断/事件 

中断:上图中的线路①; 中断会打断CPU当前正在执行的程序,转而去执行中断服务程序,待中断服务程序执行完毕后,CPU会返回到原来的程序执行点继续执行。

事件:上图中线路③事件只是简单地表示某个动作或状态的变化,而不会打断CPU当前正在执行的程序。

事件触发中断:上图线路②;当事件发生时,它会根据配置来决定是否触发相应的中断。如果开放了对应的中断屏蔽位,事件就可以触发相应的中断否则事件只会作为一个信号存在,不会被CPU处理。

EXTI基本结构

 EXTI基本框图

 EXTI寄存器

(参考手册上)

  • 中断屏蔽寄存器(EXTI_IMR) 

31:20
保留,必须始终保持为复位状态(0)
19:0
MRx : 线 x 上的中断屏蔽 (Interrupt Mask on line x)
0 :屏蔽来自线 x 上的中断请求;
1 :开放来自线 x 上的中断请求。
注:位 19 只适用于互联型产品,对于其它产品为保留位。
  •  上升沿触发选择寄存器(EXTI_RTSR)

  •   下降沿触发选择寄存器(EXTI_FTSR)

  •  挂起寄存器(EXTI_PR)

EXTI相关函数介绍

EXTI函数没有专门的.c文件。包含在stm32f1xx_hal_gpio.c文件中

  •  初始化函数:HAL_GPIO_Init()

  • void HAL_GPIO_EXTI_IRQHandler (uint16_t GPIO_Pin) :中断服务函数

 函数①:操作PR寄存器

 函数②:回调函数(写服务代码)

 AFIO

AFIO的介绍

        AFIO 是(Alternate Function Input/Output)的缩写,表示复用功能 IO,主要用于实现 I/O 端口的复用功能以及外部中断的控制(本章主要介绍这个功能)

AFIO与IO口的关系

(参考手册中的示意图)

简化图: 

注意:由上面两个框可知,EXTI 支持所有的 GPIO 口,但需要注意的是,相同的 Pin 不能同时触发中断。例如,PA0 和 PB0 不能同时被配置为中断源

AFIO外部中断配置寄存器

总共由四个外部中断配置寄存器,如下所示:

每个寄存器控制只有前八位有效,一个控制四个EXTI口,对应四个GPIO口,如下所示, 

AFIO函数

HAL_GPIO_Init( )函数里:

对AFIO寄存器进行配置: 

EXTI配置流程


 小实验:按键点灯(中断法)

实验目的使用中断的方法,按下 KEY1 翻转 LED1 状态,而 LED2 一直保持 500ms 的频率闪烁。

注意事项:

  • 按键驱动一般用轮询法即按照一定的频率和周期不断地检测某些事件的发生主要由CPU直接负责),不需要中断来控制(因为按键要消抖,使用延时函数)。
  • 中断服务函数:不能加延时函数,阻塞性函数,不能操作硬件(简单的可以,例如GPIO口;OLED显示屏等复杂的不允许),写Printf()函数有时也会导致异常,中断服务函数中一般设置标志位,在主函数中看到标志有变化,做到业务的处理。 

exti.c文件中代码:

#include "exti.h"
#include "stm32f1xx.h"
#include "delay.h"
#include "led.h"

void exti_init(void){
    //打开时钟
    __HAL_RCC_GPIOA_CLK_ENABLE();
    
    //初始化GPIO口
    GPIO_InitTypeDef GPIO_Initstruct;
    
    GPIO_Initstruct.Mode =GPIO_MODE_IT_FALLING;
    GPIO_Initstruct.Pin = GPIO_PIN_0;
    GPIO_Initstruct.Pull = GPIO_PULLUP;
    GPIO_Initstruct.Speed = GPIO_SPEED_FREQ_HIGH;
    
    HAL_GPIO_Init(GPIOA,&GPIO_Initstruct);
    
    //在HAL_Init()函数中优先级分组,默认第四种,实际用二种
    HAL_NVIC_SetPriority(EXTI0_IRQn,2,0);
    HAL_NVIC_EnableIRQ(EXTI0_IRQn);
    
}

//中断服务函数,
void EXTI0_IRQHandler(void){
    //调用GPIO的中断公共函数,不同外设不同
    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
    
}
//回调函数,业务代码:按键;消抖
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){
    //消抖
    delay_ms(20);
    if(GPIO_Pin == GPIO_PIN_0){  //判断EXTI0是否是GPIO_PIN0
        if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == GPIO_PIN_RESET){//判断GPIO口是否是低电平
            led1_toggle();
        }
    }   
}

main.c文件中的代码:

#include "sys.h"
#include "led.h"
#include "delay.h"
#include "exti.h"


int main(void)
{
    HAL_Init();                         /* 初始化HAL库 */
    stm32_clock_init(RCC_PLL_MUL9);     /* 设置时钟, 72Mhz */
    led_init();                         /* LED初始化 */
    exti_init();
    
    
    while(1)
    { 
      
        led2_on();
        delay_ms(500);
        led2_off();
        delay_ms(500);
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2343001.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【因果推断】(二)CV中的应用

文章目录 因果表征学习因果图 (Causal Diagram)“后门准则”(backdoor criterion)和“前门准则”(frontdoor criterion)后门调整Visual Commonsense R-CNNCausal Intervention for Weakly-Supervised Semantic SegmentationCausal…

分享Matlab成功安装Support Package硬件支持包的方法

分享Matlab成功安装Support Package硬件支持包的方法 文章目录 分享Matlab成功安装Support Package硬件支持包的方法一、 引言二、 操作步骤三、 附件资料四、总结 一、 引言 最近,我想学习基于Matlab simscape & Arduino实现硬件在环仿真,其中物理…

电子级甲基氯硅烷

电子级甲基氯硅烷是一类高纯度有机硅化合物,主要用于半导体制造、光伏产业及高端电子材料领域。以下从技术特性、应用场景、生产工艺、市场动态及安全规范等方面展开分析: 一、核心特性与技术标准 高纯度要求 电子级甲基氯硅烷的纯度通常需达到99.99% 以…

【金仓数据库征文】- 深耕国产数据库优化,筑牢用户体验新高度

目录 引言 一、性能优化:突破数据处理极限,提升运行效率 1.1 智能查询优化器:精准优化数据检索路径 1.2 并行处理技术:充分释放多核计算潜力 1.3 智能缓存机制:加速数据访问速度 二、稳定性提升:筑牢…

热度大幅度下降,25西电经济与管理学院(考研录取情况)

1、经济与管理学院各个方向 2、经济与管理学院近三年复试分数线对比 学长、学姐分析 由表可看出: 1、应用经济及学25年相较于24年下降25分,为325分 2、管理科学与工程25年相较于24年保持不变,为375分 3、工商管理学25年相较于24年下降5分…

DeepSeek+Mermaid:轻松实现可视化图表自动化生成(附实战演练)

目录 一、引言:AI 与图表的梦幻联动二、DeepSeek:大语言模型新星崛起2.1 DeepSeek 全面剖析2.2 多场景应用示例2.2.1 文本生成2.2.2 代码编写 三、Mermaid:代码式图表绘制专家3.1 Mermaid 基础探秘3.2 语法与图表类型详解3.2.1 流程图&#x…

今日行情明日机会——20250425

指数依然在震荡,等待方向选择,整体量能不搞但个股红多绿少。 2025年4月25日涨停板行业方向分析如下: 一、核心行业方向及驱动逻辑 一季报增长(17家涨停) 核心个股:惠而浦、鸿博股份、卫星化学驱动逻辑&am…

一道MySQL索引题

复合索引基础 MySQL中的复合索引(Composite Index)是指由多个列组成的索引。与单列索引不同、复合索引的结构更为复杂,但使用得当可以大幅提升查询性能。 复合索引的工作原理 复合索引的本质是一种有序的数据结、每个列是建立在那个索引前一列存在的情况下、那一…

【linux】设置邮件发送告警功能

当服务器内存不足或者其他故障时,可以通过自动发送故障到邮箱进行提醒。 步骤: 以qq邮箱为例: 登录qq邮箱点击设置 点击账号后,往下翻 找到POP3/IMAP...开启服务 复制授权码 安装邮箱功能 编辑/etc/s-nail.rc 验证 …

【手机】vivo手机应用声音分离方案

文章目录 前言方案 前言 尝试分离vivo手机音乐与其他应用的声音 方案 最佳方案:网易云音乐设置内关闭音量均衡 上传不同的白噪音,成功 goodlock,主要适用于三星手机,vivo不一定适用 app volume control ,可行

关于Safari浏览器在ios<16.3版本不支持正则表达式零宽断言的解决办法

异常原因 今天在升级Dify版本的时候发现低版本的ios手机出现了以下报错: SyntaxError: Invalid regular expression: invalid group specifier nameError: Invalid regular expression: invalid group specifier name Call Stack 46 eval [native code] (0:0) ./n…

管理+技术”双轮驱动工业企业能源绿色转型

00序言 在“3060双碳”政策目标下,工业领域作为碳排放的主要来源(占比约70%),国家出台《工业领域碳达峰实施方案》《加快推动制造业绿色化发展的指导意见》等文件,明确行业碳达峰时间表和重点任务,完善碳市…

每天学一个 Linux 命令(30):cut

​​可访问网站查看,视觉品味拉满: http://www.616vip.cn/30/index.html cut 命令用于从文件或输入流中提取文本的特定部分(如列、字符或字节位置)。它常用于处理结构化数据(如 CSV、TSV)或按固定格式分割的文本。以下是详细说明和示例: 命令格式 cut [选项] [文件...]…

智慧养老综合实训室规划与实施:产教融合的智慧养老实践

智慧养老综合实训室作为智慧养老、智慧康养产业发展的关键支撑,深度融合物联网、大数据、人工智能等前沿技术,搭建虚实结合的教学场景,依托DeepSeek知识库模型实现知识的高效转化与创新,旨在打造产教融合的实践平台,为…

JAVA | 聚焦 OutOfMemoryError 异常

个人主页 文章专栏 在正文开始前,我想多说几句,也就是吐苦水吧…最近这段时间一直想写点东西,停下来反思思考一下。 心中万言,真正执笔时又不知先写些什么。通常这个时候,我都会随便写写,文风极像散文&…

CF-Hero:自动绕过CDN找真实ip地址

CF-Hero:自动绕过CDN找真实ip地址 CF-Hero 是一个全面的侦察工具,用于发现受 Cloudflare 保护的 Web 应用程序的真实 IP 地址。它通过各种方法执行多源情报收集。目前仅支持Cloudflare的cdn服务查找真实ip,但从原理上来说查找方法都是通用的…

Linux基础IO(十一)之动态库(基础IO的最后一篇啦!)

文章目录 动态库生成动态库使用动态库现象事实使用外部库动态库怎么被加载的进程地址空间的第二讲关于地址1.程序没有加载前的地址(程序)2.程序加载后的地址(进程)3.动态库的地址 动态库 生成动态库 shared: 表示生成共享库格式…

【前端】CSS 基础

> 作者:დ旧言~ > 座右铭:松树千年终是朽,槿花一日自为荣。 > 目标:了解 CSS 基础语法。 > 毒鸡汤:有些事情,总是不明白,所以我不会坚持。早安! > 专栏选自:前端基础…

【金仓数据库征文】——选择金仓,选择胜利

目录 第一部分:金仓数据库——开创数据库技术的新时代 1.1 金仓数据库的技术底蕴 1.2 高可用架构与灾备能力 1.3 分布式架构与弹性扩展能力 第二部分:金仓数据库助力行业数字化转型 2.1 电信行业:核心系统国产化替代 2.2 医疗行业&…

跟着尚硅谷学vue-day5

计算属性和watch监视 一.姓名案例 1.姓名案例-插值语法 <div id"root">姓&#xff1a;<input type"text" value"张" v-model"firstname"><br/><br/>名&#xff1a;<input type"text" value&q…