硬件方面
先上烘托图
实物图
装备
- 主控:esp32 micro32 plus
- 主频:240Mhz
- Flash:8M
- PSRAM:2M
软件方面
众所周知,LVGL是一个非常优异的图形结构,小到几百kb的单片机,大到Linux都能够运行。既然它这么优异,各种组件又非常的全面,没道理不必。
跟着官方例程适配esp32
显现驱动
因为我的像素屏规划的是32*16尺寸的,运用的是512个WS2812B灯珠,所以LVGL官方适配的屏幕驱动是没法运用的,所以首要需求自己完成WS2812B的驱动,这儿选用的是FastLED。然后直接去适配LVGL的制作办法就能够了。 官方供给的lv_port_disp.cpp中有disp_flush函数,这个函数便是用来填充屏幕,只需求将它的每个像素制作到屏幕中就能够了。
static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
if(disp_flush_enabled) {
/*将一切像素逐一放到屏幕上的最简单的情况(但也是最慢的情况)*/
int32_t x;
int32_t y;
for(y = area->y1; y <= area->y2; y++) {
for(x = area->x1; x <= area->x2; x++) {
/*Put a pixel to the display. For example:*/
/*put_px(x, y, *color_p)*/
// 设置像素点
pixels[matrixIndex[y * SCREEN_WIDTH + x]]=CRGB(color_p->ch.red,color_p->ch.green,color_p->ch.blue);
color_p++;
}
}
// 刷新
FastLED.show();
}
/*IMPORTANT!!!
*Inform the graphics library that you are ready with the flushing 最终必须得调用,告诉 lvgl 库你现已 flushing 拷贝完成了*/
lv_disp_flush_ready(disp_drv);
}
用disp_drv.hor_res和disp_drv.ver_res设置屏幕的宽高
/*Set the resolution of the display*/
disp_drv.hor_res = MY_DISP_HOR_RES;
disp_drv.ver_res = MY_DISP_VER_RES;
设置好这些,就能够显现了。
输入驱动
LVGL的输入操控方式有许多中能够选择,具体能够根据硬件灵敏运用,因为我的硬件直规划了两个按钮,想要用两个按钮完成上下左右承认回来等操控是非常困难的,所以传统的按键映射操控是不行了,这儿我选用的是仿照编码器操控,编码器只要上滚动、下滚动和承认;我将每个button按钮分红click和longClick两个事情,故两个按钮就能够发生四个事情,这样仿照编码器的三个事情足够了。
- btn1 OnClick => left事情
- btn2 OnClick => right事情
- btn1 LongClick => enter事情
- btn2 LongClick => esc事情
在LVGL例程中需求完成keypad_read 和 keypad_get_key函数;这儿运用OneButton库来扫描按钮事情 因为OneButton只要按键事情回调,没有按键扫描函数,所以修改了一下OneButton的代码,使其能够回来按键状况。
/*Get the currently being pressed key. 0 if no key is pressed 获取当前按下的键。假如未按键,则为0*/
static uint32_t keypad_get_key(void)
{
/*Your code comes here*/
// OneButton 中修改了tick()函数,使其能够回来按键状况,用来获取扫描按键状况
stateType_t type1 = buttons[0]->tick();
stateType_t type2 = buttons[1]->tick();
if (type1!=BTN_TYPE_NONE){
switch (type1) {
case BTN_TYPE_CLICK:
return 1;
case BTN_TYPE_LONG_PRESS_START:
return 3;
}
} else if (type2!=BTN_TYPE_NONE){
switch (type2) {
case BTN_TYPE_CLICK:
return 2;
case BTN_TYPE_LONG_PRESS_START:
return 4;
}
}
return 0;
}
/*Will be called by the library to read the keypad*/
static void keypad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
static uint32_t last_key = 0;
/*Get the current x and y coordinates*/
// mouse_get_xy(&data->point.x, &data->point.y);
/*Get whether the a key is pressed and save the pressed key 获取是否按下了a键并保存按下的键 */
uint32_t act_key = keypad_get_key();
if(act_key != 0) {
data->state = LV_INDEV_STATE_PR;
/*Translate the keys to LVGL control characters according to your key definitions 根据您的密钥定义将密钥转换为LVGL操控字符*/
switch(act_key) {
case 1:
// 单击key1
act_key = LV_KEY_LEFT;
// Serial.println("LV_KEY_LEFT");
break;
case 2:
// 单击key2
act_key = LV_KEY_RIGHT;
// Serial.println("LV_KEY_RIGHT");
break;
case 3:
// 长按key1
act_key = LV_KEY_ENTER;
// Serial.println("LV_KEY_ENTER");
break;
case 4:
// 长按key2
act_key = LV_KEY_ESC;
// Serial.println("LV_KEY_ESC");
break;
}
last_key = act_key;
} else {
data->state = LV_INDEV_STATE_REL;
}
data->key = last_key;
}
输入输出适配完成,就能够愉快的玩耍LVGL了,可是LVGL自带的字体是16px和8px的,而且还有亚像素烘托,导致字体显现虚化,有堆叠。理论上16px和8px的字符都是能够显现的,可是因为有亚像素烘托,就会导致字体有重影,究竟咱像素屏只要32*16的巨细,最终的显现作用便是黏在一起辨认不清,而这还仅仅显现英文字符,汉字就更困难了,通用字库的汉字最小像素巨细便是16px,即假如想要显现完好的汉字细节,咱整个屏幕一次只能放下两个汉字,体会感太差了。通过不懈努力下,我找到了一款8px的字体,非常的优异,能够在32*16像素的屏幕能够足足显现8个汉字。而且仿照8段数码管,自定义了一套3*5巨细的数字。
记载一下自定义字体的坑,LVGL自定义字体lv_font_fmt_txt_glyph_dsc_t类型的字段说明
uint32_t bitmap_index : 20; /**< 位图的开始索引。一个字体最多可所以1MB.*/
uint32_t adv_w : 12; /**<在此宽度之后制作下一个图示符。8.4格式(存储real_value*16).*/
uint8_t box_w; /**< 图示符的鸿沟框的宽度*/
uint8_t box_h; /**< 图示符的鸿沟框的高度*/
int8_t ofs_x; /**< 鸿沟框的x偏移*/
int8_t ofs_y; /**< 鸿沟框的y偏移。从线路顶部开始测量*/
划重点,adv_w属性为字符宽度,它的巨细是16的倍数,即不管你的字符高多少,假如你的字符宽1,那么adv_w=16 宽2 adv_w=32;假如将adv_w了解成字符编码的宽度,那么3*5巨细的字符adv_w=15,这样是不对的,它的adv_w应该是3*16=48.
应用程序结构规划
为了更愉快的玩转像素屏,方便以后的扩展功能,规划了一套App程序结构,该结构有App的发动、毁掉等生命周期,使命栈功能,能够完成页面的切换,毁掉等。
别的因为LVGL不是线程安全的,所以在多使命更新界面时,LVGL会有冲突,这儿我参照Android的音讯机制写了一个轻量级的多使命音讯告诉结构,这部分比较复杂,放在下篇文章单独写一下。