您当前的位置: 首页 >  linux

韦东山

暂无认证

  • 0浏览

    0关注

    506博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

Linux应用开发【第一章】Framebuffer应用开发

韦东山 发布时间:2021-12-13 14:08:10 ,浏览量:0

文章目录
  • 1 Framebuffer应用开发
    • 1.1 LCD Framebuffer操作原理
    • 1.2 Framebuffer API接口
      • 1.2.1 open系统调用
      • 1.2.2 ioctl系统调用
      • 1.2.3 mmap系统调用
    • 1.3 在LCD上描点操作
      • 1.3.1 在LCD上显示点阵理论基础
      • 1.3.2 获取fb_var_screeninfo结构体
      • 1.3.3 根据fb_var_screeninfo计算变量
      • 1.3.4 使用mmap系统调用,映射内存
      • 1.3.5 描点函数编写
    • 1.4 在LCD上使用点阵写字
      • 1.4.1 在LCD上显示英文字母
      • 1.4.2 在LCD上显示汉字
    • 1.5 搭建freetype相关环境
      • 1.5.1 交叉编译freetype,并安装
        • 1.5.2 freetype库,头文件移植至开发板
    • 1.6 使用freetype
      • 1.5.1 矢量字体引入
      • 1.5.2 Freetype理论介绍
      • 1.5.2 在LCD上显示一个矢量字体
      • 1.5.3 在LCD上令矢量字体旋转某个角度

1 Framebuffer应用开发 1.1 LCD Framebuffer操作原理

​ LCD Framebuffer 就是一块显存,在嵌入式系统中,显存是被包含在内存中。LCD Framebuffer里的若干字节(根据驱动程序对LCD控制器的配置而定)表示LCD屏幕中的一个像素点,一一对应整个LCD屏幕。举个例子,LCD屏幕是800*600的分辨率,即LCD屏幕存在480000个像素点,若每个像素点4个字节表示,那么LCD Framebuffer显存大小为480000 *4=960000字节,即1.92MB。因此我们的内存将会分割至少1.92MB的空间用作显存。具体地址在哪里,这个就是又驱动程序去定,应用程序只需直接使用即可,硬件相关操作已由驱动程序封装好。

FramebufferAPP_Image00001

​ 如上图,我们只需要往Framebuffer中填入不同的值,驱动程序和硬件控制器就会把这些数据传输到对应LCD屏幕上的像素点,从而显示不同的颜色。由此可知,我们应用程序只需要针对Framebuffer操作即可,其他交给驱动程序和硬件。

1.2 Framebuffer API接口 1.2.1 open系统调用

FramebufferAPP_Image00002

头文件:#include ,#include ,#include

函数原型:

  • int open(const char *pathname, int flags);
  • int open(const char *pathname, int flags, mode_t mode);

函数说明:

  • pathname 表示打开文件的路径;

  • Flags表示打开文件的方式,常用的有以下6种,

    ①:O_RDWR表示可读可写方式打开;

    ②:O_RDONLY表示只读方式打开;

    ③:O_WRONLY表示只写方式打开;

    ④:O_APPEND 表示如果这个文件中本来是有内容的,则新写入的内容会接续到原来内容的后面;

    ⑤:O_TRUNC表示如果这个文件中本来是有内容的,则原来的内容会被丢弃,截断;

    ⑥:O_CREAT表示当前打开文件不存在,我们创建它并打开它,通常与O_EXCL结合使用,当没有文件时创建文件,有这个文件时会报错提醒我们;

Mode表示创建文件的权限,只有在flags中使用了O_CREAT时才有效,否则忽略。

返回值:打开成功返回文件描述符,失败将返回-1。

1.2.2 ioctl系统调用

FramebufferAPP_Image00003

头文件:#include

函数原型:

  • int ioctl(int fd, unsigned long request, …);

函数说明:

  • fd 表示文件描述符;
  • request表示与驱动程序交互的命令,用不同的命令控制驱动程序输出我们需要的数据;
  • … 表示可变参数arg,根据request命令,设备驱动程序返回输出的数据。

返回值:打开成功返回文件描述符,失败将返回-1。

1.2.3 mmap系统调用

FramebufferAPP_Image00004

头文件:#include

函数原型:

  • void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);

函数说明:

  • addr表示指定映射的內存起始地址,通常设为 NULL表示让系统自动选定地址,并在成功映射后返回该地址;

  • length表示将文件中多大的内容映射到内存中;

  • prot 表示映射区域的保护方式,可以为以下4种方式的组合

    ①PROT_EXEC 映射区域可被执行

    ②PROT_READ 映射区域可被读写

    ③PROT_WRITE 映射区域可被写入

    ④PROT_NONE 映射区域不能存取

  • Flags 表示影响映射区域的不同特性,常用的有以下两种

    ①MAP_SHARED 表示对映射区域写入的数据会复制回文件内,原来的文件会改变。

    ②MAP_PRIVATE 表示对映射区域的操作会产生一个映射文件的复制,对此区域的任何修改都不会写回原来的文件内容中。

返回值:若成功映射,将返回指向映射的区域的指针,失败将返回-1。

1.3 在LCD上描点操作 1.3.1 在LCD上显示点阵理论基础

FramebufferAPP_Image00005

​ 如上图,当我们需要显示一个字母‘A’时,是通过判断点阵的每一个位数值状态,来填充颜色,达到显示字符效果。其中‘1’表示一种颜色,‘0’表示填充另一种颜色。上图的是8*16的点阵,我们也可以用其他不同大小点阵,只要有这个点阵,我们就可以在LCD上面描点,达到显示字符的效果。

1.3.2 获取fb_var_screeninfo结构体

​ 在用点阵显示字符之前,我们需要先从设备fb0中获取相关的LCD信息,下图截取我们将用到的fb_info结构体部分内容。

FramebufferAPP_Image00006

​ 通过系统调用ioctl,获取xres(x方向总像素点),yres(y方向总像素点),bits_per_pixel(每个像素点占据的位数),根据获取的三个资源,外加点阵,根据这四个资源,我们就可以显示一个字符。

程序文件:show_ascii.c

4718        fd_fb = open("/dev/fb0", O_RDWR);
4719        if (fd_fb > 16) & 0xff;
4663				green = (color >> 8) & 0xff;
4664				blue  = (color >> 0) & 0xff;
4665				color = ((red >> 3)  2)  3);
4666				*pen_16 = color;
4667				break;
4668			}
4669			case 32:
4670			{
4671				*pen_32 = color;
4672				break;
4673			}
4674			default:
4675			{
4676				printf("can't surport %dbpp\n", var.bits_per_pixel);
4677				break;
4678			}
4679		}
4680	}

​ 根据设备fb0实际的bits_per_pixel值,选择对应的pen(pen_8,pen_16,pen_32其中一个),最后把color颜色变量传入选择的pen中。

1.4 在LCD上使用点阵写字 1.4.1 在LCD上显示英文字母

①找出英文字母在点阵数组中的地址,c所代表的是一个英文字母(ASCII值)。

程序文件:show_ascii.c

4693		unsigned char *dots = (unsigned char *)&fontdata_8x16[c*16];

②根据获得的英文字母点阵,每一位依次判断,描点,‘1’表示白色,‘0’表示黑色。

FramebufferAPP_Image00007

​ 根据上图,我们分析下如何利用点阵在LCD上显示一个英文字母,因为有十六行,所以首先要有一个循环16次的大循环,然后每一行里有8位,那么在每一个大循环里也需要一个循环8次的小循环,小循环里的判断单行的描点情况,如果是1,就填充白色,如果是0就填充黑色,如此一来,就可以显示出黑色底,白色轮廓的英文字母。

程序文件:show_ascii.c

4697		for (i = 0; i = 0; b--)
4701			{
4702				if (byte & (1buffer[q * bitmap->width + p]);

⑥编译C程序文件freetype_show_font.c

编译命令:arm-linux-gnueabihf-gcc -finput-charset=GBK -fexec-charset=GBK -o freetype_show_font freetype_show_font.c -lfreetype -lm

⑦将编译好的freetype_show_font的文件与simsun.ttc字体文件拷贝至开发板,simsun.ttc字体文件放在freetype_show_font执行文件的上一层目录下,执行以下命令。

执行命令:./freetype_show_font …/simsun.ttc

如果实验成功,我们将看到屏幕中间会比之前实验多出一个蓝色的‘繁’字。

1.5.3 在LCD上令矢量字体旋转某个角度

在实现显示一个矢量字体后,我们可以添加让该字旋转某个角度的功能。

我们根据输入的第二个参数,判断其旋转角度,主要代码还是参照example1.c

FramebufferAPP_Image00020

根据上图,增加旋转角度功能,旋转的角度由执行命令的第二个参数指定。

程序文件:freetype_show_font_angle.c

		/* use 25 degrees */
4894	angle = ( 1.0 * strtoul(argv[2], NULL, 0) / 360 ) * 3.14159 * 2;

4895	/* set up matrix */
4896	matrix.xx = (FT_Fixed)( cos( angle ) * 0x10000L );
4897	matrix.xy = (FT_Fixed)(-sin( angle ) * 0x10000L );
4898	matrix.yx = (FT_Fixed)( sin( angle ) * 0x10000L );
4899	matrix.yy = (FT_Fixed)( cos( angle ) * 0x10000L );
4900
4901    /* set transformation */
4902    FT_Set_Transform( face, &matrix, &pen);

最后编译,在开发板上运行

编译命令如下:

编译命令:arm-linux-gnueabihf-gcc -finput-charset=GBK -fexec-charset=GBK -o freetype_show_font_angle freetype_show_font_angle.c -lfreetype -lm

编译出的文件名为freetype_show_font_angle,将文件拷贝至开发板

在含有该文件的目录下执行以下命令,以下命令正确执行前提是执行文件freetype_show_font在此目录,而且字体文件simsun.ttc,在上一级目录:

执行命令:./freetype_show_font_angle …/simsun.ttc 90

如果实验成功,我们将看到屏幕中间的蓝色‘繁’字,旋转了90度。

关注
打赏
1658827356
查看更多评论
0.1722s