基于Arduino的LVGL移植

这是一篇如何将LVGL移植到Arduino的教程(基于芯片ESP32 Pico D4); 软件版本 这次实验使用的lvgl版本是8.1.1,要先配置好tft_espi,确保显示正常;如果要使用触摸屏设备,在移植之前要确保能获取到触摸数据; 工程配置 库安装 添加lvgl库 ,最好也添加lv_examples库,自带的例子虽然内容完全一样,但是并不能直接使用; 库安装 然后复制为lv_conf_template.h为lv_conf.h: lv_conf.h创建 然后复制为lv_demo_conf_template.h为lv_demo_conf.h: lv_demo_conf.h创建 配置文件 lv_conf.h 修改这几个地方; 启动lv_conf.h: 启动lv_conf 设置色深,一般都是16: 设置色深 启动自定义时钟,不设置的话只会显示第一帧不动: 启动自定义时钟 LV_DPI_DEF 注意这里,虽然LVGL的作者说这个没这么重要,但他会严重影响到LVGL的动画效果,你应该进行DPI的手动计算,例如240x280分辨率1.69英寸的屏幕,那么 DPI为: LV_DPI_DEF =\frac{\sqrt{240*280} }{1.69} ≈ 153 LV_DPI_DEF配置 也可以使能日志打印: 使能日志打印 lv_demo_conf.h 修改这几个地方; 启动lv_demo_conf.h: 启动Demo 配置要运行的Demo: Demo选择 自定义显示接口和外部输入接口 文件添加 在src文件夹下添加以下两个文件: 自定义接口 代码内容 my_lv_ports.cpp #include "my_lv_ports.h" #include "CST816T.h" // TFT_eSPI tft = TFT_eSPI(screenWidth, screenHeight); /* TFT instance */ TFT_eSPI tft = TFT_eSPI(); /* TFT instance */ CST816T touch(19, 21, -1, 22); // sda, scl, rst, irq // /*Read the touchpad*/ void my_touchpad_read(lv_indev_drv_t *indev_driver, lv_indev_data_t *data) { bool FingerNum = 0; uint8_t gesture; uint16_t touchX, touchY; FingerNum = touch.getTouch(&touchX, &touchY, &gesture); if (FingerNum) { data->state = LV_INDEV_STATE_REL; data->point.x = touchX; data->point.y = touchY; #if LV_USE_LOG != 0 Serial.printf("Touch: x=%d y=%d mode=%d\r\n", touchX, touchY, gesture); #endif FingerNum = 0; } else { data->state = LV_INDEV_STATE_PR; } } /* Display flushing */ 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.setSwapBytes(true); // tft.pushImageDMA(area->x1, area->y1, w, h, (uint16_t *)&color_p->full); tft.pushImage(area->x1, area->y1, w, h, (uint16_t *)&color_p->full); // 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); } #if LV_USE_LOG != 0 void my_print(const char *buf) { Serial.printf("%s \r\n", buf); } #endif void my_disp_init(void) { // 绘图缓冲初始化 // static lv_disp_draw_buf_t draw_buf; // static lv_color_t buf[screenWidth * 10]; // lv_disp_draw_buf_init(&draw_buf, buf, NULL, screenWidth * 10); static lv_disp_draw_buf_t draw_buf; static lv_color_t buf_2_1[screenWidth * 40]; /*A buffer for 10 rows*/ static lv_color_t buf_2_2[screenWidth * 40]; /*An other buffer for 10 rows*/ lv_disp_draw_buf_init(&draw_buf, buf_2_1, buf_2_2, screenWidth * 30); /*Initialize the display buffer*/ // TFT驱动初始化 tft.begin(); /* TFT init */ // tft.initDMA(); tft.setRotation(0); /* Landscape orientation, flipped */ // 设置LVGL显示设备 static lv_disp_drv_t disp_drv; lv_disp_drv_init(&disp_drv); /*Change the following line to your display resolution*/ 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); touch.begin(); // 设置LVGL输入设备(电阻屏) static lv_indev_drv_t indev_drv; lv_indev_drv_init(&indev_drv); indev_drv.type = LV_INDEV_TYPE_POINTER; indev_drv.read_cb = my_touchpad_read; lv_indev_drv_register(&indev_drv); // 设置LVGL串口输出设备(调试用) #if LV_USE_LOG != 0 lv_log_register_print_cb(my_print); #endif } my_lv_ports.h ...

April 7, 2023 · 2 min · Rancho

AT32F403A系列单片机开发

记录AT32开发中遇到的问题; 硬件部分: 硬件部分我是参考官方开发板来做的; 经过测试,硬件部分没有任何问题; 原理图 PCB仿真图 实物图 显示效果 有几个值得关注的地方,我将在下面列出: 使用编码器开关作为输入设备; 使用CH340E芯片作为串口转USB; 通过TYPE-C接口的正反插实现不同的功能(连接CH340E芯片和AT32的USB引脚): 屏幕接口采用的是FPC0.5mm接口,方便安装; 硬件部分的测试很快就结束了,主要就是测试各个外设是否能正常使用; 经测试,主控芯片、屏幕、spiflash、USB接口、CH340E、编码器开关、RTC时钟均能正常使用; 软件开发: 参考资料: 主控芯片使用的是雅特力的AT32F403ACGU7,其特性如下所示: 参考资料网站:https://www.arterytek.com/cn/product/AT32F403A.jsp 下载固件库源码,经解压后,可以在目录: .\AT32F403A_407_Firmware_Library_V2.1.2\project\at_start_f403a\examples 找到各个外设的例子: $ ls acc/ crm/ gpio/ spi/ wwdt/ adc/ dac/ i2c/ sram/ xmc/ bpr/ debug/ i2s/ tmr/ can/ dma/ pwc/ usart/ cortex_m4/ exint/ rtc/ usb_device/ crc/ flash/ sdio/ wdt/ 首先当然是串口打印和点灯,这样能测试时钟配置是否正常,以及判断芯片好坏与否; 具体开发: 关键代码如下: 点灯: void at32_led_init(void) { gpio_init_type gpio_init_struct; /* enable the led clock */ crm_periph_clock_enable(USER_LED_GPIO_CRM_CLK, TRUE); /* set default parameter */ gpio_default_para_init(&gpio_init_struct); /* configure the led gpio */ gpio_init_struct.gpio_pins = USER_LED_PIN; gpio_init_struct.gpio_mode = GPIO_MODE_OUTPUT; gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL; gpio_init_struct.gpio_pull = GPIO_PULL_NONE; gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER; gpio_init(USER_LED_GPIO, &gpio_init_struct); } void at32_led_on(void) { USER_LED_GPIO->clr = USER_LED_PIN; } void at32_led_off(void) { USER_LED_GPIO->scr = USER_LED_PIN; } void at32_led_toggle(void) { USER_LED_GPIO->odt ^= USER_LED_PIN; } 串口: void uart_print_init(uint32_t baudrate) { gpio_init_type gpio_init_struct; /* enable the uart and gpio clock */ crm_periph_clock_enable(PRINT_UART_CRM_CLK, TRUE); crm_periph_clock_enable(PRINT_UART_TX_GPIO_CRM_CLK, TRUE); gpio_default_para_init(&gpio_init_struct); /* configure the uart tx pin */ gpio_init_struct.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER; gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL; gpio_init_struct.gpio_mode = GPIO_MODE_MUX; gpio_init_struct.gpio_pins = PRINT_UART_TX_PIN; gpio_init_struct.gpio_pull = GPIO_PULL_NONE; gpio_init(PRINT_UART_TX_GPIO, &gpio_init_struct); /* configure uart param */ usart_init(PRINT_UART, baudrate, USART_DATA_8BITS, USART_STOP_1_BIT); usart_transmitter_enable(PRINT_UART, TRUE); usart_enable(PRINT_UART, TRUE); } 串口重定向: ...

October 12, 2022 · 7 min · Rancho

lvgl显示txt文本(指定字体)

前些天做微机课设,给小一加了几个功能,其中一个重要功能是显示中文文本; 字体取模: 屏幕要显示图案,例如某个汉字或者数字、图案等,都需要对图案进行取模操作; 使用的是LvglFontTool工具,LVGL官网的字体转化用于单个字体取模比较方便;批量的话,使用这个离线取模软件比较方便; 操作界面如下所示: 步骤还是很简单的: 首先选择字体,包括一个TFF字体文件还有选择需要取模的字体大小; 然后加入汉字,我是将所有常用的汉字都加入了; 然后在右边配置一些选项,按照图片上的配置就可以; 最后点击开始转换就可以生成一个myFont.c和myFont.bin文件,bin文件加载到SPI FLASH中,C文件加入Keil工程即可; 如果只需要显示数量比较少的文本,取模后得到的数组可以直接放在一个.c或者.h文件中,直接下载到单片机的FLASH中即可,但是如果要显示各种不同样式和不同大小的字体,取模后得到的文件会很大,加载到FLASH中存放是不合理的。 文件放置: 小一这一版的硬件是带了一个8M的SPI FLASH,所以取模后的数据可以放在这块SPI FLASH中,可以用哪些方法通过单片机读取bin文件中的内容呢? 一般是有两个方法: 放入移植好的Fatfs文件系统中,通过文件系统提供的接口读取该bin文件; 加载进SPI FLASH中,直接通过最底层的读取函数读取; 两种方案各有优缺点,第一种更换字体取模文件很方便,但是由于字体取模文件会频繁被读取,所以这个方案的效率会比较差;第二种方案更换字体取模文件比较麻烦,但是读取的效率会高不少。我是选择了第二种方案,第一种我也试了,效率确实不是很高。 对于第二种方案,首先要将取模文件从PC机放入SPI FLASH中,我采用的方案是将SPI FLASH划分为两部分: 前4MB 后4MB 用于存储字体取模数据 用于建立文件系统 然后将SPI FLASH模拟为USB设备,插入PC机,会弹出一个U盘,将字体文件拖入;然后通过一个函数,将bin文件分段读取并分段写入SPI FLASH的前4MB部分中,具体函数如下所示: void write_to_flash(void) { uint8_t i; f_res = f_open(&file1, "myFont.bin", FA_READ);//打开对应文件 count_f = 0; for (i = 0; i 如果有多个字体文件,可以将写入的地址偏移一个大小即可。 ## 文件读取: 字体取模文件读取只需要修改`myFont.c`中的一个函数: ```c static uint8_t __g_font_buf[324]; //如bin文件存在SPI FLASH可使用此buff static uint8_t *__user_font_getdata(int offset, int size) { //如字模保存在SPI FLASH, SPIFLASH_Read(__g_font_buf,offset,size); //如字模已加载到SDRAM,直接返回偏移地址即可如:return (uint8_t*)(sdram_fontddr+offset); my_W25QXX_Read(__g_font_buf, offset, size); return __g_font_buf; } 如果有多个字体文件,可以在对应的myFont文件中将读出的地址偏移一个大小即可。 ...

May 16, 2022 · 1 min · Rancho

LVGL开发

最近要做一个GUI界面,自己开发各种功能是极其麻烦的(对的,我之前是做过的),需要注意很多问题,而且开发起来很多功能基本上是实现不了的,所以只能想其他办法了,因为之前用LVGL做过一个很简单的GUI界面,所以这次也打算用LVGL来做,也算是再复习一下这个界面的使用。 以下是关于LVGL的简介以及特点: LVGL(Light and Versatile Graphics Library,轻巧而多功能的图形库)是一个免费的开放源代码图形库,它提供创建具有易于使用的图形元素,精美的视觉效果和低内存占用的嵌入式GUI所需的一切。 LVGL主要特性 功能强大的构建块,例如按钮,图表,列表,滑块,图像等. 带有动画,抗锯齿,不透明,平滑滚动的高级图形. 各种输入设备,例如触摸板,鼠标,键盘,编码器等. 支持UTF-8编码的多语言. 多显示器支持,如TFT,单色显示器. 完全可定制的图形元素. 独立于任何微控制器或显示器使用的硬件. 可扩展以使用很少的内存(64 kB闪存,16 kB RAM)进行操作. 操作系统,支持外部存储器和GPU,但不是必需的. 单帧缓冲区操作,即使具有高级图形效果. 用C语言编写,以实现最大的兼容性(与C ++兼容). 模拟器可在没有嵌入式硬件的PC上进行嵌入式GUI设计. 可移植到MicroPython. 可快速上手的教程、示例、主题. 丰富的文档教程. 在MIT许可下免费和开源. LVGL硬件要求 基本上,每个现代控制器(肯定必须要能够驱动显示器)都适合运行LVGL。LVGL的最低运行要求很低: 16、32或64位微控制器或处理器. 最低 16 MHz 时钟频率. Flash/ROM::对于非常重要的组件要求 >64 kB(建议 > 180 kB). RAM 静态 RAM 使用量:~2 kB,取决于所使用的功能和对象类型. 堆栈: > 2kB(建议 > 8 kB). 动态数据(堆):> 2 KB(如果使用多个对象,则建议 > 16 kB)。由 lv_conf.h 中的 LV_MEM_SIZE 宏进行设置. 显示缓冲区:> “水平分辨率”像素(建议 > 10× “水平分辨率” ). MCU 或外部显示控制器中的一帧缓冲区. ...

January 3, 2022 · 1 min · Rancho