需先安裝 LCD Driver,接著撰寫應用程式,導入HZK16漢字庫,將要顯示的字元,透過漢字庫,尋找到相應字元,輸出到 LCD 螢幕上。
- HZK16是符合GB23121UL 標準,每個漢字用16*16 BIT来表示,也就是說需要32個字元來顯示一個漢字
- 每個漢字由兩個字元編碼,範圍是 A1A1~FEFE,分為區碼和位碼,如圖a:
- 圖a所示每區有94個漢字,每區用32字元表示,所以所尋找漢字偏移量是: (94*(區碼-0xA1) +位碼-0xA1)*32
fig. a |
=====================================================================
show_font.c
show_font.c
#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>
#define FONTDATAMAX 4096
static const unsigned char fontdata_8x16[FONTDATAMAX] = {
/* 0 0x00 '^@' */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
/* 1 0x01 '^A' */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x7e, /* 01111110 */
0x81, /* 10000001 */
0xa5, /* 10100101 */
0x81, /* 10000001 */
0x81, /* 10000001 */
0xbd, /* 10111101 */
0x99, /* 10011001 */
0x81, /* 10000001 */
0x81, /* 10000001 */
0x7e, /* 01111110 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
/* 2 0x02 '^B' */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x7e, /* 01111110 */
0xff, /* 11111111 */
0xdb, /* 11011011 */
0xff, /* 11111111 */
0xff, /* 11111111 */
0xc3, /* 11000011 */
0xe7, /* 11100111 */
0xff, /* 11111111 */
0xff, /* 11111111 */
0x7e, /* 01111110 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
.................................
/* 255 0xff '' */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
0x00, /* 00000000 */
};
int fd_fb;
struct fb_var_screeninfo var;
struct fb_fix_screeninfo fix;
int screen_size;
unsigned char *fbmem;
unsigned int line_width;
unsigned int pixel_width;
unsigned char *hzkmem;
int fd_hzk16;
struct stat hzk_stat;
// display pixel
void lcd_put_pixel(int x, int y, unsigned int color)
{
unsigned char *pen_8 = fbmem+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;
}
}
// input ascii
void lcd_put_ascii(int x, int y, unsigned char c)
{
unsigned char *dots = (unsigned char *)&fontdata_8x16[c*16];
int i,b;
unsigned char byte;
for(i=0; i<16; i++) // y axiel
{
byte = dots[i]; // 一個 i 表示一個 byte
for(b=7; b>=0; b--) // x axiel
{
if(byte & (1<<b))
{
lcd_put_pixel(x+7-b, y+i, 0xffffff);
}
else
{
lcd_put_pixel(x+7-b, y+i, 0);
}
}
}
}
// input 漢字
void lcd_put_chinese(int x, int y, unsigned char *str)
{
unsigned int area = str[0] - 0xA1; // HZK16 區碼第一個為空字元
unsigned int where = str[1] - 0xA1; // HZK16 位碼第一個為空字元
unsigned char *dots = hzkmem + (area * 94 + where)*32;
unsigned char byte;
int i, j, b;
for(i=0; i<16; i++)
{
for(j=0; j<2; j++) // y axiel
{
byte = dots[i*2+j]; // 一個 i or j 表示一個 byte
for(b=7; b>=0; b--) // x axiel
{
// show
if(byte & (1<<b))
{
lcd_put_pixel(x+j*8+7-b, y+i, 0xffffff);
}
else // hide
{
lcd_put_pixel(x+j*8+7-b, y+i, 0);
}
}
}
}
}
int main(int argc, char **argv)
{
unsigned char str[] = "中";
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;
}
// 這裡可以獲得LCD的可變參數
if(ioctl(fd_fb, FBIOGET_FSCREENINFO, &fix))
{
printf("can't get fix\n");
return -1;
}
line_width = var.xres * var.bits_per_pixel / 8; // Representative of the number of bytes per row
pixel_width = var.bits_per_pixel / 8; // Representative of the number of bytes per pixel
screen_size = var.xres * var.yres * var.bits_per_pixel / 8; // Representative of the number of bytes per frame
// 映射一塊顯存,第一個參數代表映射的位址,NULL表示自由分配
fbmem = (unsigned char *)mmap(NULL , screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);
if(fbmem == (unsigned char *)-1)
{
printf("can't mmap\n");
return -1;
}
fd_hzk16 = open("HZK16", O_RDONLY);
if(fd_hzk16 < 0)
{
printf("can't open HZK16\n");
return -1;
}
// 獲取漢字庫文件的資訊,我們主要是為了獲得其大小
if(fstat(fd_hzk16, &hzk_stat))
{
printf("can't get fstat\n");
return -1;
}
// 為漢字庫映射一部分記憶體:這樣我們就可以像訪問陣列一樣來訪問漢字庫了
hzkmem = (unsigned char *)mmap(NULL , hzk_stat.st_size, PROT_READ, MAP_SHARED, fd_hzk16, 0);
if(hzkmem == (unsigned char *)-1)
{
printf("can't mmap for hzk16\n");
return -1;
}
// clear lcd screen
memset(fbmem, 0, screen_size);
lcd_put_ascii(var.xres/2, var.yres/2, 'A'); // display "A"
printf("chinese code: %02x %02x\n", str[0], str[1]); // print 0xXX of "中"
lcd_put_chinese(var.xres/2 + 8, var.yres/2,str); // display "中"
return 0;
}
===================================================================
測試:
1. 安裝 lcd driver
- 配置、修改内核支持把lcd.c编译进去
- 把驱动程序lcd.c拷贝到内核的drivers/video/目录下
- 修改drivers/video/Makefile-----------------------
#obj-$(CONFIG_FB_S3C2410) += s3c2410fb.o
obj-$(CONFIG _FB_S3C2410) += lcd.o------------------------ - make menuconfig选择上对lcd的配置
Device Drivers --->
Graphics support --->
<*> Support for frame buffer devices --->
<*> S3C2410 LCD framebuffer support
- make uImage
- 新kernel啟動
2. 編譯應用程式
$ arm-linux-gcc -o show_font show_font.c
./show_font
./show_font
3. 結果
console 顯示如下:
console 顯示如下:
/mnt/nfs # ./show_font
chinese code: d6 d0
JZ2440 開發版顯示如下:
參考資料:
- 嵌入式Linux應用開發完全手冊
- 韋東山視頻三期
- http://wenku.baidu.com/view/170f49d049649b6648d7478e.html (hzk16 介紹)
- http://wenku.baidu.com/view/0774d20c52ea551810a68768.html (hzk16範例)
No comments:
Post a Comment