1,显示屏和帧缓冲
我们开发板有一块7英寸的电容屏,用来显示图像。
该屏幕的分辨率是 480*800,也就是有480行,每行有800个像素点。
帧缓冲(Frame buffer):帧指的是一帧图像,缓冲是暂时存放的意思,连起来就是暂时存放一帧图像,相当于模拟了PC机中显卡的显存作用,在嵌入式设备中,一般是没有显卡这种专门处理图像的设备,所以就使用了帧缓冲这种机制用软件来模拟显存。Frame Buffer为显示设备提供了一个统一的接口(开发板连接不同的屏幕,操作方法是一样的,屏幕了底层硬件的差异),允许上传应用直接对帧缓冲区进行读写操作。
对于应用层而言,只需要在帧缓冲区写入颜色值,就能在屏幕上对应位置显示颜色。
比如,把帧缓冲区第一个单元的值变为红色值,那么屏幕左上角那个像素点就会自动变为红色。
linux中有一中文件,叫做字符设备文件,每个字符设备(什么是字符设备,4阶段学驱动时会讲)都有一个对应的字符设备文件(Everything is a file ,in linux), Frame Buffer是一个标准的字符设备,对应的文件为 /dev/fb0 (device :设备,所有的设备文件都存在 /dev目录下, fb0: Frame Buffer)
与普通文件不一样,这种设备文件的内容不是存在硬盘中,而是存在内核中,掉电不保存,但是操作方法和普通文件类似。
开发板屏幕一个像素点占4字节,也就是说,每个像素点有 2^32 种颜色可以显示,帧缓冲中的一个单元就是4字节。
2,颜色
RGB色彩模式是工业界的一种颜色标准,是通过对红(R)、绿(G)、蓝(B)三个颜色通道的变化以及它们相互之间的叠加来得到各式各样的颜色的,RGB即是代表红、绿、蓝三个通道的颜色,这个标准几乎包括了人类视力所能感知的所有颜色,是运用最广的颜色系统之一。
ARGB是一种色彩模式,也就是RGB色彩模式附加上Alpha(透明度)通道,常见于32位位图的存储结构。
不管是 RGB还是ARGB,每个通道都是1字节,取值范围 [0,255],A是高位(24-31),R是次高位(16-23),G是次低位(8-15),B是最低位(0-8)。
不同的 RGB组合成一个不同的颜色值 color
color = A<<24 | R<<16 | G<<8|B
R G B color
0 0 255 0x0000ff 蓝色
0 255 0 0x00ff00 绿色
255 0 0 0xff0000 红色
0 0 0 0x000000 黑色
255 255 255 0xffffff 白色
100 200 255 0x64c8ff
......
100 << 16 0x640000
200 << 8 0x00c800
255 0x0000ff
|--------------
0x64c8ff
具体颜色可以参考 windows自带的画图板
3,显示屏的基本操作
3.1 打开帧缓冲文件
lcd_fd = open(“/dev/fb0”,O_RDWR);
3.2 获取屏幕信息
前面告诉大家,我们开发板的分辨率是480*800,每个想像素点4字节(ARGB),但是如果下次换了一块屏幕,需要用代码获取这些信息。通过 ioctl 函数获取
#include <sys/ioctl.h>
int ioctl(int fd, unsigned long request, ...);
fd:文件描述符
request:请求命令,每个设备会支持不同的请求,具体支持哪些请求需要和对应的驱动工程去沟通
获取屏幕信息的话,该参数为 FBIOGET_VSCREENINFO
还需要第三个参数,来保存获取到的屏幕信息
struct fb_var_screeninfo 该结构体用来保存屏幕信息,声明在 /usr/include/linux/fb.h
使用这个结构体需要包含 头文件 #include <linux/fb.h>
.xres 宽度(一行有多少像素点)
.yres 高度(总共有多少行)
.bits_per_pixel 一个像素点有多少bit
所以第三个参数应该是 struct fb_var_screeninfo类型变量的地址
示例代码:
struct fb_var_screeninfo info;
ioctl(lcd_fd,FBIOGET_VSCREENINFO,&info);
//如果 ioctl成功了,那么屏幕相关信息就保存在 info中了
lcd_width = info.xres;
lcd_height = info.yres;
lcd_pixel = info.bits_per_pixel/8;//lcd_pixel表示一个像素点占多少字节
3.3 映射
mmap 功能:把文件或者设备映射到内存,映射成功后就可以通过操作内存达到操作文件或设备的目的,相比直接操作(read/write)文件或设备的优势是:方便、高效
lcd_height* #include <sys/mman.h>
void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);
addr:映射内存的首地址,一般设置为NULL,表示由系统决定映射区的起始地址
length:映射区的长度(一般为文件的大小)
但是需要注意的是:实际映射的时候映射内存的大小是 PAGE_SIZE(4096)的整数倍,超出部分
自动清0,操作超出部分没有意义
prot:
PROT_EXEC Pages may be executed.
PROT_READ Pages may be read.
PROT_WRITE Pages may be written.
PROT_NONE Pages may not be accessed.
读写权限: PROT_READ | PROT_WRITE
flags:
MAP_SHARED:共享映射区,怎么理解?
多进程的情况下,一个进行修改了这块内存,其他进行也是可见的。
MAP_PRIVATE:私有的
fd:要映射的文件/设备的文件描述符
offset:偏移量,表示从文件的指定位置开始映射
返回值:
失败返回NULL,同时 errno被设置
成功返回映射区首地址,通过该地址就能够操作整个映射区内存,从而达到改变帧缓冲区内存的效果,最终达到
改变屏幕显示颜色的目的。
lcd_ptr = mmap(NULL,lcd_width*lcd_height*lcd_pixel,PROT_READ | PROT_WRITE,
MAP_SHARED,lcd_fd,0);
lcd_ptr应该是什么类型的指针? int * ,为什么?因为一个像素点4字节,并且颜色值是整数
假设已经映射成功,怎么操作像素点呢?
为了描述方便,从0开始计数!!!
怎么让第0行第0列那个像素点显示为红色?
*lcd_ptr = 0xff0000;
怎么让第0行第1列那个像素点显示为红色?
*(lcd_ptr+1) = 0xff0000;
怎么让第0行第2列那个像素点显示为红色?
*(lcd_ptr+2) = 0xff0000;
怎么让第0行第x列那个像素点显示为红色?
*(lcd_ptr+x) = 0xff0000;
怎么让第1行第x列那个像素点显示为红色?
*(lcd_ptr+lcd_width+x) = 0xff0000;
怎么让第y行第x列那个像素点显示为红色?
*(lcd_ptr+lcd_width*y+x) = 0xff0000;
在映射成功后,就可以使用 *(lcd_ptr+lcd_width*y+x) = color; 操作任意像素点
3.4 解除映射,关闭文件
int munmap(void *addr, size_t length);
addr:映射区内存的首地址,mmap的返回值
lenght:当时映射的长度
失败返回-1,成功返回0
munmap(lcd_ptr,lcd_width*lcd_height*lcd_pixel);
close(lcd_fd);
4,显示字符
字符(包括:数字,字母,汉字,符号等一切可以用键盘输入的内容)
需要借助软件: 点阵液晶取模.EXE
5,显示BMP图片
计算机中基本分为两种:文本文件和二进制文件
文本文件中的内容都是字符,存储的是这些字符的编码,用普通的文本编辑器软件就能打开并显示其内容(字符串)。常见的文本文件有: .txt .c .h .sh ….
二进制文件,内容不是字符串,有其固定的格式和含义。常见的有 a.out .o .bmp .mp3 .mp4 ….,不同的二进制文件中的内容含义是不一样的,如:图片文件中存储了颜色信息,音频文件中存储了声音信息,a.out存储了机器指令 ……
BMP取自位图BitMaP的缩写,也称为DIB(与设备无关的位图),是微软视窗图形子系统(Graphics Device Interface)内部使用的一种位图图形格式,它是微软视窗平台上的一个简单的图形文件格式。
特点如下:
图像通常保存的颜色深度有2(1位)、16(4位)、256(8位)、65536(16位)和1670万(24位)种颜色(其中位是表示每点所用的数据位)。这是一个BMP图片的发展过程,目前来讲一般都是 24位的BMP图片,也就是说每个像素点占24bit/3字节,RGB。
BMP文件通常是不压缩的,所以它们通常比同一幅图像的压缩图像文件格式要大很多。例如,一个800×600的24位几乎占据1.4MB空间。因此它们通常不适合在因特网或者其他低速或者有容量限制的媒介上进行传输。
如 .png .jpg .jpeg 等格式的图片都是通过压缩算法进行压缩的,打开该图片的时候需要解压缩才能获取信息。
我们要在开发板屏幕上显示图片,采用 .bmp图片相对简单,因为不需要解压缩。
24位bmp图片的大小
像素数组按照从下到上从左到右的顺序依次存储每个像素点的 BGR数据
但是,每一行的末尾通过填充若干个字节的数据(并不一定为0)使该行的长度为4字节的倍数。像素数组读入内存后,每一行的起始地址必须为4的倍数。
例如:对于24位色的位图,如果它的宽度为1像素,那么除了每一行的数据(蓝、绿、红)需要占3字节外,还会填充1字节;而如果宽为2像素,则需要2字节的填充;宽为3像素时,需要3字节填充;宽为4像素时则不需要填充。
我们一般把每行填充的字节叫做“赖子点”。
赖子点怎么计算?
int laizi = width%4;