嵌入式铁头山羊stm32-SPI番外之按钮驱动程序的编写-Day15
嵌入式铁头山羊STM32-各章节详细笔记-查阅传送门(点击传送)
https://blog.csdn.net/m0_56408226/article/details/151870808
目录
使用串口调试助手实现,按钮的多种操作实现串口助手的数字变化。(单机-数字+1,双击数字清零,长按数字持续++)
一、按钮简单操作回忆
首先,回忆一下之前学过的GPIO的按钮实验,即做到了持续按下按钮,灯持续亮,松开按钮,则灯灭。
代码的简单逻辑是:

二、按钮新操作实现
(1)按钮的点击实现灯亮/灭
最终实现:当点击按钮并松开的时候,实现灯亮,再点击然后松开的时候,实现灯灭,即不断的点击切换灯的状态。(这就不是之前的长按了)

①连接电路


②初始化板载LED和按钮
初始化按钮,其实就是初始化单片机的随便一个正常的GPIO的引脚,初始化为输入上拉模式;
初始化板子上的LED,其实就是将指定的GPIO的13引脚初始化为输出开漏模式;
③按钮程序的基本原理(核心仍为0亮/1灭)
这里主要的难点是当按钮被点击后,你松开按钮的一瞬间让灯实现状态的转换。
所以需要获取松开按钮的指令,核心为0亮/1灭,所以使用两变量存储状态的变化,当变化发送,并且是信号从0变为1,表示松开按钮了,那就向板载灯发送对应的信号。

这里逻辑很简单,就是默认是按钮松开的,所以默认是1的信号,然后不断的读当前的输入寄存器的信号,当发生变化了,就:
首先判断当前的变化是松开还是按下,我们这里实现的是按钮松开去实现灯的变化,所以选择第一个去实现。
之后在当前的if条件里面去切换亮灭状态。(这里有个小难点,你不知道当前的灯的状态是啥,所以你不好控制让他亮还是灭,所以这里使用GPIO自带的读取输出寄存器的值(读取最近一次发送的值)接口去读取他之前是的状态是啥,如果之前的输出寄存器是1(灭),那么就写0让他亮,相反同理。)


④按钮消抖的原理
通过前面的实验会进行基本的实现,但是会出现一个问题,就是按钮有时候按下去失灵,这就是抖动出现的毛刺现象。
比如当按下的时候,会出现不稳定的波动毛刺,既而导致刚按下或者松开的一会,会有高低电压的抖动,而失灵也正是因为此时你刚按下的时候,他一开始抖动造成的0-1-0-1-0这种,那因为一开始这种抖动变化的很快,导致人眼只能看见一开始的0和最后抖完的0,所以就相当于没有变化,即失灵现象。
要解决这种,直接加个延迟就行。


三、按钮封装的操作-点击,双击,多击,长按
(1)实验结果
使用串口调试助手实现,按钮的多种操作实现串口助手的数字变化。(单机-数字+1,双击数字清零,长按数字持续++)

(2)搭建电路

(3)串口的初始化
串口初始化,就两步
(1)IO引脚的初始化
(2)自身模块的初始化

(4)按钮初始化
封装函数里面有这个button的封装,直接用就行,其中有按钮的Init,具体的功能为:
实现了按钮的初始化,同样是两个参数:
一个是名称(需要自己定义一个变量去传地址进去)
一个是结构体(内部的那几个可以都默认为0)
注意:这里按钮的初始化里面没有初始化引脚为IPU即输入上拉模式,是因为在这个初始化参数里面默认实现了,所以这里的结构体只需提供GPIO名称和引脚编号

(5)进程函数(必须要有的)
该函数需要放到main的while里面生效。
原因就是这个函数内部就是前面实现的那个按钮点击实现灯亮/灭的操作,这里去掉了灯的亮灭指令保留按钮的按或者释放的检测功能。
当按钮按下/释放的时候,会自动执行(按钮按下/或者按钮释放的回调函数)以及一个按钮轮询的一个函数,这个函数里面就根据检测到按钮的实现情况去动态的调用你自己实现的按钮点击和按钮长按的回调函数


四、最终代码
#include "stm32f10x.h"
#include "Delay.h"
#include "button.h"
#include "usart.h"
uint8_t value=0;
void App_LED_Init(void);
void App_Button_Init(void);
Button_TypeDef button={0};
int main(void)
{
App_LED_Init();
App_Button_Init();
// uint8_t pdata[]={0,1,2};
// My_USART_SendBytes(USART1,pdata,3);
while(1)
{
My_Button_Proc(&button);
}
}
void button_clicked_cb(uint8_t click){
if(click==1){
value++;
My_USART_SendBytes(USART1,&value,1);
}else if(click==2){
value=0;
My_USART_SendBytes(USART1,&value,1);
}
}
void button_long_pressed_cb(uint8_t click){
value++;
My_USART_SendBytes(USART1,&value,1);
}
void App_Button_Init(void){
//按钮初始化
Button_InitTypeDef Button_InitStruct={0};
Button_InitStruct.GPIOx=GPIOA;
Button_InitStruct.GPIO_Pin=GPIO_Pin_1;
Button_InitStruct.LongPressTickInterval=10;
Button_InitStruct.LongPressTime=1000;
Button_InitStruct.ClickInterval=100;
Button_InitStruct.button_clicked_cb=button_clicked_cb;
Button_InitStruct.button_long_pressed_cb=button_long_pressed_cb;
My_Button_Init(&button,&Button_InitStruct);
}
void App_LED_Init(void){
//LED灯的初始化
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitStruct={0};
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_2MHz;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_Init(GPIOA,&GPIO_InitStruct);//初始化引脚0
// //按钮初始化
// GPIO_InitStruct.GPIO_Pin=GPIO_Pin_1;
// GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU;
//
// GPIO_Init(GPIOA,&GPIO_InitStruct);//初始化引脚1
//串口的初始化
//下面的两个初始化是USART的tx和rx在GPIO引脚的重映射
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef gpio_initStruct2={0};
gpio_initStruct2.GPIO_Pin=GPIO_Pin_9;
gpio_initStruct2.GPIO_Mode=GPIO_Mode_AF_PP;
gpio_initStruct2.GPIO_Speed=GPIO_Speed_10MHz;
GPIO_Init(GPIOA,&gpio_initStruct2);
gpio_initStruct2.GPIO_Pin=GPIO_Pin_10;
gpio_initStruct2.GPIO_Mode=GPIO_Mode_IPU;
GPIO_Init(GPIOA,&gpio_initStruct2);
//USART的五大初始化
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
USART_InitTypeDef unit_initStruct={0};
unit_initStruct.USART_BaudRate=115200;
unit_initStruct.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;
unit_initStruct.USART_WordLength=USART_WordLength_8b ;
unit_initStruct.USART_StopBits=USART_StopBits_1;
unit_initStruct.USART_Parity=USART_Parity_No;
USART_Init(USART1,&unit_initStruct);
//开启USART
USART_Cmd(USART1,ENABLE);
}
更多推荐



所有评论(0)