蓝桥杯嵌入式1--滴答定时器,输入输出模式,LED,按键

蓝桥杯嵌入式1--滴答定时器,输入输出模式,LED,按键

滴答定时器

滴答定时器是放在stm32内核中的一个定时器,用户不可以随便操作滴答定时器的寄存器,滴答定时器就相当于整个芯片系统的一个“心跳”。只要不操作它的寄存器,他就会永不停息的工作下去。对于SMT32G431RBT6来说,以80Mhz进行工作的话,一直不关机的情况下,大概49天左右,滴答定时器的寄存器中的变量才会溢出。
而滴答定时器的四个寄存器如下:

SysTick->CTRL, --控制和状态寄存器
SysTick->LOAD, --重装载寄存器
SysTick->VAL, --当前值寄存器
SysTick->CALIB, --校准值寄存器

对于我们用户来说,主要用到的是SysTick->LOADSysTick->VAL这两个寄存器。
滴答定时器可以做到非常精准的延时,在配置的时候需要将其设置为外部晶振模式。如下图所示
在这里插入图片描述
因为只有采用外部晶振震荡的周期,才会使得滴答定时器的时间非常的准确。

我是在按键的时候用到了滴答定时器来对按键的按下与谈起进行精确的扫描,代码如下:

if ((uwTick - uwTick_Set_Point) <= 200) 
	{
    
    
		return;
	}
	uwTick_Set_Point = uwTick;
	//此代码是通过一个变量来控制滴答定时器的频率 使其保持不变。
	//其中也可以通过改变(200)数值来改变其频率的快慢。

输入输出模式

对于输入模式来说共有
输入浮空(GPIO_Mode_IN_FLOATING)
这种模式输入的时候,没有上下拉电阻的作用,其引脚是一种悬空的状态,引脚输出的电压值不确定。
输入上拉(GPIO_Mode_IPU)
通过一个上拉电阻,使得引脚为高电平。
输入下拉(GPIO_Mode_IPD)
通过一个下拉电阻,使得引脚为低电平。
模拟输入(GPIO_Mode_AIN)
此信号可以理解为是未加处理的信号,就是原信号。

对于输出模式来说共有
开漏输出(GPIO_Mode_Out_OD)
就需要再外部接一个上拉电阻,电源为5V,把GPIO设置为开漏模式, 当输出高组态时,由上拉电阻和电源向外输出5V的电压。一般用在电平不匹配的场合,如需要输出5V的高电平。输出电平:在开漏输出模式时,如果输出为0,低电平,则使N_MOS 导通,使输 出接地。若控制输出为1(无法直接输出高电平),则既不输出高电平 也不输出低电平,为高组态。为正常使用,必须在外部接一个上拉电 阻。
开漏复用功能(GPIO_Mode_AF_OD)
用作IIC。
推挽输出(GPIO_Mode_Out_PP)
直接拿来使用。一般用在0V和3.3V的场合。线路经过两个P_MOS 和N_MOS 管,负责上拉和下拉电流。推挽输出的低电平是0V,高电平是3.3V。
推挽复用功能(GPIO_Mode_AF_PP)
用作串口的输出。

LED

对于hal库来说,直接使用STM32CubeMx直接对LED灯的对应引脚进行配置,对于LED引脚来说开始需要使其熄灭,即对应的应写入高电平(特别注意的是PD2锁存器控制引脚,开始时需要配置低电平)如下图所示
在这里插入图片描述
对LED灯对应的引脚配置的时候直接使用下列代码即可

HAL_GPIO_WritePin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, GPIO_PinState PinState);

而在我们使用的过程中为了方便对8个灯进行操作,像15单片机那样,我们可以写成一个结构体,代码如下所示

void LED_Disp(unsigned char ucLed)
{
    
    
	//**将所有灯熄灭
	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_SET);
	HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
	HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
	
	//**根据ucLed的数值点亮对应的灯
	HAL_GPIO_WritePin(GPIOC,ucLed<<8,GPIO_PIN_RESET);
	HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
	HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
}

即在主函数中对ucLed进行赋值即可,如下所示

while (1)
  {
    
    
   LED_Disp(0x88);
  }

如要操作其他不用的点亮防止,就可像15单片机那样直接操作对应的值。

按键

对于按键,在STM32CubeMx中的配置如下
在这里插入图片描述对于按键来说,对按键的状态进行读取,即对应的代码如下:

HAL_GPIO_ReadPin(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin);

同样的,为了对应15单片机,使得操作起来更加方便,key.c文件中的代码如下所示:

#include "key\bsp_key.h"

void KEY_Init(void)
{
    
    
	GPIO_InitTypeDef GPIO_InitStruct = {
    
    0};
	
  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();
  
  /*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);
}

unsigned char Key_Scan(void)
{
    
    
	
	unsigned char unKey_Val =0;
	
	if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0)==RESET)
	{
    
    
		unKey_Val =1;
	}
	if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1)==RESET)
	{
    
    
		unKey_Val =2;
	}
	if(HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2)==RESET)
	{
    
    
		unKey_Val =3;
	}
		if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)==RESET)
	{
    
    
		unKey_Val =4;
	}
	return unKey_Val;
}

主函数中的代码如下所示:


#include "main.h"
#include "led\bsp_led.h"
#include "key\bsp_key.h"


__IO uint32_t uwTick_Set_Point =0;//控制Key_Proc的执行速度
unsigned char i;

//*按键扫描专用变量
unsigned char ucKey_Val,ucKey_Down,ucKey_Up,ucKey_Old;


void SystemClock_Config(void);
void Key_Proc();

int main(void)
{
    
    
  HAL_Init();
  SystemClock_Config();
  //MX_GPIO_Init();
  LED_Init();
	KEY_Init();
	
  while (1)
  {
    
    
		Key_Proc();
  }
}
void Key_Proc(void)
{
    
    
	if ((uwTick - uwTick_Set_Point) <= 200) 
	{
    
    
		return;
	}
	uwTick_Set_Point = uwTick;
	
	//分为几种情况
	//情况1:100ms两次扫描,按键得到的结果从0(没有按下)到B4按下,产生了下降沿
	//ucKey_Val = 4(0000 0100)
	//ucKey_Down = 0000 0100 &( 0000 0000 ^ 0000 0100) = 0000 0100 & 0000 0100 = 0000 0100 (4)
	//ucKey_Up = 1111 1011 & 0000 0100 = 0000 0000
	//ucKey_Old = 4
	
	//情况2:B4产生下降沿后 并且按键一直按着不放
	//ucKey_Val = 4(0000 0100)
	//ucKey_Down = 0000 0100 &( 0000 0100 ^ 0000 0100) = 0000 0100 & 0000 0000 = 0000 0000 (0)
	//ucKey_Up = 1111 1011 & 0000 0000 = 0000 0000
	//ucKey_Old = 4
	
	//情况3:B4按键一直按着然后松手弹起
	//ucKey_Val = 0(0000 0000)
	//ucKey_Down = 0000 0100 &( 0000 0100 ^ 0000 0000) = 0000 0000 & 0000 0100 = 0000 0000 (0)
	//ucKey_Up = 1111 1111 & 0000 0100 = 0000 0100 (4)
	//ucKey_Old = 0

	ucKey_Val = Key_Scan();
	ucKey_Down = ucKey_Val &(ucKey_Old ^ ucKey_Val);
	ucKey_Up = ~ucKey_Val & (ucKey_Old ^ ucKey_Val);
	ucKey_Old = ucKey_Val;
	
	if(ucKey_Down == 4)
	{
    
    
		LED_Disp(0x88);
	}
	else if(ucKey_Down == 3)
	{
    
    
		LED_Disp(0x00);
	}

おすすめ

転載: blog.csdn.net/Akoasm_/article/details/122352402