Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >推荐一款不错的嵌入式GUI(玲珑GUI)及在嵌入式linux上的移植

推荐一款不错的嵌入式GUI(玲珑GUI)及在嵌入式linux上的移植

作者头像
杨永贞
发布于 2022-01-07 07:45:30
发布于 2022-01-07 07:45:30
2.2K00
代码可运行
举报
运行总次数:0
代码可运行

玲珑GUI介绍

玲珑GUI(LLGUI)是一套使用简单、低价的单片机GUI解决方案。可以用来代替串口屏、组态,降低产品成本,产品软硬件自主可控。 配套界面开发软件,图形化编辑界面,生成C代码。

如其名字玲珑小巧,代码量不大,纯c语言写的,适用各类资源受限的单片机mcu,且开源免费。(协议使用Apache License, Version 2.0,可以二次开发类GPL,非二次开发类使用Apache,多许可协议的方式。

资料地址

教程地址:玲珑GUI教程 · 语雀

Gitee地址:LingLongGUI: 玲珑GUI是高效的界面开发解决方案。 代替串口屏、组态,降低产品成本,产品软硬件自主可控。 配套界面开发软件,图形化编辑界面,生成C代码。

简单体验

简单体验了一把,感觉挺不错的,在这里推荐下。

尤其是它还提供了类似QT的可视化的GUI界面编辑器GUIBulider,可以可视化的编辑UI。同时还提供了类似于QT的信号和曹机制真心不错。虽然基础控件还不够多,比如常见的label控件没找到(作者说可以使用Text替代,我觉得label挺常用的,还是能有个单独的label组件比较好)。但是对于嵌入式应用差不多够用了,就像官方的介绍一样,可作为替代串口屏的一种低价的单片机GUI解决方案。

期待后续有更多好用的组件出来,期望llgui作为国产开源中的一员不断发展壮大。至少截止目前,配合这么好用的GUIBulider,可以和LittlevGL比个高下了。虽然组件丰富度不如LittlevGL,但是使用的易用性上还是这个小巧易用啊,类QT但比QT小巧太多,很有特色。

也希望作者开源出来一些自定义组件的方法和文档或教程,这样更利于生态扩建,丰富更多好用的组件。如一些仪表、曲线、table、chart等。

关于中文字库的支持方面(文档,示例等)期待再完善些。可能目前主要是瞄准嵌入式mcu上,在嵌入式linux上其实可以完善些常用字库。

GUIBulider长这样,有一种QT设计师的风格:

可以直接拖动编辑界面UI,最右侧可以更改属性。下方可以编辑发送者,信号和接收者。

点击工具栏上的绿色三角图标,自动生成对应的ui代码和对应的逻辑层处理代码文件。

嵌入式linux上的移植

在嵌入式linux上的移植(底层基于framebuffer的fb0):

新建一文件夹test,在里面新建llgui,ui和port文件夹。

其中llgui放置从gitee上下载到的最新llgui的源码。port文件夹放置跟移植相关的内容。ui文件夹里放置ui和ui的响应逻辑实现文件。

移植还是很简单的,实现LL_Config.c中的几个函数即可。主要的三个函数:画点和读点,填充矩形的函数。十分钟完整移植,此言不虚。

头文件LL_Config.h里做些配置:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
...
颜色位数
#define CONFIG_COLOR_DEPTH                    16 // 1 8 16 24 32
//屏幕宽度像素
#define LL_MONITOR_WIDTH                      480
//屏幕高度像素
#define LL_MONITOR_HEIGHT                     272

LL_Config.c文件

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include "LL_Config.h"
#include "string.h"
#include "freeRtosHeap4.h"
#include "io_fb.h"

uint8_t cfgColorDepth = CONFIG_COLOR_DEPTH;
uint16_t cfgMonitorWidth = 0;
uint16_t cfgMonitorHeight = 0;

#if USE_DOUBLE_BUFFERING == 1
uint32_t *lcdFrontBuf=LL_LCD_BUF1_POINTER;
uint32_t *lcdBackBuf=LL_LCD_BUF2_POINTER;
#endif

void llCfgSetLcdBufAddr(uint32_t *addr)
{
#if USE_DOUBLE_BUFFERING == 1
    lcdSetBufferAddr(addr);
#endif
}

void llCfgSetLcdSrcAddr(uint32_t *addr)
{
#if USE_DOUBLE_BUFFERING == 1
    lcdSetSrcAddr(addr);
#endif
}

void llCfgLcdCopyFront2Back(void)
{
#if USE_DOUBLE_BUFFERING == 1
//    memcpy(lcdBackBuf,lcdFrontBuf,SDRAM_LCD_SIZE);
    uint64_t i;
    for(i=0;i<SDRAM_LCD_SIZE;i++)
    {
        lcdBackBuf[i]=lcdFrontBuf[i];
    }
#endif
}

bool llCfgClickGetPoint(int16_t *x,int16_t *y)
{
    bool ret;
    return ret;
}

void llCfgSetPoint(int16_t x,int16_t y,llColor color)
{
    fb_setpixel(LL_MONITOR_WIDTH,LL_MONITOR_HEIGHT,x,y,color);
}

llColor llCfgGetPoint(int16_t x,int16_t y)
{
    llColor retColor;
    retColor = fb_readpixel(LL_MONITOR_WIDTH,LL_MONITOR_HEIGHT,x,y);
    return retColor;
}

void LCD_L0_SetPixelIndex(int x, int y, llColor color) {
  fb_setpixel(LL_MONITOR_WIDTH, LL_MONITOR_HEIGHT, x, y, color);
}
void LCD_L0_DrawHLine (int x0, int y,  int x1,llColor color) {
    for (; x0 <= x1; x0++) {
      LCD_L0_SetPixelIndex(x0, y, color);
    }
}
void llCfgFillSingleColor(int16_t x0,int16_t y0,int16_t x1,int16_t y1,llColor color)
{
    for (; y0 <= y1; y0++) {
    LCD_L0_DrawHLine(x0, y0, x1,color);
  }
}


void *llMalloc(uint32_t size)
{
    return malloc(size);
}

void llFree(void *p)
{
    free(p);
    p=NULL;
}

void *llRealloc(void *ptr,uint32_t newSize)
{
    return realloc(ptr,newSize);
}

void llExFlashInit(void)
{
}

void llReadExFlash(uint32_t addr,uint8_t* pBuffer,uint16_t length)
{
}

void llBuzzerBeep(void)
{
}

/***************************************************************************//**
 * @fn         void llGetRtc(uint8_t *readBuf)
 * @brief      读取年月日时分秒周
 * @param      *readBuf yy yy mm dd hh mm ss ww
 * @return     void
 * @version    V0.1
 * @date       
 * @details    数据用16进制储存,2021年 yyyy=0x07E5
 ******************************************************************************/
void llGetRtc(uint8_t *readBuf)
{
}

/***************************************************************************//**
 * @fn         void llSetRtc(uint8_t *writeBuf)
 * @brief      写入年月日时分秒
 * @param      *writeBuf yy yy mm dd hh mm ss
 * @return     void
 * @version    V0.1
 * @date       
 * @details    数据用16进制储存,2021年 yyyy=0x07E5
 ******************************************************************************/
void llSetRtc(uint8_t *writeBuf)
{
}

io_fb.c

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memory.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <sys/mman.h>
#include <linux/fb.h>

#define printV(v)				printf(#v"=%d\n", v);


static unsigned char*  npu8_fbmem;
static int             ns32_fb;
static unsigned int    nu32_screensize;

static unsigned char   displaybuffer[480*272*4];
static unsigned char*  pframebuffer;
static unsigned char   pfbStat = 0;		//0-framebuffer, 1-cache buffer


unsigned char getGUIcache(void);

int setGUIcache(unsigned char stat);

void GUIcache2fb(void);


static void* _fb_mmap(int fd, unsigned int screensize)
{
    caddr_t fbmem;

    if ((fbmem = mmap(0, screensize, PROT_READ | PROT_WRITE,
                      MAP_SHARED, fd, 0)) == MAP_FAILED) {
        perror(__func__);
        return (void *) (-1);
    }

    return fbmem;
}

static int _fb_munmap(void *start, size_t length)
{
    return (munmap(start, length));
}

static int _fb_stat(int fd, unsigned int *width, unsigned int *height, unsigned int *depth)
{
    //struct fb_fix_screeninfo fb_finfo;
    struct fb_var_screeninfo fb_vinfo;

    //if (ioctl(fd, FBIOGET_FSCREENINFO, &fb_finfo)) {
    //    perror(__func__);
    //    return -1;
    //}

    if (ioctl(fd, FBIOGET_VSCREENINFO, &fb_vinfo)) {
        perror(__func__);
        return -1;
    }

    *width  = fb_vinfo.xres;
    *height = fb_vinfo.yres;
    *depth  = fb_vinfo.bits_per_pixel;

    return 0;
}

int fb_init(void)
{ 
  unsigned int  fbw, fbh, fbd;
  
  ns32_fb = open("/dev/fb0", O_RDWR);
  if(ns32_fb<0){
    printf("can not open fb0\n");
    return -1;
  }
  if( _fb_stat(ns32_fb, &fbw, &fbh, &fbd) < 0 ) return -1;
  printf("%d, %d, %d\n", fbw, fbh, fbd);
  nu32_screensize = fbw * fbh * fbd / 8;
  npu8_fbmem = _fb_mmap(ns32_fb, nu32_screensize);
  setGUIcache(0);
  return 0;
}

void fb_deinit(void)
{ 
  close(ns32_fb);
  _fb_munmap(npu8_fbmem, nu32_screensize);
}

int fb_setpixel(int width, int height, int x, int y, unsigned short color)
{
    if ((x > width) || (y > height))
        return -1;
   	//unsigned short *dst = ((unsigned short *)npu8_fbmem + y * width + x);
	unsigned short *dst = ((unsigned short *)pframebuffer + y * width + x);

    *dst = color;
    return 0;
}

unsigned short fb_readpixel(int width, int height, int x, int y)
{
  if ((x > width) || (y > height)) return -1;
  //unsigned short *dst = ((unsigned short *)npu8_fbmem + y * width + x);
  unsigned short *dst = ((unsigned short *)pframebuffer + y * width + x);

  return *dst;
}

unsigned char getGUIcache(void)
{
	//printf("%s\n", __FUNCTION__);
	return pfbStat;
}

int setGUIcache(unsigned char stat)
{
	//printf("%s\n", __FUNCTION__);
	if( stat ) {
		pframebuffer = displaybuffer;
		pfbStat      = 1;
	} else {
		pframebuffer = npu8_fbmem;
		pfbStat      = 0;
	}

	return 0;
}

void GUIcache2fb(void)
{
	printf("%s\n", __FUNCTION__);
	memcpy( npu8_fbmem, displaybuffer, nu32_screensize);
}

最后是makefile文件,更改下交叉编译工具链,直接执行make即可。

附:makefile文件:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
########################################
##makefile template by yangyongzhen
########################################
#****************************************************************************
# Cross complie path
#****************************************************************************
# CHAIN_ROOT=/home/yang/imax283/ctools/gcc-4.4.4-glibc-2.11.1-multilib-1.0/arm-fsl-linux-gnueabi/bin

# CROSS_COMPILE=$(CHAIN_ROOT)/arm-none-linux-gnueabi-

CHAIN_ROOT= /opt/gcc-linaro-arm-linux-gnueabihf-4.9-2014.09_linux/bin
CROSS_COMPILE=$(CHAIN_ROOT)/arm-linux-gnueabihf-
#CROSS_COMPILE = 

CC     := $(CROSS_COMPILE)gcc
CXX    := $(CROSS_COMPILE)g++
AS	   := $(CROSS_COMPILE)as
AR     := $(CROSS_COMPILE)ar 
LD     := $(CROSS_COMPILE)ld
RANLIB := $(CROSS_COMPILE)ranlib
OBJDUMP:= $(CROSS_COMPILE)objdump
OBJCOPY:= $(CROSS_COMPILE)objcopy
STRIP  := $(CROSS_COMPILE)strip

#****************************************************************************
# Source files
#****************************************************************************
SRC_C=$(shell find . -name "*.c")

OBJ_C=$(patsubst %.c, %.o, $(SRC_C))

SRCS := $(SRC_C) $(SRC_C)

OBJS := $(OBJ_C) 

#****************************************************************************
# Flags
#****************************************************************************
LIBS := -LLIBS
INCS := -I./llgui/Gui -I./llgui/Misc -I./Fonts -I./port -I./ui -I./
CFLAGS= -std=gnu99  -fno-common  -fsanitize=address -fno-stack-protector -fno-omit-frame-pointer -fno-var-tracking -g1
LDSCRIPT= 
LDFLAGS= -lasan
#****************************************************************************
# Targets of the build
#****************************************************************************
TARGET   	:= testllgui
TARGETLIB  	:= libllgui


.PHONY: clean
all:  prebuild  $(TARGET)

lib:  prebuild  $(TARGETLIB).so

#****************************************************************************
# TARGET
#****************************************************************************
prebuild:
	@echo Building...

$(TARGET): $(OBJS)
	@echo Generating exe...
	$(CC)   -o  $(TARGET) $(OBJS) $(LIBS) $(LDFLAGS)
	@echo OK!

$(TARGETLIB).so : $(OBJS)
	@echo Generating shared lib...
	$(CC)  -shared -fPIC -o  $(TARGETLIB).so $(OBJS) 
	@echo OK!

%.o : %.c
	$(CC) -c -fPIC $(CFLAGS) $(INCS) $< -o  $@
	
clean:
	@echo The following files:
	rm  -f  $(TARGET) *.so
	find . -name "*.[od]" |xargs rm
	@echo Removed!

最后把编译生成的可执行文件,放在板子上,改下执行权限,直接运行即可。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021/12/08 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
ucgui在嵌入式linux下的移植
前几天在研究minigui,照着官方的步骤编译,竟然一堆错,不是缺这库,就是缺那库。好不容易快到了最后一步,竟然再链接时告诉我用的64位系统不兼容32位的minigui。
杨永贞
2020/08/04
2.1K0
freetype的交叉编译及在嵌入式linux上的简单使用及改变字体背景和颜色
FreeType库是一个完全免费(开源)的、高质量的且可移植的字体引擎,它提供统一的接口来访问多种字体格式文件,包括TrueType, OpenType, Type1, CID, CFF, Windows FON/FNT, X11 PCF等。它支持单色位图、反走样位图的渲染。FreeType库是高度模块化的程序库,虽然它是使用ANSI C开发,但是采用面向对象的思想,因此,FreeType的用户可以灵活地对它进行裁剪。关于freetype的详细信息可以参考freetype的官方网站:https://www.freetype.org/来获取更多相关的信息。
杨永贞
2020/12/16
5.4K0
freetype的交叉编译及在嵌入式linux上的简单使用及改变字体背景和颜色
littlevgl(Lvgl)最新版V7.4移植
LittleVGL最新已经更新到V7,网上大多数移植教程的版本比较老,很多特性没有,界面也不够酷炫。
杨永贞
2020/09/02
3.5K0
Linux应用开发:嵌入式Linux下矢量字体运用
FreeType库是一个完全免费(开源)的、高质量的且可移植的字体引擎,它提供统一的接口来访问多种字体格式文件,可以非常方便我们开发字体显示相关的程序功能。它支持单色位图、反走样位图的渲染。FreeType库是高度模块化的程序库,虽然它是使用ANSI C开发,但是采用面向对象的思想,因此,FreeType的用户可以灵活地对它进行裁剪。关于freetype的详细信息可以参考freetype的官方网站:https://www.freetype.org/来获取更多相关的信息。
DS小龙哥
2022/01/12
4.8K0
Linux应用开发:嵌入式Linux下矢量字体运用
嵌入式Linux下LCD应用编程: 读取摄像头画面完成本地视频监控画面显示
完整项目代码下载地址(包含矢量字库源码和编译安装方法): https://download.csdn.net/download/xiaolong1126626497/16680219
DS小龙哥
2022/01/12
2.3K0
嵌入式Linux下LCD应用编程: 读取摄像头画面完成本地视频监控画面显示
Linux小项目-数码相册设计
这是基于Linux系统开发板设计一个小项目-数码相册,在LCD屏上可以显示完成常见的图片显示,翻页、旋转、缩放等功能。
DS小龙哥
2022/05/11
1.5K0
Linux小项目-数码相册设计
sm2,sm3,sm4国密算法的纯c语言版本,使用于任何嵌入式平台
国密即国家密码局认定的国产密码算法。主要有SM1,SM2,SM3,SM4。密钥长度和分组长度均为128位。
杨永贞
2020/08/04
14K1
Linux应用开发-LCD显示BMP图片
BMP是一种与硬件设备无关的图像文件格式,是Windows环境中交换与图有关的数据的一种标准,在Windows环境中运行的图形图像软件都支持BMP图像格式。BMP格式的图片存放的就是原始的RGB数据,一般没有做压缩,也就是图片的画质是最原始的,也导致BMP图片占用的内存非常大。现在常用的jpg、jpeg格式都是压缩格式,保存的时候通过算法编码压缩,显示的时候再解压成RGB数据渲染显示。
DS小龙哥
2022/05/11
4.3K0
Linux应用开发-LCD显示BMP图片
Linux驱动开发: FrameBuffe(LCD)驱动开发
帧缓冲(framebuffer)是Linux 系统为显示设备提供的一个接口,它将显示缓冲区抽象,屏蔽图像硬件的底层差异,允许上层应用程序在图形模式下直接对显示缓冲区进行读写操作。用户不必关心物理显示缓冲区的具体位置及存放方式,这些都由帧缓冲设备驱动本身来完成。
DS小龙哥
2022/01/12
49.9K0
Linux驱动开发: FrameBuffe(LCD)驱动开发
将jpeg图片显示在framebuffer上
点击(此处)折叠或打开 /************************************************** * example5.c * Author: T-bagwell * * Compile:gcc -Wall example5.c -o example5 *************************************************/ #include <stdio.h> #inclu
用户3765803
2019/03/05
1.5K0
LCD Framebuffer应用开发 - 操作原理
​ LCD Framebuffer 就是一块显存,在嵌入式系统中,显存是被包含在内存中。LCD Framebuffer里的若干字节(根据驱动程序对LCD控制器的配置而定)表示LCD屏幕中的一个像素点,一一对应整个LCD屏幕。举个例子,LCD屏幕是800* 600的分辨率,即LCD屏幕存在480000个像素点,若每个像素点4个字节表示,那么LCD Framebuffer显存大小为480000 * 4=960000字节,即1.92MB。因此我们的内存将会分割至少1.92MB的空间用作显存。具体地址在哪里,这个就是又驱动程序去定,应用程序只需直接使用即可,硬件相关操作已由驱动程序封装好。
阿志小管家
2024/11/23
1710
LCD Framebuffer应用开发 - 操作原理
荔枝派Zero(全志V3S)驱动开发之RGB LCD屏幕显示bmp图片
显示设备例如 LCD,在 Linux 中用 Framebuffer 来表征, Framebuffer 翻译过来就是帧缓冲,简称 fb,在 /dev 目录下显示设备一般表示成这样:/dev/fbn,应用程序通过访问这个设备来访问 LCD,实际上应用程序通过操作显存来操作显示设备,显存由驱动程序设置。说白了,我们要在 linux 下操作屏幕进行显示那么直接对 /dev/fbn 进行操作即可。
Gnep@97
2023/08/10
1.1K0
荔枝派Zero(全志V3S)驱动开发之RGB LCD屏幕显示bmp图片
全志R128应用开发案例——SPI 驱动 TFT LCD 屏
我们使用的开发板是 R128-Devkit,需要开发 C906 核心的应用程序,所以载入方案选择 r128s2_module_c906
阿志小管家
2024/02/02
2630
全志R128应用开发案例——SPI 驱动 TFT LCD 屏
M5ATOMS3基础01按键
注意: 1.如果您不想使用M5.begin() 初始化LCD,请在使用显示器之前调用此功能
zhangrelay
2023/07/27
5520
M5ATOMS3基础01按键
i.MX6ULL嵌入式Linux开发2-uboot移植实践
上篇文章,我们介绍了如何使用NXP原厂的uboot进行编译和烧写,将uboot运行在自己的开发板上。NXP原厂的uboot,直接烧录到我的开发板中,LCD的驱动是不正常的,需要进行修改。本篇我们就来继续研究uboot,「使得uboot能匹配我们自己的开发板」。
xxpcb
2021/07/20
1.5K0
Linux应用开发-libjpeg库交叉编译与使用
在开发板上如果想要显示jpeg格式的图片,必须用到libjpeg库,不可能自己去编写jpg的解码代码。
DS小龙哥
2022/05/09
4K0
Linux应用开发-libjpeg库交叉编译与使用
Linux应用开发【第一章】Framebuffer应用开发
​ LCD Framebuffer 就是一块显存,在嵌入式系统中,显存是被包含在内存中。LCD Framebuffer里的若干字节(根据驱动程序对LCD控制器的配置而定)表示LCD屏幕中的一个像素点,一一对应整个LCD屏幕。举个例子,LCD屏幕是800*600的分辨率,即LCD屏幕存在480000个像素点,若每个像素点4个字节表示,那么LCD Framebuffer显存大小为480000 *4=960000字节,即1.92MB。因此我们的内存将会分割至少1.92MB的空间用作显存。具体地址在哪里,这个就是又驱动程序去定,应用程序只需直接使用即可,硬件相关操作已由驱动程序封装好。
韦东山
2021/12/15
1.9K0
Linux应用开发【第一章】Framebuffer应用开发
全志V831基于pjsip的双向视频通话实现
注意显示设备的注册顺序,video_dev.c中,注册显示设备的时候,要放到camera适配设备的后面,这样子默认的capture设备,即时不配置,也能找到第一个。
呱牛笔记
2024/07/18
3790
全志V831基于pjsip的双向视频通话实现
day24-库的使用(2022.2.21)
=============== 2.字体库的使用 ====================
天天Lotay
2022/12/02
9890
day24-库的使用(2022.2.21)
嵌入式Linux下LCD应用编程: 调用giflib库解码显示GIF动态图
生活中常用图片格式有BMP、PNG、JPG、GIF等。BMP图片的显示很简单,可以直接从图片文件里读取RGB数据进行显示.。PNG格式图片显示,直接调用libpng库里的接口函数解码显示;JPG格式图片也一样,调用libjpeg库的接口函数完成解码即可得到原始RGB数据完成显示;如果要在LCD屏上显示GIF图片,那么也是调用giflib库的接口函数完成解码显示。
DS小龙哥
2022/01/12
3.2K0
嵌入式Linux下LCD应用编程: 调用giflib库解码显示GIF动态图
推荐阅读
相关推荐
ucgui在嵌入式linux下的移植
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验