? ? ? ? 上一篇文章讲解了如何快速点灯,当一名点灯工程师(o(* ̄▽ ̄*)ブ)这一章加入按键,快速实现GPIO的输入和输出功能,实现按键按下,灯的状态进行取反的操作。
? ? ? ? 一般来说查看硬件原理图看硬件,应该在建立工程根据数据手册和需求分配引脚时进行查看,但是由于写博客还是要分一些先后顺序,故将查看硬件原理图放在第二步。同时一般在使用CubeMX创建工程时,基本也不太需要查看数据手册进行引脚的判别,因为CubeMX都将引脚都呈现出来了。
? ? ? ? 每次创建工程有两项都是恒定不变的,配置RCC和配置Debug,后续的章节中都将省略具体截图步骤,取名老三样,因为配置了三个项目
? ? ? ? 配置RCC,在第一张说设置好那几个参数之后按Resovle Clock Issues,后来发现不如直接按回车好用
? ? ? ? 配置PB12为输出引脚,推挽输出模式,默认高电平,LED灭,无上下拉,配置PA0为输入模式,无上下拉,根据原理图来分析,在按键按下时,输入为低电平,松开时输入为高电平。选择上下拉和默认高低电平,要根据硬件原理图和需求来进行分析选择。
????????
? ? ? ? 相关的代码编写也是很简单的,因为CubeMX都自动生成好了,一个电平反转函数,一个读GPIO电平函数。
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == RESET)
{
HAL_Delay(100); //软件消抖
if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0) == RESET)
{
HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_12);
}
}
}
/* USER CODE END 3 */
}
? ? ? ? 首先建立一个bitstatus变量,是GPIO_PinState类型,PIO_PinState是一个枚举,参数为GPIO_PIN_RESET = 0,GPIO_PIN_SET,GPIO_PIN_SET默认为GPIO_PIN_SET=1。
? ? ? ? 接着是断言,检查是不是GPIO口,从GPIO_PIN_0到GPIO_PIN_ALL。
? ? ? ? 然后是if else,判断GPIO的IDR寄存器与上GPIO_Pin是否等于GPIO_PIN_RESET也就是0,不等于0,返回GPIO_PIN_SET也就是1。
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;
}
? ? ? ? 这里可能很多人不太明白,按照GPIOA和PIN0这里进行讲解,GPIOx->IDR & GPIO_Pin表示与,也就是当IDR为0x0000和GPIO_Pin——0为0x0001,GPIOx->IDR & GPIO_Pin则为0,0=(uint32_t)GPIO_PIN_RESET,所以就是输入为低电平则为GPIO_PIN_RESET,逻辑是正确的。
? ? ? ? 同样的分析方法。当电平是高电平的时候,将GPIO->BSRR寄存器数据左移16位,也就是对应的GPIO口置0,当电平是低电平的时候,将GPIO->BSRR寄存器数据等于GPIO_Pin,也就是对应为1。
void HAL_GPIO_TogglePin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
/* Check the parameters */
assert_param(IS_GPIO_PIN(GPIO_Pin));
if ((GPIOx->ODR & GPIO_Pin) == GPIO_Pin)
{
GPIOx->BSRR = (uint32_t)GPIO_Pin << GPIO_NUMBER;
}
else
{
GPIOx->BSRR = GPIO_Pin;
}
}
????????