(蓝桥杯)STM32G431RBT6(按键中/模块化)

一、CubeMx配置

        看上一篇CSDN有讲解

二、Keil5配置

1、新建空白页
2、ctrl+s保存、添加文件.c
3、添加文件/.h

4、在目录栏里面添加key.c

 

 

 

三、模块化代码

1、报错原因 

 update_key_status();
 (1)是因为原来的stm32g4xx_it.c文件里面没有包含“key.h”

 

#include "key.h"
(2)main文件里面也要包含

2、key.c代码
#include "key.h"

uint16_t key_delay_filter_count[4]={0,0,0,0};
key_status keys_status[4];//一共有四个按键,所以需要一个数组

void update_key_status(void)//第一个按键的状态
{
	if(HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin)==0)
	{
		key_delay_filter_count[0]<<=1;
		key_delay_filter_count[0]|=0x0001; 
		if(key_delay_filter_count[0] >0x03FF)
		{
			if(keys_status[0]==key_released)
			keys_status[0]=key_pressed;
		}
	}
	else
	{
		key_delay_filter_count [0]>>=1;
		if(key_delay_filter_count[0]==0)
		{
			keys_status[0]=key_released;
		}
	}
	
}
uint16_t get_key_status(uint8_t key_num)
{
	return keys_status[key_num];
}

void do_it_once(uint8_t key_num)
{
	keys_status[key_num]=key_waiting_for_release ;
}
3、key.h代码
#ifndef __KEY_H__
#define __KEY_H__
#include "main.h"//这一步要包含,否则最起码类型的定义可能跳转不出来
typedef enum
{
	key_released=0U,
	key_pressed,
	key_waiting_for_release
}key_status;

extern key_status keys_status[4];

void update_key_status(void);
uint16_t get_key_status(uint8_t key_num);

void do_it_once(uint8_t key_num);

#endif
4、stm32g4xx_it.c代码

void SysTick_Handler(void)
{
  /* USER CODE BEGIN SysTick_IRQn 0 */

  /* USER CODE END SysTick_IRQn 0 */
  HAL_IncTick();
  /* USER CODE BEGIN SysTick_IRQn 1 */
  update_key_status();
  /* USER CODE END SysTick_IRQn 1 */
}
 5、main代码

  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
	   if(get_key_status(0)==key_pressed)
	  {
		HAL_GPIO_TogglePin (LED1_GPIO_Port ,LED1_Pin );
		
		  do_it_once(0);
	  }
  }
 6、逻辑分析

(1)首先程序进入的是void SysTick_Handler(void)这个中断函数,这个中断函数里面包含的就是update_key_status();这个更新的状态函数,然后我们跳转到这个函数的具体程序

(2)update_key_status();这个函数就是在我们的key.c里面。

        它的逻辑就是,一旦检测到我们按键按下的信号,就开始进行一个按键消抖的计时,一旦大于10ms,就确认为按键按下(这一步可以忽略认为按键按下的信号)。        

        if(keys_status[0]==key_released)这一句的意思就是,我按键原来的状态如果是松开的状态,然后就把我的按键状态改为keys_status[0]=key_pressed;所以下面的else只是为了给我的按键赋值一个状态,然后当我的按键按下,我再给他赋值为另外一个状态。

(3)然后跳转到我们的main函数

        if(get_key_status(0)==key_pressed);这个函数可以继续看看我们的key.c里面对get_key_status(uint8_t key_num)的函数的理解

        就是相当于我们给get_key_status赋一个值,例如(0),然后它的按键状态的名字就是keys_status[0]。当我们按键按下,此时的keys_status[0]=keys_status[0]=key_pressed;然后我的main函数里面就是判断我的按键是否按下。

        按键按下之后就开始翻转我们的电平,对应的LED灯的电平

        此时还进入了一个函数do_it_once(0),此时还是跳转到key.c里面。意思就是我给do_it_once输入一个值,例如(0),就变成keys_status[0]=key_waiting_for_release。此时我的按键状态就不再是key_pressed就不能够继续翻转我的电平,且此时就算进入我的中断函数,因为我只按下还为松开,所以我的按键状态也就没有变成key_released,所以此时就算每隔1ms进入中断函数,也不能改变我的按键状态key_waiting_for_release,直到我松开手再次按下才能翻转我的电平。我松开手之后我的电平状态就变成了key_released,因为此时没有给这个状态赋其它程序,所以它不会改变我之前的LED灯的现象

(4)头文件之间包含的关系及key.h的作用

        main函数里面包含key.h和stm32g4xx_it.c和里面包含key.h还有key.c里面要包含key,h都是因为这两个文件里面都要用到key.h里面包含的函数。

        key.h里面包含“main.h”是因为它也需要main.h里面的函数。而且key.h里面包含了,我的key.c里面也可以用main.c里面的函数。

        所以key.h里面定义的枚举类型,在其它函数里面都不需要声明就直接用,就是因为ley.h里面已经写好了,甚至是在main函数里面的外部声明 extern 都有。

(5)总结

        以上的这些分析其实跟上一篇(按键上)的逻辑是一样的,这样写的好处,就是模块化分开来了,不至于在SysTick_Handler这里面所有的函数阻塞住。

 

四、一个按键控制一个LED灯的代码

(1)key.c代码
#include "key.h"

uint16_t key_delay_filter_count[4]={0,0,0,0};
key_status keys_status[4];//一共有四个按键,所以需要一个数组

void update_key_status1(void)//第一个按键的状态
{
	if(HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin)==0)
	{
		key_delay_filter_count[0]<<=1;
		key_delay_filter_count[0]|=0x0001; 
		if(key_delay_filter_count[0] >0x03FF)
		{
			if(keys_status[0]==key_released)
			keys_status[0]=key_pressed;
		}
	}
	else
	{
		key_delay_filter_count [0]>>=1;
		if(key_delay_filter_count[0]==0)
		{
			keys_status[0]=key_released;
		}
	}
}

void update_key_status2(void)//第一个按键的状态
{
	if(HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin)==0)
	{
		key_delay_filter_count[1]<<=1;
		key_delay_filter_count[1]|=0x0001; 
		if(key_delay_filter_count[1] >0x03FF)
		{
			if(keys_status[1]==key_released)
			keys_status[1]=key_pressed;
		}
	}
	else
	{
		key_delay_filter_count [1]>>=1;
		if(key_delay_filter_count[1]==0)
		{
			keys_status[1]=key_released;
		}
	}
}

void update_key_status3(void)//第一个按键的状态
{
	if(HAL_GPIO_ReadPin(KEY3_GPIO_Port,KEY3_Pin)==0)
	{
		key_delay_filter_count[2]<<=1;
		key_delay_filter_count[2]|=0x0001; 
		if(key_delay_filter_count[2] >0x03FF)
		{
			if(keys_status[2]==key_released)
			keys_status[2]=key_pressed;
		}
	}
	else
	{
		key_delay_filter_count [2]>>=1;
		if(key_delay_filter_count[2]==0)
		{
			keys_status[2]=key_released;
		}
	}
}

void update_key_status4(void)//第一个按键的状态
{
	if(HAL_GPIO_ReadPin(KEY4_GPIO_Port,KEY4_Pin)==0)
	{
		key_delay_filter_count[3]<<=1;
		key_delay_filter_count[3]|=0x0001; 
		if(key_delay_filter_count[3] >0x03FF)
		{
			if(keys_status[3]==key_released)
			keys_status[3]=key_pressed;
		}
	}
	else
	{
		key_delay_filter_count [3]>>=1;
		if(key_delay_filter_count[3]==0)
		{
			keys_status[3]=key_released;
		}
	}
}




uint16_t get_key_status(uint8_t key_num)
{
	return keys_status[key_num];
}

void do_it_once(uint8_t key_num)
{
	keys_status[key_num]=key_waiting_for_release ;
}
 (2)key.h代码
#ifndef __KEY_H__
#define __KEY_H__
#include "main.h"//这一步要包含,否则最起码类型的定义可能跳转不出来
typedef enum
{
	key_released=0U,
	key_pressed,
	key_waiting_for_release
}key_status;

extern key_status keys_status[4];

void update_key_status1(void);
void update_key_status2(void);
void update_key_status3(void);
void update_key_status4(void);
uint16_t get_key_status(uint8_t key_num);

void do_it_once(uint8_t key_num);

#endif
(3)stm32g4xx_it.c代码
void SysTick_Handler(void)
{
  /* USER CODE BEGIN SysTick_IRQn 0 */

  /* USER CODE END SysTick_IRQn 0 */
  HAL_IncTick();
  /* USER CODE BEGIN SysTick_IRQn 1 */
  update_key_status1();
  update_key_status2();
  update_key_status3();
  update_key_status4();
  /* USER CODE END SysTick_IRQn 1 */
}
(4)main代码
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
	  if(get_key_status(0)==key_pressed)
	  {
		HAL_GPIO_TogglePin (LED1_GPIO_Port ,LED1_Pin );
		
		  do_it_once(0);
	  }
	  if(get_key_status(1)==key_pressed)
	  {
		HAL_GPIO_TogglePin (LED2_GPIO_Port ,LED2_Pin );
		
		  do_it_once(1);
	  }
	  if(get_key_status(2)==key_pressed)
	  {
		HAL_GPIO_TogglePin (LED3_GPIO_Port ,LED3_Pin );
		
		  do_it_once(2);
	  }
	  if(get_key_status(3)==key_pressed)
	  {
		HAL_GPIO_TogglePin (LED4_GPIO_Port ,LED4_Pin );
		
		  do_it_once(3);
	  }
  }
(5)逻辑分析

        其实大概的逻辑分析跟上述相同,唯一的区别点就在于,我给不同的按键(KEY1、KEY2等)按键按下给了不同的按键按下状态的名字(keys_status[0]、keys_status[1]等),给了不同状态的名字,所以不同的按键按下能执行相对应的程序。

五、while循环里面只有一个函数

(1)key.c代码
#include "key.h"

uint16_t key_delay_filter_count[4]={0,0,0,0};
key_status keys_status[4];//一共有四个按键,所以需要一个数组

void update_key_status1(void)//第一个按键的状态
{
	if(HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin)==0)
	{
		key_delay_filter_count[0]<<=1;
		key_delay_filter_count[0]|=0x0001; 
		if(key_delay_filter_count[0] >0x03FF)
		{
			if(keys_status[0]==key_released)
			keys_status[0]=key_pressed;
		}
	}
	else
	{
		key_delay_filter_count [0]>>=1;
		if(key_delay_filter_count[0]==0)
		{
			keys_status[0]=key_released;
		}
	}
}

void update_key_status2(void)//第一个按键的状态
{
	if(HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin)==0)
	{
		key_delay_filter_count[1]<<=1;
		key_delay_filter_count[1]|=0x0001; 
		if(key_delay_filter_count[1] >0x03FF)
		{
			if(keys_status[1]==key_released)
			keys_status[1]=key_pressed;
		}
	}
	else
	{
		key_delay_filter_count [1]>>=1;
		if(key_delay_filter_count[1]==0)
		{
			keys_status[1]=key_released;
		}
	}
}

void update_key_status3(void)//第一个按键的状态
{
	if(HAL_GPIO_ReadPin(KEY3_GPIO_Port,KEY3_Pin)==0)
	{
		key_delay_filter_count[2]<<=1;
		key_delay_filter_count[2]|=0x0001; 
		if(key_delay_filter_count[2] >0x03FF)
		{
			if(keys_status[2]==key_released)
			keys_status[2]=key_pressed;
		}
	}
	else
	{
		key_delay_filter_count [2]>>=1;
		if(key_delay_filter_count[2]==0)
		{
			keys_status[2]=key_released;
		}
	}
}

void update_key_status4(void)//第一个按键的状态
{
	if(HAL_GPIO_ReadPin(KEY4_GPIO_Port,KEY4_Pin)==0)
	{
		key_delay_filter_count[3]<<=1;
		key_delay_filter_count[3]|=0x0001; 
		if(key_delay_filter_count[3] >0x03FF)
		{
			if(keys_status[3]==key_released)
			keys_status[3]=key_pressed;
		}
	}
	else
	{
		key_delay_filter_count [3]>>=1;
		if(key_delay_filter_count[3]==0)
		{
			keys_status[3]=key_released;
		}
	}
}

void key(void)
{
	if(get_key_status(0)==key_pressed)
	  {
		HAL_GPIO_TogglePin (LED1_GPIO_Port ,LED1_Pin );
		
		  do_it_once(0);
	  }
	  if(get_key_status(1)==key_pressed)
	  {
		HAL_GPIO_TogglePin (LED2_GPIO_Port ,LED2_Pin );
		
		  do_it_once(1);
	  }
	  if(get_key_status(2)==key_pressed)
	  {
		HAL_GPIO_TogglePin (LED3_GPIO_Port ,LED3_Pin );
		
		  do_it_once(2);
	  }
	  if(get_key_status(3)==key_pressed)
	  {
		HAL_GPIO_TogglePin (LED4_GPIO_Port ,LED4_Pin );
		
		  do_it_once(3);
	  }
}
/*
这一段程序的含义是
首先进入中断函数,中断函数里面跳转到key.c
当我的按键按下,然后我的按键状态[1]就变成按下,然后在while循环里面执行的就是key()
kye()这个函数的意思就是,看我get_key_status对应的是哪个数字,然后就是对应的哪个按键状态,然后就开始翻转电平
*/



uint16_t get_key_status(uint8_t key_num)
{
	return keys_status[key_num];
}

void do_it_once(uint8_t key_num)
{
	keys_status[key_num]=key_waiting_for_release ;
}

(2)key.h代码
#ifndef __KEY_H__
#define __KEY_H__
#include "main.h"//这一步要包含,否则最起码类型的定义可能跳转不出来
typedef enum
{
	key_released=0U,
	key_pressed,
	key_waiting_for_release
}key_status;

extern key_status keys_status[4];

void update_key_status1(void);
void update_key_status2(void);
void update_key_status3(void);
void update_key_status4(void);

void key(void);
	
uint16_t get_key_status(uint8_t key_num);

void do_it_once(uint8_t key_num);

#endif

 

(3)stm32g4xx_it.c代码

 头文件还是要包含"key.h"

void SysTick_Handler(void)
{
  /* USER CODE BEGIN SysTick_IRQn 0 */

  /* USER CODE END SysTick_IRQn 0 */
  HAL_IncTick();
  /* USER CODE BEGIN SysTick_IRQn 1 */
  update_key_status1();
  update_key_status2();
  update_key_status3();
  update_key_status4();
  /* USER CODE END SysTick_IRQn 1 */
}
(4)main代码

 头文件还是要包含"key.h"

 while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
	 key();
	  
  }

六、学习资料来源

(1)B站

【STM32G431RBT6_STM32CubeMX_Keil_按键篇_中-哔哩哔哩】 https://b23.tv/WwbEEEk

(2)Keil5代码

文件包:KEY2

(“按键上”的代码时KEY1)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值