STM32U5]【NUCLEO-U5A5ZJ-Q测评】无需移植使用lvgl驱动SSD1306 OLED显示中英文和绘图

这篇文章分享的内容,是在Zephyr系统中,直接使用lvgl驱动 NUCLEO-U5A5ZJ-Q 连接的SSD1306 OLED显示屏,来显示中英文字符,以及绘图。


一、硬件连接
NUCLEO-U5A5ZJ-Q开发板提供了Arduino兼容接口,我手头有之前在Arduino Uno R3上使用的SSD1306 OLED,IIC接口的,可以应用上来。
查看手册,可以得知Arduino兼容接口部分IIC接口的位置:



在开发板上的实际位置如下:



然后,将IIC接口的SSD 1306 OLED连接到Arduino兼容引脚:
 



一定要注意你所使用的SSD1306 OLED的驱动电压是5V还是3.3V, 不然可能会烧毁。

二、驱动SSD1306 OLED
经过研究Zephyr的文档,发现Zephyr已经内置了LVGL模块,并且还能够用于驱动SSD1306。
下面就是一个简单的实例代码,用于在屏幕上显示Hello World,并且还有一个计数器计数:

复制

#include <zephyr/device.h>

#include <zephyr/devicetree.h>

#include <zephyr/drivers/display.h>

#include <zephyr/drivers/gpio.h>

#include <lvgl.h>

#include <stdio.h>

#include <string.h>

#include <zephyr/kernel.h>



#define LOG_LEVEL CONFIG_LOG_DEFAULT_LEVEL

#include <zephyr/logging/log.h>

LOG_MODULE_REGISTER(app);



static uint32_t count;



int main(void)

{

    char count_str[11] = {0};

    const struct device *display_dev;

    lv_obj_t *hello_world_label;

    lv_obj_t *count_label;



    display_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_display));

    if (!device_is_ready(display_dev)) {

        LOG_ERR("Device not ready, aborting test");

        return 0;

    }



<blockquote>hello_world_label = lv_label_create(lv_scr_act());



上述的代码逻辑较为简单,简单说明如下:
首先是引入lvgl头文件:

复制

#include <lvgl.h>



然后再定义一个计数器:

复制

static uint32_t count;



在main调用中,先检查设备是否初始化好了:

复制

display_dev = DEVICE_DT_GET(DT_CHOSEN(zephyr_display));

    if (!device_is_ready(display_dev)) {

        LOG_ERR("Device not ready, aborting test");

        return 0;

    }



再创建2个Lable对象用于显示文字和计数器,并给按键设置好回调。

复制

<blockquote>hello_world_label = lv_label_create(lv_scr_act());



最后,在while循环中,更新计数器的值:

复制

    while (1) {

        if ((count % 100) == 0U) {

            sprintf(count_str, "%d", count/100U);

            lv_label_set_text(count_label, count_str);

        }

        lv_task_handler();

        ++count;

        k_sleep(K_MSEC(10));

    }



需要注意的是,在Zephyr中,没有处理LVGL的自动刷新,需要自己调用 lv_task_handler() 来更新显示内容到屏幕上。


要在工程中使用LVGL模块,还需要在prj.conf中添加下面的配置:

复制

CONFIG_LV_Z_MEM_POOL_SIZE=16384

CONFIG_LV_Z_SHELL=y

CONFIG_MAIN_STACK_SIZE=2048



CONFIG_DISPLAY=y

CONFIG_DISPLAY_LOG_LEVEL_ERR=y



CONFIG_LOG=y

CONFIG_SHELL=y



CONFIG_LVGL=y

CONFIG_LV_MEM_CUSTOM=y

CONFIG_LV_USE_LOG=y

CONFIG_LV_USE_LABEL=y

CONFIG_LV_USE_BTN=y

CONFIG_LV_USE_ARC=y

CONFIG_LV_USE_IMG=y

CONFIG_LV_USE_MONKEY=y

CONFIG_LV_FONT_MONTSERRAT_14=y



编译的时候,需要使用下面的参数:

复制

west build -b nucleo_u5a5zj_q . -- -DSHIELD=ssd1306_128x64



编译烧录后,运行结果如下:
 



我所使用的SSD 1306 OLED为底色上黄下蓝,所以看到是有颜色的,但实际显示的时候,就是底色能使上面的颜色,显示文本只有黑色一种。

三、图形的绘制
使用LVGL,还可以在SSD1306 OLED上面绘图。
不过需要注意的是,毕竟SSD1306分辨率有限,显示颜色只有单色,所以效果一般,但用于一些基础信息的显示,还是可以的。
下面就演示在SSD1306 OLED上面,根据给定的坐标点,画一条折线:

复制

 lv_obj_clean(lv_scr_act());

    static lv_point_t line_points[] = { {5, 15}, {30, 50}, {60, 20}, {90, 60}, {120, 30} };



    /*Create style*/

    static lv_style_t style_line;

    lv_style_init(&style_line);

    lv_style_set_line_width(&style_line, 1);

    // lv_style_set_line_color(&style_line, lv_palette_main(LV_PALETTE_WHITE));

    lv_style_set_line_rounded(&style_line, true);



    /*Create a line and apply the new style*/

    lv_obj_t * line1;

    line1 = lv_line_create(lv_scr_act());

    lv_line_set_points(line1, line_points, 5);     /*Set the points*/

    lv_obj_add_style(line1, &style_line, 0);

    lv_obj_center(line1);



        lv_task_handler();



在上述代码中,先定义了一个一批坐标到 line_points,然后定义划线的样式 style_line,再使用 lv_line_create 创建 Line对象,使用lv_line_set_points添加要绘制的处理的折线点,以及使用 lv_obj_add_style 设置样式。

最终的显示效果如下:
 



四、中文的显示
LVGL对Unicode字符的处理提供了很好的处理,包括中文在内。
不过,要显示中文,需要提前准备好专门的字形文件。
我们可以直接把一个ttf字体,转换为字形文件,但是这样包含的中文字符比较多,生成的文件比较大,嵌入式设备不一定都能存放得下,而且运行起来速度也会收到影响。
所以,通常情况下,只会为需要显示的中文字符,生成对应的字形文件。
要给LVGL生成中文字形文件,可以使用lv_font_conv,可以从 https://github.com/lvgl/lv_font_conv 下载。

下面,我要在显示屏上显示"你好,世界!",那么可以试用如下的指令来生成:

复制

lv_font_conv --no-compress --format lvgl --font OPPOSans-M.ttf -o opposans_m_16_2.c --bpp 4 --size 16 -r 0x20-0x7F --symbols 你好,世界!

上述指令的含义,是从 OPPOSans-M.ttf 字体文件中,提取 "你好,世界!" 的字形数据以及ASCII码对应的字形数据,生成16号字体对应的c文件opposans_m_16_2.c,生成后的内容如下:



因为字形数据较多,所以只展示上面一部分。

将生成的字形数据的c文件,放置到项目的src目录下,然后,在代码中,include 之后,添加字体定义:

复制

LV_FONT_DECLARE(opposans_m_16_2);


然后设置一个演示使用中文字体:

复制

static lv_style_t label_style_cn;                                                                                                // 创建一个风格

lv_style_init(&label_style_cn);                                                                                                // 初始化风格

lv_style_set_text_font(&label_style_cn, &opposans_m_16_2);        // 设置字体



再给前面显示的 hello_world_label 添加定义的样式:

复制

lv_label_set_text(hello_world_label, "Hello world!");

lv_obj_align(hello_world_label, LV_ALIGN_CENTER, 0, 0);

lv_obj_add_style(hello_world_label, &label_style_cn, LV_PART_MAIN);                // 应用效果风格



最后,在代码中调用:

复制

while (1) {

        if ((count % 100) == 0U) {

                sprintf(count_str, "%d", count/100U);

                lv_label_set_text(count_label, count_str);



                if (((count / 100) % 2) == 0U) {

                        lv_label_set_text(hello_world_label, "Hello world!");

                } else {

                        lv_label_set_text(hello_world_label, "你好,世界!");

                }

        }

        lv_task_handler();

        ++count;

        k_sleep(K_MSEC(10));

}



编译运行后,实际效果如下:




五、总结
NUCLEO-U5A5ZJ-Q的良好硬件设计,使得开发者可以很方便的连接Arduino兼容的硬件,大大方便了开发工作。
Zephyr对NUCLEO-U5A5ZJ-Q的给力支持,以及提供的LVGL模块支持,能够让开发者聚焦于核心业务的处理,真的是非常的方便。
有一点需要注意的是,Zephyr提供的LVGL版本并不是最新的,所以有极少部分调用,可能与新版本的LVGL存在差异,编译的时候会有提示。
后续将会继续使用彩色显示屏来进行测试,并继续给大家分享。
---------------------
作者:HonestQiao
链接:https://bbs.21ic.com/icview-3346778-1-1.html
来源:21ic.com
此文章已获得原创/原创奖标签,著作权归21ic所有,任何人未经允许禁止转载。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值