0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

HAL库GPIO输入模式在cubemx中的配置

jf_L18yujSQ 来源:小飞哥玩嵌入式 作者:小飞哥玩嵌入式 2022-11-02 09:33 次阅读

HAL库GPIO输入模式在cubemx中的配置

上节课程介绍了GPIO输出模式的配置,包括修改IO标签,选择GPIO模式、GPIO上下拉等,本节输入模式有很多相同之处,节省时间,小飞哥就简单介绍一下

GPIO选择与配置

依然是先来看看我们的Alios 开发板上的按键硬件连接,总共有3个用户按键,分别挂在GPIOE11、GPIOE14和GPIOE10上,连接方式采用的是低电平有效,也即是,按键按下之后,MCU检测到的电平为低电平,松开之后检测为高电平,外部上拉电阻4.7K2dfb7494-5a43-11ed-a3b6-dac502259ad0.png2e12674e-5a43-11ed-a3b6-dac502259ad0.png接下来,我们只需要在cubemx对这3个GPIO进行配置即可,工程在上一节内容上继续添加,打开上一节的cubemx工程,选择PE14引脚,选择引脚模式为输入模式2e490ace-5a43-11ed-a3b6-dac502259ad0.png然后修改标签为USR_KEY2,其他两个按键一样的配置方法,3个按键配置完成之后如下图所示:2e5ccc76-5a43-11ed-a3b6-dac502259ad0.png接下来依然是对GPIO的模式、配置进行修改,这里需要注意一点就是GPIO的上下拉配置,不要瞎选,这个一定是跟硬件相关的,比如本次硬件设计,空闲时是保持高电平的,那么配置上拉是比较合适的,但是呢,此时外部已经有了上拉电阻,我们内部上拉就不是很有必要了,也可以配置为不上拉也不下拉,但是配置为下拉一定是不合适的,可能会引起信号的误动作,功耗的增加等不必要的麻烦,所以说,cubemx配置只是为你减轻了重复性搬运工作,电路工作原理必须了然于胸,选择最为合适的配置2e83dc62-5a43-11ed-a3b6-dac502259ad0.png配置比较简单,我们此次采用的是轮询获取GPIO状态的方法来实现按键,当然也可以采用外部中断的方式,对于普通按键来讲,不是很有必要,轮询GPIO状态即可

HAL库GPIO输入模式操作详解与结构介绍

接下来,我们生成代码即可2ea319ec-5a43-11ed-a3b6-dac502259ad0.png打开工程之后,我们发现上一节配置的输出IO和这一节的输入IO是放在一起的,cubemx生成代码的规则是把同一类外设统一放在相应的模块初始化代码中,宏定义统一放在main.h中如果能够接受这个布局的话是没有问题的,如果不能还是比较麻烦的2ecb7b8a-5a43-11ed-a3b6-dac502259ad0.png2f2a6686-5a43-11ed-a3b6-dac502259ad0.png输入模式相关的GPIO API也比较少,只涉及到关于GPIO操作的API:

/*Initializationandde-initializationfunctions*****************************/
voidHAL_GPIO_Init(GPIO_TypeDef*GPIOx,GPIO_InitTypeDef*GPIO_Init);
voidHAL_GPIO_DeInit(GPIO_TypeDef*GPIOx,uint32_tGPIO_Pin);

/**
*@}
*/

/**@addtogroupGPIO_Exported_Functions_Group2IOoperationfunctions
*@{
*/

/*IOoperationfunctions*****************************************************/
GPIO_PinStateHAL_GPIO_ReadPin(GPIO_TypeDef*GPIOx,uint16_tGPIO_Pin);

如何使用呢?

参数GPIO_TypeDef *GPIOx可以是GPIO组的地址:

#defineGPIOA((GPIO_TypeDef*)GPIOA_BASE)
#defineGPIOB((GPIO_TypeDef*)GPIOB_BASE)
#defineGPIOC((GPIO_TypeDef*)GPIOC_BASE)
#defineGPIOD((GPIO_TypeDef*)GPIOD_BASE)
#defineGPIOE((GPIO_TypeDef*)GPIOE_BASE)
#defineGPIOF((GPIO_TypeDef*)GPIOF_BASE)
#defineGPIOG((GPIO_TypeDef*)GPIOG_BASE)
#defineGPIOH((GPIO_TypeDef*)GPIOH_BASE)
#defineGPIOI((GPIO_TypeDef*)GPIOI_BASE)
参数GPIO_Pin可以是GPIO的引脚号:

#defineGPIO_PIN_0((uint16_t)0x0001)/*Pin0selected*/
#defineGPIO_PIN_1((uint16_t)0x0002)/*Pin1selected*/
#defineGPIO_PIN_2((uint16_t)0x0004)/*Pin2selected*/
#defineGPIO_PIN_3((uint16_t)0x0008)/*Pin3selected*/
#defineGPIO_PIN_4((uint16_t)0x0010)/*Pin4selected*/
#defineGPIO_PIN_5((uint16_t)0x0020)/*Pin5selected*/
#defineGPIO_PIN_6((uint16_t)0x0040)/*Pin6selected*/
#defineGPIO_PIN_7((uint16_t)0x0080)/*Pin7selected*/
#defineGPIO_PIN_8((uint16_t)0x0100)/*Pin8selected*/
#defineGPIO_PIN_9((uint16_t)0x0200)/*Pin9selected*/
#defineGPIO_PIN_10((uint16_t)0x0400)/*Pin10selected*/
#defineGPIO_PIN_11((uint16_t)0x0800)/*Pin11selected*/
#defineGPIO_PIN_12((uint16_t)0x1000)/*Pin12selected*/
#defineGPIO_PIN_13((uint16_t)0x2000)/*Pin13selected*/
#defineGPIO_PIN_14((uint16_t)0x4000)/*Pin14selected*/
#defineGPIO_PIN_15((uint16_t)0x8000)/*Pin15selected*/
#defineGPIO_PIN_All((uint16_t)0xFFFF)/*Allpinsselected*/

输入模式返回值为获取到的GPIO状态,也即是高低电平状态,在没有按键按下的时候,返回GPIO_PIN_SET,按键按下时候,返回GPIO_PIN_SET

@endverbatim
*@{
*/

/**
*@briefReadthespecifiedinputportpin.
*@paramGPIOxwherexcanbe(A..H)toselecttheGPIOperipheralforSTM32L4family
*@paramGPIO_Pinspecifiestheportbittoread.
*ThisparametercanbeanycombinationofGPIO_Pin_xwherexcanbe(0..15).
*@retvalTheinputportpinvalue.
*/
GPIO_PinStateHAL_GPIO_ReadPin(GPIO_TypeDef*GPIOx,uint16_tGPIO_Pin)
{
GPIO_PinStatebitstatus;

/*Checktheparameters*/
assert_param(IS_GPIO_PIN(GPIO_Pin));

if((GPIOx->IDR&GPIO_Pin)!=0x00u)
{
bitstatus=GPIO_PIN_SET;
}
else
{
bitstatus=GPIO_PIN_RESET;
}
returnbitstatus;
}

GPIO输入模式的简单测试

接下来在之前led的任务中,对按键状态进行测试,这里涉及到按键的消抖,所谓“消抖”就是:2f53b0a4-5a43-11ed-a3b6-dac502259ad0.png当检测到按键状态变化时,不是立即去响应动作,而是先等待闭合或断开稳定后再进行处理。即为按键消抖按键消抖:可分为硬件消抖和软件消抖。

硬件消抖就是在按键上并联一个电容,如图 8-11 所示,利用电容的充放电特性来对抖动过程中产生的电压毛刺进行平滑处理,从而实现消抖。

但实际应用中,这种方式的效果往往不是很好,而且还增加了成本和电路复杂度,所以实际中使用的并不多。绝大多数情况下,我们是用软件即程序来实现消抖的

延时消抖

最简单的消抖原理,就是当检测到按键状态变化后,先等待一个 10ms 左右的延时时间,让抖动消失后再进行一次按键状态检测,如果与刚才检测到的状态相同,就可以确认按键已经稳定的动作了

staticvoidrt_led1_flash_entry(void*parameter)
{
for(;;)
{
if(!HAL_GPIO_ReadPin(USR_KEY1_GPIO_Port,USR_KEY1_Pin))
{
rt_thread_mdelay(100);
if(!HAL_GPIO_ReadPin(USR_KEY1_GPIO_Port,USR_KEY1_Pin))//消抖
{
rt_kprintf("Key1ispresseded!
");
}
}
if(!HAL_GPIO_ReadPin(USR_KEY2_GPIO_Port,USR_KEY2_Pin))
{
rt_thread_mdelay(100);
if(!HAL_GPIO_ReadPin(USR_KEY2_GPIO_Port,USR_KEY2_Pin))//消抖
{
rt_kprintf("Key2ispresseded!
");
}
}
if(!HAL_GPIO_ReadPin(USR_KEY3_GPIO_Port,USR_KEY3_Pin))
{
rt_thread_mdelay(100);
if(!HAL_GPIO_ReadPin(USR_KEY3_GPIO_Port,USR_KEY3_Pin))//消抖
{
rt_kprintf("Key3ispresseded!
");
}
}
}
}

测试结果:2f9441fa-5a43-11ed-a3b6-dac502259ad0.png

324fdfbc-5a43-11ed-a3b6-dac502259ad0.png

多功能按键移植

上面是简单的按键状态获取,实际中,一个项目可能按键有限但同时又要实现复杂的功能切换,那么按键的功能如果很单一的话,就不能够满足需求,接下来,小飞哥带大家一起移植一个很不错的多功能按键框架,代码来源是github的jiejieTop

源码地址:GitHub - jiejieTop/ButtonDrive: 纯C语言实现的一个按键驱动,可移植性强,支持单双击、连按、连按释放、长按;采用回调处理按键事件(自定义消抖时间),使用只需3步,1:创建按键,2:按键事件与回调处理函数链接映射。然后周期检查按键。326db8b6-5a43-11ed-a3b6-dac502259ad0.png我们下载源码进行移植,把文件夹里面的这些文件,我们移植到自己的文件目录,下载文件中包含的main.c中是一个完整的按键初始化,实现,大家可以看看就知道如何使用了3296d3c2-5a43-11ed-a3b6-dac502259ad0.png32b0e5e6-5a43-11ed-a3b6-dac502259ad0.png下面小飞哥就带大家来看看如何移植到自己的系统里面

![e7d83ed083514e07e330211e338b33b7.png](en-resource://datab331bf5d4-5a43-11ed-a3b6-dac502259ad0.png可以把memset,printff替换为rt-thread的驱动,当然也可以不关注341080c2-5a43-11ed-a3b6-dac502259ad0.png3426be6e-5a43-11ed-a3b6-dac502259ad0.png重新编译一下,刚才的警告已经消失了345549e6-5a43-11ed-a3b6-dac502259ad0.png然后我们看看如何实现这个多功能按键:

先来看看一些配置项宏定义,位域、结构体、回调函数,面向对象的一套东西都在,是很适合学习的,有关于短按、长按、单击、双击等等的配置,我们根据自己的需要配置即可

#defineBTN_NAME_MAX32//名字最大为32字节

/*按键消抖时间40ms,建议调用周期为20ms
只有连续检测到40ms状态不变才认为有效,包括弹起和按下两种事件
*/

#defineCONTINUOS_TRIGGER0//是否支持连续触发,连发的话就不要检测单双击与长按了

/*是否支持单击&双击同时存在触发,如果选择开启宏定义的话,单双击都回调,只不过单击会延迟响应,
因为必须判断单击之后是否触发了双击否则,延迟时间是双击间隔时间 BUTTON_DOUBLE_TIME。
而如果不开启这个宏定义,建议工程中只存在单击/双击中的一个,否则,在双击响应的时候会触发一次单击,
因为双击必须是有一次按下并且释放之后才产生的*/
#defineSINGLE_AND_DOUBLE_TRIGGER1

/*是否支持长按释放才触发,如果打开这个宏定义,那么长按释放之后才触发单次长按,
否则在长按指定时间就一直触发长按,触发周期由BUTTON_LONG_CYCLE决定*/
#defineLONG_FREE_TRIGGER0

#defineBUTTON_DEBOUNCE_TIME2//消抖时间(n-1)*调用周期
#defineBUTTON_CONTINUOS_CYCLE1//连按触发周期时间(n-1)*调用周期
#defineBUTTON_LONG_CYCLE1//长按触发周期时间(n-1)*调用周期
#defineBUTTON_DOUBLE_TIME20//双击间隔时间(n-1)*调用周期建议在200-600ms
#defineBUTTON_LONG_TIME50/*持续n秒((n-1)*调用周期ms),认为长按事件*/

#defineTRIGGER_CB(event)
if(btn->CallBack_Function[event])
btn->CallBack_Function[event]((Button_t*)btn)

typedefvoid(*Button_CallBack)(void*);/*按键触发回调函数,需要用户实现*/



typedefenum{
BUTTON_DOWM=0,
BUTTON_UP,
BUTTON_DOUBLE,
BUTTON_LONG,
BUTTON_LONG_FREE,
BUTTON_CONTINUOS,
BUTTON_CONTINUOS_FREE,
BUTTON_ALL_RIGGER,
number_of_event,/*触发回调的事件*/
NONE_TRIGGER
}Button_Event;

/*
每个按键对应1个全局的结构体变量。
其成员变量是实现滤波和多种按键状态所必须的
*/
typedefstructbutton
{
/*下面是一个函数指针,指向判断按键手否按下的函数*/
uint8_t(*Read_Button_Level)(void);/*读取按键电平函数,需要用户实现*/

charName[BTN_NAME_MAX];

uint8_tButton_State:4;/*按键当前状态(按下还是弹起)*/
uint8_tButton_Last_State:4;/*上一次的按键状态,用于判断双击*/
uint8_tButton_Trigger_Level:2;/*按键触发电平*/
uint8_tButton_Last_Level:2;/*按键当前电平*/

uint8_tButton_Trigger_Event;/*按键触发事件,单击,双击,长按等*/

Button_CallBackCallBack_Function[number_of_event];

uint8_tButton_Cycle;/*连续按键周期*/

uint8_tTimer_Count;/*计时*/
uint8_tDebounce_Time;/*消抖时间*/

uint8_tLong_Time;/*按键按下持续时间*/

structbutton*Next;

}Button_t;

然后看看如何使用API,我们只需要实现GPIO的状态获取、创建按键对象、编写回调函数即可,在任务中轮询按键状态,移植起来是非常方便的

#defineKEY_ON0
/*Privatemacro-------------------------------------------------------------*/

/*Privatevariables---------------------------------------------------------*/
Button_tButton1;
/*Privatefunctionprototypes-----------------------------------------------*/
staticuint8_trt_read_key1(void)
{
returnHAL_GPIO_ReadPin(USR_KEY1_GPIO_Port,USR_KEY1_Pin);
}

staticvoidBtn1_Dowm_CallBack(void*btn)
{
PRINT_INFO("Button1单击!");
}

staticvoidBtn1_Double_CallBack(void*btn)
{
PRINT_INFO("Button1双击!");
}

staticvoidBtn1_Long_CallBack(void*btn)
{
PRINT_INFO("Button1长按!");
}

staticvoidBtn1_Continuos_CallBack(void*btn)
{
PRINT_INFO("Button1连按!");
}
staticvoidBtn1_ContinuosFree_CallBack(void*btn)
{
PRINT_INFO("Button1连按释放!");
}
/*Privateusercode---------------------------------------------------------*/

/**
*@functionrt_ledflash_entry
*@author:小飞哥玩嵌入式-小飞哥
*@TODO:LED控制线程
*@param:
*@return:NULL
*/
staticvoidrt_led1_flash_entry(void*parameter)
{

Button_Create("Button1",
&Button1,
rt_read_key1,
KEY_ON);
Button_Attach(&Button1,BUTTON_DOWM,Btn1_Dowm_CallBack);//单击
Button_Attach(&Button1,BUTTON_DOUBLE,Btn1_Double_CallBack);//双击
Button_Attach(&Button1,BUTTON_CONTINUOS,Btn1_Continuos_CallBack);//连按
Button_Attach(&Button1,BUTTON_CONTINUOS_FREE,Btn1_ContinuosFree_CallBack);//连按释放
Button_Attach(&Button1,BUTTON_LONG,Btn1_Long_CallBack);

for(;;)
{

Button_Process();//需要周期调用按键处理函数
rt_thread_mdelay(20);
//if(!HAL_GPIO_ReadPin(USR_KEY1_GPIO_Port,USR_KEY1_Pin))
//{
//rt_thread_mdelay(100);
//if(!HAL_GPIO_ReadPin(USR_KEY1_GPIO_Port,USR_KEY1_Pin))//消抖
//{
//rt_kprintf("Key1ispresseded!
");
//}
//}
//if(!HAL_GPIO_ReadPin(USR_KEY2_GPIO_Port,USR_KEY2_Pin))
//{
//rt_thread_mdelay(100);
//if(!HAL_GPIO_ReadPin(USR_KEY2_GPIO_Port,USR_KEY2_Pin))//消抖
//{
//rt_kprintf("Key2ispresseded!
");
//}
//}
//if(!HAL_GPIO_ReadPin(USR_KEY3_GPIO_Port,USR_KEY3_Pin))
//{
//rt_thread_mdelay(100);
//if(!HAL_GPIO_ReadPin(USR_KEY3_GPIO_Port,USR_KEY3_Pin))//消抖
//{
//rt_kprintf("Key3ispresseded!
");
//}
//}
}

}

来看一下测试效果:348f5564-5a43-11ed-a3b6-dac502259ad0.png

审核编辑:彭静
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 硬件
    +关注

    关注

    11

    文章

    3408

    浏览量

    66534
  • GPIO
    +关注

    关注

    16

    文章

    1217

    浏览量

    52485
  • 低电平
    +关注

    关注

    1

    文章

    117

    浏览量

    13362

原文标题:03-HAL库GPIO输入与多功能按键实现

文章出处:【微信号:小飞哥玩嵌入式,微信公众号:小飞哥玩嵌入式】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    HALGPIOcubemx配置及注意事项

    上节课程我们介绍了cubemx的界面、时钟配置以及如何新建工程等,本节咱们就继续进行程序员届的“hello world”-“点灯”。
    的头像 发表于 10-19 09:10 1733次阅读

    使用STM32 HAL进行GPIO控制的实例

    基于STM32微控制器的嵌入式系统开发GPIO(GeneralPurposeInput/Output)控制是其中最基本、最常见的操作之一。通过使用STM32的HAL
    的头像 发表于 12-21 15:22 3748次阅读

    使用CUBEMX配置hal输入捕获

    之前有使用标准配置的,具体可以看我之前的博客这个项目是使用CUBEMX配置hal来写,相
    发表于 01-06 07:23

    STM32CubeMXHAL对F103和F411的GPIO配置和使用方法

    文章目录STM32CubeMX第一章GPIO前言一、GPIO的工作模式二、使用步骤1.引入库2.读入数据总结前言  本文使用STM32CubeMX
    发表于 01-26 06:28

    STM32CubeMX 配置STM32F407 实现HAL延时微妙方案

    STM32CubeMX 配置STM32F407 实现HAL延时微妙方案
    发表于 11-24 20:51 20次下载
    STM32<b class='flag-5'>CubeMX</b> <b class='flag-5'>配置</b>STM32F407 实现<b class='flag-5'>HAL</b><b class='flag-5'>库</b>延时微妙方案

    基于hal的stm32f411re的GPIO输出模式下电平的读取

    基于hal的stm32f411re的GPIO输出模式下电平的读取1.硬件的配置GPIO的参数
    发表于 11-29 16:06 5次下载
    基于<b class='flag-5'>hal</b><b class='flag-5'>库</b>的stm32f411re的<b class='flag-5'>GPIO</b>输出<b class='flag-5'>模式</b>下电平的读取

    STM32CubeMX应用教程 第一章 GPIO

       Nucleo-F411RE文章目录STM32CubeMX第一章 GPIO前言一、GPIO的工作模式二、使用步骤1.引入库2.读入数据总结前言  本文使用STM32
    发表于 12-02 13:51 9次下载
    STM32<b class='flag-5'>CubeMX</b>应用教程 第一章 <b class='flag-5'>GPIO</b>

    HALGPIO八种工作模式

    众所周知,STM32的GPIO的工作模式有八种,但是打开HAL发现,有12可以供自己设置。先不要懵,下面解释一下这12种工作
    发表于 12-05 13:06 8次下载
    <b class='flag-5'>HAL</b><b class='flag-5'>库</b>的<b class='flag-5'>GPIO</b>八种工作<b class='flag-5'>模式</b>

    【STM32】标准HAL对照学习教程三--使用库函数配置GPIO点亮LED灯

    【STM32】标准HAL对照学习教程三--使用库函数配置GPIO点亮LED灯一、前言二、准备工作三、LED硬件电路四、使用标准
    发表于 12-05 14:06 15次下载
    【STM32】标准<b class='flag-5'>库</b>与<b class='flag-5'>HAL</b><b class='flag-5'>库</b>对照学习教程三--使用库函数<b class='flag-5'>配置</b><b class='flag-5'>GPIO</b>点亮LED灯

    00_STM32F4学习_HAL_GPIO函数

    00_STM32F4学习_HAL_GPIO函数最近重学STM32,打算从HAL+STM32CubeM
    发表于 12-05 14:21 12次下载
    00_STM32F4学习_<b class='flag-5'>HAL</b><b class='flag-5'>库</b>_<b class='flag-5'>GPIO</b>函数

    STM32 CubeMX+HAL基本操作

    STM32 CubeMX+HAL基本操作
    发表于 12-07 11:21 50次下载
    STM32 <b class='flag-5'>CubeMX+HAL</b><b class='flag-5'>库</b>基本操作

    基于STM32CubeMX——HAL开发的串口通讯(DMA模式

    的是F103R6Tx的芯片。然后第一步选择SYS里面的debug模式,如果用HAL不进行SWD或JTAG配置,单片机只能进行下载一次程序,要进行第二次或更多次程序下载,需要按复位键(
    发表于 12-24 18:48 13次下载
    基于STM32<b class='flag-5'>CubeMX</b>——<b class='flag-5'>HAL</b><b class='flag-5'>库</b>开发的串口通讯(DMA<b class='flag-5'>模式</b>)

    STM32 HAL CubeMX教程(五)串口通信基础

    STM32 HAL CubeMX教程(五)串口通信基础串口通信简介CubeMX配置初始化程序分析程序编写UART: 通用异步收发传输器(U
    发表于 12-24 18:49 12次下载
    STM32 <b class='flag-5'>HAL</b><b class='flag-5'>库</b> <b class='flag-5'>CubeMX</b>教程(五)串口通信基础

    STM32 HAL CUBEMX配置 ADC采集

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档文章目录STM32 HAL CUBEMX配置 ADC采集软硬件型号1.单通道不定时任意时刻采集信号
    发表于 12-27 18:57 25次下载
    STM32 <b class='flag-5'>HAL</b><b class='flag-5'>库</b> <b class='flag-5'>CUBEMX</b><b class='flag-5'>配置</b> ADC采集

    【STM32】标准HAL对照学习教程特别篇--GPIO详讲

    【STM32】SMT32标准HAL对照学习教程特别篇--GPIO详讲一、前言二、GPIO简介1、定义2、分类3、复用三、
    发表于 01-13 16:12 12次下载
    【STM32】标准<b class='flag-5'>库</b>与<b class='flag-5'>HAL</b><b class='flag-5'>库</b>对照学习教程特别篇--<b class='flag-5'>GPIO</b>详讲