移植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入门
学习的最大理由是想摆脱平庸,早一天就多一份人生的精彩;迟一天就多一天平庸的困扰。各位小伙伴,如果您: 想系统/深入学习某技术知识点… 一个人摸索学习很难坚持,想组团高效学习… 想写博客但无从下手,急需…...
在软件开发中正确使用MySQL日期时间类型的深度解析
在日常软件开发场景中,时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志,到供应链系统的物流节点时间戳,时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库,其日期时间类型的…...
手游刚开服就被攻击怎么办?如何防御DDoS?
开服初期是手游最脆弱的阶段,极易成为DDoS攻击的目标。一旦遭遇攻击,可能导致服务器瘫痪、玩家流失,甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案,帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...
docker详细操作--未完待续
docker介绍 docker官网: Docker:加速容器应用程序开发 harbor官网:Harbor - Harbor 中文 使用docker加速器: Docker镜像极速下载服务 - 毫秒镜像 是什么 Docker 是一种开源的容器化平台,用于将应用程序及其依赖项(如库、运行时环…...
椭圆曲线密码学(ECC)
一、ECC算法概述 椭圆曲线密码学(Elliptic Curve Cryptography)是基于椭圆曲线数学理论的公钥密码系统,由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA,ECC在相同安全强度下密钥更短(256位ECC ≈ 3072位RSA…...
day52 ResNet18 CBAM
在深度学习的旅程中,我们不断探索如何提升模型的性能。今天,我将分享我在 ResNet18 模型中插入 CBAM(Convolutional Block Attention Module)模块,并采用分阶段微调策略的实践过程。通过这个过程,我不仅提升…...
线程与协程
1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指:像函数调用/返回一样轻量地完成任务切换。 举例说明: 当你在程序中写一个函数调用: funcA() 然后 funcA 执行完后返回&…...
Python实现prophet 理论及参数优化
文章目录 Prophet理论及模型参数介绍Python代码完整实现prophet 添加外部数据进行模型优化 之前初步学习prophet的时候,写过一篇简单实现,后期随着对该模型的深入研究,本次记录涉及到prophet 的公式以及参数调优,从公式可以更直观…...
三体问题详解
从物理学角度,三体问题之所以不稳定,是因为三个天体在万有引力作用下相互作用,形成一个非线性耦合系统。我们可以从牛顿经典力学出发,列出具体的运动方程,并说明为何这个系统本质上是混沌的,无法得到一般解…...
NFT模式:数字资产确权与链游经济系统构建
NFT模式:数字资产确权与链游经济系统构建 ——从技术架构到可持续生态的范式革命 一、确权技术革新:构建可信数字资产基石 1. 区块链底层架构的进化 跨链互操作协议:基于LayerZero协议实现以太坊、Solana等公链资产互通,通过零知…...
Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理
引言 Bitmap(位图)是Android应用内存占用的“头号杀手”。一张1080P(1920x1080)的图片以ARGB_8888格式加载时,内存占用高达8MB(192010804字节)。据统计,超过60%的应用OOM崩溃与Bitm…...
