【STM32F407 开发板】实验三 :按键扫描实验

前言:

这个实验,可以算是一个小小的综合一点的实验叭,就是通过读取按键的输入,来控制对应的LED的亮灭,比较新颖的地方是读取管脚的输入,其他的没啥,然后就是分析电路

一、创建工程

创建工程这里,其实和以前的实验,没啥太大区别,就是管脚选择不一样,多了几个INPUT的管脚而已

在Cube中是这个样子:
在这里插入图片描述
在这里插入图片描述

二、时钟配置

时钟配置和之前的一样,都是用的GPIO口嘛,所以都是AHB总线:
在这里插入图片描述
然后点击生成源代码的时候,配置和之前是一模一样的,接下来就是用Keil5打开工程,进行一些业务逻辑上的编码而已。

三、电路分析

这里面的电路,主要是两个电路,一个是按键管脚的输入电路,一个是LED灯的电路,如下:

在这里插入图片描述
对于按键电路,可以看到当按键没有被按下的时候,电路是断路,所以那些KEY的电压都是和VCC一样,都是高电压,所以就是对应的按键没有被按下,对应管脚输入高电压,当按键被按下了,那么对应管脚就接地了,就成了低电压,所以就是当按键按下的时候,对应管脚输入低电压。

在这里插入图片描述
LED灯的电路还是和之前是一样的,都是低电压灯亮。

四、编辑工程,编译工程

编写代码主要还是在main.c中编写,只不过这次用到了一个HAL的一个函数接口用来读取对应管脚的输入罢了。

函数声明部分:
在这里插入图片描述
在main中声明局部变量:
在这里插入图片描述
在main的while循环中写简单的业务逻辑:
在这里插入图片描述
调用的函数KEY_Scan()
在这里插入图片描述

uint8_t KEY_Scan(uint8_t mode)
{
	uint8_t KEY1=HAL_GPIO_ReadPin(GPIOI,GPIO_PIN_9);
	uint8_t KEY2=HAL_GPIO_ReadPin(GPIOF,GPIO_PIN_11);
	uint8_t KEY3=HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_13);
	uint8_t KEY4=HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0);
	static uint8_t key_up=1;
	if(mode)key_up=1;
	if(key_up&&(KEY1==GPIO_PIN_RESET||KEY2==GPIO_PIN_RESET||KEY3==GPIO_PIN_RESET||KEY4==GPIO_PIN_RESET))
	{
	HAL_Delay(10);
	key_up=0;
	if(KEY1==0)return 1;
	else if(KEY2==0)return 2;
	else if(KEY3==0)return 3;
	else if(KEY4==0)return 4;
	}else if(KEY1==GPIO_PIN_SET&&KEY2==GPIO_PIN_SET&&KEY3==GPIO_PIN_SET&&KEY4==GPIO_PIN_SET)key_up=1;/* Ö±µ½ËùÓа´¼ü¶¼Ðü¿Õ£¬²Å¿ªÊ¼ÏÂÒ»´ÎµÄ°´¼üɨÃè */
	return 0;
	}

全部编写完了之后,就可以编译,然后链接,然后LOAD到板子上,按下复位键,运行代码

然后就可以按下对应的按键,对应的LED灯亮了。(照片就不贴了,长得和以前的实验都一样)

五、详细代码分析

主要分析几个函数叭,说明一下是怎么亮的

  1. MX_GPIO_Init();

    void MX_GPIO_Init(void)
    {
    
      GPIO_InitTypeDef GPIO_InitStruct;
    
      /* GPIO Ports Clock Enable */
      __HAL_RCC_GPIOE_CLK_ENABLE();
      __HAL_RCC_GPIOC_CLK_ENABLE();
      __HAL_RCC_GPIOI_CLK_ENABLE();
      __HAL_RCC_GPIOF_CLK_ENABLE();
      __HAL_RCC_GPIOH_CLK_ENABLE();
      __HAL_RCC_GPIOA_CLK_ENABLE();
    
      /*Configure GPIO pin Output Level */
      HAL_GPIO_WritePin(GPIOE, GPIO_PIN_2, GPIO_PIN_SET);
    
      /*Configure GPIO pin Output Level */
      HAL_GPIO_WritePin(GPIOF, GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10, GPIO_PIN_SET);
    
      /*Configure GPIO pin : PE2 */
      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(GPIOE, &GPIO_InitStruct);
    
      /*Configure GPIO pin : PC13 */
      GPIO_InitStruct.Pin = GPIO_PIN_13;
      GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
      GPIO_InitStruct.Pull = GPIO_NOPULL;
      HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
    
      /*Configure GPIO pin : PI9 */
      GPIO_InitStruct.Pin = GPIO_PIN_9;
      GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
      GPIO_InitStruct.Pull = GPIO_NOPULL;
      HAL_GPIO_Init(GPIOI, &GPIO_InitStruct);
    
      /*Configure GPIO pins : PF8 PF9 PF10 */
      GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10;
      GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
      GPIO_InitStruct.Pull = GPIO_NOPULL;
      GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
      HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
    
      /*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 pin : PF11 */
      GPIO_InitStruct.Pin = GPIO_PIN_11;
      GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
      GPIO_InitStruct.Pull = GPIO_NOPULL;
      HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
    
    }
    

    这个代码都是重复性的代码,主要说两部分,其一是这句话

    HAL_GPIO_WritePin(GPIOE, GPIO_PIN_2, GPIO_PIN_SET);

    就是这个函数,是向管脚中输出电压,因为这个大函数脚MX_GPIO_Init(),是一个初始化函数,所以这个函数在这里的作用可以看为对应管脚的初始值。这里设置的SET,也就是置位,也就是高电压,所以一开始对应的LED灯是不亮的。

    其二就是接下来这一堆在Cube中已经配置过的管脚属性配置,都是重复性的代码,就是配置一些管脚而已。

  2. uint8_t KEY_Scan(uint8_t mode);

    这个函数,就是扫描按键是否有被按下的操作,这里有一个比较骚气的一点,就是当你按下一个按键,但是不抬起按键的时候,你按下其他按键是不起作用的。比如我按下KEY1,对应的LED1亮了,但是我不抬起KEY1,直接再次按下KEY2,这时LED2灯是不亮的。主要是key_up 这个变量的原因,它在有按键被按下的时候,被置位为0,此后只有四个按键全部悬空的时候,才被再次置位为1,而且它用了一个static局部变量,所以每次调用这个函数,key_up这个变量还是保存的上一次调用时的值,会一直保存下来。

  3. HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_13);

    /**
      * @brief  Reads the specified input port pin.
      * @param  GPIOx: where x can be (A..K) to select the GPIO peripheral for STM32F429X device or
      *                      x can be (A..I) to select the GPIO peripheral for STM32F40XX and STM32F427X devices.
      * @param  GPIO_Pin: specifies the port bit to read.
      *         This parameter can be GPIO_PIN_x where x can be (0..15).
      * @retval The input port pin value.
      */
    GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
    {
      GPIO_PinState bitstatus;
    
      /* Check the parameters */
      assert_param(IS_GPIO_PIN(GPIO_Pin));
    
      if((GPIOx->IDR & GPIO_Pin) != (uint32_t)GPIO_PIN_RESET)
      {
        bitstatus = GPIO_PIN_SET;
      }
      else
      {
        bitstatus = GPIO_PIN_RESET;
      }
      return bitstatus;
    }
    
    

    这个函数就是读取对应管脚输入的函数。它主要是用了对应管脚的IDR寄存器与对应管脚相与,获得当前管脚的输入状态。

    IDR寄存器如下:
    在这里插入图片描述
    寄存器默认为复位模式,即低电平输入状态。然后当有高电平输入的时候,对应的管脚的二进制位被置位为1,故,if((GPIOx->IDR & GPIO_Pin) != (uint32_t)GPIO_PIN_RESET) { bitstatus = GPIO_PIN_SET; }中,当对应管脚的值不为RESET(0)的时候,将返回对应管脚获得了高电平输入SET(1) 。
    在这里插入图片描述
    获得了对应管脚的输入之后,就是点亮或熄灭对应的LED灯

  4. void HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

    /**
      * @brief  Toggles the specified GPIO pins.
      * @param  GPIOx: Where x can be (A..K) to select the GPIO peripheral for STM32F429X device or
      *                      x can be (A..I) to select the GPIO peripheral for STM32F40XX and STM32F427X devices.
      * @param  GPIO_Pin: Specifies the pins to be toggled.
      * @retval None
      */
    void HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
    {
      /* Check the parameters */
      assert_param(IS_GPIO_PIN(GPIO_Pin));
    
      GPIOx->ODR ^= GPIO_Pin;
    }
    

    这个函数就是转换LED灯状态的函数,调整对应的管脚所属组的ODR寄存器,对指定的管脚进行异或操作,这样,0会变成1,1会变成0,状态来回切换。

六、总结

这个实验,感觉其实真的没啥,就是寄存器的读写操作,好简单。我又飘了,哈哈哈哈

  • 3
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值