668|1

104

帖子

0

资源

一粒金砂(中级)

【平头哥Sipeed LicheeRV 86 Panel测评】十四、lvgl显示图片和本地时间 [复制链接]

本帖最后由 sonicfirr 于 2022-4-25 21:03 编辑

本篇记录使用lvgl框架显示图片的过程,另外获取系统的本地时间并以标签控件显示出来。

1lvgl的图片显示

lvgl框架中图片可以是一个文件也可以是一个变量(数组形式的图片码),当然文件还需要初始化lvgl对文件系统的接口,本例暂以变量形式提供。

应用要显示图片,则需要引入一个图片控件,然后设置它的数据源——使用“lv_img_set_src()”函数。示例如下:

lv_obj_t * icon = lv_img_create(lv_scr_act(), NULL);
/*From variable*/
lv_img_set_src(icon, &my_icon_dsc);

 

上述代码中icon”是一个lvgl对象指针,通过“lv_img_create()”实例化,则对应图片控件。设置数据源时传入参数“my_icon_dsc”是lvgl中的图片描述符数据结构“lv_img_dsc_t”——本身是一个结构体类型,其定义源码如下:

//in “../lvgl/src/draw/lv_img_buf.h”
typedef struct {
    uint32_t cf : 5;          /*Color format: See `lv_img_color_format_t`*/
    uint32_t always_zero : 3; /*It the upper bits of the first byte. Always zero to look like a
                                 non-printable character*/

    uint32_t reserved : 2; /*Reserved to be used later*/
    uint32_t w : 11; /*Width of the image map*/
    uint32_t h : 11; /*Height of the image map*/
} lv_img_header_t;

typedef struct {
    lv_img_header_t header; /**< A header describing the basics of the image*/
    uint32_t data_size;     /**< Size of the image in bytes*/
    const uint8_t * data;   /**< Pointer to the data of the image*/
} lv_img_dsc_t;

 

示例代码中,图片描述符变量的定义过程如下代码:

uint8_t my_icon_data[] = {0x00, 0x01, 0x02, ...};

static lv_img_dsc_t my_icon_dsc = {
    .header.always_zero = 0,
    .header.w = 80,
    .header.h = 60,
    .data_size = 80 * 60 * LV_COLOR_DEPTH / 8,
    .header.cf = LV_IMG_CF_TRUE_COLOR,          /*Set the color format*/
    .data = my_icon_data,
};

 

其中,枚举LV_IMG_CF_TRUE_COLOR”是色彩格式定义,表示RGB格式。

LV_COLOR_DEPTH”则定义色彩深度,它位于“lv_conf.h”,用户可以自定义。本例中设置为32,即4字节的ARGB8888格式。

2、时间获取

86板的Tina Linux可以通过C time库轻松地获得本地时间等数据。本例使用的API有:time()localtime()strftime()以及time_tstruct tm

 

image-20220425205601-1.png

 

14-1 函数time()说明

image-20220425205601-2.png

14-2 函数localtime()说明

 

image-20220425205601-3.png

14-3 函数strftime()说明

3、图片和时间显示案例

本例继续使用线程管理lvgl刷新,创建1s周期的lvgl定时器,在定时器回调中获取本地时间并格式化输出。另外,系统初始时显示一个“天津”的Logo,而且初始即做一次时间获取和输出(如果不做,初始刹那label会显示默认“text”字样)。

图片码通过软件Img2Lcd”获取,软件配置方式如下图所示。图片生成的数组有72008个字节,被放置到头文件“aita_logo.h”。

 

image-20220425205601-4.png

14-4 图片扣码格式

 

/* Includes ------------------------------------------------------- */
#include "lvgl/lvgl.h"
#include "lv_drivers/display/fbdev.h"
#include "lv_drivers/indev/evdev.h"
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <time.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "aita_logo.h"

/* Private macro -------------------------------------------------- */
#define AITA_DISP_BUF_SIZE     (128 * 1024)
#define AITA_SCREEN_WIDTH      480
#define AITA_SCREEN_HEIGHT     480
#define AITA_TITLE_STRING      "AITA Weather for LicheeRV with LVGL"
#define SEND_PERIOD            1000
#define errlog(errmsg)         do{ perror(errmsg);\
    printf("----%s----%s----%d----\n", __FILE__, __func__, __LINE__);\
    return;\
    } while(0)

/* Global variables ----------------------------------------------- */
lv_indev_t *aita_indev;   //pointer of indev
lv_obj_t *sys_scr;        //pointer of system screen instance
lv_obj_t *head_label;     //pointer of title label instance
lv_obj_t *main_label;     //pointer of main label instance
char main_label_text[32]; //main label text string for datetime
lv_obj_t *logo_img;       //pointer of city logo image instance
lv_timer_t *sec_timer;    //pointer of timer instance for tcp polling
pthread_t lvgl_tid;       //lvgl thread id
pthread_t tcprecv_tid;    //tcp receive thread id
pthread_mutex_t lvgl_mutex;  //mutex for lvgl tick
//image descriptor for logo_img
//ARGB8888 image 180*100 which code array is 'tj_logo' 
lv_img_dsc_t img_dsc_city = {
  .header.always_zero = 0,
  .header.w = 180,
  .header.h = 100,
  .data_size = 18000 * LV_COLOR_SIZE / 8,
  .header.cf = LV_IMG_CF_TRUE_COLOR,
  .data = tj_logo,
};

/* Private function prototypes ------------------------------------ */
void aita_InitLVGL(void);
void aita_CreateMainUI(void);
void *thread_lvgl(void *arg);
void sec_timer_cb(lv_timer_t *timer);
void aita_InitTimer(void);
void aita_GetTime(void);

/* Private functions ---------------------------------------------- */
int main(void) {
    void *retval;

//by author. initialize lvgl including displaybuffer, device for disp & input
    aita_InitLVGL();
    
//by author. initialize and register event device
//these code must be in main(), otherwise the touch will fail.
    static lv_indev_drv_t indev_drv;
    lv_indev_drv_init(&indev_drv);
    indev_drv.type = LV_INDEV_TYPE_POINTER; //by author. choice touchpad
    indev_drv.read_cb = evdev_read;         //by author. input callback
    aita_indev = lv_indev_drv_register(&indev_drv);

//by author. create the main view when the demo starts up    
    aita_CreateMainUI();

//by author. create a timer
    aita_InitTimer();

//by author. create mutex for lvgl
    if(pthread_mutex_init(&lvgl_mutex, NULL) != 0) {
        errlog("initialize mutex error");
    }

//by author. create lvgl thread
    if(pthread_create(&lvgl_tid, NULL, thread_lvgl, (void *)0) != 0) {
        errlog("create lvgl thread error");
    }

//by author. wait for thread exit, this demo should never be here.
    pthread_join(lvgl_tid, &retval);
    printf("lvgl thread exit, return value: %s\n", (char *)retval);
    pthread_mutex_destroy(&lvgl_mutex);
    return 0;
}

/*Set in lv_conf.h as `LV_TICK_CUSTOM_SYS_TIME_EXPR`*/
uint32_t custom_tick_get(void)
{
    static uint64_t start_ms = 0;
    if(start_ms == 0) {
        struct timeval tv_start;
        gettimeofday(&tv_start, NULL);
        start_ms = (tv_start.tv_sec * 1000000 + tv_start.tv_usec) / 1000;
    }

    struct timeval tv_now;
    gettimeofday(&tv_now, NULL);
    uint64_t now_ms;
    now_ms = (tv_now.tv_sec * 1000000 + tv_now.tv_usec) / 1000;

    uint32_t time_ms = now_ms - start_ms;
    return time_ms;
}

void aita_InitLVGL(void) {
    /*LittlevGL init*/
    lv_init();

    /*Linux frame buffer device init*/
    fbdev_init(); //by author. initialize framebuffer device for display
    evdev_init(); //by author. initialize event device for touchpad

    /*A small buffer for LittlevGL to draw the screen's content*/
    static lv_color_t buf[AITA_DISP_BUF_SIZE];
    /*Initialize a descriptor for the buffer*/
    static lv_disp_draw_buf_t disp_buf;
    lv_disp_draw_buf_init(&disp_buf, buf, NULL, AITA_DISP_BUF_SIZE);
    /*Initialize and register a display driver*/
    static lv_disp_drv_t disp_drv;
    lv_disp_drv_init(&disp_drv);
    disp_drv.draw_buf   = &disp_buf;
    disp_drv.flush_cb   = fbdev_flush;
    disp_drv.hor_res    = 480;
    disp_drv.ver_res    = 480;
    lv_disp_drv_register(&disp_drv);
}

void aita_CreateMainUI(void) {
    //by author. create system screen which is basic graphic level
    sys_scr = lv_obj_create(lv_scr_act());
    lv_obj_set_size(sys_scr, AITA_SCREEN_WIDTH, AITA_SCREEN_HEIGHT);
    //by author. create the main title which is just a label
    head_label = lv_label_create(sys_scr);
    lv_label_set_text(head_label, AITA_TITLE_STRING);
    lv_obj_align(head_label, LV_ALIGN_TOP_MID, 0, 10);
    //by author. create the city logo image
    logo_img = lv_img_create(sys_scr);
    lv_img_set_src(logo_img, &img_dsc_city);
    lv_obj_align(logo_img, LV_ALIGN_TOP_LEFT, 10, 40);
    //by author. get local time and show string
    aita_GetTime();
    main_label = lv_label_create(sys_scr);
    lv_label_set_text(main_label, main_label_text);
    lv_obj_align(main_label, LV_ALIGN_TOP_LEFT, 200, 40);
    lv_obj_set_style_text_font(main_label, &lv_font_montserrat_20, 0);
}

//by author. lvgl core thread function
void *thread_lvgl(void *arg) {
    while(1) {
        pthread_mutex_lock(&lvgl_mutex);
        lv_task_handler();
        pthread_mutex_unlock(&lvgl_mutex);
        usleep(5000); /* sleep for 5 ms */
    }
}

//by author. sec_timer callback which refresh date string
void sec_timer_cb(lv_timer_t *timer) {
    aita_GetTime();
    lv_label_set_text(main_label, main_label_text);  
}
//by author. initialize timer for 1s timing
void aita_InitTimer(void) {
    sec_timer = lv_timer_create(sec_timer_cb, 1000, NULL);
    lv_timer_set_repeat_count(sec_timer, -1);
}
//by author. get local time string
void aita_GetTime(void) {
    time_t    tsec;
    struct tm *tlocal;
    tsec = time(NULL);
    tlocal = localtime(&tsec);
    memset(main_label_text, 0, 32);
    strftime(main_label_text, 32, "%Y-%m-%d %a %H:%M:%S", tlocal);
}

 

image-20220425205601-5.png

14-5 案例显示效果

 

 

 

 

 

 

 


回复

5390

帖子

18

资源

五彩晶圆(中级)

可以可以,加油!

个人签名

默认摸鱼


回复
您需要登录后才可以回帖 登录 | 注册

查找数据手册?

EEWorld Datasheet 技术支持

最新文章 更多>>
    推荐帖子
    预览TI 狂欢+CC1350 LauchPad评测

    本帖最后由 北方 于 2017-12-12 14:26 编辑 1. CC1350是一款TI独有的双频MCU,同时支持2.4GHz和sub1GHz的协议。BLE可以支持通 ...

    开发板流动站又回归了一块ST电机套件开发板

    116号: STM32 Nucleo Pack FOC and 6 step motor control(ST 3相电机套件) http://5.eewimg.cn/data/attachment/forum/201 ...

    急聘:实施工程师|具备机械、软件、电子、电气专业背景

    【急聘】上海AGV企业急聘大量实施工程师 职位月薪: 4000-7000元 http://p6uhzbk4k.bkt.clouddn.com/newsimage/20188/153743 ...

    基于MSP430单片机实现的无线传输模块.c

    #include "Msp430X14X.h" #define CE BIT0 #define CS BIT1 #define PWR_UP BIT3 #define ADDR_INDEX 8 #d ...

    有没有专门讲运放时域方面的书

    本帖最后由 sunboy25 于 2020-9-13 10:35 编辑 我想问一下,有没有讲运放时域分析和计算方面的教材的?

    【拓普微智能显示模块测评】6.基于开发板NUCLEO-F746ZG的电机应用平台诞生

    经过2天业余时间的修炼,把智能显示模块的所有命令码的控制函数做完了,只需要根据自己的需求,随意调用函数即可实现自己的功能 ...

    关闭
    站长推荐上一条 1/7 下一条

    About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

    站点相关: 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

    北京市海淀区知春路23号集成电路设计园量子银座1305 电话:(010)82350740 邮编:100191

    电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2022 EEWORLD.com.cn, Inc. All rights reserved
    快速回复 返回顶部 返回列表