1.stm32点亮LED

目录

  • 直接控制LED灯
  • 按键控制LED灯
  • 定时器控制led闪烁

蓝桥杯LED部分电路图如下图所示


蓝桥杯G4开发板LED外设电路图

板载8个LED灯由74HC573锁存器控制。74HC573是透明的D型锁存器,当使能(G)为高时,Q输出将数据(D)输入而变。当使能为低时,输出将锁存在已建立的数据电平之上。输出控制不影响锁存器内部工作,即原输出保持。
真值表:
OE = L LE = H D = L 时 Q = L;
OE = L LE = H D = H 时 Q = H;
OE = L LE = L 时 Q 不变化

项目准备

1.CT117E实验板一个
2.MDK

工程创建

主函数程序如下

#include "main.h"

void SystemClock_Config(void);//系统时钟设置
static void MX_GPIO_Init(void);//初始化GPIO

#define DELAY_TIME  100  //延时时间

void LED_TEST(void)
{
 //后续测试使用
}

int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();

  while (1)
  {
        LED_TEST();
  }

}

void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};


  HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1);
  /** Initializes the CPU, AHB and APB busses clocks 
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
  RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV2;
  RCC_OscInitStruct.PLL.PLLN = 20;
  RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
  RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
  RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_3) != HAL_OK)
  {
    Error_Handler();
  }
}


static void MX_GPIO_Init(void)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOF_CLK_ENABLE();
  __HAL_RCC_GPIOD_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15|GPIO_PIN_8 
                          |GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12, GPIO_PIN_RESET);

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);

  /*Configure GPIO pins : PC13 PC14 PC15 PC8 
                           PC9 PC10 PC11 PC12 */
  GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15|GPIO_PIN_8 
                          |GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

  /*Configure GPIO pin : PD2 */
  GPIO_InitStruct.Pin = GPIO_PIN_2;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);

}


/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */

  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{ 
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

1.1 直接控制LED灯

与LED相关的函数单独写到led.c文件中,led.c中需要用到的常量和函数声明放到led.h文件中。
在main.c文件中引用led.h即可。

 #include "led.h"

led.c中的内容包含:

  • 点亮某一led灯
  • 熄灭某一led灯
  • 点亮所有灯
  • 熄灭所有led灯
#include "main.h"
#include "led.h"

void turn_on_all_led(void){
    HAL_GPIO_WritePin(GPIOC, led1,GPIO_PIN_RESET);//turn on led1
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
    
    HAL_GPIO_WritePin(GPIOC, led2,GPIO_PIN_RESET);//turn on led2
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
    
    HAL_GPIO_WritePin(GPIOC, led3,GPIO_PIN_RESET);//turn on led3
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
    
    HAL_GPIO_WritePin(GPIOC, led4,GPIO_PIN_RESET);//turn on led4
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
    
    HAL_GPIO_WritePin(GPIOC, led5,GPIO_PIN_RESET);//turn on led5
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
    
    HAL_GPIO_WritePin(GPIOC, led6,GPIO_PIN_RESET);//turn on led6
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
    
    HAL_GPIO_WritePin(GPIOC, led7,GPIO_PIN_RESET);//turn on led7
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
    
    HAL_GPIO_WritePin(GPIOC, led8,GPIO_PIN_RESET);//turn on led8
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
}

void turn_off_all_led(void){
    HAL_GPIO_WritePin(GPIOC, led1,GPIO_PIN_SET);//turn off led1
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
    
    HAL_GPIO_WritePin(GPIOC, led2,GPIO_PIN_SET);//turn off led2
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
    
    HAL_GPIO_WritePin(GPIOC, led3,GPIO_PIN_SET);//turn off led3
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
    
    HAL_GPIO_WritePin(GPIOC, led4,GPIO_PIN_SET);//turn off led4
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
    
    HAL_GPIO_WritePin(GPIOC, led5,GPIO_PIN_SET);//turn off led5
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
    
    HAL_GPIO_WritePin(GPIOC, led6,GPIO_PIN_SET);//turn off led6
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
    
    HAL_GPIO_WritePin(GPIOC, led7,GPIO_PIN_SET);//turn off led7
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
    
    HAL_GPIO_WritePin(GPIOC, led8,GPIO_PIN_SET);//turn off led8
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
}

//turn on the led of searies number
void turn_on_parti_led(int sn){ //sn means the searies number.
    if(sn == 1){
        HAL_GPIO_WritePin(GPIOC, led1,GPIO_PIN_RESET);//turn on led1
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
    }
    if(sn == 2){
        HAL_GPIO_WritePin(GPIOC, led2,GPIO_PIN_RESET);//turn on led2
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
    }
    if(sn == 3){
        HAL_GPIO_WritePin(GPIOC, led3,GPIO_PIN_RESET);//turn on led3
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
    }
    if(sn == 4){
        HAL_GPIO_WritePin(GPIOC, led4,GPIO_PIN_RESET);//turn on led4
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
    }
    if(sn == 5){
        HAL_GPIO_WritePin(GPIOC, led5,GPIO_PIN_RESET);//turn on led5
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
    }
    if(sn == 6){
        HAL_GPIO_WritePin(GPIOC, led6,GPIO_PIN_RESET);//turn on led6
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
    }
    if(sn == 7){
        HAL_GPIO_WritePin(GPIOC, led7,GPIO_PIN_RESET);//turn on led7
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
    }
    if(sn == 8){
        HAL_GPIO_WritePin(GPIOC, led8,GPIO_PIN_RESET);//turn on led8
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
    }
}

//turn off the led of searies number
void turn_off_parti_led(int sn){ //sn means the searies number.
    if(sn == 1){
        HAL_GPIO_WritePin(GPIOC, led1,GPIO_PIN_SET);//turn off led1
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
    }
    if(sn == 2){
        HAL_GPIO_WritePin(GPIOC, led2,GPIO_PIN_SET);//turn off led2
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
    }
    if(sn == 3){
        HAL_GPIO_WritePin(GPIOC, led3,GPIO_PIN_SET);//turn off led3
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
    }
    if(sn == 4){
        HAL_GPIO_WritePin(GPIOC, led4,GPIO_PIN_SET);//turn off led4
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
    }
    if(sn == 5){
        HAL_GPIO_WritePin(GPIOC, led5,GPIO_PIN_SET);//turn off led5
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
    }
    if(sn == 6){
        HAL_GPIO_WritePin(GPIOC, led6,GPIO_PIN_SET);//turn off led6
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
    }
    if(sn == 7){
        HAL_GPIO_WritePin(GPIOC, led7,GPIO_PIN_SET);//turn off led7
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
    }
    if(sn == 8){
        HAL_GPIO_WritePin(GPIOC, led8,GPIO_PIN_SET);//turn off led8
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
        HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
    }
}

led.h中的内容:

#define led1 GPIO_PIN_8
#define led2 GPIO_PIN_9
#define led3 GPIO_PIN_10
#define led4 GPIO_PIN_11
#define led5 GPIO_PIN_12
#define led6 GPIO_PIN_13
#define led7 GPIO_PIN_14
#define led8 GPIO_PIN_15

void turn_on_all_led(void);
void turn_off_all_led(void);
void turn_on_parti_led(int);
void turn_off_parti_led(int);

1.2 按键控制LED灯

HAL_GPIO_ReadPin(GPIOx, GPIO_Pin);//读取GPIO引脚的电平

蓝桥杯G4按键按键外设

配置引脚口

/*Configure GPIO pin : PA0 */
  GPIO_InitStruct.Pin = GPIO_PIN_0;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /*Configure GPIO pins : PB0 PB1 PB2 */
  GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

GPIO模式:

(1)GPIO_Mode_ANALOG 模拟输入
(2)GPIO_Mode_INPUT 浮空输入
(3)GPIO_Mode_IT_FALLING 下拉输入
(4)GPIO_Mode_IT_RISING 上拉输入
(5)GPIO_Mode_Out_OD 开漏输出
(6)GPIO_Mode_Out_PP 推挽输出
(7)GPIO_Mode_AF_OD 复用开漏输出
(8)GPIO_Mode_AF_PP 复用推挽输出

“ 一般开漏输出模式时,如果外部不接上拉电阻时,只能输出低电平,所以要想输出高电平必须要外接上拉电阻。这样做的有一个好处,可以用来匹配不同的电平信号,也就是用于不同电压的系统之间的通信;另外,因为要输出高电平需要有外部的上拉电阻,所以在进行通信时,通信的速度也受到上拉电阻阻值的影响,阻值小时,通信速度可以很快,阻值大时,通信速度变慢,但也不能为了通信速度把上拉电阻用的很小,也要注意在电阻很小时,功耗会变大,所以要平衡好这个度。”——来自CSDN _广广科技的博客
“推挽结构一般是指两个三极管分别受两个互补信号的控制,总是在一个三极管导通的时候另一个截止。这种结构既可以输出高电平,也可以输出低电平,可以用于连接数字器件。”——来自CSDN _广广科技的博客

区分IO口输出

如果是output,那个一般选择no pull,这样,引脚才能根据你的output数据,进行正确输出。
如果是input,那么需要看具体应用的默认输入值是0还是1. 如果默认是输入0,则最好配置为pull down,反之则配置为pull up.
这样做,主要是为了外部电路在没有上下拉的情况下,出现不确定情况。

在while函数中加入判断按键代码:

turn_off_all_led();
  while (1)
  {
        if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET){
            HAL_Delay(10);
            if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_RESET){
                    turn_on_all_led();
                    HAL_Delay(DELAY_TIME*100);
                    turn_off_all_led();
        }
    }
  }

1.3 定时器控制led闪烁

时钟介绍

全局性时钟和独立的外设时钟构成了stm32片上系统的时钟树。
系统时钟是片上除去RTC和看门狗外所有其他外设的时钟源。
特殊外设时钟有两部分:一是为整个系统正常工作服务的外设时钟,如HCLK;二是扩展的高速时钟,如USB总线。
一般外设时钟:通用外设,如DMA,所具有的时钟。
二级时钟(低速):为时钟(RTC)和看门狗提供工作频率,其作用侧重于在节能模式下对关键信息的保存和系统唤醒。
片内时钟输出(MCO):本系统作为时钟源为扩展板提供十种驱动时,可以通过软件设置将内部的SYSTick、PLLCK、HSE等通过GPIO引脚输出。

系统时钟有三种时钟源:
1.HSI(高速内部时钟):由芯片内部8MHz RC振荡器产生,可直接作为系统时钟输出。
2.HSE(高速外部时钟):由外部晶振电路产生的4~16MHz
3.PLL(锁相环):HSI或HSE的输出作为PLL的输入,通过倍频和分频来获得所需要的时钟频率。
特殊外设时钟分为全局性外设时钟和高速总线时钟(扩展设备用)。
全局性外设时钟有:
· HCLK(高速时钟):是Cortex内核运行的时钟(CPU主频),也是AHB的时钟信号,提供给存储器、DMA等高速外设
· FCLK(内核自由运行时钟):确保处理器在休眠时也能采样到中断和跟踪休眠事件,并与HCLK同步。
· SYSTicker(系统定时器):其实质为一个硬件定时器,由它来产生软件系统所需要的“滴答”中断,作为整个系统的根基,以方便操作系统进行时间片管理,以满足多任务1的同时运行。
一般外设时钟有:APB1时钟和APB2时钟
二级时钟有:LSE(低速外部时钟)、LSI(低速内部时钟),其为RTC和看门狗提供工作频率

异常和中断

如果引起状态变化的信号由内核引起,这种事件称为系统异常;片上外设引起的状态变化称为外部中断。当处理器检测到有事件发生时,他会根据一张异常向量表(NVIC)的跳转表来将程序流程切换到相应的异常处理程序。

中断可以分为SysTick中断、NMI中断、EXTI中断和其他外设中断。

  1. SysTick中断。滴答定时器中断直接集成到NVIC内部。SysTick的作用是每隔一定时间产生SysYick异常,作为整个系统的时基。
  2. NMI(非屏蔽中断)中断。大多数情况下,NMI会连接到电压监视模块、看门狗等重要模块,在危险状况时会被激活。NMI任何时间均可被激活。
  3. 有中断先与NVIC连接的外设可分为两类。一是EXTI,由GPIO引脚产生。另一是运行协议的外设,通过外设中的内部状态/中断控制寄存器来管理外设产生的中断信号并传给NVIC。

本例中,通过配置滴答定时器函数来实现led灯闪烁的效果。

SysTick_Handler(void)该函数在stm32g4xx_it.c文件中
HAL_IncTick();
可以理解为每隔1ms其后代码运行一次。所以实现的效果是每隔0.5s led灯亮再隔0.5s led灯灭。

void SysTick_Handler(void)
{
  /* USER CODE BEGIN SysTick_IRQn 0 */
    
  /* USER CODE END SysTick_IRQn 0 */
  HAL_IncTick();
  /* USER CODE BEGIN SysTick_IRQn 1 */
    led_ms++;
    if(led_ms == 500){
        turn_on_all_led();//上文中写好的点亮全部led的代码
    }
    if(led_ms == 1000){
        led_ms = 0;
        turn_off_all_led();//上文中写好的关闭全部led的代码
    }
  /* USER CODE END SysTick_IRQn 1 */
}

1.4 按键中断控制led闪烁

STM32中断分为两类:一类是通过外设内部状态/专断寄存器来管理的中断;另一类是直接通过芯片的引脚将外接部件的电信号传导到CPU而引起的中断。后者称为EXTI(外部中断)。
EXTI 0~15:分别连接到GPIO端口(GPIOx,x = AE)中的Pin0Pin15,即Pin0对应EXTI_Line0,···,Pin15对应EXTI_Line15。
EXTI16:连接到电源电压检测(PVD)中断
EXTI17:连接到RTC闹钟中断

EXTI模块主要分为3部分:
1.工作模式:中断屏蔽寄存器、事件屏蔽寄存器配置EXTI控制器为中断或事件工作模式
2.触发方式:沿触发寄存器配置某种模式下的触发方式,如:上升沿触发、下降沿触发、双沿(上升沿和下降沿)触发方式,软件触发。
3.挂起寄存器:标识在“外部中断线”上是否发生了所设置选择的边沿事件。

EXTI控制器的工作过程:外部部件(如按键)的电信号通过GPIO引脚传输到EXTI控制器后,其内的边沿检测器根据设定的中断触发方式,置挂起寄存器对应的EXTI_Line位为1,标明发生了相应的中断。如果此时中断寄存器相应位设置为1(表示放开线上的中断请求),则中断信号就顺利地传向NVIC,NVIC再查异常向量表,跳转到相应的中断服务程序并执行。

工程代码
实现效果:按下B4,led亮,再按下B4键,led灭。

在 MX_GPIO_Init()中初始化中断

  HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0);
  HAL_NVIC_EnableIRQ(EXTI0_IRQn);

按键IO口初始化改为

  GPIO_InitStruct.Pin = GPIO_PIN_0;
  GPIO_InitStruct.Mode =  GPIO_MODE_IT_FALLING;//下降沿触发
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

在stm32g4xx_it.c文件中找到中断服务函数,再找到其中的 HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0)函数。

void EXTI0_IRQHandler(void)//EXTI0中断服务函数
{
  /* USER CODE BEGIN EXTI0_IRQn 0 */

  /* USER CODE END EXTI0_IRQn 0 */
  HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
  /* USER CODE BEGIN EXTI0_IRQn 1 */
    }
  }

在stm32g4xx_hal_gpio.c文件中找到该函数。

void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{
  /* EXTI line interrupt detected */
  if (__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != 0x00u)
  {
    __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
    HAL_GPIO_EXTI_Callback(GPIO_Pin);
  }
}

在该函数中,HAL_GPIO_EXTI_Callback是虚函数,用户可以再main.c中重新编辑该函数,也可以单独开一个interrupt.c文件。
如:

#include "main.h"
#include "interrupt.h"
#include "key.h"

extern char led_status;

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){
    
        change_led_status();    //能进入的该函数时已经发生中断,所以可以直接编写中断代码
}

void change_led_status(void){
    if(led_status == 1){
        led_status = 0;
    }else{
        led_status = 1;
    }
}

在main.c的while(1)中执行更改led。

char led_status = 0;
while (1)
  {
        if(led_status == 1){
            turn_on_all_led();
        }else{
            turn_off_all_led();
        }
    } 

特别的,如果在HAL_GPIO_EXTI_Callback函数中再加一重判断,即可实现只有同时按下B1,B4才能更改灯的亮灭。

if(HAL_GPIO_ReadPin(GPIOB,key4) == GPIO_PIN_RESET){
        change_led_status();     
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容