移植LVGL到像素屏,从此玩转像素屏0门槛
硬件方面
先上渲染图

实物图

配置
- 主控: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的消息机制写了一个轻量级的多任务消息通知框架,这部分比较复杂,放在下篇文章单独写一下。
相关文章:
移植LVGL到像素屏,从此玩转像素屏0门槛
硬件方面 先上渲染图 实物图 配置 主控:esp32 micro32 plus主频:240MhzFlash:8MPSRAM:2M 软件方面 众所周知,LVGL是一个十分优秀的图形框架,小到几百kb的单片机,大到Linux都可以运行。既然它…...
stateflow 之图函数、simulink函数和matlab函数使用及案例分析
目录 前言 1. 图函数graph function 2.simulink function 3.matlab function 4.调用stateflow中的几种函数方式 前言 对于stateflow实际上可以做simulink和matlab的所有任务,可以有matlab的m语言,也可以有simulink的模块,关于几种函数在…...
C# 加载本地文件设置应用程序图标
static class Program{[STAThread]static void Main(){Application.EnableVisualStyles();Application.SetCompatibleTextRenderingDefault(false);Form mainForm new Form1();mainForm.Show();//IntPtr hProcess Process.GetCurrentProcess().MainWindowHandle;// 设置应用程…...
苹果计划将全球1/4的IPhone产能转移至印度
KlipC报道:据相关人士报道,苹果希望在未来2到3年内每年在印度生产超过5000万部iphone,要是该计划得以实现,印度将占领全球iPhone产量的四分之一。 KlipC的分析师Alex Su表示:“此次iPhone15推出是苹果印度制造计划的一…...
el-date-picker 选择一个或多个日期
el-date-picker可选择多个日期 type“dates” 加个s即可 <div><span>el-date-picker选择多个日期</span><el-date-pickertype"dates"v-model"dateList"placeholder"选择一个或多个日期"></el-date-picker></di…...
5个创建在线帮助文档的好方法!
在线帮助文档是企业为用户提供支持服务的重要工具,它能够帮助用户更好地了解和使用产品,提高用户体验。然而,创建一份优秀的在线帮助文档需要掌握一定的技巧和方法。接下来就介绍一下创建在线帮助文档的5个好方法,帮助企业更好地为…...
听GPT 讲Rust源代码--src/tools(14)
File: rust/src/tools/rust-analyzer/crates/cfg/src/lib.rs 在Rust源代码中,rust/src/tools/rust-analyzer/crates/cfg/src/lib.rs这个文件是Rust语言分析器(Rust Analyzer)的一部分,用于处理和管理条件编译指令(Cond…...
arcgis api for js 中使用API的代理页面(跨越配置)
以下仅作为自己阅读官网api的对reques的理解做的备忘笔记。一知半解,仅供参考。 1、获取或者构建第三方代理 官网解释:代理在其自己的 Web 服务器上安装并运行,而不是在 Esri 服务器或安装了 ArcGIS Enterprise 的计算机上安装和运行&#…...
Unity_FairyGUI发布导入Unity编辑器资源报错
Unity_FairyGUI发布导入Unity编辑器资源报错 报错: FairyGUI: settings for Assets/UI/XMUI/XMSubway_atlas0.png is wrong! Correct values are: (Generate Mip Mapsunchecked) UnityEngine.Debug:LogWarning (object) FairyGUI.UIPackage:LoadAtlas (FairyGUI.P…...
1.5【应用开发】缓冲区(二)
二,附加缓冲区 你可以通过分别调用以下函数来附加一个缓冲区(screen_buffer_t类型),以将其与像素图、流或窗口相关联: screen_attach_pixmap_buffer() //用于附加像素图缓冲区 screen_attach_stream_buffers()//用于附加流缓冲区 screen_attach_window_buffers()屏幕附加…...
RTMP流设置超时时间失败
使用FFmpeg(版本是5.0.3)将rtmp流作为输入,设置超时时间(使用-timeout参数),结果报错:Cannot open Connection tcp://XXX:1935?listen&listen_timeout 通过./ffmpeg -help full 命令查看FFmpeg帮助&am…...
如何一步步让MySQL支撑亿级流量
1 主从读写分离 大部分互联网业务都是读多写少,因此优先考虑DB如何支撑更高查询数,首先就需要区分读、写流量,这才方便针对读流量单独扩展,即主从读写分离。 若前端流量突增导致从库负载过高,DBA会优先做个从库扩容上去…...
MFC CLXHHandleEngine动态库-自定义设置对话框使用
实现的效果如下所示: void CSampleDlg::OnBnClickedButton2() { // TODO: 在此添加控件通知处理程序代码 CSgxMemDialog dlg(180, 100); dlg.SetEnable(true); dlg.SetWindowTitle(_T("自定义对话框")); dlg.AddStatic(1000, //控件资源…...
Python生成器(Generator)(继续更新...)
学习网页: Welcome to Python.orghttps://www.python.org/https://www.python.org/ Python生成器 生成器(Generator)是 Python 的一种特殊类型的迭代器。生成器允许你创建自己的数据流,每次从数据流中获取一个元素,…...
Spring Boot 3 整合 Mybatis-Plus 动态数据源实现多数据源切换
🚀 作者主页: 有来技术 🔥 开源项目: youlai-mall 🍃 vue3-element-admin 🍃 youlai-boot 🌺 仓库主页: Gitee 💫 Github 💫 GitCode 💖 欢迎点赞…...
快速学习C++中的模板
模板是一个让C支持范型编程的重要功能,它本质上是一个万能变量适配器;vector,pair等都是使用模板实现的 模板是C的一个强大特性,它允许您编写通用的代码来处理不同的数据类型。您可以有函数模板和类模板。 函数模板: 函数模板允许您创建一…...
Pandas-DataFtame的索引与切片(第3讲)
Pandas-DataFtame的索引与切片(第3讲) 🍹博主 侯小啾 感谢您的支持与信赖。☀️ 🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ�…...
MySQL低版本中:字符串中的数字、英文字符、汉字提取
我们如何提醒一个字段中的汉字和数字呢 高版本指mysql8.0以上 使用sql语句 SELECT REGEXP_REPLACE(column_name, [^\\p{Han}], ) AS chinese_characters FROM table_name;其中 column_name指名称列,table_name是表名 2.低版本使用 需要新建函数 DELIMITER $$DR…...
多窗口文件管理工具Q-Dir安装以及使用教程
软件介绍 Q-Dir 是一款功能强大的Windows资源管理器,可以非常方便的管理你的各种文件。Q-Dir有4 个窗口,特别适用于频繁在各个目录间跳跃复制粘贴的情况,每个窗口都可以方便的切换目录,以不同颜色区分不同类型的文件,…...
Spring入门
学习的最大理由是想摆脱平庸,早一天就多一份人生的精彩;迟一天就多一天平庸的困扰。各位小伙伴,如果您: 想系统/深入学习某技术知识点… 一个人摸索学习很难坚持,想组团高效学习… 想写博客但无从下手,急需…...
SciencePlots——绘制论文中的图片
文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了:一行…...
Nginx server_name 配置说明
Nginx 是一个高性能的反向代理和负载均衡服务器,其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机(Virtual Host)。 1. 简介 Nginx 使用 server_name 指令来确定…...
ip子接口配置及删除
配置永久生效的子接口,2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...
听写流程自动化实践,轻量级教育辅助
随着智能教育工具的发展,越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式,也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建,…...
蓝桥杯 冶炼金属
原题目链接 🔧 冶炼金属转换率推测题解 📜 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V,是一个正整数,表示每 V V V 个普通金属 O O O 可以冶炼出 …...
Java数值运算常见陷阱与规避方法
整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...
解读《网络安全法》最新修订,把握网络安全新趋势
《网络安全法》自2017年施行以来,在维护网络空间安全方面发挥了重要作用。但随着网络环境的日益复杂,网络攻击、数据泄露等事件频发,现行法律已难以完全适应新的风险挑战。 2025年3月28日,国家网信办会同相关部门起草了《网络安全…...
逻辑回归暴力训练预测金融欺诈
简述 「使用逻辑回归暴力预测金融欺诈,并不断增加特征维度持续测试」的做法,体现了一种逐步建模与迭代验证的实验思路,在金融欺诈检测中非常有价值,本文作为一篇回顾性记录了早年间公司给某行做反欺诈预测用到的技术和思路。百度…...
Spring Boot + MyBatis 集成支付宝支付流程
Spring Boot MyBatis 集成支付宝支付流程 核心流程 商户系统生成订单调用支付宝创建预支付订单用户跳转支付宝完成支付支付宝异步通知支付结果商户处理支付结果更新订单状态支付宝同步跳转回商户页面 代码实现示例(电脑网站支付) 1. 添加依赖 <!…...
UE5 音效系统
一.音效管理 音乐一般都是WAV,创建一个背景音乐类SoudClass,一个音效类SoundClass。所有的音乐都分为这两个类。再创建一个总音乐类,将上述两个作为它的子类。 接着我们创建一个音乐混合类SoundMix,将上述三个类翻入其中,通过它管理每个音乐…...
