在開發板上顯示字符和中文


我們在寫lcd驅動程序時,測試時可以在lcd上顯示信息,那么他怎么能顯示出信息呢,內核里有字符點陣編碼,我們在內核里打開字符編碼,可以看到很多字符點陣也稱為字體。下面我們來自已寫一個應用程序在lcd顯示屏上顯示字母以及顯示中文。字符編碼 在前面有一個隨筆里有寫,對於英文字母,用ascii碼即可,那么如果我們要顯示中文的話應該是要用到漢字庫編碼即GBK編碼表,下面來寫一段程序來試驗和理解如何在開發板的lcd上顯示。

一、首先我們要獲得lcd的信息,例:固定信息和可變信息等 這些我們都需要知道可以操作lcd。

二、得到lcd的信息后,把 framebuffer進行內存映射,然后就可以直接操作framebuffer來顯示了。

三、然后就可以根據ascii點陣一個一個的把點顯示在framebuffer中即可實現了,

四、顯示中文不同的是,需要找到一個漢字庫文件,然后打開這個文件獲得統計信息

五、得到文件統信息后,同樣可以把這個字庫文件進行內存映射,然后直接操作這個內存進行訪問

六、和上面第三步一樣,寫出顯示中文的函數,進行描點即可。

 

注意:顯示的位置坐標要經過計算,要小心算,不然很容易出錯和亂碼。漢字庫的文件解壓后要放到根目錄下,否則在打開漢字庫文件時位置要改為你存放的位置

下面列出列子,實測在板子上可以運行的 ascii 字體頭文件在內核里有,復制過來即可 漢字庫可以去網上下載

#include <sys/mman.h>
#include "ascii.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <linux/fb.h>
#include <fcntl.h>
#include <string.h>




static int fd_fb;
static struct fb_var_screeninfo var;    /* 定義一個可變信息結構體 用於保存獲得的可變信息 */
static struct fb_fix_screeninfo fix;    /* 定義一個固定信息結構體 用於保存獲得的固定信息 */
static int screen_size;                /* 定義一個變量 表示 framebuffer 進行內存映射 */
static unsigned char *fbmem;            /* 定認一個指針變量 用於保存內存映射后的地址 */

static int fd_hzk;
static struct stat hzk_stat;            /* 定義一個結構體用於保存統計信息 */
static unsigned char *hzkmem;            /* 定義一個指針變量 用於保存央存映射的地址 */

static unsigned int line_width;
static unsigned int pixel_whdth;

static unsigned char *str = "";

/* 描點函數 根據 x,y,值 確定對應framebuffer的位置
 * 然后依次的在對應的framebuffer上寫入顏色值即可
 */
void lcd_put_pixel(int x, int y, unsigned int color)
{
    unsigned char *pen = fbmem + y*line_width + x*pixel_whdth;

    *pen = color;
}

/* 顯示ascii字符 那么如何顯示呢?
 * 1:根據字符獲得字體的點陣
 * 2:根據x,y 的坐標值把點陣的數據放入framebuffer 即可顯示出來
 */
void lcd_put_ascii(int x, int y, unsigned char c)
{
    /* 得到字符點陣在數組中的起始位置 */
    unsigned char *dots = (unsigned char *)&fontdata_8x16[c*16];
    int i,j;
    unsigned char byte;

    for (i = 0;i < 16;i ++)
    {
        /* 取出一個字節 */
        byte = dots[i];
        for (j = 7;j >= 0;j --)
        {
            if (byte & (1 << j))
            {
                /* 傳入參數的值是lcd要顯示的起點坐標 這里每個點的坐標每描一個點要移動一次 */
                lcd_put_pixel(x + 7 - j, y + i, 0xffffff);    /* 0xffffff 表示白色 */
            }
            else
            {
                /* 傳入參數的值是lcd要顯示的起點坐標 這里每個點的坐標每描一個點要移動一次 */
                lcd_put_pixel(x + 7 - j, y + i, 0);        /* 0 表示黑色 */
            }
        }
    }
}

/* 顯示中文 如何顯示呢?
 * 1: 先得到漢字庫的文件 然后可以像打開framebuffe一樣打開這個文件
 * 2: 打開后就可以去讀了,我們也可以把這個文件當成內存一樣用 即映射一下
 * 3: 然后就可以去里面得到字體點陣數據了,接着和顯示字符一樣描點即可
 * 把文件當成內存去映射先要得到文件大小 可以用 fstat 這個函數來獲得大小
 * 如何使用這個函數 可以在服務器上輸入 man fstat 得到使用說明
 * 漢字庫的使用方法可以去"度娘"去找,基本上就是下面幾個注意的地方
 * 1: GBK編碼用四個字節表示一個中文 第一個字節表示區碼 第二個字節表示位碼
 * 2: 為了兼容ascii碼 編碼從a1 開始 例:"中"字 值是 D6 D0 D6=區碼 D0=位碼
 * 3: 所以編碼的值是 區碼+A1 位碼+A1
 */
void lcd_put_chinses(int x, int y, unsigned char *str)
{
    unsigned int area   = str[0] - 0xa1;
    unsigned int where  = str[1] - 0xa1;
    unsigned char *dots = hzkmem + (area * 94 + where) * 32; 
    unsigned char byte;
    int i,j,k;

    for (i = 0;i < 16;i ++)
    {
        for (j = 0;j < 2;j ++)
        {
            byte = dots[i * 2 + j];
            for (k = 7;k >=0;k --)
            {
                if (byte & (1 << k))
                {
                    /* 傳入參數的值是lcd要顯示的起點坐標 這里每個點的坐標每描一個點要移動一次 */
                    lcd_put_pixel(x + j * 8 + 7 - k, y + i, 0xffffff);    /* 0xffffff 表示白色 */
                }
                else
                {
                    /* 傳入參數的值是lcd要顯示的起點坐標 這里每個點的坐標每描一個點要移動一次 */
                    lcd_put_pixel(x + j * 8 + 7 - k, y + i, 0);        /* 0 表示黑色 */
                }                
            }
        }
    }
    
}

int main(int argc, char **agrv)
{
    
    fd_fb = open("/dev/fb0", O_RDWR);    /* 打開lcd設備 可讀可寫 */
    if (fd_fb < 0)
    {
        printf("cnt't open /dev/fb0 !\n");
        return -1;
    }

    if (ioctl(fd_fb, FBIOGET_VSCREENINFO, &var))        /* 獲得可變信息 */
    {
        /* 正常獲得信息的話 ioctl 會返回0 如果返回值不為0時表示出錯 */
        printf("can't get var! \n");
        return -1;
    }
    if (ioctl(fd_fb,FBIOGET_FSCREENINFO, &fix))        /* 獲得固定信息 */
    {
        /* 正常獲得信息的話 ioctl 會返回0 如果返回值不為0時表示出錯 */
        printf("can't get fix! \n ");
        return -1;
    }
    /* 計算 framebuffer 的大小 用於內存映射單位字節 用x分辯率*y分辯率*每個像素得到總大小這時的單位是bit 除以8 轉換成字節 */
    screen_size = var.xres * var.yres * var.bits_per_pixel / 8;
    /* 內存映射 mmap 怎么用呢,可以在服務器上輸入man mmap 得到說明 
     * void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);
     * 參數說明:void *addr     設置為0 讓內核自動給我們分配地址
     *         :size_t length  映射內存大小
     *         :int prot       屬性為可讀可寫
     *         :int flags      共享 其它進程都可見
     *         :int fd           framebuffer
     *         :off_t offset   偏移值
     */
    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;
    }

    line_width  = var.xres * var.bits_per_pixel / 8;
    pixel_whdth = var.bits_per_pixel / 8;
    
    /* 打開當前目錄下的 HZK16 文件 屬性設為只讀 */
    fd_hzk = open("HZK16", O_RDONLY);
    if (fd_hzk < 0)
    {
        printf("can't open HZK16\n");
        return -1;
    }
    /* 得到這個件的統計信息當然也包含了大小 */
    if (fstat(fd_hzk, &hzk_stat))
    {
        printf("can't get hzk_stat! \n ");
        return -1;
    }
    /* 內存映射 mmap 怎么用呢,可以在服務器上輸入man mmap 得到說明 
     * void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);
     * 參數說明:void *addr     設置為0 讓內核自動給我們分配地址
     *         :size_t length  映射內存大小
     *         :int prot       屬性為可讀可寫
     *         :int flags      共享 其它進程都可見
     *         :int fd           文件
     *         :off_t offset   偏移值
     */
    hzkmem = (unsigned char *)mmap(NULL, hzk_stat.st_size, PROT_READ, MAP_SHARED, fd_hzk, 0);
    if (hzkmem == (unsigned char *)-1)
    {
        printf("can't mmap!\n");
        return -1;
    }    

    /* 這里先清屏 全部顯黑色 */
    memset(fbmem, 0, screen_size);

    /* 在lcd上顯示ascii字符 即然是顯示,肯定要有位置 在那顯示先定在中間 */
    lcd_put_ascii(var.xres / 2, var.yres / 2, 'F');
    /* 在lcd上顯示中文 即然是顯示,肯定要有位置 在那顯示 */
    lcd_put_chinses(var.xres / 2 + 8, var.yres / 2, str);

    return 0;
}
View Code

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM