- 說明
- LV_INDEV_TYPE_BUTTON的使用
- LV_INDEV_TYPE_KEYPAD的使用
說明
本實驗使用LVGL版本為v9.2
LVGL中有四種輸入設備,如下
LV_INDEV_TYPE_POINTER, /**< Touch pad, mouse, external button*/
LV_INDEV_TYPE_KEYPAD, /**< Keypad or keyboard*/
LV_INDEV_TYPE_BUTTON, /**< External (hardware button) which is assigned to a specific point of the screen*/
LV_INDEV_TYPE_ENCODER, /**< Encoder with only Left, Right turn and a Button*/
這里只記錄LV_INDEV_TYPE_KEYPAD和LV_INDEV_TYPE_BUTTON的使用。因為這兩個輸入設備都可以用實體按鍵實現。當然,這兩個輸入設備掌握了,LV_INDEV_TYPE_ENCODER也是很容易類推的。
LV_INDEV_TYPE_BUTTON的使用
此輸入設備其實是模擬的 LV_INDEV_TYPE_POINTER設備相應坐標被按下。使用它之前,應該有明確UI的布局,特別屏幕上按鈕的坐標是明確的。
- 實體按鍵初始化
void key_init(void)
{// 配置 GPIOgpio_config_t io_conf = {.pin_bit_mask = (1ULL << KEY1)|(1ULL << KEY2)|(1ULL << KEY3), // 選擇 GPIO.mode = GPIO_MODE_INPUT, // 設置為輸出模式.pull_up_en = GPIO_PULLUP_ENABLE, // 啟用上拉.pull_down_en = GPIO_PULLDOWN_DISABLE, // 不啟用下拉.intr_type = GPIO_INTR_DISABLE // 不啟用中斷};gpio_config(&io_conf);
}
- 按鍵匹配鍵值
此鍵值將對應一個數組的序號,此數組是由BUTTON控件的坐標構成。
源碼如下:
static int read_key(void)
{if(gpio_get_level(KEY1)==0){return 0;}if(gpio_get_level(KEY2)==0){return 1;}if(gpio_get_level(KEY3)==0){return 2;} return -1;
}
- 讀取鍵值并保存到lv_indev_data_t數據結構中
目的是將實體按鍵與LVGL建立聯系,后面通過創建輸入設備相關API完成建立
void button_read(lv_indev_t * drv, lv_indev_data_t*data){static uint32_t last_btn = 0; /*Store the last pressed button*/int btn_pr = read_key(); /*Get the ID (0,1,2...) of the pressed button*/if(btn_pr >= 0) { /*Is there a button press? (E.g. -1 indicated no button was pressed)*/data->state = LV_INDEV_STATE_PRESSED; /*Set the pressed state*/last_btn = btn_pr; /*Save the ID of the pressed button*/} else {data->state = LV_INDEV_STATE_RELEASED; /*Set the released state*/}data->btn_id = last_btn; /*Save the last button*/
}
- 創建輸入設備
lv_indev_t * button_indev_drv;
button_indev_drv=lv_indev_create();
lv_indev_set_type(button_indev_drv,LV_INDEV_TYPE_BUTTON);//將輸入設備設置為BUTTON模式
lv_indev_set_read_cb(button_indev_drv, button_read);//注冊回調函數,即上一步實現的函數,這樣就完成了硬件和LVGL的聯系
//配置坐標點
static const lv_point_t btn_points[5] = {{0, 0}, /*當鍵值為0時模擬點擊的坐標*/{80, 0}, /*當鍵值為1時模擬點擊的坐標*/{160, 1}, /*當鍵值為2時模擬點擊的坐標*/{320, 120}, /*當鍵值為3時模擬點擊的坐標*/{160, 240}, /*當鍵值為4時模擬點擊的坐標*/
};
lv_indev_set_button_points(button_indev_drv, btn_points);//將按鍵與坐標連接
- 使用LVGL的API在界面上創建三個BUTTON控件
lv_obj_t * btn1;btn1 = lv_button_create(scr);lv_obj_set_width(btn1,80);lv_obj_set_height(btn1,35);lv_obj_set_pos(btn1,0,0);/*Button event*/lv_obj_add_event_cb(btn1, btn_event_handler, LV_EVENT_ALL, NULL);lv_obj_add_flag(btn1, LV_OBJ_FLAG_CHECKABLE);lv_obj_t * lbl1 = lv_label_create(btn1);lv_label_set_text_static(lbl1, "LEFT");lv_obj_align(lbl1, LV_ALIGN_CENTER,0, 0);lv_obj_t * btn2;btn2 = lv_button_create(scr);lv_obj_set_width(btn2,80);lv_obj_set_height(btn2,35);lv_obj_set_pos(btn2,80,0);/*Button event*/lv_obj_add_event_cb(btn2, btn_event_handler, LV_EVENT_ALL, NULL);lv_obj_add_flag(btn2, LV_OBJ_FLAG_CHECKABLE);lv_obj_t * lbl2 = lv_label_create(btn2);lv_label_set_text_static(lbl2, "RIGHT");lv_obj_t * btn3;btn3 = lv_button_create(scr);lv_obj_set_width(btn3,80);lv_obj_set_height(btn3,35);lv_obj_set_pos(btn3,0,70);/*Button event*/lv_obj_add_event_cb(btn3, btn_event_handler, LV_EVENT_ALL, NULL);lv_obj_add_flag(btn3, LV_OBJ_FLAG_CHECKABLE);lv_obj_t * lbl3 = lv_label_create(btn3);lv_label_set_text_static(lbl3, "DOWN");lv_obj_align(lbl3, LV_ALIGN_CENTER,0, 0);
- 創建群組,并將輸入設備綁定到群組且將以上三個BUTTON加入
lv_group_t *g = lv_group_create();lv_indev_set_group(button_indev_drv, g); //綁定定義的lv_indev_t lv_group_add_obj(g ,btn1);lv_group_add_obj(g ,btn2);lv_group_add_obj(g ,btn3);
此時按下實體按鍵將會控制對應BUTTON控件按下。
- 此時可以創建BUTTON回調函數了
void btn_event_handler(lv_event_t *e)//按鍵回調函數
{lv_event_code_t code = lv_event_get_code(e);if(code == LV_EVENT_CLICKED) {ESP_LOGI(TAG,"Clicked");}
}
LV_INDEV_TYPE_KEYPAD的使用
LV_INDEV_TYPE_KEYPAD的鍵值LVGL已經有實現,固定死了。
LV_KEY_NEXT 專注于下一個對象
LV_KEY_PREV 專注于上一個對象
LV_KEY_ENTER 觸發器 LV_EVENT_PRESSED/CLICKED/LONG_PRESSED 等事件
LV_KEY_UP 增加值或向上移動
LV_KEY_DOWN 減小值或向下移動
LV_KEY_RIGHT 增加值或向右移動
LV_KEY_LEFT 減小值或向左移動
LV_KEY_ESC 關閉或退出(例如,關閉下拉列表)
LV_KEY_DEL 刪除(例如,“ 文本”區域中右側的字符)
LV_KEY_BACKSPACE 刪除左側的字符(例如,在文本區域中)
LV_KEY_HOME 轉到開頭/頂部(例如,在“ 文本”區域中)
LV_KEY_END 轉到末尾(例如,在“ 文本”區域中)
LV_INDEV_TYPE_KEYPAD按鍵分兩個狀態,導航態和編輯態。導航態就是在同組中選擇相關控件,編輯態就是對控件數值上的增加/減少。LV_KEY_NEXT/PREV、LV_KEY_ENTER則是作為導航態。LV_KEY_UP/DOWN/LEFT/RIGHT則可以對控件進行數值上的編輯,一般而言LEFT/RIGHT就足夠使用了。
LV_INDEV_TYPE_KEYPAD只需要對上面的代碼做一些簡單的調整,如下:
- 鍵值匹配
static int read_key(void)
{if(gpio_get_level(KEY1)==0){return LV_KEY_NEXT;}if(gpio_get_level(KEY2)==0){return LV_KEY_RIGHT;}if(gpio_get_level(KEY3)==0){return LV_KEY_LEFT;} return -1;
}
- 輸入設備的回調函數
void button_read(lv_indev_t * drv, lv_indev_data_t*data){static uint32_t last_btn = 0; /*Store the last pressed button*/int btn_pr = read_key(); /*Get the ID (0,1,2...) of the pressed button*/if(btn_pr >= 0) { /*Is there a button press? (E.g. -1 indicated no button was pressed)*/data->state = LV_INDEV_STATE_PRESSED; /*Set the pressed state*/last_btn = btn_pr; /*Save the ID of the pressed button*/} else {data->state = LV_INDEV_STATE_RELEASED; /*Set the released state*/}
//注意這個地方做了修改data->key = last_btn; /*Save the last button*/
}
- 創建輸入設備
lv_indev_t * button_indev_drv;
button_indev_drv=lv_indev_create();
lv_indev_set_type(button_indev_drv,LV_INDEV_TYPE_KEYPAD);//將輸入設備設置為KEYPAD模式
lv_indev_set_read_cb(button_indev_drv, button_read);//注冊回調函數,即上一步實現的函數,這樣就完成了硬件和LVGL的聯系
- 按鍵回調函數
既然編輯態會有值的變化,那自然會觸發相關事件,所以有了下面的改變
void btn_event_handler(lv_event_t *e)//按鍵回調函數
{lv_event_code_t code = lv_event_get_code(e);
//LV_EVENT_CLICKED這個事件在KEYPAD中只有ENTER才會觸發if(code == LV_EVENT_CLICKED) {ESP_LOGI(TAG,"Clicked");}else if(code == LV_EVENT_VALUE_CHANGED) {ESP_LOGI(TAG,"BUTTUN");}
}
- 只是按鍵不太能看到效果,可以創建一個slider加入組中,通過導航按鍵選中后,用LEFT/RIGHT進行編輯
lv_obj_t *slider1;slider1=lv_slider_create(scr);lv_obj_set_pos(slider1,0,140);lv_group_add_obj(g ,slider1);
總結
經過以上編程后,其實LV_INDEV_TYPE_ENCODER也是很容易實現的,只要將左右旋轉和按下動作對應LV_KEY_LEFT/RIGHT以及LV_KEY_ENTER,剩下的代碼基本都差不多了。