LCD开发之汉字显示
一、LCD显示原理
利用液晶制成的显示器称为LCD,依据驱动方式可分为静态驱动、简单矩阵驱动以及 主动矩阵驱动3种。其中,简单矩阵型又可再细分扭转向列型(TN)和超扭转式向列型(STN)两种,而主动矩阵型则以薄膜式晶体管型( TFT)为主流。
一块LCD 屏显示图像不但需要 LCD驱动器,还需要有相应的 LCD控制器。通常 LCD 驱动器会以 COF/COG的形式与LCD 玻璃基板制作在一起,而 LCD 控制器则由外部电路来实现。许多MCU 内部直接集成了LCD 控制器,通过LCD控制器可以方便地控制 STN 和 TFT 屏。
TFT屏是目前入式系统应用的主流,下图给出了TFT屏的典型时序。时序图中的VCLK、HSYNC 和 VSYNC 分别为像素时钟信号(用于锁存图像数据的像素时钟)、行同步信号和帧同步信号,VDEN 为数据有效标志信号,VD 为图像的数据信号。
作为帧同步信号的 VSYNC,每发出一个脉冲,都意味着新的一屏图像数据开始发送。而作为行同步信号的 HSYNC,每发出一个脉冲都表明新的一行图像资料开始发送。在帧同步以及行同步的头尾都必须留有回扫时间。
下图给出了 LCD 控制器中应该设置的 TFT屏的参数,其中的上边界和下边界即为帧切换的回扫时间,左边界和右边界即为行切换的回扫时间,水平同步和垂直同步分别是行和帧同步本身需要的时间。 xres 和 yres 则分别是屏幕的水平和垂直分辨率,常见的嵌入式设备的 LCD 分辨率主要为 320*240、640*480 等。
二、帧缓冲
1、基本概念
帧缓冲(framebuffer)是 Linux 系统为显示设备提供的一个接口,它将显示缓冲区抽象,屏蔽图像硬件的底层差异,允许上层应用程序在图形模式下直接对显示缓冲区进行读写操作。用户不必关心物理显示缓冲区的具体位置及存放方式,这些都由帧缓冲设备驱动本身来完成。对于帧缓冲设备而言,只要在显示缓冲区中与显示点对应的区域写入颜色值,对应的颜色会自动在屏幕上显示。
帧缓冲设备为标准字符设备,主设备号为29,对应于/dev/fb%d 设备文件。帧缓冲驱动的应用非常广泛,在Linux的桌面系统中,X window服务器就是利用帧缓冲进行窗口的绘制。嵌入式系统中的Qt/Embedded等图形用户界面环境也基于帧缓冲而设计。另外,通过帧缓冲可支持汉字点阵的显示,因此帧缓冲也成为Linux汉化的可行方案。
2、显示缓冲区与显示点
在帧缓冲设备中,对屏幕显示点的操作通过读写显示缓冲区来完成,在不同的色彩模式下,显示缓冲区和屏幕上的显示点有不同的对应关系。下表分别是8位色和16 位色时显示缓冲区与显示点的对应关系:
3、Linux 帧缓冲相关数据结构与函数
1)fb_info 结构体
帧缓冲设备最关键的一个数据结构体是fb_info 结构体,它包括了关于帧缓冲设备属性和操作的完整描述,这个结构体定义在/include/linux/fb.h中,代码如下所示:
该结构体记录了帧缓冲设备的全部信息,包括设备的设置参数、状态以及操作函数指针。每一个帧缓冲设备都必须对应一个fb_info。
2)fb_ops结构体
fb_ops 的fb_check_var()成员函数用于检查可以修改的屏幕参数并调整到合适的值,而 fb_set_par()则使得用户设置的屏幕参数在硬件上有效。
3)fb_var_screeninfo和 fb_fix_screeninfo 结构体
fb_var_screeninfo记录用户可修改的显示控制器参数,包括屏幕分辨率和每个像素点的比特数。fb_var_screeninfo 中的 xres 定义屏幕一行有多少个点, yres 定义屏幕一列有多少个点,bits_per_pixel 定义每个点用多少个字节表示。而 fb_fix_screeninfo 中记录用户不能修改的显示控制器的参数,如屏幕缓冲区的物理地址、长度。当对帧缓冲设备进行映射操作的时候,就是从 fb_fix_screeninfo 中取得缓冲区物理地址的。上述数据成员都需要在驱动程序中初始化和设置。
fb_var_screeninfo和 fb_fix_screeninfo 结构体的定义在/include/linux/fb.h中,代码分别如下:
fb_fix_screeninfo结构体定义中第8 行的 visual 记录屏幕使用的色彩模式,在 Linux 系统中,支持的色彩模式包括如下几种。
● Monochrome(FB_VISUAL_MONO01、FB_VISUAL_MONO10),每个像素是黑或白。
● Pseudo color ( FB_VISUAL_PSEUDOCOLOR 、FB_VISUAL_ST ATIC_PSEUDOCOLOR),即伪彩色,采用索引颜色显示。
● T rue color(FB_VISUAL_TRUECOLOR),真彩色,分成红、绿、蓝三基色。
● Direct color(FB_VISUAL_DIRECTCOLOR),每个像素颜色也是有红、绿、
蓝组成,不过每个颜色值是个索引,需要查表。
● Grayscale displays,灰度显示,红、绿、蓝的值都一样。
4)文件操作结构体
作为一种字符设备,帧缓冲设备的文件结构体定义在/linux/drivers/vedio/fbmem.c文件中,代码如下:
帧缓冲设备驱动的文件操作接口函数已经在fbmem.c 中被统一实现,一般不需要由驱动工程师再编写。
5)注册与注销帧缓冲设备
Linux 内核提供了register_framebuf fer()和 unregister_framebu销帧缓冲设备,这两个函数都接受fb_info指针为参数,原型为:
对于register_framebuffer()函数而言,如果注册的帧缓冲设备数超过了 FB_MAX(目前定义为 32),则函数返回-ENXIO,注册成功则返回 0。
三、Linux 帧缓冲设备驱动结构
Linux 帧缓冲设备驱动的主要结构如下图所示,帧缓冲设备提供给用户空间的file_operations 结构体由fbmem.c 中的file_operations 提供,而特定帧缓冲设备fb_info结构体的注册、注销以及其中成员的维护,尤其是fb_ops中成员函数的实现则由对应的 xxxfb.c 文件实现,fb_ops 中的成员函数最终会操作 LCD 控制器硬件寄存器。
四、帧缓冲设备的用户空间访问
通过/dev/fbns,应用程序可进行的针对帧缓冲设备的操作主要有如下几种。
● 读/写 dev/fbn:相当于读/写屏幕缓冲区。例如用cp /dev/fb0 tmp 命令可将当前屏幕的内容复制到一个文件中,而命令cp tmp > /dev/fb0 则将图形文件tmp 显示在屏幕上。
● 映射操作:对于帧缓冲设备,可通过mmap()映射操作将屏幕缓冲区的物理地址映射到用户空间的一段虚拟地址中,之后用户就可以通过读/写这段虚拟地址访问屏幕缓冲区,在屏幕上绘图。而且若干个进程可以映射到同一个显示缓冲区。实际上,使用帧缓冲设备的应用程序都是通过映射操作来显示图形的。
● I/O 控制:对于帧缓冲设备,对设备文件的ioctl()操作可读取/设置显示设备及屏幕的参数,如分辨率、显示颜色数、屏幕大小等。
在应用程序中,操作/dev/fbn 的一般步骤如下。
(1)打开/dev/fbn 设备文件;
(2)用 ioctl()操作取得当前显示屏幕的参数,如屏幕分辨率、每个像素点的比特数和偏移;根据屏幕参数可计算屏幕缓冲区的大小;
(3)将屏幕缓冲区映射到用户空间;
(4)映射后就可以直接读/写屏幕缓冲区,进行绘图和图片显示了。
例子:
功能:在LCD屏幕上显示红色汉字“赵”。
源码如下:
#include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <fcntl.h> #include <linux/fb.h> #include <sys/mman.h> int main() { int fbfd=0; struct fb_var_screeninfo vinfo; unsigned long screensize=0; char *fbp=0; int x=0,y=0; fbfd=open("/dev/fb0",O_RDWR); //打开帧缓冲设备 if(!fbfd){ printf("error\n"); exit(1); } if(ioctl(fbfd,FBIOGET_VSCREENINFO,&vinfo)){ //获取屏幕可变参数 printf("error\n"); exit(1); } //打印屏幕可变参数 printf("%dx%d,%dbpp\n",vinfo.xres,vinfo.yres,vinfo.bits_per_pixel); screensize=vinfo.xres*vinfo.yres* vinfo.bits_per_pixel/2; //缓冲区字节大小 fbp=(char *)mmap(0,screensize,PROT_READ|PROT_WRITE,MAP_SHARED,fbfd,0);//映射 if((int)fbp==-1){ printf("error\n"); exit(4); } memset(fbp,0,screensize); //清屏 char hz[16][2]={ 0x08, 0x00, 0x08, 0x00, 0x08, 0x04, 0x7E, 0x84, 0x08, 0x48, 0x08, 0x28, 0xFF, 0x10, 0x08, 0x10, 0x28, 0x28, 0x2F, 0x28, 0x28, 0x44, 0x28, 0x84, 0x58, 0x00, 0x48, 0x00, 0x87, 0xFE, 0x00, 0x00, }; //16*16字模库中提取的“赵”字对应的字符数组 int i,j,k; for(j=0;j<16;j++){ for(i=0;i<2;i++){ for(k=0;k<8;k++){ if(hz[j][i]&(0x80>>k)) *((unsigned short *)(fbp + j*vinfo.xres*2 + i*16 + k*2))=0xf100; } } } munmap(fbp,screensize); close(fbfd); return 0; }
ps:0xf100即对应16位:1111 1000 0000 0000,查看16位色时显示缓冲区与显示点的对应关系表,可以得出此像素点对应红色。
参考资料:《Linux设备驱动开发详解》
2014年6月23日星期一22时54分