当前位置: 首页 > news >正文

wordpress管理网址网站seo优化方法

wordpress管理网址,网站seo优化方法,网站建设理论知识,中山做外贸网站目录 前言 LCD操作原理 涉及的 API 函数 open函数 ioctl 函数 mmap 函数 Framebuffer程序分析 源码 1.打开设备 2.获取LCD参数 3.映射Framebuffer 4.描点函数 5.随便画几个点 上机实验 前言 本文介绍LCD的操作原理和涉及到的API函数,分析Framebuffer…

目录

前言

LCD操作原理

涉及的 API 函数

open函数

ioctl 函数

mmap 函数

Framebuffer程序分析

源码

1.打开设备

2.获取LCD参数

3.映射Framebuffer

4.描点函数

5.随便画几个点

上机实验


前言

本文介绍LCD的操作原理和涉及到的API函数,分析Framebuffer部分代码,


LCD操作原理

在 Linux 系统中通过 Framebuffer 驱动程序来控制 LCD。Frame 是帧的意思,buffer 是缓冲的意思,这意味着 Framebuffer 就是一块内存,里面保存着一帧图像。Framebuffer 中保存着一帧图像的每一个像素的颜色值。Framebuffer的大小为:屏幕分辨率x每一个像素所占的字节数

LCD操作流程如下:
\bullet 驱动程序设置好 LCD 控制器(我并没有学习linux驱动,本文只介绍要用到的函数和分析                 Framebuffer代码,注重应用编程,实在看不懂原理的会用就行,应用为王道)
\bullet APP 使用 ioctl 获得 LCD 分辨率、BPP(每一个像素所占的位数)
\bullet APP 通过 mmap 映射 Framebuffer,在 Framebuffer 中写入数据


(LCD操作原理图)

 问:怎么知道内存中的哪个地址对应哪个元素呢?
        假设需要设置 LCD 中坐标(x,y)处像素的颜色,首要要找到这个像素对应的内存,然后根据它的 BPP 值设置颜色。假设 fb_base 是 APP 执行 mmap 后得到的 Framebuffer 地址,如下图:

假设一个元素的左上角表示这个元素的地址 ,(x,y)坐标的元素前面有y行,在这一行的前面又有x个元素,我们不需要知道它是第几个元素,这样子会很混乱,我们只需要计算在它之前的所有元素占多大内存,那么计算出来的内存空间再加上 fb_base 就是(x,y)坐标元素的地址

可以用以下公式算出(x,y)坐标处像素对应的 Framebuffer 地址:
(x,y)像素起始地址=fb_base+(xres*bpp/8)*y + x*bpp/8

最后一个要解决的问题就是像素的颜色怎么表示?
        
它是用 RGB 三原色(红、绿、 蓝)来表示的,在不同的 BPP 格式中,用不同的位来分别表示 R、G、B。

对于 32BPP,一般只设置其中的低 24 位,高 8 位表示透明度,一般的 LCD 都不支持。
对于 16BPP,常用的是 RGB565;很少的场合会用到 RGB555,这可以通过 ioctl 读取驱动程序中的 RGB 位偏移来确定使用哪一种格式。


涉及的 API 函数

open函数

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>int open(const char *pathname, int flags);
int open(const char *pathname, int flags, mode_t mode);

open函数之前用的很多了,这里就不过多介绍了,可以看我之前的博客Linux文件编程。

ioctl 函数

#include <sys/ioctl.h>int ioctl(int fd, unsigned long request, ...);

函数说明
\bullet fd 表示文件描述符
\bullet request 表示与驱动程序交互的命令,用不同的命令控制驱动程序输出我们需要的数据
\bullet … 表示可变参数 arg;根据 request 命令,设置驱动程序返回输出的数据
\bullet 返回值:打开成功返回文件描述符,失败将返回-1
        ioctl 的作用非常强大、灵活。不同的驱动程序内部会实现不同的 ioctl,APP 可以使用各种 ioctl 跟驱动程序交互:可以传数据给驱动程序,也可以从驱动程序中读出数据。

mmap 函数

#include <sys/mman.h>void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);

mmap 函数的功能是将文件或其他对象映射到进程的内存地址空间。这使得程序可以通过内存操作直接访问文件内容,而无需使用传统的文件读写函数。其主要功能包括:
\bullet 文件映射:将文件内容映射到内存,使得文件可以像数组一样进行读取和修改
\bullet 共享内存:在多个进程之间共享数据,通过映射同一文件或匿名映射区域实现进程间通信
\bullet 内存映射设备映射设备文件到内存,以便进行高效的数据访问和操作

函数说明
\bullet addr 表示指定映射的內存起始地址,通常设为 NULL 表示让系统自动选定地址,并在成功映射       后返回该地址
\bullet length 表示将文件中多大的内容映射到内存中
\bullet prot 表示映射区域的保护方式,可以为以下 4 种方式的组合
        \circ PROT_EXEC 映射区域可被执行
        \circ PROT_READ 映射区域可被读出
        \circ PROT_WRITE 映射区域可被写入
        \circ PROT_NONE 映射区域不能存取
\bullet Flags 表示影响映射区域的不同特性,常用的有以下两种
        \circ MAP_SHARED 表示对映射区域写入的数据会复制回文件内,原来的文件会改变
        \circ MAP_PRIVATE 表示对映射区域的操作会产生一个映射文件的复制,对此区域的任何修改               都不会写回原来的文件内容中
返回值:若成功映射,将返回指向映射的区域的指针,失败将返回-1


Framebuffer程序分析

源码

#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>static int fd_fb;
static struct fb_var_screeninfo var;	/* Current var */
static int screen_size;
static unsigned char *fb_base;
static unsigned int line_width;
static unsigned int pixel_width;/*********************************************************************** 函数名称: lcd_put_pixel* 功能描述: 在LCD指定位置上输出指定颜色(描点)* 输入参数: x坐标,y坐标,颜色* 输出参数: 无* 返 回 值: 会* 修改日期        版本号     修改人	      修改内容* -----------------------------------------------* 2020/05/12	     V1.0	  zh(angenao)	      创建***********************************************************************/ 
void lcd_put_pixel(int x, int y, unsigned int color)
{unsigned char *pen_8 = fb_base+y*line_width+x*pixel_width;unsigned short *pen_16;	unsigned int *pen_32;	unsigned int red, green, blue;	pen_16 = (unsigned short *)pen_8;pen_32 = (unsigned int *)pen_8;switch (var.bits_per_pixel){case 8:{*pen_8 = color;break;}case 16:{/* 565 */red   = (color >> 16) & 0xff;green = (color >> 8) & 0xff;blue  = (color >> 0) & 0xff;color = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3);*pen_16 = color;break;}case 32:{*pen_32 = color;break;}default:{printf("can't surport %dbpp\n", var.bits_per_pixel);break;}}
}int main(int argc, char **argv)
{int i;fd_fb = open("/dev/fb0", O_RDWR);if (fd_fb < 0){printf("can't open /dev/fb0\n");return -1;}if (ioctl(fd_fb, FBIOGET_VSCREENINFO, &var)){printf("can't get var\n");return -1;}line_width  = var.xres * var.bits_per_pixel / 8;pixel_width = var.bits_per_pixel / 8;screen_size = var.xres * var.yres * var.bits_per_pixel / 8;fb_base = (unsigned char *)mmap(NULL , screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);if (fb_base == (unsigned char *)-1){printf("can't mmap\n");return -1;}/* 清屏: 全部设为白色 */memset(fb_base, 0xff, screen_size);/* 随便设置出100个为红色 */for (i = 0; i < 100; i++)lcd_put_pixel(var.xres/2+i, var.yres/2, 0xFF0000);munmap(fb_base , screen_size);close(fd_fb);return 0;	
}

1.打开设备

首先打开设备节点:

fd_fb = open("/dev/fb0", O_RDWR);
if (fd_fb < 0)
{printf("can't open /dev/fb0\n");return -1;
}

2.获取LCD参数

        LCD 驱动程序给 APP 提供 2 类参数:可变的参数 fb_var_screeninfo、固定的参数 fb_fix_screeninfo。编写应用程序时主要关心可变参数,它的结构体定义如下(#include <linux/fb.h>):

可以使用以下代码获取 fb_var_screeninfo: 

static struct fb_var_screeninfo var; /* Current var */if (ioctl(fd_fb, FBIOGET_VSCREENINFO, &var))
{printf("can't get var\n");return -1;
}

        注意到 ioctl 里用的参数是:FBIOGET_VSCREENINFO,它表示 get var screeninfo,获得屏幕的可变信息;当然也可以使用 FBIOPUT_VSCREENINFO 来调整这些参数,但是很少用到。

对于固定的参数 fb_fix_screeninfo,在应用编程中很少用到。它的结构体定义如下:

可以使用 ioctl FBIOGET_FSCREENINFO 来读出这些信息,但是很少用到。(F表示fix,确定的,V表示var-variable 可变的)

3.映射Framebuffer

要映射一块内存,需要知道它的地址──这由驱动程序来设置,需要知道它的大小──这由应用程序决定。代码如下:

line_width = var.xres * var.bits_per_pixel / 8;
pixel_width = var.bits_per_pixel / 8;
screen_size = var.xres * var.yres * var.bits_per_pixel / 8;
fb_base = (unsigned char *)mmap(NULL , screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);if (fb_base == (unsigned char *)-1)
{printf("can't mmap\n");return -1;
}

        第3行中,screen_size 是整个 Framebuffer 的大小;PROT_READ | PROT_WRITE 表示该区域可读、可写;MAP_SHARED 表示该区域是共享的,APP 写入数据时,会直达驱动程序,这个参数的更深刻理解可以参考后面驱动基础中讲到的 mmap 知识。(我的理解是将驱动程序所控制的硬件的真实地址映射(mmap)到文件里,linux一切皆文件,然后往地址写数据对硬件进行操作

4.描点函数

        能够在 LCD 上描绘指定像素后,就可以写字、画图,描点函数是基础。代码如下:

1    void lcd_put_pixel(int x, int y, unsigned int color)
2    {
3    	unsigned char *pen_8 = fb_base+y*line_width+x*pixel_width;
4    	unsigned short *pen_16;	
5    	unsigned int *pen_32;	
6
7    	unsigned int red, green, blue;	
8
9	    pen_16 = (unsigned short *)pen_8;
10	    pen_32 = (unsigned int *)pen_8;
11
12	    switch (var.bits_per_pixel)
13      {
14	    	case 8:
15	    	{
16	    		*pen_8 = color;
17	    		break;
18	    	}
19	    	case 16:
20	    	{
21	    		/* 565 */
22	    		red   = (color >> 16) & 0xff;
23	    		green = (color >> 8) & 0xff;
24	    		blue  = (color >> 0) & 0xff;
25		    	color = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3);
26		    	*pen_16 = color;
27	    		break;
28	    	}
29	    	case 32:
30	    	{
31	    		*pen_32 = color;
32	    		break;
33	    	}
34	    	default:
35	    	{
36	    		printf("can't surport %dbpp\n", var.bits_per_pixel);
37	    		break;
38	    	}
39       }
40    }

        第 1 行中传入的 color 表示颜色,它的格式永远是 0x00RRGGBB,即 RGB888。当 LCD 是 16bpp 时,要把 color 变量中的 R、G、B 抽出来再合并成 RGB565 格式。

        第 3 行计算(x,y)坐标上像素对应的 Framebuffer 地址。

        第 16 行,对于 8bpp,color 就不再表示 RBG 三原色了,这涉及调色板的概念,color 是调色板的值。

        第 22~24 行,先从 color 变量中把 R、G、B 抽出来。

        第 25 行,把 red、green、blue 这三种 8 位颜色值,根据 RGB565 的格式,只保留 red 中的高 5 位、green 中的高 6 位、blue 中的高 5 位,组合成一个新的 16 位颜色值。

        第 26 行,把新的 16 位颜色值写入 Framebuffer。

        第 31 行,对于 32bpp,颜色格式跟 color 参数一致,可以直接写入Framebuffer。

5.随便画几个点

本程序的 main 函数,在最后只是简单地画了几个点:

/* 清屏: 全部设为白色 */
memset(fb_base, 0xff, screen_size);/* 随便设置出100个为红色 */
for (i = 0; i < 100; i++)lcd_put_pixel(var.xres/2+i, var.yres/2, 0xFF0000);

上机实验

板子用的是韦东山老师的imx6ull板,由于我的屏幕被烧坏了,这里就演示不了了。

在 Ubuntu 中编译程序,先设置交叉编译工具链,再执行以下命令:
arm-buildroot-linux-gnueabihf-gcc -o show_pixel show_pixel.c

交叉编译后在板子上就能运行应用程序了,正常会在屏幕中心显示一条红色的线。 

http://www.zhongyajixie.com/news/64628.html

相关文章:

  • 企业建设网站公司郑州百度快照优化排名
  • 安徽省住房和城乡建设厅官方网站站长工具关键词排名怎么查
  • 专注软件开发网站关键词优化建议
  • 做家教网站怎么样google引擎入口
  • 沧州市高速公路建设管理局网站正规代运营公司排名
  • 采用wordpress太原百度网站快速优化
  • 免费注册自己的网站北京seo网站优化培训
  • lnmp搭建后怎么做网站怎么自己做网页
  • wordpress 分页导航无效seo新人怎么发外链
  • 高端网页制作公司哪家好石家庄自动seo
  • 微信创建公众号seo外链工具
  • 企业网站模板 简洁百度收录技巧
  • 做门户网站起什么域名好国外友链买卖平台
  • 影视广告网站seo研究院
  • 内网小网站的建设国内最好用的免费建站平台
  • nginx进wordpress不能进目录seo全网优化推广
  • 哪个网站网页做的好看网络推广费用预算表
  • cms中文名称是什么关键词优化外包
  • linux下做网站产品营销方案案例范文
  • 中央广播电视总台级别天津seo诊断
  • 有个性的个人网站谷歌seo和百度seo
  • 国外那些视频网站做的不错软文文案范文
  • 外包网站建设网站关键词排名seo
  • 门户网站整改情况报告软件培训班学费多少
  • 云南省建设厅官方网站不良记录太原百度公司地址
  • 简单的网站建设步骤免费百度广告怎么投放
  • 惠州淘宝网站建设百度竞价电话
  • 免费空间测试网站最新军事头条
  • 网站快速办理备案搜索引擎优化技术都有哪些
  • 重庆定制网站建设地址软文广告经典案例600