珠海建设网站首页,外包公司能去吗,哈尔滨网站公司,办公楼网络组建方案设计前言#xff1a; 前面我们已经对这个项目的基本框架有了一个初步的了解与认识#xff0c;要实现显示管理器与输入管理器#xff0c;有输入有输出基本就实现这个项目的大部分功能了#xff0c;首先我们先来做显示系统#xff0c;对于上层系统为了让程序更好扩展#xff0c… 前言 前面我们已经对这个项目的基本框架有了一个初步的了解与认识要实现显示管理器与输入管理器有输入有输出基本就实现这个项目的大部分功能了首先我们先来做显示系统对于上层系统为了让程序更好扩展我们得添加一个显示管理器在下面有各种设备就比如有Framebufler和web输出。 一、数据结构抽象 我们添加的一个显示管理器中有Framebufler和web输出对于俩个不同的设备我们需要抽象出同一个结构体类型。
1.使用场景 在上图中我们可以将其分为两层上层要获得下层某个结构体通过这个结构体中的函数来操作、绘制、刷新上层的界面。 所有我们需要定义一个统一的结构体DispOpr 2.disp_manager.h 1 #ifndef _DISP_MANAGER_H2 #define _DISP_MANAGER_H34 typedef struct Region {5 int iLeftUpX; //左上角x坐标6 int iLeftUpY; //左上角y坐标7 int iWidth; //宽度8 int iHeigh; //高度9 }Region, *PRegion;1011 typedef struct DispOpr {12 char *name; //显示模块的名字 13 char *GetBuffer(int *pXres, int *pYres, int *pBpp);//分辨率长和宽每个像素占据多少位14 int FlushRegion(PRegion ptRegion, char *buffer);//刷出某个区域15 struct DispOpr *ptNext; //链表16 };1718 #endif19 第1~2行防止头文件在.c文件中多次定义 第4~9行定义刷新区域结构体 第11~16行定义统一管理的结构体 二、Framebuffer编程
1.disp_manager.h 1 #ifndef _DISP_MANAGER_H2 #define _DISP_MANAGER_H34 typedef struct Region {5 int iLeftUpX;6 int iLeftUpY;7 int iWidth;8 int iHeigh;9 }Region, *PRegion;1011 typedef struct DispOpr {12 char *name;13 int DeviceInit(void);14 int DeviceExit(void);15 char *GetBuffer(int *pXres, int *pYres, int *pBpp);16 int FlushRegion(PRegion ptRegion, char *buffer);17 struct DispOpr *ptNext;18 }DispOpr, *PDispOpr;1920 #endif第13行初始化函数定义 第14行退出函数定义 2.framebuffer.c 1 #include sys/mman.h2 #include sys/types.h3 #include sys/stat.h4 #include unistd.h5 #include linux/fb.h6 #include fcntl.h7 #include stdio.h8 #include string.h9 #include sys/ioctl.h1011 #include disp_manager.h1213 static int fd_fb; //framebuffer文件14 static struct fb_var_screeninfo var; /* Current var */15 static int screen_size; //framebuffer长度16 static unsigned char *fb_base; //framebuffer地址17 static unsigned int line_width;18 static unsigned int pixel_width;1920 static int DeviceInit(void)21 {22 fd_fb open(/dev/fb0, O_RDWR);23 if (fd_fb 0)24 {25 printf(cant open /dev/fb0\n);26 return -1;27 }28 if (ioctl(fd_fb, FBIOGET_VSCREENINFO, var))29 {30 printf(cant get var\n);31 return -1;32 }3334 line_width var.xres * var.bits_per_pixel / 8;35 pixel_width var.bits_per_pixel / 8;36 screen_size var.xres * var.yres * var.bits_per_pixel / 8;37 fb_base (unsigned char *)mmap(NULL , screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);38 if (fb_base (unsigned char *)-1)39 {40 printf(cant mmap\n);41 return -1;42 }4344 return 0;45 }4647 static int DeviceExit(void)48 {49 munmap(fb_base, screen_size);50 close(fd_fb);51 return 0;52 }535455 /* 可以返回LCD的framebuffer, 以后上层APP可以直接操作LCD, 可以不用FbFlushRegion56 * 也可以malloc返回一块无关的buffer, 要使用FbFlushRegion刷到LCD上57 */58 static int FbGetBuffer(PDispBuff ptDispBuff);5960 {61 ptDispBuff-iXres var.xres;62 ptDispBuff-iYres var.yres;63 ptDispBuff-iBpp var.bits_per_pixel;64 ptDispBuff-buff (char *)fb_base;65 return 0;66 }6768 static int FbFlushRegion(PRegion ptRegion, PDispBuff ptDispBuff)69 {70 return 0;71 }727374 static DispOpr g_tFramebufferOpr {75 .name fb,76 .DeviceInit FbDeviceInit,77 .DeviceExit FbDeviceExit,78 .GetBuffer FbGetBuffer,79 .FlushRegion FbFlushRegion,80 };818283 void FramebufferInit(void)84 {85 RegisterDisplay(g_tFramebufferOpr);86 }8720 static int DeviceInit(void) 第20~45行初始化函数 47 static int DeviceExit(void) 第47~52行退出函数 第58~66行的FbGetBuffer是已经封装好的详细封装过程后续会讲 第61~62行设置分辨率 第63行设置bpp 74 static DispOpr g_tFramebufferOpr 第74~80行上层代码可以根据这个结构体里的函数来初始化LCD来得到Buffer 第78行通过.GetBuffer FbGetBuffer来构建好图像和文字 第79行通过.FlushRegion FbFlushRegion来刷新到LCD上 第83~86行注册结构体g_tFramebufferOpr详细介绍在三、显示管理 三、显示管理 上层函数想要选择哪个设备进行显示需要中间加一个函数进行选择起到承上启下的作用用来实现显示管理是操作Framebuffer还是WEB设备需要进行选择某个模块好可以提供一些函数描点等 1.disp_manager.h 1 #ifndef _DISP_MANAGER_H2 #define _DISP_MANAGER_H34 #ifndef NULL5 #define NULL (void *)06 #endif78 typedef struct DispBuff {9 int iXres; //x坐标分辨率10 int iYres; //y坐标分辨率11 int iBpp; //bpp12 char *buff; 缓冲区地址13 }DispBuff, *PDispBuff;141516 typedef struct Region {17 int iLeftUpX;18 int iLeftUpY;19 int iWidth;20 int iHeigh;21 }Region, *PRegion;2223 typedef struct DispOpr {24 char *name;25 int (*DeviceInit)(void);26 int (*DeviceExit)(void);27 int (*GetBuffer)(PDispBuff ptDispBuff);28 int (*FlushRegion)(PRegion ptRegion, PDispBuff ptDispBuff);29 struct DispOpr *ptNext;30 }DispOpr, *PDispOpr;3132 void RegisterDisplay(PDispOpr ptDispOpr);3334 void DisplayInit(void);35 int SelectDefaultDisplay(char *name);36 int InitDefaultDisplay(void);37 int PutPixel(int x, int y, unsigned int dwColor);38 int FlushDisplayRegion(PRegion ptRegion, PDispBuff ptDispBuff);39 PDispBuff GetDisplayBuffer(void);404142 #endif第8~13行进一步封装GetBuffer(int *pXres, int *pYres, int *pBpp) 第27行将4~9行的PDispBuff保存到GetBuffer中 第32行定义注册函数RegisterDisplay 第34行调用底层提供的模块 第35行定义选择模块函数 第36行选择默认的SelectDefaultDisplay后我们还需要定义初始化函数 第37行提供绘制图像函数 第38行将绘制好的图像刷新到硬件上 第39行返回取址 2.disp_manager.c 1 #include disp_manager.h2 #include stdio.h2 #include string.h23 /* 管理底层的LCD、WEB */4 static PDispOpr g_DispDevs NULL;5 static PDispOpr g_DispDefault NULL;6 static DispBuff g_tDispBuff;7 static int line_width;8 static int pixel_width;910 int PutPixel(int x, int y, unsigned int dwColor)11 {12 unsigned char *pen_8 (*unsigned char*)(g_tDispBuff.buffy*line_widthx*pixel_width);13 unsigned short *pen_16;14 unsigned int *pen_32;1516 unsigned int red, green, blue;1718 pen_16 (unsigned short *)pen_8;19 pen_32 (unsigned int *)pen_8;2021 switch (g_tDispBuff.iBpp)22 {23 case 8:24 {25 *pen_8 dwColor;26 break;27 }28 case 16:29 {30 /* 565 */31 red (dwColor 16) 0xff;32 green (dwColor 8) 0xff;33 blue (dwColor 0) 0xff;34 dwColor ((red 3) 11) | ((green 2) 5) | (blue 3);35 *pen_16 dwColor;36 break;37 }38 case 32:39 {40 *pen_32 dwColor;41 break;42 }43 default:44 {45 printf(cant surport %dbpp\n, g_tDispBuff.iBpp);45 return -1;46 break;47 }48 }48 return 0;49 }50515253 void RegisterDisplay(PDispOpr ptDispOpr)54 {55 ptDispOpr-ptNext g_DispDevs;56 g_DispDevs ptDispOpr;57 }585960 int SelectDefaultDisplay(char *name)61 {62 PDispOpr pTmp g_DispDevs;63 while (pTmp)64 {65 if (strcmp(name, pTmp-name) 0)66 {67 g_DispDefault pTmp;68 return 0;69 }7071 pTmp pTmp-ptNext;72 }7374 return -1;75 }7677 int InitDefaultDisplay(void)78 {79 int ret;8081 ret g_DispDefault-DeviceInit();82 if (ret)83 {84 printf(DeviceInit err\n);85 return -1;86 }878889 ret g_DispDefault-GetBuffer(g_tDispBuff);90 if (ret)91 {92 printf(GetBuffer err\n);93 return -1;94 }9596 line_width g_tDispBuff.iXres * g_tDispBuff.iBpp/8;97 pixel_width g_tDispBuff.iBpp/8;9899 return 0;
100 }
101
102
103 int FlushDisplayRegion(PRegion ptRegion, PDispBuff ptDispBuff)
104 {
105 return g_DispDefault-FlushRegion(ptRegion, ptDispBuff);
106 }
107
108
109 void DisplayInit(void)
110 {
111 void FramebufferInit(void);
112 FramebufferInit();
113 }
114
115 PDispBuff GetDisplayBuffer(void)
116 {
117 return g_tDispBuff;
118 }第4行将底层的LCD、WEB所实现的结构体放入到链表指针中所以我们需要提供一个函数。void RegisterDisplay(PDispOpr ptDispOpr) 第5行存放找到名字的新链表 第6行定义一个全局变量 g_tDispBuff之后用来放第89行中GetBuffer中的int* pxres, int * pYres, int * pBpp 53 void RegisterDisplay(PDispOpr ptDispOpr) 第53~57行构造注册函数将typedef struct DispOpr这个结构体注册到g_DispDevs链表中 第55行传入底层结构体指针ptDispOpr指向链表头g_DispDevs 第56行链表头g_DispDevs指向ptDispOpr 109 void DisplayInit(void)第109~112行调用底层提供的 FramebufferInit();目前我们只需要调用FramebufferInit()即可还没有实现WEB的功能 如果g_DispDevs链表中有好几个模块那我们应该如何选择呢现在我们就要设计一个模块选择函数进行模块的选择 60 int SelectDefaultDisplay(char *name) 第60~75行模块选择函数 定义一个临时指针pTmp存放链表头 while循环里根据名字name找到那一项 找到的名字放到新链表g_DispDefault中在第五行中有定义 第71行如果这个不对这找寻下一个是否正确 因为上层需要通过中间的显示管理来绘制图像坐标反馈给底层进行反应所有需要在中间层加入绘制函数 10 int PutPixel(int x, int y, unsigned int dwColor)第7~8行每个像素占据多长多少像素可以先定义好事先计算好每一行多少字节每个像素多少宽度这个在InitDefaultDisplay()中已经计算好了 第10~49行设置绘制图像函数 函数内表示绘制的x、y坐标和绘制图像的颜色 第12行g_tDispBuff.buff是写存的基地址 第21行g_tDispBuff.iBpp是每个像素的宽度 想要在上层显示一个像素首先需要得到一块内存内存可以调用到底层提供的结构体里面的g_tDispBuff这个函数在上层得到一个新的buf在这块buf里面绘制图像但是g_tDispBuff不可以放到PutPixel我们需要再定义一个函数 InitDefaultDisplay(void) 选择默认的SelectDefaultDisplay后我们还需要初始化 77 int InitDefaultDisplay(void) 第77~100行 第81行 调用 g_DispDefault 中的DeviceInit() 第89行 调用 g_DispDefault 中的GetBuffer(g_tDispBuff) 这里我们需要定义一个新的GetBuffer结构体把它的int* pxres, int * pYres, int * pBpp再次进行封装封装结构体在disp_manager.h中的DispBuff 第89行将GetBuffer中的int* pxres, int * pYres, int * pBpp放到全局变量 g_tDispBuff中 第96行line_width表示每一行占据多少个字节 第97行pixel_width表示每个像素的宽度 当我们上层已经通过 PutPixel 已经绘制好图像那我们就需要把它刷到硬件上我们需要再提供一个函数FlushDisplayRegion 103 int FlushDisplayRegion(PRegion ptRegion, PDispBuff ptDispBuff)第105行调用底层设备提供的FlushRegion函数 返回取址 114 PDispBuff GetDisplayBuffer(void) 献上韦东山老师对以上代码流程的梳理过程 电子产品量产工具显示系统代码流程 四、测试单元 book100ask:~/04_disp_unittest/display$ vi Makefile1.通用Makefile 12 CROSS_COMPILE ?3 AS $(CROSS_COMPILE)as4 LD $(CROSS_COMPILE)ld5 CC $(CROSS_COMPILE)gcc6 CPP $(CC) -E7 AR $(CROSS_COMPILE)ar8 NM $(CROSS_COMPILE)nm910 STRIP $(CROSS_COMPILE)strip11 OBJCOPY $(CROSS_COMPILE)objcopy12 OBJDUMP $(CROSS_COMPILE)objdump1314 export AS LD CC CPP AR NM15 export STRIP OBJCOPY OBJDUMP1617 CFLAGS : -Wall -O2 -g18 CFLAGS -I $(shell pwd)/include1920 LDFLAGS :2122 export CFLAGS LDFLAGS2324 TOPDIR : $(shell pwd)25 export TOPDIR2627 TARGET : test282930 obj-y display/31 obj-y unittest/3233 all : start_recursive_build $(TARGET)34 echo $(TARGET) has been built!3536 start_recursive_build:37 make -C ./ -f $(TOPDIR)/Makefile.build3839 $(TARGET) : built-in.o40 $(CC) -o $(TARGET) built-in.o $(LDFLAGS)4142 clean:43 rm -f $(shell find -name *.o)44 rm -f $(TARGET)4546 distclean:47 rm -f $(shell find -name *.o)48 rm -f $(shell find -name *.d)49 rm -f $(TARGET)50第27行编译出test的应用程序 第30行指定display下的目录 第31行指定unittest下的目录 2.display下的Makefile
1 EXTRA_CFLAGS :2 CFLAGS_file.o :34 obj-y disp_manager.o5 obj-y framebuffer.o3. unittest下的Makefile 1 EXTRA_CFLAGS :2 CFLAGS_file.o :34 obj-y disp_test.o4.
#include sys/mman.h
#include sys/types.h
#include sys/stat.h
#include unistd.h
#include linux/fb.h
#include fcntl.h
#include stdio.h
#include string.h
#include sys/ioctl.h#include disp_manager.h#define FONTDATAMAX 4096static const unsigned char fontdata_8x16[FONTDATAMAX] {//字符编码由于太多就不展示了.........
}void lcd_put_ascii(int x, int y, unsigned char c)
{unsigned char *dots (unsigned char *)fontdata_8x16[c*16];int i, b;unsigned char byte;for (i 0; i 16; i){byte dots[i];for (b 7; b 0; b--){if (byte (1b)){/* show */PutPixel(x7-b, yi, 0xffffff); /* 白 */}else{/* hide */PutPixel(x7-b, yi, 0); /* 黑 */}}}
}int main(int argc, char **argv)
{Region region; //定义刷新区域的大小PDispBuff ptBuffer;DisplayInit(); //调用DisplayInit()SelectDefaultDisplay(fb); //选择默认的设备传入一个名字为fd的设备InitDefaultDisplay(); //初始化这个默认的设备lcd_put_ascii(100, 100, A); //在屏幕100100的位置显示一个字母Aregion.iLeftUpX 100;region.iLeftUpY 100;region.iWidth 8;region.iHeigh 16;ptBuffer GetDisplayBuffer();FlushDisplayRegion(region, ptBuffer);//将这块区域刷到这个硬件中return 0;
}
五、上板测试
将原有的qt程序停止
[root100ask:~]# systemctl stop myir最终效果在开发板上打印出字符A