发帖
2 0 0

LGVL 使用物理按键控制界面切换

浪夏
中级会员

3

主题

3

回帖

447

积分

中级会员

积分
447
LVGL教程玩法 46 2 12 小时前

1.手上只有0.96寸7735S控制的屏幕,想玩LVGL,只有用按钮模拟触摸实现界面切换

界面1上面的按钮添加了切换到界面3事件,下面的切换到界面2,界面2界面3的按钮切换到界面1

image.png

image.png
image.png

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

──── 0人觉得很赞 ────

使用道具 举报

厉害
👍
您需要登录后才可以回帖 立即登录
高级模式
返回
统计信息
  • 会员数: 29272 个
  • 话题数: 42230 篇