1.手上只有0.96寸7735S控制的屏幕,想玩LVGL,只有用按钮模拟触摸实现界面切换
界面1上面的按钮添加了切换到界面3事件,下面的切换到界面2,界面2界面3的按钮切换到界面1



2.使用方法,在 主函数lv_port_indev_init();
触摸初始化中注释掉原来的触摸初始化,仿照其写一个BUtton的初始化,仿照的代码如下
button_init();
/*Register a button input device*/
lv_indev_drv_init(&indev_drv);
indev_drv.type = LV_INDEV_TYPE_BUTTON;
indev_drv.read_cb = button_read;
indev_button = lv_indev_drv_register(&indev_drv);
/*Assign buttons to points on the screen*/
static const lv_point_t btn_points[3] = {
{ 20, 128 },
//{ 10, 10 }, /*Button 0 -> x:10; y:10*/
{ 13, 79 }, /*Button 1 -> x:40; y:100*/
{ 5, 91 },
};
lv_indev_set_button_points(indev_button, btn_points);
btn_points就是按钮的位置
static void button_init(void)
{
/Your code comes here/
}
/* Will be called by the library to read the button /
static bool button_read(lv_indev_drv_t indev_drv, lv_indev_data_t* data)
{
//printf("lvgl 331\r\n");
static uint8_t last_btn = 0;
/*Get the pressed button's ID*/
int8_t btn_act = button_get_pressed_id();
if (btn_act >= 0) {
data->state = LV_INDEV_STATE_PR;
last_btn = btn_act;
} else {
data->state = LV_INDEV_STATE_REL;
}
/*Save the last pressed button's ID*/
data->btn_id = last_btn;
/*Return `false` because we are not buffering and no more data to read*/
return false;
}
/Get ID (0, 1, 2 ..) of the pressed button/
static int8_t button_get_pressed_id(void)
{
uint8_t i;
/*Check to buttons see which is being pressed (assume there are 2 buttons)*/
for (i = 0; i < 3; i++) {
/*Return the pressed button's ID*/
if (button_is_pressed(i)) {
return i;
}
}
/*No button pressed*/
return -1;
}
/Test if id
button is pressed or not/
static bool button_is_pressed(uint8_t id)
{
if ((key_state == 1) && (id == 0)) {
printf("lvgl %d\r\n", id);
key_state = 0;
return LV_INDEV_STATE_PR; // 和 LV_INDEV_STATE_PR 对应
} else if ((key_state == 3) && (id == 2)) {
printf("lvgl %d\r\n", id);
key_state = 0;
return LV_INDEV_STATE_PR; // 和 LV_INDEV_STATE_PR 对应
}
//else {
// return LV_INDEV_STATE_REL; // 自己添加和 LV_INDEV_STATE_REL 对应
// }
else if ((key_state == 2) && (id == 1)) {
printf("lvgl 1\r\n");
key_state = 0;
return LV_INDEV_STATE_PR; // 和 LV_INDEV_STATE_PR 对应
} else {
return LV_INDEV_STATE_REL; // 自己添加和 LV_INDEV_STATE_REL 对应
}
/*Your code comes here*/
return false;
}
上面是实现的函数,key_state
是主函数的一个全局变量用来存储按键按下的次数
3.主函数用了论坛大佬的按键控制
#include "FreeRTOS.h"
#include "task.h"
#include "timers.h"
#include "board.h"
#include "bflb_gpio.h"
#include "bflb_l1c.h"
#include "bflb_mtimer.h"
#include "lv_conf.h"
#include "lvgl.h"
#include "lv_port_disp.h"
#include "lv_port_indev.h"
#include "lcd.h"
#include "gui_guider.h"
#include "custom.h"
#include "lv_user_indev.h"
lv_ui guider_ui;
struct bflb_device_s gpio;
// 该类型变量必须是全局变量
static TaskHandle_t lvgl_TaskHandle;
#define LVGL_STACK_SIZE 1024
#define LVGL_TASK_PRIORITY 15
int key_state = 0;
int flag = 1;
/ lvgl log cb */
void lv_log_print_g_cb(const char *buf)
{
printf("[LVGL] %s", buf);
}
void lvgl_task(void *param)
{
while (1)
{
lv_task_handler();
vTaskDelay(1);
// bflb_mtimer_delay_ms(1);
}
}
// 10ms定时扫描
#define JITTER_CNT 5 // 抖动时间,大约50ms
#define LONG_PRESS_CNT 100 // 长按检测时间,长按不参与前后连击检测
#define COUNTDOWN_INIT 20 // 连击检测倒计时
static TaskHandle_t key_TaskHandle;
uint8_t key_pin = 31;
void key_scan_task()
{
uint32_t timer_cnt = 0, countdown = 0;
uint32_t click_cnt = 0; // 短按次数
bool long_press = false;
bflb_gpio_init(gpio, key_pin, GPIO_INPUT | GPIO_FLOAT | GPIO_SMT_EN | GPIO_DRV_0);
while (1)
{
if (!bflb_gpio_read(gpio, key_pin))
{ // 高电平时计数
if (timer_cnt < 10000000)
timer_cnt++; // 避免一直长按时溢出
}
else
{ // 低电平时判断状态
if (countdown > 0)
countdown--; // 倒计时
if (timer_cnt >= LONG_PRESS_CNT)
long_press = true;
else if (timer_cnt >= JITTER_CNT)
{
click_cnt++;
countdown = COUNTDOWN_INIT; // 重新倒计时
}
// 状态输出
if (long_press)
{ // 长按
printf("long_press:%d\r\n", timer_cnt);
long_press = false;
click_cnt = countdown = 0; // 重置,丢弃前面的连击
}
else if (click_cnt > 0 && countdown == 0)
{ // 点击1次或多次
printf("%d click\r\n", click_cnt);
// if (click_cnt == 1)
// {
// key_state = 1;
// }
key_state = click_cnt;
// if (click_cnt == 2)
// {
// key_state = 2;
// }
click_cnt = 0;
}
// else {} // 未按键,抖动,连击检测倒计时未结束
timer_cnt = 0; // 重置
}
vTaskDelay(10);
}
}
int main(void)
{
board_init();
gpio = bflb_device_get_by_name("gpio"); // 给外设句柄复位gpio句柄
printf("gpio interrupt\r\n");
printf("lvgl case\r\n");
/* lvgl init */
lv_log_register_print_cb(lv_log_print_g_cb);
lv_init();
// 显示器初始化
lv_port_disp_init();
// 外部输入初始化(Touch触摸)
lv_port_indev_init();
// lv_keypad_init();
// 设计小部件的UI布局
setup_ui(&guider_ui);
printf("lv_task_handler\r\n");
custom_init(&guider_ui);
printf("lvgl success\r\n");
// lv_scr_load(guider_ui.screen);
// 颜色不对 LV_COLOR_16_SWAP lvgl提供了宏去交换高八位和低八位。将lv_conf.h的LV_COLOR_16_SWAP改为1即可。
xTaskCreate(lvgl_task, (char *)"lvgl", LVGL_STACK_SIZE, NULL, LVGL_TASK_PRIORITY, &lvgl_TaskHandle);
xTaskCreate(key_scan_task, (char *)"lvgl1", LVGL_STACK_SIZE, NULL, LVGL_TASK_PRIORITY, &key_TaskHandle);
vTaskStartScheduler();
// while (1)
// {
// // LVGL事物处理
// // lv_task_handler();
// // bflb_mtimer_delay_ms(1);
// }
}
4.备注:只用了一个按键按1下切换界面2按两下切换到界面3,界面2按一下切换到界面1(好是因为界面2的按钮跟界面1的按钮重合了所以可以复用点击一下就行),界面3按3下可返回界面1
5.附上B站视频链接:【小安派M61 32s LVGL使用物理按键模拟触摸实现界面切换】 https://www.bilibili.com/video/BV14BuxzRE4Y/?share_source=copy_web&vd_source=c1da45cbba140ee49020a8c4167aba21