野火F1开发板STM32案例-MultiButton移植

硬件平台

  1. 野火STM32F103ZET6 霸道V2开发板
  2. 正点原子F1系列开发板

软件平台

  1. Keil MDK 5.31
  2. 串口调试助手

MultiButton

简介

开源项目 MultiButton,一个小巧简单易用的事件驱动型按键驱动模块,作者 0x1abin。
这个项目非常精简,只有两个文件,可无限量扩展按键,按键事件的回调异步处理方式可以简化程序结构,去除冗余的按键处理硬编码,让你的按键业务逻辑更清晰。
MultiButton 是一个小巧简单易用的事件驱动型按键驱动模块,可无限量扩展按键,按键事件的回调异步处理方式可以简化你的程序结构,去除冗余的按键处理硬编码,让你的按键业务逻辑更清晰。

使用方法

1.先申请一个按键结构

struct Button button1;

2.初始化按键对象,绑定按键的GPIO电平读取接口read_button_pin() ,后一个参数设置有效触发电平

button_init(&button1, read_button_pin, 0);

3.注册按键事件

button_attach(&button1, SINGLE_CLICK, Callback_SINGLE_CLICK_Handler);
button_attach(&button1, DOUBLE_CLICK, Callback_DOUBLE_Click_Handler);
...

4.启动按键

button_start(&button1);

5.设置一个5ms间隔的定时器循环调用后台处理函数

while(1) {...if(timer_ticks == 5) {timer_ticks = 0;button_ticks();}
}

特性

MultiButton 使用C语言实现,基于面向对象方式设计思路,每个按键对象单独用一份数据结构管理:

struct Button {uint16_t ticks;uint8_t  repeat: 4;uint8_t  event : 4;uint8_t  state : 3;uint8_t  debounce_cnt : 3; uint8_t  active_level : 1;uint8_t  button_level : 1;uint8_t  (*hal_button_Level)(void);BtnCallback  cb[number_of_event];struct Button* next;
};

这样每个按键使用单向链表相连,依次进入 button_handler(struct Button* handle) 状态机处理,所以每个按键的状态彼此独立。

按键事件

事件 说明
PRESS_DOWN 按键按下,每次按下都触发
PRESS_UP 按键弹起,每次松开都触发
PRESS_REPEAT 重复按下触发,变量repeat计数连击次数
SINGLE_CLICK 单击按键事件
DOUBLE_CLICK 双击按键事件
LONG_RRESS_START 达到长按时间阈值时触发一次
LONG_PRESS_HOLD 长按期间一直触发

官方Examples

#include "button.h"struct Button btn1;int read_button1_GPIO()
{return HAL_GPIO_ReadPin(B1_GPIO_Port, B1_Pin);
}int main()
{button_init(&btn1, read_button1_GPIO, 0);button_attach(&btn1, PRESS_DOWN,       BTN1_PRESS_DOWN_Handler);button_attach(&btn1, PRESS_UP,         BTN1_PRESS_UP_Handler);button_attach(&btn1, PRESS_REPEAT,     BTN1_PRESS_REPEAT_Handler);button_attach(&btn1, SINGLE_CLICK,     BTN1_SINGLE_Click_Handler);button_attach(&btn1, DOUBLE_CLICK,     BTN1_DOUBLE_Click_Handler);button_attach(&btn1, LONG_RRESS_START, BTN1_LONG_RRESS_START_Handler);button_attach(&btn2, LONG_PRESS_HOLD,  BTN1_LONG_PRESS_HOLD_Handler);button_start(&btn1);//make the timer invoking the button_ticks() interval 5ms.//This function is implemented by yourself.__timer_start(button_ticks, 0, 5); while(1) {}
}
void BTN1_PRESS_DOWN_Handler(void* btn)
{//do something...
}void BTN1_PRESS_UP_Handler(void* btn)
{//do something...
}

野火F1开发板STM32案例-MultiButton移植

MAIN.C

/********************************************************************************* @file    main.c* 实验平台:野火 F103-霸道 STM32 开发板 ******************************************************************************* 第三方库文件导入  START THE FILE*******************************************************************************/
//基本库
#include "stm32f10x.h"
#include "bsp_SysTick.h"
#include "bsp_usart.h"
#include <stdio.h>
#include "delay.h"
//扩展库
#include "multi_button.h"//按键驱动/********************************************************************************
变量定义
*********************************************************************************/
struct Button button1;
//  引脚定义
#define    KEY1_GPIO_CLK     RCC_APB2Periph_GPIOA
#define    KEY1_GPIO_PORT    GPIOA
#define    KEY1_GPIO_PIN         GPIO_Pin_0#define    KEY2_GPIO_CLK     RCC_APB2Periph_GPIOC
#define    KEY2_GPIO_PORT    GPIOC
#define    KEY2_GPIO_PIN         GPIO_Pin_13/********************************************************************************
函数部分
*********************************************************************************/
void KEY_Init(void) //IO初始化
{GPIO_InitTypeDef GPIO_InitStructure;/*开启按键端口的时钟*/RCC_APB2PeriphClockCmd(KEY1_GPIO_CLK|KEY2_GPIO_CLK,ENABLE);//选择按键KEY1的引脚 GPIO_InitStructure.GPIO_Pin = KEY1_GPIO_PIN; // 设置按键的引脚为浮空输入GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //使用结构体初始化按键GPIO_Init(KEY1_GPIO_PORT, &GPIO_InitStructure);//选择按键的引脚GPIO_InitStructure.GPIO_Pin = KEY2_GPIO_PIN; //设置按键的引脚为浮空输入GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //使用结构体初始化按键GPIO_Init(KEY2_GPIO_PORT, &GPIO_InitStructure);
}
//按键状态读取接口  按键输入模式 ReadInputDataBit
uint8_t read_button1_GPIO()
{return GPIO_ReadInputDataBit(KEY1_GPIO_PORT, KEY1_GPIO_PIN);
}
//按键1按下事件回调函数
void btn1_press_down_Handler(void* btn)
{printf("---> key1 press down! <---\r\n");
}
//按键1松开事件回调函数
void btn1_press_up_Handler(void* btn)
{printf("***> key1 press up! <***\r\n");
}void button_callback(void *button)
{uint32_t btn_event_val; btn_event_val = get_button_event((struct Button *)button); switch(btn_event_val){case PRESS_DOWN:printf("---> key1 press down! <---\r\n"); break; case PRESS_UP: printf("***> key1 press up! <***\r\n");break; case PRESS_REPEAT: printf("---> key1 press repeat! <---\r\n");break; case SINGLE_CLICK: printf("---> key1 single click! <---\r\n");break; case DOUBLE_CLICK: printf("***> key1 double click! <***\r\n");break; case LONG_PRESS_START: printf("---> key1 long press start! <---\r\n");break; case LONG_PRESS_HOLD: printf("***> key1 long press hold! <***\r\n");break; }
}/*** @brief  HardWare_Iint* @param  无* @retval 无*/ void HardWare_Iint(void)
{SysTick_Init();delay_init();KEY_Init();}
/*** @brief  主函数* @param  无* @retval 无*/
int main(void)
{   /* 硬件端口初始化 */HardWare_Iint(); printf("MultiButton Test...\r\n");//初始化按键对象button_init(&button1, read_button1_GPIO, 0);//注册按钮事件回调函数button_attach(&button1, PRESS_DOWN,       button_callback);button_attach(&button1, PRESS_UP,         button_callback);//启动按键button_start(&button1);while(1){button_ticks();delay_ms(5);} }

multi_button.c

/** Copyright (c) 2016 Zibin Zheng <znbin@qq.com>* All rights reserved*/#include "multi_button.h"#define EVENT_CB(ev)   if(handle->cb[ev])handle->cb[ev]((Button*)handle)//button handle list head.
static struct Button* head_handle = NULL;/*** @brief  Initializes the button struct handle.* @param  handle: the button handle strcut.* @param  pin_level: read the HAL GPIO of the connet button level.* @param  active_level: pressed GPIO level.* @retval None*/
void button_init(struct Button* handle, uint8_t(*pin_level)(), uint8_t active_level)
{memset(handle, 0, sizeof(struct Button));handle->event = (uint8_t)NONE_PRESS;handle->hal_button_Level = pin_level;handle->button_level = handle->hal_button_Level();handle->active_level = active_level;
}/*** @brief  Attach the button event callback function.* @param  handle: the button handle strcut.* @param  event: trigger event type.* @param  cb: callback function.* @retval None*/
void button_attach(struct Button* handle, PressEvent event, BtnCallback cb)
{handle->cb[event] = cb;
}/*** @brief  Inquire the button event happen.* @param  handle: the button handle strcut.* @retval button event.*/
PressEvent get_button_event(struct Button* handle)
{return (PressEvent)(handle->event);
}/*** @brief  Button driver core function, driver state machine.* @param  handle: the button handle strcut.* @retval None*/
void button_handler(struct Button* handle)
{uint8_t read_gpio_level = handle->hal_button_Level();//ticks counter working..if((handle->state) > 0) handle->ticks++;/*------------button debounce handle---------------*/if(read_gpio_level != handle->button_level) { //not equal to prev one//continue read 3 times same new level changeif(++(handle->debounce_cnt) >= DEBOUNCE_TICKS) {handle->button_level = read_gpio_level;handle->debounce_cnt = 0;}} else { //leved not change ,counter reset.handle->debounce_cnt = 0;}/*-----------------State machine-------------------*/switch (handle->state) {case 0:if(handle->button_level == handle->active_level) {   //start press downhandle->event = (uint8_t)PRESS_DOWN;EVENT_CB(PRESS_DOWN);handle->ticks = 0;handle->repeat = 1;handle->state = 1;} else {handle->event = (uint8_t)NONE_PRESS;}break;case 1:if(handle->button_level != handle->active_level) { //released press uphandle->event = (uint8_t)PRESS_UP;EVENT_CB(PRESS_UP);handle->ticks = 0;handle->state = 2;} else if(handle->ticks > LONG_TICKS) {handle->event = (uint8_t)LONG_PRESS_START;EVENT_CB(LONG_PRESS_START);handle->state = 5;}break;case 2:if(handle->button_level == handle->active_level) { //press down againhandle->event = (uint8_t)PRESS_DOWN;EVENT_CB(PRESS_DOWN);handle->repeat++;handle->event = (uint8_t)PRESS_REPEAT;//添加EVENT_CB(PRESS_REPEAT); // repeat hithandle->ticks = 0;handle->state = 3;} else if(handle->ticks > SHORT_TICKS) { //released timeoutif(handle->repeat == 1) {handle->event = (uint8_t)SINGLE_CLICK;EVENT_CB(SINGLE_CLICK);} else if(handle->repeat == 2) {handle->event = (uint8_t)DOUBLE_CLICK;EVENT_CB(DOUBLE_CLICK); // repeat hit}handle->state = 0;}break;case 3:if(handle->button_level != handle->active_level) { //released press uphandle->event = (uint8_t)PRESS_UP;EVENT_CB(PRESS_UP);if(handle->ticks < SHORT_TICKS) {handle->ticks = 0;handle->state = 2; //repeat press} else {handle->state = 0;}}break;case 5:if(handle->button_level == handle->active_level) {//continue hold triggerhandle->event = (uint8_t)LONG_PRESS_HOLD;EVENT_CB(LONG_PRESS_HOLD);} else { //releasdhandle->event = (uint8_t)PRESS_UP;EVENT_CB(PRESS_UP);handle->state = 0; //reset}break;}
}/*** @brief  Start the button work, add the handle into work list.* @param  handle: target handle strcut.* @retval 0: succeed. -1: already exist.*/
int button_start(struct Button* handle)
{struct Button* target = head_handle;while(target) {if(target == handle) return -1;  //already exist.target = target->next;}handle->next = head_handle;head_handle = handle;return 0;
}/*** @brief  Stop the button work, remove the handle off work list.* @param  handle: target handle strcut.* @retval None*/
void button_stop(struct Button* handle)
{struct Button** curr;for(curr = &head_handle; *curr; ) {struct Button* entry = *curr;if (entry == handle) {*curr = entry->next;
//          free(entry);} elsecurr = &entry->next;}
}/*** @brief  background ticks, timer repeat invoking interval 5ms.* @param  None.* @retval None*/
void button_ticks()
{struct Button* target;for(target=head_handle; target; target=target->next) {button_handler(target);}
}

multi_button.h

/** Copyright (c) 2016 Zibin Zheng <znbin@qq.com>* All rights reserved*/#ifndef _MULTI_BUTTON_H_
#define _MULTI_BUTTON_H_#include "stdint.h"
#include "string.h"
#include "stm32f10x.h"
//According to your need to modify the constants.
#define TICKS_INTERVAL    5 //ms
#define DEBOUNCE_TICKS    3 //MAX 8
#define SHORT_TICKS       (300 /TICKS_INTERVAL)
#define LONG_TICKS        (1000 /TICKS_INTERVAL)typedef void (*BtnCallback)(void*);typedef enum {PRESS_DOWN = 0,PRESS_UP,PRESS_REPEAT,SINGLE_CLICK,DOUBLE_CLICK,LONG_PRESS_START,LONG_PRESS_HOLD,number_of_event,NONE_PRESS
}PressEvent;typedef struct Button {uint16_t ticks;uint8_t  repeat : 4;uint8_t  event : 4;uint8_t  state : 3;uint8_t  debounce_cnt : 3;uint8_t  active_level : 1;uint8_t  button_level : 1;uint8_t  (*hal_button_Level)(void);BtnCallback  cb[number_of_event];struct Button* next;
}Button;#ifdef __cplusplus
extern "C" {#endifvoid button_init(struct Button* handle, uint8_t(*pin_level)(), uint8_t active_level);
void button_attach(struct Button* handle, PressEvent event, BtnCallback cb);
PressEvent get_button_event(struct Button* handle);
int  button_start(struct Button* handle);
void button_stop(struct Button* handle);
void button_ticks(void);#ifdef __cplusplus
}
#endif#endif

bsp_usart.c

/********************************************************************************* @file    bsp_usart.c* @version V1.0* @date    2013-xx-xx* @brief   调试用的printf串口,重定向printf到串口******************************************************************************* @attention** 实验平台:野火 F103-霸道 STM32 开发板 * 论坛    :http://www.firebbs.cn* 淘宝    :https://fire-stm32.taobao.com********************************************************************************/ #include "./usart/bsp_usart.h"/*** @brief  USART GPIO 配置,工作参数配置* @param  无* @retval 无*/
void USART_Config(void)
{GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;// 打开串口GPIO的时钟DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_CLK, ENABLE);// 打开串口外设的时钟DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK, ENABLE);// 将USART Tx的GPIO配置为推挽复用模式GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_GPIO_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure);// 将USART Rx的GPIO配置为浮空输入模式GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_GPIO_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);// 配置串口的工作参数// 配置波特率USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE;// 配置 针数据字长USART_InitStructure.USART_WordLength = USART_WordLength_8b;// 配置停止位USART_InitStructure.USART_StopBits = USART_StopBits_1;// 配置校验位USART_InitStructure.USART_Parity = USART_Parity_No ;// 配置硬件流控制USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;// 配置工作模式,收发一起USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;// 完成串口的初始化配置USART_Init(DEBUG_USARTx, &USART_InitStructure);// 使能串口USART_Cmd(DEBUG_USARTx, ENABLE);
}///重定向c库函数printf到串口,重定向后可使用printf函数
int fputc(int ch, FILE *f)
{/* 发送一个字节数据到串口 */USART_SendData(DEBUG_USARTx, (uint8_t) ch);/* 等待发送完毕 */while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET);      return (ch);
}///重定向c库函数scanf到串口,重写向后可使用scanf、getchar等函数
int fgetc(FILE *f)
{/* 等待串口输入数据 */while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_RXNE) == RESET);return (int)USART_ReceiveData(DEBUG_USARTx);
}

bsp_usart.h

#ifndef __USART_H
#define __USART_H#include "stm32f10x.h"
#include <stdio.h>
/** * 串口宏定义,不同的串口挂载的总线和IO不一样,移植时需要修改这几个宏* 1-修改总线时钟的宏,uart1挂载到apb2总线,其他uart挂载到apb1总线* 2-修改GPIO的宏*/// 串口1-USART1
#define  DEBUG_USARTx                   USART1
#define  DEBUG_USART_CLK                RCC_APB2Periph_USART1
#define  DEBUG_USART_APBxClkCmd         RCC_APB2PeriphClockCmd
#define  DEBUG_USART_BAUDRATE           115200
void USART_Config(void);#endif /* __USART_H */

串口打印效果


野火F1开发板STM32案例-MultiButton移植相关推荐

  1. 野火F1开发板STM32案例-USART使用

    野火F1开发板STM32-USART使用 硬件平台 野火STM32F103ZET6 霸道V2开发板 正点原子F1开发板 STM32蓝色板 软件平台 Keil MDK 5.31 串口调试助手 串口配置步 ...

  2. 野火霸道开发板 STM32 keil5 报错:flash download failed-cortex M3解决方法

    起因是我使用野火霸道开发板报错了,报错现象如下图 后来修改后我发现必须要在keil中修改参数如下图 需要在选择好芯片型号 设置使用DAP

  3. [长文干货]MicroPython移植到野火STM32F429开发板

    最近通过参考网上的文章,成功将MicroPython移植到野火STM32F429开发板上,给大家分享一下自己的移植过程,可以作为STM32系列移植MicroPY的参考. 1.移植前准备工作 实验环境: ...

  4. 将linux内核烧进arm板,ARM开发板上uClinux内核移植

    <ARM开发板上uClinux内核移植>由会员分享,可在线阅读,更多相关<ARM开发板上uClinux内核移植(19页珍藏版)>请在人人文库网上搜索. 1.纷傲掌秀悸篷益哑檀扬 ...

  5. 小熊开发板STM32工具出现错误Error:an error occured while uploading data from the virtual partition 0xF1

    小熊开发板STM32工具出现错误Error:an error occured while uploading data from the virtual partition 0xF1 最近在做小熊派开 ...

  6. 【GD32F427开发板试用】FreeRTOS移植工程

    本篇文章来自极术社区与兆易创新组织的GD32F427开发板评测活动,更多开发板试用活动请关注极术社区网站.作者:kings669669 前言 为了方便需要FreeRTOS,附上移植完毕的工程,方便大家 ...

  7. 野火STM32F103开发板使用串口3接收数据并通过串口2发送

    废话不多说先上最终效果图,硬件连接如下所示,野火的开发板在使用串口2和串口3时需要用黄色跳帽如下图连接: 具体代码如下所示: static void NVIC_Configuration(void) ...

  8. STM32F407ZGT6开发板STM32学习设计资料原理图PCB

    STM32F407ZGT6开发板STM32学习设计资料原理图PCB赠AD元件封装库 STM32F407ZGT6开发板STM32学习设计资料原理图PCB赠AD元件封装库id=657509557280&a ...

  9. 【MM32F5270开发板试用】快速移植STM32应用到MM32F5270(以OLED为例)

    本篇文章来自极术社区与灵动组织的MM32F5270开发板评测活动,更多开发板试用活动请关注极术社区网站.作者:@#@ 本篇文章来自极术社区与灵动组织的MM32F5270开发板评测活动,更多开发板试用活 ...

最新文章

  1. python-web自动化-Python+Selenium之expected_conditions:各种判断
  2. php redis 接口,PHP 开发 APP 接口 --Redis篇(示例代码)
  3. PL/SQL Virtual Machine Memory Usage
  4. Angular复习笔记(一)
  5. SpringBoot系列:Spring Boot集成定时任务Quartz
  6. 不再迷惑,无值和 NULL 值
  7. RxSwift之深入解析核心逻辑Observable的底层原理
  8. 联想linux笔记本评测,联想(lenovo)G460AL-ITH Linux笔记本电脑接口评测-ZOL中关村在线...
  9. js aes加密_某高考咨询网js逆向分析笔记
  10. Python获取同目录下json文件内容
  11. 富国基金:基金公司是如何进行数据架构规划与实践的
  12. 数字孪生网络(DTN)架构
  13. 电子口岸客户端控件首次安装
  14. 英雄联盟显示服务器属于高限制,玩英雄联盟出现超出频率限制,该怎么处理?
  15. FineUIMvc随笔(5)UIHelper是个什么梗?
  16. 非平衡电桥电阻计算_非平衡电桥的原理和应用 - 范文中心
  17. 基于宽表的数据建模应用
  18. 易语言安卓模拟器adb模块制作查看模拟器设备adb devices
  19. Java上帝类(Object类)源码总结(1)
  20. 业务架构师如何进阶成长

热门文章

  1. SuperMap Vue-iClient3D-WebGL 使用指南
  2. syncthing下载_syncthing下载-Syncthing-Fork(文件同步)下载v1.1.3.1 安卓版-西西软件下载...
  3. 设置按峰值带宽计费_计费系统—音视频云服务
  4. HCIA 8-17 笔记
  5. 中国石油化工产业发展环境深度分析及投资价值评估报告2022-2028年版
  6. MFC在dlg当中添加view
  7. 赵哲焕 Clock work RNN(CW-RNN)
  8. 二、Apollo高精地图详解(3.Apollo地图采集和生产)
  9. cifar10数据集训练
  10. 微信公众号开发---微信开发学习路线(及供参考)