ucgui在嵌入式linux下的移植

简介: ucgui在嵌入式linux下的移植

前几天在研究minigui,照着官方的步骤编译,竟然一堆错,不是缺这库,就是缺那库。好不容易快到了最后一步,竟然再链接时告诉我用的64位系统不兼容32位的minigui。


早不说呀,真折腾,这是让我再重装个32位系统么。想出来个helloworld,竟在编译环境上浪费时间,太坑。也不喜欢minigui的为win32风格,应用都得在他的框架下写,必须得有入口函数。类似于win32的api编程,很原始,连个界面的长宽高都要自己去定义。也没有好用的可视化的窗口设计及仿真环境。其实,如果没有那么多的人机交互,比如车载pos,不需要这些吧。不如直接调用显示接口函数,比如想显示个内容,直接LCD_DisplayString()来的容易。


用 ucgui还有个好处是,只要应用做稳定了,界面根本不会卡死或down掉。因为界面就像一个画布,让显示什么,什么时候显示,都是受应用控制的,界面是被动的。但是,如果应用跑在miniGUI的框架下,如果界面消息循环阻塞,或者minigui挂掉,整个应用就完了。且minigui的让显示什么,就发个消息,然后在主线程对消息就行处理再显示,感觉像是平白无故兜了一圈。完全没有直接操作屏幕爽。让什么时候显示什么直接LCD_Display,安全稳定。当然,这只针对目前的应用而言,界面不那么重要。如果是靠界面取胜的应用,都这么来会很累。


无意间发现了一个好东西,ucgui,这在原来单片机stm32上跑过,以及ucosII。之前也用过。ucgui占用资源很少,在stm32等单片机上都能跑,在linux 上更是没一点儿问题。


而且超轻量级,代码很好移植。甚至因为小巧,可以用来学习研究GUI用,或者增加定制些功能。


同事说这么小巧的东西在linux上有点儿不搭吧,linux那么强大,应该首先考虑minigui和QT。但是我我举得对于目前正在做的新项目而言,不需要界面太花哨,功能稳定就行,先快速出来产品再说吧。先整出来个界面用用,毕竟也不占多少精力。越是简单小巧越容易掌控,不容易掉坑里。


对于一款智能pos来说,从功能上无非是 卡处理、记录存储、通信、显示、这几块功能。目前 通信库,和文件存储库都已封装好。把显示也搞定了,就剩封装读卡库了。最后再实现个多线程框架把这些轮子组装起来,就是一完整 pos 了,也不是什么难事。难在接口封装和风格尽量要做到和原来一致啊,要不那么多地方的应用,移植是件痛苦的事。


进一步查资料发现,用这个 ucgui,电脑上还有模拟器可以用,那么界面设计部分,完全可以在电脑上仿真啦。这样,想设计个漂亮的界面出来,也不难啊。别抱怨说界面原生丑陋,那是没经过设计。至于是否支持中文,以及字体有哪些,那就自己画呗,用工具生成各种需要的中文字库导进去。 想让界面漂亮些,那自己画呗,正好考验下有没艺术细胞。反正画着也挺简单的,最底层的画点画线基本函数都有了。甚至可以移植gif解码库,让支持更多类型的图片动画。后续准备加入常用的中文字库支持。以及gif动画支持。


官方的模拟器  emWin(UCGUI)模拟器。在电脑上有模拟器啊,这是不是很赞。


移植之后,使用也很简单 。就一个libucgui.a库文件和gui.h头文件包含进来即可。


使用类似这样:


#include <stdio.h>
#include "GUI.h"
int main(int argc, char* argv[])
{ 
  char c;
  printf("this is ucgui-linux test!\n");
  GUI_Init();
  GUI_SetBkColor(GUI_BLUE);
  GUI_Clear();
  GUI_SetColor(GUI_WHITE);
  GUI_SetTextAlign(GUI_TA_HCENTER);
  GUI_SetFont(&GUI_Font16B_ASCII);
  GUI_DispStringAt("hello world, ucgui-linux",240,100);
  GUI_DrawCircle(100,100,50);//画圆
  printf("system pause\n");
  while ((c = getchar()) != '\n');
  system("pause");
  return 0;
}


先来张运行成功的截图:





又发现ucGUI一个强大功能,竟可以windows上设计界面自动生成代码,带仿真执行功能。附图:是不是很赞,这是minigui远远不能及的....





连带电脑上的代码编写仿真环境都有,




进入正题,移植minigui,


很好移植,把底层调用的几个函数,用linux上的frambuffer实现就可以了。


具体文件是LCDDummy.c那么文件 里的LCD_L0_Init(void),LCD_L0_SetPixelIndex,LCD_L0_GetPixelIndex,这三个函数,实现这三个函数。


/*********************************************
*
*       LCD_L0_Init
*
**********************************************
Purpose:
  Initialises the LCD-controller.
*/
int  LCD_L0_Init(void) {
  return fb_init();
}


/*********************************************
*
*       LCD_L0_SetPixelIndex
*
**********************************************
Purpose:
  Sets the index of the given pixel. The upper layers of emWin
  calling this routine make sure that the coordinates are in range, so
  that no check on the parameters needs to be performed.
*/
void LCD_L0_SetPixelIndex(int x, int y, int PixelIndex) {
  /* Convert logical into physical coordinates (Dep. on LCDConf.h) */
  #if LCD_SWAP_XY | LCD_MIRROR_X| LCD_MIRROR_Y
    int xPhys = LOG2PHYS_X(x, y);
    int yPhys = LOG2PHYS_Y(x, y);
  #else
    #define xPhys x
    #define yPhys y
  #endif
  /* Write into hardware ... Adapt to your system */
  {
    /* ... */
    fb_setpixel(480, 272, xPhys, yPhys, PixelIndex);
  }
}
/*********************************************
*
*       LCD_L0_GetPixelIndex
*
**********************************************
Purpose:
  Returns the index of the given pixel. The upper layers of emWin
  calling this routine make sure that the coordinates are in range, so
  that no check on the parameters needs to be performed.
*/
unsigned int LCD_L0_GetPixelIndex(int x, int y) {
  LCD_PIXELINDEX PixelIndex;
  /* Convert logical into physical coordinates (Dep. on LCDConf.h) */
  #if LCD_SWAP_XY | LCD_MIRROR_X| LCD_MIRROR_Y
    int xPhys = LOG2PHYS_X(x, y);
    int yPhys = LOG2PHYS_Y(x, y);
  #else
    #define xPhys x
    #define yPhys y
  #endif
  /* Read from hardware ... Adapt to your system */
  {
    PixelIndex = 0;/* ... */
    PixelIndex = fb_readpixel(480, 272, xPhys, yPhys);
  }
  return PixelIndex;
}


#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>
static unsigned char*  npu8_fbmem;
static int             ns32_fb;
static unsigned int    nu32_screensize;
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);
  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);
    *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);
  return *dst;
}


最后,要在linux上编译,写个makefile吧,简单省事。写完后配置下工具链直接make即可。

 

########################################
##makefile
########################################
#****************************************************************************
# Cross complie path
#****************************************************************************
#CHAIN_ROOT=/home/yangyongzhen/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-
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
#****************************************************************************
CFLAGS=  -I./GUI_X -I./GUI/Core -I./GUI/WM -I./GUI/Widget
LDSCRIPT= 
LDFLAGS= 
#****************************************************************************
# Targets of the build
#****************************************************************************
TARGET    := libucgui
.PHONY: clean
all:  prebuild  $(TARGET).a
#****************************************************************************
# TARGET
#****************************************************************************
prebuild:
  @echo Building lib...
$(TARGET).a : $(OBJS)
  @echo Generating lib...
  ar crv $(TARGET).a $(OBJS) 
  cp $(TARGET).a ../
  @echo OK!
%.o : %.c
  $(CC) -c $(CFLAGS) $< -o  $@
clean:
  @echo The following files:
  rm  -f  $(TARGET) *.a
  find . -name "*.[od]" |xargs rm
  @echo Removed!


相关文章
|
10天前
|
Ubuntu Linux 开发者
Ubuntu20.04搭建嵌入式linux网络加载内核、设备树和根文件系统
使用上述U-Boot命令配置并启动嵌入式设备。如果配置正确,设备将通过TFTP加载内核和设备树,并通过NFS挂载根文件系统。
51 15
|
24天前
|
存储 监控 Linux
嵌入式Linux系统编程 — 5.3 times、clock函数获取进程时间
在嵌入式Linux系统编程中,`times`和 `clock`函数是获取进程时间的两个重要工具。`times`函数提供了更详细的进程和子进程时间信息,而 `clock`函数则提供了更简单的处理器时间获取方法。根据具体需求选择合适的函数,可以更有效地进行性能分析和资源管理。通过本文的介绍,希望能帮助您更好地理解和使用这两个函数,提高嵌入式系统编程的效率和效果。
94 13
|
7月前
|
网络协议 算法 Linux
【嵌入式软件工程师面经】Linux网络编程Socket
【嵌入式软件工程师面经】Linux网络编程Socket
211 1
|
5月前
|
NoSQL Linux C语言
嵌入式GDB调试Linux C程序或交叉编译(开发板)
【8月更文挑战第24天】本文档介绍了如何在嵌入式环境下使用GDB调试Linux C程序及进行交叉编译。调试步骤包括:编译程序时加入`-g`选项以生成调试信息;启动GDB并加载程序;设置断点;运行程序至断点;单步执行代码;查看变量值;继续执行或退出GDB。对于交叉编译,需安装对应架构的交叉编译工具链,配置编译环境,使用工具链编译程序,并将程序传输到开发板进行调试。过程中可能遇到工具链不匹配等问题,需针对性解决。
196 3
|
5月前
|
传感器 人工智能 网络协议
:嵌入式 Linux 及其用途
【8月更文挑战第24天】
229 0
|
6月前
|
Ubuntu 算法 Linux
嵌入式Linux的学习误区
**嵌入式Linux学习误区摘要** 1. **过度聚焦桌面Linux** - 许多学习者误将大量时间用于精通桌面Linux系统(如RedHat、Fedora、Ubuntu),认为这是嵌入式Linux开发的基石。 - 实际上,桌面Linux仅作为开发工具和环境,目标不应是成为Linux服务器专家,而应专注于嵌入式开发工具和流程。 2. **盲目阅读Linux内核源码** - 初学者在不了解Linux基本知识时试图直接研读内核源码,这往往导致困惑和挫败感。 - 在具备一定嵌入式Linux开发经验后再有针对性地阅读源码,才能有效提升技能。
|
7月前
|
存储 编解码 Ubuntu
【QT】linux下alsa库的移植和QT中音视频的处理&笔记
【QT】linux下alsa库的移植和QT中音视频的处理&笔记
|
7月前
|
网络协议 Linux 编译器
【原创】EtherCAT主站IgH解析(二)-- 如何将Igh移植到Linux/Windows/RTOS等多操作系统移植指南
EtherCAT主站方案对比:商业的如Acontis、TwinCAT3和开源的igh、SOEM。SOEM易移植但功能和实时性不足,适合简单应用;igh功能强大,实时性能优秀,基于内核态,适合复杂场景。igh能移植到其他RTOS,但需克服多任务无调度的挑战。依赖操作系统服务如定时器、内存分配,适合Linux内核,但移植到裸机复杂。
351 0
|
2月前
|
Linux 网络安全 数据安全/隐私保护
Linux 超级强大的十六进制 dump 工具:XXD 命令,我教你应该如何使用!
在 Linux 系统中,xxd 命令是一个强大的十六进制 dump 工具,可以将文件或数据以十六进制和 ASCII 字符形式显示,帮助用户深入了解和分析数据。本文详细介绍了 xxd 命令的基本用法、高级功能及实际应用案例,包括查看文件内容、指定输出格式、写入文件、数据比较、数据提取、数据转换和数据加密解密等。通过掌握这些技巧,用户可以更高效地处理各种数据问题。
170 8
|
2月前
|
监控 Linux
如何检查 Linux 内存使用量是否耗尽?这 5 个命令堪称绝了!
本文介绍了在Linux系统中检查内存使用情况的5个常用命令:`free`、`top`、`vmstat`、`pidstat` 和 `/proc/meminfo` 文件,帮助用户准确监控内存状态,确保系统稳定运行。
704 6