本文着重讲解怎么移植与怎么使用,对于原理可自行百度或者B站检索相关资料,推荐百问网。
阅读本文需要你会基本的Arduino 、lvgl及硬件知识。
LVGL(Light and Versatile Graphics Library)是一个免费的开源图形库,提供创建具有易于使用的图形元素、美丽的视觉效果和低内存占用的嵌入式GUI所需的一切。更多详情请点击这里。
由于一般的单片机内存很小,可能不够用于显示图片等需要较大内存的资源。那么我们可以使用SD卡来存储这些文件,当MCU需要时,读取使用即可。本实验分为两步,一是lvgl文件的移植,二是文件系统的使用,所有操作基于Arduino平台。
平台:Arduino 2.11 +lvgl 8.3;
硬件:Esp32 4M + SD卡2G + 240x240TFT屏幕;
Esp32与SD卡的链接引脚
注:有些引脚可自定。
1 、打开lv_conf.h文件打开#IF_USE_FS_FATFS 。
“S”为盘符,就像我们的电脑一样,有很多硬盘,C盘,F盘等,当我们访问文件时就可以拿着盘符去访问,例如:“S:/test.png”,意为访问S盘下test.png文件。
#define LV_USE_FS_FATFS 1
#if LV_USE_FS_FATFS
#define LV_FS_FATFS_LETTER 'S' /*Set an upper cased letter on which the drive will accessible (e.g. 'A')*/
#define LV_FS_FATFS_CACHE_SIZE 1024*20 /*>0 to cache this number of bytes in lv_fs_read()*/
#endif
2、初始化SD卡。
void initSDCard() {
if(!SD_MMC.begin()){
Serial.println("Card Mount Failed");
return;
}
uint8_t cardType = SD_MMC.cardType();
if(cardType == CARD_NONE){
Serial.println("No SD_MMC card attached");
return;
}
Serial.print("SD_MMC Card Type: ");
if(cardType == CARD_MMC){
Serial.println("MMC");
} else if(cardType == CARD_SD){
Serial.println("SDSC");
} else if(cardType == CARD_SDHC){
Serial.println("SDHC");
} else {
Serial.println("UNKNOWN");
}
}
注意,初始化SD卡需要在lv_init();方法之前,因为执行lv_init()时已经将FatFs文件系统与lvgl对接。故我们需要在此之前初始化SD卡,注意:初始化SD卡不能在lv_fs_port.c中的lv_fs_init()中,会报错,可能是由于C与C++混编引起的。
上面的操作完成后,编译运行即可。
1、在lv_conf.h中打开#IF_USE_PNG 或#IF_USE_SJPG 或#IF_USE_GIF,打开什么取决于你用什么格式的图片,这些是lvgl自带的第三方解码库,解码库在lvgl 8.0版本以上才有,可以显示png、
bmp、jpg/sjpg(sjpg是官方专门为lvgl制作的一种图片格式,其特点为解码迅速、体积小)、GIF、QROCODE(二维码),当我们打开其中任一个宏时,lvgl会自动为我们的项目加入相关的解码器,不需要我们再去移植。
#define LV_USE_PNG 1
/*BMP decoder library*/
#define LV_USE_BMP 0
/* JPG + split JPG decoder library.
* Split JPG is a custom format optimized for embedded systems. */
#define LV_USE_SJPG 1
/*GIF decoder library*/
#define LV_USE_GIF 0
/*QR code library*/
#define LV_USE_QRCODE 1
2、制作相关文件
我们先制作一张72x72的图片,这里我们用官方的图片。
在Arduino 中写下方代码,值得注意的是“S:/test1.png”,这里是绝对路径,可以设置为你自己的SD卡中的文件,注意图片不可以太大,否则屏幕上会有“No data”的提示,此问题可以自行百度解决。一般是RAM不足所致。
lv_obj_t *img_bg = lv_img_create(lv_scr_act());
lv_img_set_src(img_bg, "S:/test1.png");
lv_obj_center(img_bg);
如若设置的都正确,那么编译烧录后屏幕将显示如下。
自定义字体的显示,有两种方式一种是C数组,一种是bin文件,本文中心是文件系统的使用,那么我们将使用bin文件,我们先制作bin文件,将其放入SD卡中,然后利用lvgl文件系统读取显示在屏幕上。
1、bin字体文件的制作。
先按照it网王老师的方法安装lv_font_conv工具,也可以直接用王老师的方法去制作bin字体文件,如果你有Python环境的话,也可以用我用tkinter写的带UI的转换工具(前提是你已经按照王老师的方法安装好lv_font_conv)。
from tkinter import *
from tkinter.filedialog import askopenfilename
import os
root=Tk()
root.geometry("250x300+552+173")
root.title("LVGL字体转换")
var=StringVar()
def file():
global path,savepath
path=askopenfilename(title="选择一个字体文件")
if path:
savepath="/".join(path.split("/")[:-1])+"/"
else:
var.set("文件错误,请重试")
def but():
global inp1,inp2,tex1
btn1=Button(root,text="点击选择字体文件夹",fg="blue",command=file)
btn1.pack(side=TOP,anchor="e")
btn2=Button(root,text="点击开始转换",fg="red",command=save)
btn2.pack(side=TOP,anchor="e")
lab1=Label(root,textvariable=var,fg="Pink")
lab1.pack(side=TOP,anchor="w")
lab=Label(root,text="名称:",fg="red")
lab1=Label(root,text="大小:",fg="red")
lab.place(relx=0,rely=0.01)
lab1.place(relx=0,rely=0.07)
var.set("请在上方输入框内输入字体名称与大小\n且在下方输入想要的汉字然后点击转换")
inp1=Entry(root,bg="yellow")
inp1.place(relx=0.15,rely=0.07,relheight=0.08,relwidth=0.3)
inp2=Entry(root,bg="hotpink")
inp2.place(relx=0.15,rely=0.01,relheight=0.08,relwidth=0.3)
tex1=Text(root,bg="pink",width=248,height=200)
tex1.pack(side=BOTTOM)
def save():
o="lv_font_conv --size {0} --format bin --bpp 1 --font {1} --symbols {2} --no-compress -o {3}.bin".format(inp1.get(),path,tex1.get("1.0",END).replace("\n",""),savepath+inp2.get())
try:
os.system(o)
var.set("转换成功,字体保存在\n{0}".format(savepath))
except:
var.set("失败")
def run():
but()
root.mainloop()
if __name__ == "__main__":
run()
如设置无错误的话,将得到一个xxx.bin文件。
然后在主程序中写下如下代码
lv_font_t *font;
font = lv_font_load("S:ttf1.bin");
if (font == NULL)
{
Serial.println("font load failed");
}
static lv_style_t font_style;
lv_style_init(&font_style);
lv_style_set_text_font(&font_style, font);
lv_obj_t *label_zh = lv_label_create(lv_scr_act());
lv_obj_center(label_zh);
lv_obj_add_style(label_zh, &font_style, 0);
lv_label_set_text(label_zh, "安");
编译烧录后,我们的屏幕将显示如下:
我们的自定义字体显示成功,其实还可以显示图标字体,那么这里不再过多介绍,感兴趣的同学可以自行百度或者查阅相关手册学习。
二维码我们不需要文件系统就可以显示,这里作为一个简单介绍。显示二维码的前提是,保证你已经打开#LV_USE_QRCODE宏定义。那么在我们的程序中输入以下代码,编译烧录后即可以在屏幕上显示如图所示的二维码了,
其中data里存放的是百度首页的网址,手机扫二维码后就可以跳转百度网页,同学们可以借助此组件,创造一些有意思的内容出来。
lv_color_t bg_color = lv_palette_lighten(LV_PALETTE_LIGHT_BLUE, 5);
lv_color_t fg_color = lv_palette_darken(LV_PALETTE_BLUE, 4);
const char* data = "https://baidu.com";
lv_obj_t * qr = lv_qrcode_create(lv_scr_act(),150,fg_color, bg_color);
lv_qrcode_update(qr,data,strlen(data));
lv_obj_center(qr);
7、完整代码
#include <lvgl.h>
#include <TFT_eSPI.h>
#include <SD_MMC.h>
static const uint16_t screenWidth = 240;
static const uint16_t screenHeight = 240;
static lv_disp_draw_buf_t draw_buf;
static lv_color_t buf[screenWidth * 10];
TFT_eSPI tft = TFT_eSPI( screenWidth, screenHeight);
void initSDCard() {
if(!SD_MMC.begin()){
Serial.println("Card Mount Failed");
return;
}
uint8_t cardType = SD_MMC.cardType();
if(cardType == CARD_NONE){
Serial.println("No SD_MMC card attached");
return;
}
Serial.print("SD_MMC Card Type: ");
if(cardType == CARD_MMC){
Serial.println("MMC");
} else if(cardType == CARD_SD){
Serial.println("SDSC");
} else if(cardType == CARD_SDHC){
Serial.println("SDHC");
} else {
Serial.println("UNKNOWN");
}
}
void my_disp_flush(lv_disp_drv_t *disp, const lv_area_t *area, lv_color_t *color_p) {
uint32_t w = (area->x2 - area->x1 + 1);
uint32_t h = (area->y2 - area->y1 + 1);
tft.startWrite();
tft.setAddrWindow(area->x1, area->y1, w, h);
tft.pushColors((uint16_t *)&color_p->full, w * h, true);
tft.endWrite();
lv_disp_flush_ready(disp);
}
void setup(){
Serial.begin(115200);
initSDCard();
lv_init();
tft.begin();
tft.setRotation(3);
lv_disp_draw_buf_init(&draw_buf, buf, NULL, screenWidth * 10);
static lv_disp_drv_t disp_drv;
lv_disp_drv_init(&disp_drv);
disp_drv.hor_res = screenWidth;
disp_drv.ver_res = screenHeight;
disp_drv.flush_cb = my_disp_flush;
disp_drv.draw_buf = &draw_buf;
lv_disp_drv_register(&disp_drv);
/*二维码显示*/
lv_color_t bg_color = lv_palette_lighten(LV_PALETTE_LIGHT_BLUE, 5);
lv_color_t fg_color = lv_palette_darken(LV_PALETTE_BLUE, 4);
const char* data = "https://baidu.com";
lv_obj_t * qr = lv_qrcode_create(lv_scr_act(),150,fg_color, bg_color);
lv_qrcode_update(qr,data,strlen(data));
lv_obj_center(qr);
/* 图片显示*/
lv_obj_t *img_bg = lv_img_create(lv_scr_act());
lv_img_set_src(img_bg, "S:/wink.png");
lv_obj_center(img_bg);
/* 字体测试*/
lv_font_t *font;
font = lv_font_load("S:ttf1.bin");
if (font == NULL)
{
Serial.println("font load failed");
}
static lv_style_t font_style;
lv_style_init(&font_style);
lv_style_set_text_font(&font_style, font);
lv_obj_t *label_zh = lv_label_create(lv_scr_act());
lv_obj_center(label_zh);
lv_obj_add_style(label_zh, &font_style, 0);
lv_label_set_text(label_zh, "安");
}
void loop(){
lv_timer_handler();
vTaskDelay(5);
}
基于Arduino框架的lvgl8.3文件系统的移植与使用就展示完毕,感兴趣的可以尝试一下,第一篇文章,有写的不对的地方请指正。
注:原创作品,转载请注明出处,谢谢合作;
文章浏览阅读1.6k次。安装配置gi、安装数据库软件、dbca建库见下:http://blog.csdn.net/kadwf123/article/details/784299611、检查集群节点及状态:[root@rac2 ~]# olsnodes -srac1 Activerac2 Activerac3 Activerac4 Active[root@rac2 ~]_12c查看crs状态
文章浏览阅读1.3w次,点赞45次,收藏99次。我个人用的是anaconda3的一个python集成环境,自带jupyter notebook,但在我打开jupyter notebook界面后,却找不到对应的虚拟环境,原来是jupyter notebook只是通用于下载anaconda时自带的环境,其他环境要想使用必须手动下载一些库:1.首先进入到自己创建的虚拟环境(pytorch是虚拟环境的名字)activate pytorch2.在该环境下下载这个库conda install ipykernelconda install nb__jupyter没有pytorch环境
文章浏览阅读5.2k次,点赞19次,收藏28次。选择scoop纯属意外,也是无奈,因为电脑用户被锁了管理员权限,所有exe安装程序都无法安装,只可以用绿色软件,最后被我发现scoop,省去了到处下载XXX绿色版的烦恼,当然scoop里需要管理员权限的软件也跟我无缘了(譬如everything)。推荐添加dorado这个bucket镜像,里面很多中文软件,但是部分国外的软件下载地址在github,可能无法下载。以上两个是官方bucket的国内镜像,所有软件建议优先从这里下载。上面可以看到很多bucket以及软件数。如果官网登陆不了可以试一下以下方式。_scoop-cn
文章浏览阅读4.5k次,点赞2次,收藏3次。首先要有一个color-picker组件 <el-color-picker v-model="headcolor"></el-color-picker>在data里面data() { return {headcolor: ’ #278add ’ //这里可以选择一个默认的颜色} }然后在你想要改变颜色的地方用v-bind绑定就好了,例如:这里的:sty..._vue el-color-picker
文章浏览阅读640次。基于芯片日益增长的问题,所以内核开发者们引入了新的方法,就是在内核中只保留函数,而数据则不包含,由用户(应用程序员)自己把数据按照规定的格式编写,并放在约定的地方,为了不占用过多的内存,还要求数据以根精简的方式编写。boot启动时,传参给内核,告诉内核设备树文件和kernel的位置,内核启动时根据地址去找到设备树文件,再利用专用的编译器去反编译dtb文件,将dtb还原成数据结构,以供驱动的函数去调用。firmware是三星的一个固件的设备信息,因为找不到固件,所以内核启动不成功。_exynos 4412 刷机
文章浏览阅读2w次,点赞24次,收藏42次。Linux系统配置jdkLinux学习教程,Linux入门教程(超详细)_linux配置jdk
文章浏览阅读3.3k次,点赞5次,收藏19次。xlabel('\delta');ylabel('AUC');具体符号的对照表参照下图:_matlab微米怎么输入
文章浏览阅读119次。顺序读写指的是按照文件中数据的顺序进行读取或写入。对于文本文件,可以使用fgets、fputs、fscanf、fprintf等函数进行顺序读写。在C语言中,对文件的操作通常涉及文件的打开、读写以及关闭。文件的打开使用fopen函数,而关闭则使用fclose函数。在C语言中,可以使用fread和fwrite函数进行二进制读写。 Biaoge 于2024-03-09 23:51发布 阅读量:7 ️文章类型:【 C语言程序设计 】在C语言中,用于打开文件的函数是____,用于关闭文件的函数是____。
文章浏览阅读3.4k次,点赞2次,收藏13次。跟随鼠标移动的粒子以grid(SOP)为partical(SOP)的资源模板,调整后连接【Geo组合+point spirit(MAT)】,在连接【feedback组合】适当调整。影响粒子动态的节点【metaball(SOP)+force(SOP)】添加mouse in(CHOP)鼠标位置到metaball的坐标,实现鼠标影响。..._touchdesigner怎么让一个模型跟着鼠标移动
文章浏览阅读178次。项目运行环境配置:Jdk1.8 + Tomcat7.0 + Mysql + HBuilderX(Webstorm也行)+ Eclispe(IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持)。项目技术:Springboot + mybatis + Maven +mysql5.7或8.0+html+css+js等等组成,B/S模式 + Maven管理等等。环境需要1.运行环境:最好是java jdk 1.8,我们在这个平台上运行的。其他版本理论上也可以。_基于java技术的停车场管理系统实现与设计
文章浏览阅读3.5k次。前言对于MediaPlayer播放器的源码分析内容相对来说比较多,会从Java-&amp;gt;Jni-&amp;gt;C/C++慢慢分析,后面会慢慢更新。另外,博客只作为自己学习记录的一种方式,对于其他的不过多的评论。MediaPlayerDemopublic class MainActivity extends AppCompatActivity implements SurfaceHolder.Cal..._android多媒体播放源码分析 时序图
文章浏览阅读2.4k次,点赞41次,收藏13次。java 数据结构与算法 ——快速排序法_快速排序法