因为GUI-Guider神一般的存在,NXP的MCU在配置性能允许的情况下,必须要运行一下LVGL。
MCXA156的SDK中很贴心的提供了LVGL的例子,但没有配套的屏幕,也就无从下手了。
只有一个220*176的8位并口屏,因陋就简吧。
一、GUI-Guider
安装了GUI-Guider 1.8.1,只支持LVGL v8.3.10,并且已支持的板子中没有MCXA156。
所以Simulator开局
不支持220*176,需要打开.guiguider扩展名的文件,将其中分辨率的部分都修改成220、176,再打开GUI-Guider,这时画布就是220*176的了。
勾勾画画在上面放几个部件,算是完成,然后Generate Code
二、移植LVGL
1、拿SDK_2_16_100_FRDM-MCXA156\boards\frdmmcxa156\lvgl_examples\lvgl_guider做模板
1)将其中的generated目录用前面GUI-Guider生成的generated替换掉。
2)从LVGL 官方SDK中拷贝lv_port_disp.c、lv_port_disp.h文件到lvgl_guider,代替lvgl_support.c
lvgl_support是基于FLEXIO的LVGL支持文件,改起来费劲,还是从LVGL SDK标准接口文件入手直接一些。
3)在lvgl_guider建个LCD目录,将LCD的驱动文件拷贝到LCD
4)在keil中添加generated、LCD、lv_port_disp的*.c、*.h,去掉lvgl_support、原来generated的*.c、*.h,增加include路径。
2、lv_port_disp.c
void lv_port_disp_init(void)
void lv_port_disp_init(void) { /*------------------------- * Initialize your display * -----------------------*/ disp_init(); /*----------------------------- * Create a buffer for drawing *----------------------------*/ static lv_disp_draw_buf_t draw_buf_dsc_2; static lv_color_t buf_2_1[MY_DISP_HOR_RES * 10]; /*A buffer for 10 rows*/ static lv_color_t buf_2_2[MY_DISP_HOR_RES * 10]; /*An other buffer for 10 rows*/ lv_disp_draw_buf_init(&draw_buf_dsc_2, buf_2_1, buf_2_2, MY_DISP_HOR_RES * 10); /*Initialize the display buffer*/ /*----------------------------------- * Register the display in LVGL *----------------------------------*/ static lv_disp_drv_t disp_drv; /*Descriptor of a display driver*/ lv_disp_drv_init(&disp_drv); /*Basic initialization*/ /*Set up the functions to access to your display*/ /*Set the resolution of the display*/ disp_drv.hor_res = MY_DISP_HOR_RES; disp_drv.ver_res = MY_DISP_VER_RES; /*Used to copy the buffer's content to the display*/ disp_drv.flush_cb = disp_flush; /*Set a display buffer*/ disp_drv.draw_buf = &draw_buf_dsc_2; /*Finally register the driver*/ lv_disp_drv_register(&disp_drv); }
disp_flush
static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p) { if(disp_flush_enabled) { /*The most simple case (but also the slowest) to put all pixels to the screen one-by-one*/ int32_t x; int32_t y; for(y = area->y1; y <= area->y2; y++) { for(x = area->x1; x <= area->x2; x++) { /*Put a pixel to the display. For example:*/ put_px(x, y, (uint16_t *)color_p); //画点函数 color_p++; } } } /*IMPORTANT!!! *Inform the graphics library that you are ready with the flushing*/ lv_disp_flush_ready(disp_drv); }
定义2个空函数
void lv_port_pre_init(void) { } void lv_port_indev_init(void) { }
3、主程序文件
main()
int main(void) { stat = xTaskCreate(AppTask, "lvgl", configMINIMAL_STACK_SIZE + 800, NULL, tskIDLE_PRIORITY + 2, NULL); }
void AppTask(void *param)
static void AppTask(void *param) { lv_port_pre_init(); lv_init(); lv_port_disp_init(); lv_port_indev_init(); s_lvgl_initialized = true; disp_enable_update(); setup_ui(&guider_ui); //调用generated目录下的函数 events_init(&guider_ui); custom_init(&guider_ui); for (;;) { lv_task_handler(); vTaskDelay(5); } }
/*! * @brief FreeRTOS tick hook. */ void vApplicationTickHook(void) { if (s_lvgl_initialized) { lv_tick_inc(1); } }
4、LCD驱动文件
put_px
void put_px(int32_t x,int32_t y, uint16_t *color_p) { setXY(x, y, x, y); //设置输出区域 lcd_write_data_word(*color_p); //输出颜色 clrXY(); }
lcd_write_data_word
void lcd_write_data_word(uint16_t data) { unsigned char c[2]; c[0] = (data >> 8) & 0xFF; c[1] = data & 0xFF; LCD_CS_CLR; LCD_RS_SET; gpio_lcd_write_data(c, 2); LCD_CS_SET; }
void gpio_lcd_write_data(uint8_t* data, size_t length)
void gpio_lcd_write_data(uint8_t* data, size_t length) { for (size_t i = 0; i < length; i++) { for (int bit = 0; bit < NUM_BITS; bit++) { // 检查当前位是否为1 if (data[i] & (1 << bit)) { GPIO_PinWrite(dbPins[bit].GPIOx, dbPins[bit].GPIO_Pin, true); } else { GPIO_PinWrite(dbPins[bit].GPIOx, dbPins[bit].GPIO_Pin, false); } } LCD_WR_CLR; LCD_WR_SET; // 如果需要,可以在这里添加延时或其他处理 } }
因为8位并口屏对应MCU引脚地址不连续,用不了DMA,只能用写GPIO的方法输出,效率不高。
三、运行效果
LCD 接在板子arduino接口上。
本来想用板载温度传感器+LCD显示温度的,但是两者引脚冲突了,只能作罢。