在CodeBlocks中用SDL2在Windows上仿真LVGL嵌入式图形库

LVGL(Light and Versatile Graphics Library)是一个嵌入式图形库,主要用于开发嵌入式人机界面,文档在这里。

现在我们在CodeBlocks中基于SDL2创建一个项目,移植LVGL到SDL2。

1、创建一个SDL2项目(可参考这里)

在CodeBlocks中用SDL2在Windows上仿真LVGL嵌入式图形库_第1张图片

2、下载LVGL和LVGL示例

git clone https://github.com/lvgl/lvgl.git
git clone https://github.com/lvgl/lv_examples.git

clone在项目文件夹内:

在CodeBlocks中用SDL2在Windows上仿真LVGL嵌入式图形库_第2张图片

(1)复制lvgl/lv_conf_template.h到lvgl同级目录,重命名lv_conf_template.h为lv_conf.h;

/*lv_conf.h的修改部分如下*/

/* Maximal horizontal and vertical resolution to support by the library.*/
#define LV_HOR_RES_MAX          (800)  /*屏幕宽度*/
#define LV_VER_RES_MAX          (480)  /*屏幕高度*/

/* Color depth:
 * - 1:  1 byte per pixel
 * - 8:  RGB332
 * - 16: RGB565
 * - 32: ARGB8888
 */
#define LV_COLOR_DEPTH     32  /*颜色深度*/

/*...*/

/* Montserrat fonts with bpp = 4
 * https://fonts.google.com/specimen/Montserrat  */ /*打开所用到的字体*/
#define LV_FONT_MONTSERRAT_12    0
#define LV_FONT_MONTSERRAT_14    1
#define LV_FONT_MONTSERRAT_16    1
#define LV_FONT_MONTSERRAT_18    0
#define LV_FONT_MONTSERRAT_20    0
#define LV_FONT_MONTSERRAT_22    1
#define LV_FONT_MONTSERRAT_24    0
#define LV_FONT_MONTSERRAT_26    0
#define LV_FONT_MONTSERRAT_28    1
#define LV_FONT_MONTSERRAT_30    0
#define LV_FONT_MONTSERRAT_32    1
#define LV_FONT_MONTSERRAT_34    0
#define LV_FONT_MONTSERRAT_36    0
#define LV_FONT_MONTSERRAT_38    0
#define LV_FONT_MONTSERRAT_40    0
#define LV_FONT_MONTSERRAT_42    0
#define LV_FONT_MONTSERRAT_44    0
#define LV_FONT_MONTSERRAT_46    0
#define LV_FONT_MONTSERRAT_48    0

(2)复制lv_examples/lv_ex_conf_templ.h到lv_examples同级目录,重命名lv_ex_conf_templ.h为lv_ex_conf_.h;

/*在lv_ex_conf.h中选择打开所仿真的示例*/

/**
 * @file lv_ex_conf.h
 *
 */
/*
 * COPY THIS FILE AS lv_ex_conf.h
 */

#if 1 /*Set it to "1" to enable the content*/

#ifndef LV_EX_CONF_H
#define LV_EX_CONF_H


/*******************
 * GENERAL SETTING
 *******************/
#define LV_EX_PRINTF       0       /*Enable printf-ing data in demoes and examples*/
#define LV_EX_KEYBOARD     0       /*Add PC keyboard support to some examples (`lv_drivers` repository is required)*/
#define LV_EX_MOUSEWHEEL   0       /*Add 'encoder' (mouse wheel) support to some examples (`lv_drivers` repository is required)*/

/*********************
 * DEMO USAGE
 *********************/

/*Show some widget*/
#define LV_USE_DEMO_WIDGETS        0
#if LV_USE_DEMO_WIDGETS
#define LV_DEMO_WIDGETS_SLIDESHOW  0
#endif

/*Printer demo, optimized for 800x480*/
#define LV_USE_DEMO_PRINTER     1

/*Demonstrate the usage of encoder and keyboard*/
#define LV_USE_DEMO_KEYPAD_AND_ENCODER     0

/*Benchmark your system*/
#define LV_USE_DEMO_BENCHMARK   0

/*Stress test for LVGL*/
#define LV_USE_DEMO_STRESS      0

#endif /*LV_EX_CONF_H*/

#endif /*End of "Content enable"*/

按照文档添加port部分的代码:

To use the graphics library you have to initialize it and the other components too. The order of the initialization is:

  1. Call lv_init().

  2. Initialize your drivers.

  3. Register the display and input devices drivers in LVGL. 

  4. Call lv_tick_inc(x) in every x milliseconds in an interrupt to tell the elapsed time. 

  5. Call lv_task_handler() periodically in every few milliseconds to handle LVGL related tasks.

/*main.c*/

#include 
#include 
#include "lvgl/lvgl.h"
#include "lv_examples/lv_examples.h"

SDL_Window *gWin = NULL;
SDL_Renderer *gRenderer = NULL;
SDL_Texture *gTexture = NULL;
static uint32_t tft_buf[LV_HOR_RES_MAX * LV_VER_RES_MAX];

typedef struct InputSDL {
    bool pressed;
    lv_coord_t x;
    lv_coord_t y;
} InputSDL_t;

InputSDL_t gInput = {false, 0, 0};

static void hal_init(void);
static int tick_thread(void *data);
static int lvtask_thread(void *data);
void my_disp_flush(lv_disp_t * disp, const lv_area_t * area, lv_color_t * color_p);
void my_disp_flush_ex(lv_disp_t * disp, const lv_area_t * area, lv_color_t * color_p);
void my_set_pixel(int32_t x, int32_t y, lv_color_t *color_p);
void my_set_rect(int32_t x1, int32_t y1, int32_t x2, int32_t y2, lv_color_t *color_p);
bool my_touchpad_read(lv_indev_drv_t * indev_driver, lv_indev_data_t * data);
bool my_touchpad_is_pressed(void);
void touchpad_get_xy(lv_coord_t *x, lv_coord_t *y);

int main(int argc, char* argv[]){

    //1,Call lv_init().
    lv_init();
    printf("lvgl init ok!\n");
    //2,Initialize your drivers.
    hal_init();
    printf("hal init ok!\n");
    //3,Register the display and input devices drivers in LittlevGL.
    /*Static or global buffer(s). The second buffer is optional*/
    static lv_disp_buf_t disp_buf;
    static lv_color_t buf_1[LV_HOR_RES_MAX * 100];
    static lv_color_t buf_2[LV_HOR_RES_MAX * 100];                   /*Declare a buffer for 100 lines*/
    lv_disp_buf_init(&disp_buf, buf_1, buf_2, LV_HOR_RES_MAX * 100);    /*Initialize the display buffer*/
    lv_disp_drv_t disp_drv;               /*Descriptor of a display driver*/
    lv_disp_drv_init(&disp_drv);          /*Basic initialization*/
    disp_drv.flush_cb = my_disp_flush_ex;    /*Set your driver function*/
    disp_drv.buffer = &disp_buf;          /*Assign the buffer to the display*/
    lv_disp_drv_register(&disp_drv);      /*Finally register the driver*/

    lv_indev_drv_t indev_drv;
    lv_indev_drv_init(&indev_drv);             /*Descriptor of a input device driver*/
    indev_drv.type = LV_INDEV_TYPE_POINTER;    /*Touch pad is a pointer-like device*/
    indev_drv.read_cb = my_touchpad_read;      /*Set your driver function*/
    lv_indev_drv_register(&indev_drv);         /*Finally register the driver*/
    printf("display and input device set ok!\n");

#if LV_USE_DEMO_WIDGETS
    lv_demo_widgets();
    printf("load demo widgets ok!\n");
#elif LV_USE_DEMO_PRINTER
    lv_demo_printer();
    printf("load demo printer ok!\n");
#elif LV_USE_DEMO_BENCHMARK
    lv_demo_benchmark();
    printf("load demo benchmark ok!\n");
#elif LV_USE_DEMO_STRESS
    lv_demo_stress();
    printf("load demo stress ok!\n");
#elif LV_USE_DEMO_KEYPAD_AND_ENCODER
    lv_demo_keypad_encoder();
    printf("load demo keypad and encoder ok!\n");
#endif

    bool quit = false;
    SDL_Event e;
    while(!quit){
        while(SDL_PollEvent(&e) != 0){
            switch(e.type){
                case SDL_QUIT:
                    quit = true;
                    break;
                case SDL_MOUSEBUTTONDOWN:
                    gInput.pressed = true;
                    gInput.x = e.motion.x;
                    gInput.y = e.motion.y;
                    printf("state= %d, x=%d, y=%d\n", e.button.state, e.motion.x, e.motion.y);
                    break;
                case SDL_MOUSEBUTTONUP:
                    gInput.pressed = false;
                    printf("state= %d, x=%d, y=%d\n", e.button.state, e.motion.x, e.motion.y);
                    break;
                case SDL_MOUSEMOTION:
                    gInput.x = e.motion.x;
                    gInput.y = e.motion.y;
                    //printf("mouse motion, x=%d, y=%d\n", e.motion.x, e.motion.y);
                    break;
            }
        }
    }
    printf("program quit!\n");
    SDL_DestroyWindow(gWin);
    SDL_DestroyRenderer(gRenderer);
    SDL_DestroyTexture(gTexture);
    SDL_Quit();

    return 0;
}

void hal_init(void){
    if(SDL_Init(SDL_INIT_VIDEO) != 0){
        printf("SDL init failed: %s\n", SDL_GetError());
        return;
    }else{
        if(SDL_CreateWindowAndRenderer(LV_HOR_RES_MAX, LV_VER_RES_MAX, SDL_WINDOW_OPENGL, &gWin, &gRenderer) != 0){
            printf("SDL create window and renderer failed: %s\n", SDL_GetError());
            return;
        }else{
            SDL_SetWindowTitle(gWin, "LittlevGL PC Simulator based on SDL2");
            gTexture = SDL_CreateTexture(gRenderer, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, LV_HOR_RES_MAX, LV_VER_RES_MAX);
            if(!gTexture){
                printf("create texture failed: %s\n", SDL_GetError());
            }else{
                SDL_SetTextureBlendMode(gTexture, SDL_BLENDMODE_BLEND);
                SDL_SetRenderDrawColor(gRenderer, 0xff, 0xff, 0xff, 0xff);
                SDL_RenderClear(gRenderer);
                SDL_RenderCopy(gRenderer, gTexture, NULL, NULL);
                SDL_RenderPresent(gRenderer);
            }
        }
    }

    SDL_Thread *tickThread = SDL_CreateThread(tick_thread, "tick", NULL);
    if(tickThread) printf("create tick thread ok!\n");
    else printf("create tick thread failed: %s\n", SDL_GetError());

    SDL_Thread *lvtaskThread = SDL_CreateThread(lvtask_thread, "lvtask", NULL);
    if(lvtaskThread) printf("create lvtask thread ok!\n");
    else printf("create lvtask thread failed: %s\n", SDL_GetError());
}

static int tick_thread(void *data){
    while(1) {
        lv_tick_inc(10);
        SDL_Delay(10);   /*Sleep for 1 millisecond*/
    }
    return 0;
}

static int lvtask_thread(void *data){
    while(1){
        lv_task_handler();
        SDL_Delay(5);
    }
    return 0;
}

void my_disp_flush(lv_disp_t * disp, const lv_area_t * area, lv_color_t * color_p){
    int32_t x, y;
    for(y = area->y1; y <= area->y2; y++) {
        for(x = area->x1; x <= area->x2; x++) {
            my_set_pixel(x, y, color_p);  /* Put a pixel to the display.*/
            color_p++;
        }
    }
    SDL_RenderPresent(gRenderer);
    lv_disp_flush_ready(disp);         /* Indicate you are ready with the flushing*/
}

void my_disp_flush_ex(lv_disp_t * disp, const lv_area_t * area, lv_color_t * color_p){
    int32_t x1 = area->x1;
    int32_t x2 = area->x2;
    int32_t y1 = area->y1;
    int32_t y2 = area->y2;

    if(x1 < 0 || x2 < 0 || y1 < 0 || y2 < 0 ||
       x1 > LV_HOR_RES_MAX - 1 || x2 > LV_HOR_RES_MAX - 1 ||
       y1 > LV_VER_RES_MAX - 1 || y2 > LV_VER_RES_MAX - 1){
        lv_disp_flush_ready(disp);
        return;
    }
    uint32_t w = x2 - x1 + 1;
    for(int32_t y = y1; y <= y2; y++) {
        memcpy(&tft_buf[y * LV_HOR_RES_MAX + x1], color_p, w * sizeof(lv_color_t));
        color_p += w;
    }

    SDL_UpdateTexture(gTexture, NULL, tft_buf, LV_HOR_RES_MAX * sizeof(uint32_t));
    SDL_RenderClear(gRenderer);
    SDL_RenderCopy(gRenderer, gTexture, NULL, NULL);
    SDL_RenderPresent(gRenderer);

    lv_disp_flush_ready(disp);         /* Indicate you are ready with the flushing*/
}

void my_set_pixel(int32_t x, int32_t y, lv_color_t *color_p){
    SDL_SetRenderDrawColor(gRenderer, color_p->ch.red, color_p->ch.green, color_p->ch.blue, color_p->ch.alpha);
    SDL_RenderDrawPoint(gRenderer, x, y);
}

bool my_touchpad_read(lv_indev_drv_t * indev_driver, lv_indev_data_t * data){
    data->state = my_touchpad_is_pressed() ? LV_INDEV_STATE_PR : LV_INDEV_STATE_REL;
    if(data->state == LV_INDEV_STATE_PR) touchpad_get_xy(&data->point.x, &data->point.y);

    return false; /*Return `false` because we are not buffering and no more data to read*/
}

bool my_touchpad_is_pressed(void){
    return gInput.pressed;
}

void touchpad_get_xy(lv_coord_t *x, lv_coord_t *y){
    *x = gInput.x;
    *y = gInput.y;
}

3、编译、运行:

在CodeBlocks中用SDL2在Windows上仿真LVGL嵌入式图形库_第3张图片

4、项目地址:点击这里

你可能感兴趣的:(C)