本文以嵌入式Linux爲板載系統。寫一個測試LCD液晶點陣的小例子,在這個小例子當中主要實現液晶點陣的中文和英文實現。
一、前期準備工作
1、基本開發環境
PC機 : Ubuntu9.10
gcc版本 : gcc version 4.3.2
板載系統 :Linux(kernel version Linux-3.4.10)
2、字體文件的準備
因爲本測試程序要實現液晶點陣的中英文兩種實現方式,所以需要兩種點陣字體。
英文字體來自Linux內核中的drivers/video/console/font_8X16.c的fontdata_8X16這個數組當中。
中文字體來自於網絡下載的字體文件HZK16,可以從這個地址下載得到。
二、打開LCD驅動設備文件和HZK16點陣字體文件
在打開設備文件之前,定義一些全局變量方便測試程序的編寫,具體如下:
/* 一些全局變量的定義 */
int fd_fb; // LCD設備驅動的文件句柄
struct fb_var_screeninfo var; // 定義LCD的可變參數
struct fb_fix_screeninfo fix; // 定義LCD的固定參數
int screen_size; // 表示整個屏幕所佔顯存的大小
int line_width; // 表示屏幕每一行所佔顯存的大小
int pixel_width; // 表示每個像素點所佔顯存的大小
char *fbmem; // 表示顯存的起始地址
int fd_hzk16; // HZK16漢字庫的文件句柄
struct stat hzk16_stat; // 描述HZK16這個文件的狀態信息
char *hzk16mem; // HZK16這個漢字庫映射到內存的起始地址
1、打開LCD驅動設備文件
打開LCD設備驅動來獲取液晶的可變參數,固定參數,以及將液晶顯存映射到用戶空間,具體實現如下所示:
/* 以可讀可寫方式打開LCD液晶驅動 */
fd_fb = open("/dev/fb0", O_RDWR);
if(fd_fb == -1)
{
printf("can't open /dev/fb0!\n");
return -1;
}
/* 獲取LCD液晶的可變參數 */
ret = ioctl(fd_fb, FBIOGET_VSCREENINFO, &var);
if(ret == -1)
{
printf("can't ioctl for /dev/fb0!\n");
return -1;
}
/* 獲取LCD液晶的固定參數 */
ret = ioctl(fd_fb, FBIOGET_FSCREENINFO, &fix);
if(ret == -1)
{
printf("can't ioctl for /dev/fb0!\n");
return -1;
}
/* 獲取液晶顯存,每一行顯存,每一個像素顯存的大小 */
screen_size = var.xres * var.yres * var.bits_per_pixel / 8;
line_width = var.xres * var.bits_per_pixel / 8;
pixel_width = var.bits_per_pixel / 8;
/* 將液晶顯存映射到用戶空間 */
fbmem = mmap(NULL, screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);
if(fbmem == (char *)-1)
{
printf("mmap for /dev/fb0 error!\n");
return -1;
}
2、打開HZK16點陣字體文件
打開HZK16文件來將HZK16字庫的內容映射到程序的用戶空間,方便對字體文件的操作,具體實現如下:/* 以只讀方式打開漢子庫HZK16這個文件 */
fd_hzk16 = open("HZK16", O_RDONLY);
if(fd_hzk16 == -1)
{
printf("can't open HZK16!\n");
return -1;
}
/* 獲取HZk16這個漢字庫的文件信息 */
ret = fstat(fd_hzk16, &hzk16_stat);
if(ret == -1)
{
printf("fstat for HZK16 is error!\n");
return -1;
}
/* 將漢子庫HZK16文件中的內容映射到用戶空間 */
hzk16mem = mmap(NULL, hzk16_stat.st_size, PROT_READ, MAP_SHARED, fd_hzk16, 0);
if(hzk16mem == (char *)-1)
{
printf("mmap for HZK16 error!\n");
return -1;
}
三、液晶點陣的基本操作的實現
1、LCD液晶顯示英文字符串
這個函數的具體實現如下:
/* LCD顯示英文字符串
* x : 表示x軸座標
* y : 表示y軸座標
* str : 表示顯示的字符串的首地址
*/
void lcd_show_string(int x, int y, char* str)
{
int i = 0;
for(i = 0; str[i] != '\0'; i++) // 判斷是否顯示完畢
{
if((x + 8) > var.xres)
{
x = 0;
y = y + 16;
if(y > var.yres)
y = 0;
}
lcd_show_char(x, y, str[i]);
x = x + 8;
}
}
它的內部調用的lcd_show_char()這個顯示單個英文字符的函數,它的具體實現如下:/* LCD顯示字符函數
* x : 表示要顯示的字符的x座標
* y : 表示要顯示的字符的y座標
* c : 表示要顯示的字符
*/
void lcd_show_char(int x, int y, char c)
{
/* 獲取字符在字符數組中的起始位置 */
unsigned char *buffer = (unsigned char *)&yl_lcd_font_8x16[c * 16];
unsigned char data;
int i, j;
/* 循環操作將整個字符寫入到顯存指定位置中,達到在指定位置顯示字符 */
for(i = 0; i < 16; i++)
{
data = buffer[i];
for(j = 0; j < 8; j++)
{
if(data & 0x80)
{
lcd_put_pixel(x + j, y + i, WHITE); /*白色*/
}
else
{
lcd_put_pixel(x + j, y + i, BLACK); /*黑色*/
}
data = data << 1;
}
}
}
在這個函數的內部它有調用的lcd_put_pixel()這個函數來吧點陣寫到LCD的framebuffer中,它的具體實現如下:
/* LCD像素點顯示
* x : 表示x軸的座標
* y : 表示y軸的座標
* color : 表示像素點要顯示的顏色
*/
void lcd_put_pixel(int x, int y, int color)
{
unsigned char *pen8 = fbmem + y * line_width + x * pixel_width;
unsigned short *pen16 = (unsigned short *)pen8;
unsigned int *pen32 = (unsigned int *)pen32;
int red, green, blue;
/* 判斷像素點的大小 */
switch(var.bits_per_pixel)
{
case 16: /* 16 bit */
{
red = (color >> 16) & 0xff;
green = (color >> 8) & 0xff;
blue = color & 0xff;
*pen16 = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3);
break;
}
case 32: /* 32 bit */
{
*pen32 = color;
break;
}
default :
{
printf("Don't support this size of pixel : %d\n", var.bits_per_pixel);
break;
}
}
}
從上面可以看出不管是中文顯示還是英文顯示最終調用的都是lcd_put_pixel()這個函數來進行點陣顯示。
2、LCD液晶顯示中文字符串
LCD顯示中文字符串的具體實現如下:/* LCD顯示中文字符串
* x : 表示x軸座標
* y : 表示y軸座標
* str : 表示要顯示的漢子字符編碼的首地址
*/
void lcd_show_chinese(int x, int y, char* str)
{
int i = 0;
for(i = 0; str[i] != '\0'; i = i + 2) // 判斷是否顯示完畢
{
if((x + 16) > var.xres)
{
x = 0;
y = y + 16;
if(y > var.yres)
y = 0;
}
lcd_show_single_chinese(x, y, &str[i]);
x = x + 16;
}
}
在這個函數內部調用了lcd_show_single_chinese()這個顯示單個漢子的函數,它的具體實現如下:/* LCD液晶顯示單個漢子
* x : 表示x軸的座標
* y : 表示y軸的座標
* str : 表示要顯示的漢子的字符編碼
*/
void lcd_show_single_chinese(int x, int y, char* str)
{
/* 確定漢子在字符中的位置 */
int area = str[0] - 0xa1;
int where = str[1] - 0xa1;
unsigned char* buffer = (unsigned char *)(hzk16mem + (area * 94 + where) * 32);
unsigned short data;
int i, j;
/* 循環的將漢子的點陣寫入到LCD液晶屏的顯存當中 */
for(i = 0; i < 16; i++)
{
data = (buffer[i * 2] << 8) | buffer[i * 2 + 1];
for(j = 0; j < 16; j++)
{
if(data & 0x8000)
{
lcd_put_pixel(x + j, y + i, WHITE); /*白色*/
}
else
{
lcd_put_pixel(x + j, y + i, BLACK); /*黑色*/
}
data = data << 1;
}
}
}
3、LCD液晶進行中英文混合顯示
這個函數的具體實現如下:
/* LCD中英文混合顯示函數
* x : 表示x軸座標
* y : 表示y軸座標
* str : 表示要顯示的字符串的首地址
*/
void lcd_show_str_chn(int x, int y, char *str)
{
int i = 0;
for(i = 0; str[i] != '\0'; ) // 判斷是否顯示完
{
if(str[i] < 128) // 表示是英文字符
{
if((x + 8) > var.xres)
{
x = 0;
y = y + 16;
if(y > var.yres)
y = 0;
}
lcd_show_char(x, y, str[i]);
x = x + 8;
i = i + 1;
}
else // 表示是中文字符
{
if((x + 16) > var.xres)
{
x = 0;
y = y + 16;
if(y > var.yres)
y = 0;
}
lcd_show_single_chinese(x, y, &str[i]);
x = x + 16;
i = i + 2;
}
}
}
4、LCD液晶的清屏函數
這個函數的主要功能是清除整個屏幕爲指定的顏色,它的實現如下:
/* LCD液晶清屏
* color : 表示要將屏幕成的顏色
*/
void lcd_clear_screen(int color)
{
memset(fbmem, color, screen_size);
}
四、測試
對上面實現的基本函數進行測試,看看能不能正常進行中文顯示,英文顯示以及中英文混合顯示,具體實現如下:/* 將整個液晶屏清屏爲黑色 */
lcd_clear_screen(BLACK);
/* 在液晶屏上進行中英文的顯示操作 */
lcd_show_string(100, 100, "Hello world!");
lcd_show_string(100, 120, "Welcome to Embedded world!");
lcd_show_chinese(100, 140, "學習嵌入式開發");
lcd_show_str_chn(100, 160, "**農業大學, www.syau.edu.cn");
通過編譯並執行可以得出相應的結果。附錄:完整的程序代碼所在的位置。
http://download.csdn.net/download/tech_pro/9871728