学习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 初始化按键:
void button_init(button_t handle, uint8_t pin_index, uint8_t(*pin_level)(button_t
handle), uint8_t active_level);

3.2 按键绑定事件回调:
void button_attach(button_t handle, uint8_t event, BtnCallback cb);

3.3 启动按键事件监控:
启动按键事件监控:
int button_start(button_t handle);

3.4 暂停按键事件监控:
void button_stop(button_t handle);

3.5 按键生命周期检测函数(注意:需要放在线程中调用)
void button_ticks(void);
4.代码编写
CubeMX配置

代码编写
#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.打开串口终端观察现象(灯光按预期效果闪烁、长亮、停止)

