1. 程式人生 > >LCD開發之漢字顯示

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;
}

ps0xf100即對應16位:1111 1000 0000 0000,檢視16位色時顯示緩衝區與顯示點的對應關係表,可以得出此畫素點對應紅色。

參考資料:《Linux裝置驅動開發詳解》

2014年6月23日星期一22時54分