学习RT-thread(项目一:基于RT-thread的multi_button控制灯闪烁)

1. 项目说明:

  1. 板子包含三个按键,两个LED灯。按键1控制LED1,按键2控制LED2

  2. 按键1单击->LED1闪烁,按键1双击->LED1常亮,按键1长按->LED1常灭。

  3. 按键2单击->LED2闪烁,按键2双击->LED2常亮,按键2长按->LED2常灭。

  4. 按键的状态通过事件集方式通知LED状态。 5. 按键的控制采用multi_button组件,监测按键状态

2. 硬件说明:

开发板中,按键1接在PB5,按键2接在PA11,按键3接在PB3,LED1接在PA12,LED2接在PB4。如 下图:

3. multi_button组件

multi_button是利用线程的方式来检测按键输入的状态,它支持检测按键的单击,双击,长按三种状 态。

3.1 初始化按键:

cpp 复制代码
void button_init(button_t handle, uint8_t pin_index, uint8_t(*pin_level)(button_t 
handle), uint8_t active_level);

3.2 按键绑定事件回调:

cpp 复制代码
 void button_attach(button_t handle, uint8_t event, BtnCallback cb);

3.3 启动按键事件监控:

cpp 复制代码
启动按键事件监控: 
int  button_start(button_t handle);

3.4 暂停按键事件监控:

cpp 复制代码
void button_stop(button_t handle);

3.5 按键生命周期检测函数(注意:需要放在线程中调用)

cpp 复制代码
void button_ticks(void);

4.代码编写

CubeMX配置

代码编写

cpp 复制代码
#include "multi_button.h"
#include "stm32f1xx_hal.h"
#include <rtthread.h>

#define BTN_THREAD_STACK        1024
#define LED_THREAD_STACK        1024

#define BTN1_SIGLE_EVENT    (0X01 << 0)
#define BTN1_DOUBLE_EVENT   (0X01 << 1)
#define BTN1_LONG_EVENT     (0x01 << 2)

#define BTN2_SIGLE_EVENT    (0X01 << 3)
#define BTN2_DOUBLE_EVENT   (0X01 << 4)
#define BTN2_LONG_EVENT     (0x01 << 5)

#define BTN3_SIGLE_EVENT    (0X01 << 6)
#define BTN3_DOUBLE_EVENT   (0X01 << 7)
#define BTN3_LONG_EVENT     (0x01 << 8)

typedef enum{
    KEY1_INDEX=1,
    KEY2_INDEX,
    KEY3_INDEX,
    KEY_END
}bnt_key;

struct rt_event btn_event;

struct rt_thread btn_thread_handle;
static uint8_t btn_stack[BTN_THREAD_STACK];

struct rt_thread led_thread_handle;
static uint8_t led_stack[LED_THREAD_STACK];
 
static struct button key1_btn;
static struct button key2_btn;
static struct button key3_btn; 

void led_flash(rt_uint16_t index,rt_uint16_t event)
{
    if(index==KEY1_INDEX)
    {
        if(event==BTN1_SIGLE_EVENT)             
        {
            HAL_GPIO_WritePin(GPIOA,GPIO_PIN_12,GPIO_PIN_RESET);
            rt_thread_delay(200);
            HAL_GPIO_WritePin(GPIOA,GPIO_PIN_12,GPIO_PIN_SET);
            rt_thread_delay(200);
            HAL_GPIO_WritePin(GPIOA,GPIO_PIN_12,GPIO_PIN_RESET);
            rt_thread_delay(200);
            HAL_GPIO_WritePin(GPIOA,GPIO_PIN_12,GPIO_PIN_SET);
            rt_thread_delay(200);
        }
        else if(event==BTN1_DOUBLE_EVENT)
        {
            HAL_GPIO_WritePin(GPIOA,GPIO_PIN_12,GPIO_PIN_RESET);
        }
        else
        {
            HAL_GPIO_WritePin(GPIOA,GPIO_PIN_12,GPIO_PIN_SET);
        }
    }
    else if(index==KEY2_INDEX)
    {
         if(event==BTN2_SIGLE_EVENT)             
        {
            HAL_GPIO_WritePin(GPIOB,GPIO_PIN_4,GPIO_PIN_RESET);
            rt_thread_delay(200);
            HAL_GPIO_WritePin(GPIOB,GPIO_PIN_4,GPIO_PIN_SET);
            rt_thread_delay(200);
            HAL_GPIO_WritePin(GPIOB,GPIO_PIN_4,GPIO_PIN_RESET);
            rt_thread_delay(200);
            HAL_GPIO_WritePin(GPIOB,GPIO_PIN_4,GPIO_PIN_SET);
            rt_thread_delay(200);
        }
        else if(event==BTN2_DOUBLE_EVENT)
        {
            HAL_GPIO_WritePin(GPIOB,GPIO_PIN_4,GPIO_PIN_RESET);
        }
        else
        {
            HAL_GPIO_WritePin(GPIOB,GPIO_PIN_4,GPIO_PIN_SET);
        }
    }
    
}

void bnt_thread(void* parameter)      //线程里调用button的生命周期
{
    while(1)
    {
        /*     按键生命周期检测     */
        rt_thread_delay(5);
        button_ticks();
    }
}

void led_thread(void* parameter)      //led线程
{
    rt_uint32_t rev;
    while(1)
    {
        rt_event_recv(&btn_event,0xFFFFFFFF,RT_EVENT_FLAG_OR|RT_EVENT_FLAG_CLEAR,RT_WAITING_FOREVER,&rev);
        switch(rev)
        {
            case BTN1_SIGLE_EVENT:
                led_flash(KEY1_INDEX,BTN1_SIGLE_EVENT);
                break;
            case BTN1_DOUBLE_EVENT:
                led_flash(KEY1_INDEX,BTN1_DOUBLE_EVENT);
                break;
            case BTN1_LONG_EVENT:
                led_flash(KEY1_INDEX,BTN1_LONG_EVENT);
                break;
            case BTN2_SIGLE_EVENT:
                led_flash(KEY2_INDEX,BTN2_SIGLE_EVENT);
                break;
            case BTN2_DOUBLE_EVENT:
                led_flash(KEY2_INDEX,BTN2_DOUBLE_EVENT);
                break;
            case BTN2_LONG_EVENT:
                led_flash(KEY2_INDEX,BTN2_LONG_EVENT);
                break;
            case BTN3_SIGLE_EVENT:
                break;
            case BTN3_DOUBLE_EVENT:
                break;
            case BTN3_LONG_EVENT:
                break;
            default:
                break;
        }
    }
}

uint8_t read_pin_level(button_t handle) //读电平的函数
{
    int index=handle->pin_index;
    if(index==KEY1_INDEX)
        return HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_5);
    else if(index==KEY2_INDEX)
        return HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_11);
    else if(index==KEY3_INDEX)
        return HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_3);
    
}


void bnt_callback(button_t btn, PressEvent event) //当有事件产生的时候调用这个回调函数
{
    int index=btn->pin_index;
    
    if(index==KEY1_INDEX)
    {
        if(event==SINGLE_CLICK_EVENT)
        {
            rt_event_send(&btn_event,BTN1_SIGLE_EVENT);
            rt_kprintf("single,index:%d\n",index);
        }
            
        if(event==DOUBLE_CLICK_EVENT)
        {
            rt_event_send(&btn_event,BTN1_DOUBLE_EVENT);
            rt_kprintf("double,index:%d\n",index);
        }
            
        if(event==LONG_PRESS_HOLD_EVENT)
        {
            rt_event_send(&btn_event,BTN1_LONG_EVENT);
            rt_kprintf("long,index:%d\n",index);
        } 
    }
    else if(index==KEY2_INDEX)
    {
        if(event==SINGLE_CLICK_EVENT)
        {
            rt_event_send(&btn_event,BTN2_SIGLE_EVENT);
            rt_kprintf("single,index:%d\n",index);
        }
            
        if(event==DOUBLE_CLICK_EVENT)
        {
            rt_event_send(&btn_event,BTN2_DOUBLE_EVENT);
            rt_kprintf("double,index:%d\n",index);
        }
            
        if(event==LONG_PRESS_HOLD_EVENT)
        {
            rt_event_send(&btn_event,BTN2_LONG_EVENT);
            rt_kprintf("long,index:%d\n",index);
        } 
    }
    else if(index==KEY3_INDEX)
    {
        if(event==SINGLE_CLICK_EVENT)
        {
            rt_event_send(&btn_event,BTN3_SIGLE_EVENT);
            rt_kprintf("single,index:%d\n",index);
        }
            
        if(event==DOUBLE_CLICK_EVENT)
        {
            rt_event_send(&btn_event,BTN3_DOUBLE_EVENT);
            rt_kprintf("double,index:%d\n",index);
        }
            
        if(event==LONG_PRESS_HOLD_EVENT)
        {
            rt_event_send(&btn_event,BTN3_LONG_EVENT);
            rt_kprintf("long,index:%d\n",index);
        } 
    }
}


int riceboard_init()
{
    /*                  创建事件集                      */
    rt_event_init(&btn_event, "btn_event", RT_IPC_FLAG_PRIO);
    
     /*                 创建线程                        */
    rt_thread_init(&btn_thread_handle,"thread1",bnt_thread,NULL,btn_stack, 256,10,10);
    rt_thread_init(&led_thread_handle,"thread2",led_thread,NULL,led_stack, 256,10,10);
    
    rt_thread_startup(&btn_thread_handle);
    rt_thread_startup(&led_thread_handle);
    
    
    /*                 按键初始化                       */
    button_init(&key1_btn, KEY1_INDEX,read_pin_level, 0);
    button_init(&key2_btn, KEY2_INDEX,read_pin_level, 0);
    button_init(&key3_btn, KEY3_INDEX,read_pin_level, 0);
                                                          
    /*                  绑定按键                         */
    button_attach(&key1_btn,SINGLE_CLICK_EVENT|DOUBLE_CLICK_EVENT|LONG_PRESS_HOLD_EVENT, bnt_callback);
    button_attach(&key2_btn,SINGLE_CLICK_EVENT|DOUBLE_CLICK_EVENT|LONG_PRESS_HOLD_EVENT, bnt_callback);
    button_attach(&key3_btn,SINGLE_CLICK_EVENT|DOUBLE_CLICK_EVENT|LONG_PRESS_HOLD_EVENT, bnt_callback);
    
    /*               启动按键事件监控                    */
    button_start(&key1_btn);
    button_start(&key2_btn);
    button_start(&key3_btn);

}
INIT_APP_EXPORT(riceboard_init); //自动初始化函数

实验现象:

1.打开串口终端观察现象(灯光按预期效果闪烁、长亮、停止)

相关推荐
●VON28 分钟前
Flutter for OpenHarmony 21天训练营 Day03 总结:从学习到输出,迈出原创第一步
学习·flutter·openharmony·布局·技术
香芋Yu1 小时前
【大模型教程——第四部分:大模型应用开发】第1章:提示工程与上下文学习 (Prompt Engineering & ICL)
学习·prompt
LYS_06181 小时前
寒假学习10(HAL库1+模数电10)
学习
runningshark1 小时前
【项目】示波器学习与制作
学习
€8111 小时前
Java入门级教程24——Vert.x的学习
java·开发语言·学习·thymeleaf·数据库操作·vert.x的路由处理机制·datadex实战
自可乐1 小时前
n8n全面学习教程:从入门到精通的自动化工作流引擎实践指南
运维·人工智能·学习·自动化
深蓝海拓2 小时前
PySide6从0开始学习的笔记(二十六) 重写Qt窗口对象的事件(QEvent)处理方法
笔记·python·qt·学习·pyqt
qqssss121dfd2 小时前
STM32H750XBH6的ETH模块移植LWIP
网络·stm32·嵌入式硬件
星火开发设计3 小时前
C++ 预处理指令:#include、#define 与条件编译
java·开发语言·c++·学习·算法·知识
想放学的刺客4 小时前
单片机嵌入式试题(第27期)设计可移植、可配置的外设驱动框架的关键要点
c语言·stm32·单片机·嵌入式硬件·物联网