前言:
这个实验,可以算是一个小小的综合一点的实验叭,就是通过读取按键的输入,来控制对应的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灯亮了。(照片就不贴了,长得和以前的实验都一样)
五、详细代码分析
主要分析几个函数叭,说明一下是怎么亮的
-
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中已经配置过的管脚属性配置,都是重复性的代码,就是配置一些管脚而已。
-
uint8_t KEY_Scan(uint8_t mode);
这个函数,就是扫描按键是否有被按下的操作,这里有一个比较骚气的一点,就是当你按下一个按键,但是不抬起按键的时候,你按下其他按键是不起作用的。比如我按下KEY1,对应的LED1亮了,但是我不抬起KEY1,直接再次按下KEY2,这时LED2灯是不亮的。主要是
key_up
这个变量的原因,它在有按键被按下的时候,被置位为0,此后只有四个按键全部悬空的时候,才被再次置位为1,而且它用了一个static局部变量,所以每次调用这个函数,key_up这个变量还是保存的上一次调用时的值,会一直保存下来。 -
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灯 -
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,状态来回切换。
六、总结
这个实验,感觉其实真的没啥,就是寄存器的读写操作,好简单。我又飘了,哈哈哈哈