Framebuffer应用编程

所学参考百问网

目录

1.1 简介

1.2 设置LCD操作

1.3 设置LCD坐标颜色

2. 字符的编码格式

2.1 ASCII

2.2 ANSI

2.3 UNICODE

2.3.1 UNICODE的编码实现

2.4 编码格式的修改

3. 涉及API

4. 示例代码

4.1 显示字符

4.2 显示中文

1.1 简介

Frame是帧的意思,buffer是缓冲的意思,这意味着Framebuffer就是一块内存,里面保存着一帧图像。Framebuffer 中保存着一帧图像的每一个像素颜色值。

1.2 设置LCD操作

1.驱动程序设置好LCD控制器:

根据LCD的参数设置LCD控制器的时序、信号极性;

根据LCD分辨率、BPP分配Framebuffer。

2.APP使用ioctl获得LCD分辨率、BPP

3.APP通过mmap映射Framebuffer,在Framebuffer中写入数据

1.3 设置LCD坐标颜色

假设需要设置LCD中坐标(x,y)处像素的颜色,首先要找到这个像素对应的内存,然后根据它的BPP值(每个像素用多少位表示颜色)设置颜色。假设fb_base是APP执行mmap后得到的Framebuffer地址(即帧缓冲区的基地址)

如图 5.2所示:

可以用以下公式算出(x,y)坐标处像素对应的Framebuffer地址:

(x,y)像素起始地址= fb_base + (xres * bpp / 8) * y + x * bpp / 8
fb_base:帧缓存的基地址
xres:屏幕水平分辨率,即屏幕宽度(以像素为单位)
bpp:每个像素的比特数,表示每个像素点占用的位数,例如:对于24位深度的颜色,bpp为24。
bpp/8:即该像素占用多少个字节

像素颜色的表示

它是用RGB三原色(红、绿、 蓝)来表示的,在不同的BPP格式中,用不同的位来分别表示R、G、B,如图 5.3 所示:

对于32BPP,一般只设置其中的低24位,高8位表示透明度,一般的LCD 都不支持。

对于24BPP,硬件上为了方便处理,在 Framebuffer 中也是用 32 位来表 示,效果跟32BPP是一样的。

对于 16BPP,常用的是 RGB565;很少的场合会用到 RGB555,这可以通过 ioctl 读取驱动程序中的RGB位偏移来确定使用哪一种格式。

相关结构体

struct fb_var_screeninfo 是 Linux 帧缓冲(framebuffer)设备中用于描述屏幕变量信息的一个结构体
以下为部分结构体参数的解释
struct fb_var_screeninfo {
    __u32 xres;                 // 水平分辨率(宽度)
    __u32 yres;                 // 垂直分辨率(高度)
    __u32 xres_virtual;         / * xres_virtual、yres_virtual定义虚拟屏幕的分辨率,它可能比实际屏幕分辨率大,
    __u32 yres_virtual;             用于滚动屏幕或实现其他特效。 */
    __u32 xoffset;              /* xoffset、yoffset定义虚拟屏幕到可见屏幕的偏移量,
    __u32 yoffset;                 用于滚动屏幕或选择屏幕上的显示区域。*/
    __u32 bits_per_pixel;       // 每个像素的颜色深度,即每个像素使用多少位来表示颜色
    __u32 grayscale;            // 表示屏幕是否使用灰度模式(0=彩色,1=灰度,>1时表示使用FOURCC编码的像素格式)。
    // 以下这四个结构体成员分别定义了红色、绿色、蓝色和透明度分量在帧缓冲内存中的位置和长度,仅当使用真彩色模式时有效。
    struct fb_bitfield red;     // 红色
    struct fb_bitfield green;   // 绿色
    struct fb_bitfield blue;    // 蓝色
    struct fb_bitfield transp;  // 透明度
    ... ...
    }

示例代码

#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>
#include <sys/ioctl.h>
#include <stdlib.h> 
​
static unsigned int line_width; // 水平分辨率
static unsigned int point_width; // 一个点所占像素
static int screen_size; //整个屏幕占的像素
int fd;
static unsigned char *fb_base;
struct fb_var_screeninfo info;
int i;
​
void lcd_put_pixel(int x, int y, unsigned int color)
{
    unsigned char *pen_8 = fb_base + y * line_width + x * point_width;
    unsigned short *pen_16;
    unsigned int *pen_32; 
​
    unsigned int red,blue,green;
    
    pen_16 = (unsigned short *)pen_8;
    pen_32 = (unsigned int *)pen_8;
    switch(info.bits_per_pixel)
    {
        case 8:
        {
            *pen_8 = color;
            break;
        }
        case 16:
        {
            // 565 red 5 blue 6 green 5
            /*
                示例:color = 0xff0000
                red = (0xff0000 >> 16) & 0xff = 0xff 
                green = (0xff0000 >> 8) & 0xff = 0x00
                blue = (0xff0000 >> 0) & 0xff = 0x00
            */
            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", info.bits_per_pixel);
            break;
        }
​
    }
​
}
​
int main(int argc, char * * argv)
{
    // 打开/dev/fb0设备节点 可读可写
    fd = open("/dev/fb0",O_RDWR);
    if(fd < 0){
        perror("open");
        exit(EXIT_FAILURE);
    }
​
    // FBIOGET_VSCREENINFO:获取帧缓冲区设备的可变参数信息 
    if(ioctl(fd,FBIOGET_VSCREENINFO,&info) < 0)
    {
        perror("ioctl");
        exit(EXIT_FAILURE);
    }
​
    // 分别算出行、点、整个屏幕的所占像素大小
    line_width = info.xres * info.bits_per_pixel / 8;
    point_width = info.bits_per_pixel / 8;
    screen_size = info.xres * info.yres * info.bits_per_pixel / 8;
    // 映射整个屏幕的大小 可读可写 共享 
    fb_base = (unsigned char *)mmap(NULL,screen_size,PROT_READ | PROT_WRITE,MAP_SHARED,fd,0);
    if(fb_base < (unsigned char *)0)
    {
        perror("mmap");
        exit(EXIT_FAILURE);
    }
​
    // 清屏
    // 0:灭 1:亮
    memset(fb_base,0xff,screen_size);
​
    // 设置500个像素点为蓝色
    for(i = 0; i < 500; i++)
        lcd_put_pixel(info.xres/2+i,info.yres/2,0x0000FF);
​
    // 释放资源
    munmap(fb_base,screen_size);
    close(fd);
​
    return 0;
}

2. 字符的编码格式

2.1 ASCII

是“American Standard Code for Information Interchange”的缩写,美国信息交换标准代码。

电脑毕竟是西方人发明的,他们常用字母就26个,区分大小写、加上标点符号也没超过127个,每个字符用一个字节来表示就足够了。一个字节的7位就 可以表示128个数值,在ASCII码中最高位永远是0。

2.2 ANSI

ASNI是ASCII的扩展,向下包含ASCII。对于ASCII字符仍以一个字节来表示,对于非ASCII字符则使用2字节来表示。并没有固定的ASNI编码,它跟 “本地化”(locale)密切相关。比如在中国大陆地区,ANSI的默认编码是GB2312; 在港澳台地区默认编码是BIG5。以数值“0xd0d6”为例,对于GB2312编码它 表示“中”;对于BIG5编码它表示“笢”。

2.3 UNICODE

在ANSI标准中,很多种文字都有自己的编码标准,汉字简体字有GB2312、 繁体字有 BIG5,这难免同一个数值对应不同字符。比如数值“0xd0d6”,对于 GB2312 编码它表示“中”;对于BIG5编码它表示“笢”。这造成了使用ANSI编码保存的文件,不适合跨地区交流。

UNICODE 编码就是解决这类问题:对于地球上任意一个字符,都给它一个唯一的数值。

UNICODE 仍然向下兼容ASCII,但是对于其他字符会有对应的数值,比如对 于“中”、“笢”,它们的数值分别是:0x4e2d、0x7b22

UNICODE 中的数值范围是0x0000至0x10FFFF,有 1,114,111即100多万 个数值,可以表示100多万个字符,足够地球人使用了。

2.3.1 UNICODE的编码实现

1.UCS-2 Little endian/UTF-16 LE

每个UNICODE 值用 3 字节来表示有点浪费,那只用2字节呢?它可以表示 2^16=65536 个字符,全世界常用的字符都可以表示了。

Little endian 表示小字节序,最低有效字节(LSB, Least Significant Byte)存储在最低的内存地址处,而最高有效字节(MSB, Most Significant Byte)则存储在最高的内存地址处。比如字符 “A中”在TXT文件中的数值如下,其中的“A”使用“0x41 0x00”两字节表示;“中”使用“0x2d 0x4e”两字节表示。文件开头的“0xff 0xfe”表示“UTF 16 LE”。

2.UCS-2 Big endian/UTF-16 BE

Big endian表示大字节序,最低有效字节(LSB, Least Significant Byte)存储在最高的内存地址处,而最高有效字节(MSB, Most Significant Byte)则存储在最低的内存地址处,比如字符“ab 中”在TXT文件中的数值如下,其中的“A”使用“0x00 0x41”两字节表示; “中”使用“0x4e 0x2d”两字节表示。文件开头的“0xfe 0xff”表示“UTF 16 BE”。

3.UTF8

在上面2种方法中,每一个UNICODE使用2字节来表示,这有3个缺点: 表示的字符数量有限、对于ASCII字符有空间浪费、如果文件中有某个字节丢失,这会使得后面所有字符都因为错位而无法显示。 使用UTF8可以解决上述所有问题。UTF8是变长的编码方法,有2种UTF8 格式的文件:带有头部、不带头部。

对于其中的ASCII字符,在UTF8文件中直接用其ASCII码来表示,比如上图中的0x41表示字符A、0x42表示字符B。上图中的3个字节“0xe4 0xb8 0xad”表示的数值是0x4e2d,对应“中”的UNICODE码。

对于非ASCII字符,使用变长的编码:每一个字节的高位都自带长度信息。 请看图 6.9:

上图中,0xe4的二进制是“11100100”,高位有3个1,表示从当前字节起有3字节参与表示UNICODE;

0xb8 的二进制是“10111000”,高位有1个1,表示从当前字节起有1字节参与表示UNICODE;

0xad 的二进制是“10101101”,高位有1个1,表示从当前字节起有1字节参与表示UNICODE;

除去高位的“1110”、“ 10”、“ 10”后,剩下的二进制数组合起来得到 “01001110001101”,它就是0x4e2d,即“中”的UNICODE值。 使用UTF8编码时,即使TXT文件中丢失了某些数据,也只会影响到当前字符的显示,后面的字符不受影响。

2.4 编码格式的修改

使用点阵字库时,中文字符的显示原理跟ASCII字符是一样的。要注意的地方在于中文的编码:在C源文件中它的编码方式是GB2312还是UTF-8?编译出 的可执行程序,其中的汉字编码方式是GB2312还是UTF-8?

注意:一般不会使用UTF-16的编码方式,在这种方式下ASCII字符也是用2字 节来表示,而其中一个字节是0,但是在C语言中0表示字符串的结束符,会引 起误会。

我们编写C程序时,可以使用ANSI编码,或是UTF-8编码;在编译程序时, 可以使用以下的选项告诉编译器:

-finput-charset=UTF-8  
-finput-charset=GB2312 

如果不指定“-finput-charset”,GCC就会默认C程序的编码方式为UTF-8,即使你是以ANSI格式保存,也会被当作UTF-8来对待。

对于编译出来的可执行程序,可以指定它里面的字符是以什么方式编码,可以使用以下的选项编译器:

-fexec-charset=GB2312 
-fexec-charset=UTF-8  

如果不指定“-fexec-charset”,GCC就会默认编译出的可执行程序中字符 的编码方式为UTF-8。

如果“-finput-charset”与“-fexec-charset”不一样,编译器会进行格式转换。

3. 涉及API

open函数

  • fstat函数通过文件描述符来获取文件的状态信息

    • int fstat(int fd, struct stat *buf);

    • int fd:已打开文件的文件描述符。

    • struct stat *buf:指向struct stat结构的指针,该结构用于存储获取到的文件状态信息。

    • 返回值:执行成功时返回0,失败时返回-1,并设置全局变量errno以指示错误原因。

  • 获取LCD分辨率、BPP

    • int ioctl(int fd,unsigned long request, ...);

    • int fd:文件描述符

    • unsigned long request:表示与驱动程序交互的命令

    • ...:可变参数,根据requset命令,设置驱动程序返回输出的数据

    • 返回值:成功返回文件描述符,失败返回-1

ioctl 的作用非常强大、灵活。不同的驱动程序内部会实现不同的 ioctl, APP 可以使用各种ioctl跟驱动程序交互:可以传数据给驱动程序,也可以从驱 动程序中读出数据。

  • 映射

    • void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);

    • void *addr:addr表示指定映射的內存起始地址,通常设为 NULL表示让系统自动选定 地址,并在成功映射后返回该地址;

    • size_t length:length表示将文件中多大的内容映射到内存中

    • int prot:prot 表示映射区域的保护方式

      • PROT_EXEC 映射区域可被执行

      • PROT_READ 映射区域可被读出

      • PROT_WRITE 映射区域可被写入

      • PROT_NONE 映射区域不能存取

    • int flags:表示影响映射区域的不同特性

      • MAP_SHARED 表示对映射区域写入的数据会复制回文件内,原来的文 件会改变。

      • MAP_PRIVATE 表示对映射区域的操作会产生一个映射文件的复制,对 此区域的任何修改都不会写回原来的文件内容中。

    • off_t offset:偏移量,一般填0

    • 返回值:若成功映射,将返回指向映射的区域的指针,失败将返回-1

  • 获取已打开文件的状态信息

    • int fstat(int fd, struct stat *buf);

    • fd:需要查询状态的文件的文件描述符。

    • buf:指向struct stat结构体的指针,用于存储查询到的文件状态信息。

    • 返回值:成功时返回0,失败时返回-1,并设置errno以指示错误。

    • struct stat结构体
      struct stat{
          dev_t st_dev:设备ID。
          ino_t st_ino:inode节点号。
          mode_t st_mode:文件类型和权限。
          nlink_t st_nlink:硬链接数。
          uid_t st_uid:所有者ID。
          gid_t st_gid:组ID。
          dev_t st_rdev:设备类型(如果为inode设备)。
          off_t st_size:文件大小(字节数)。
          blksize_t st_blksize:文件系统I/O块大小。
          blkcnt_t st_blocks:分配块数。
          time_t st_atime:最后访问时间。
          time_t st_mtime:最后修改时间。
          time_t st_ctime:最后状态改变时间。
      }

4. 示例代码

4.1 显示字符

#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>
#include <sys/ioctl.h>
​
#define FONTDATAMAX 4096
​
static const unsigned char fontdata_8x16[FONTDATAMAX] = {
​
    /* 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 */
    
    ... ...
}
struct fb_var_screeninfo info;
int fd;
unsigned char *size;
int screen_size;
unsigned int line_width;
unsigned int pixel_width;
​
void put_pixel(int x,int y,unsigned int color)
{
    unsigned char *pen_8 = size + y * line_width + x * pixel_width;
    unsigned short *pen_16;
    unsigned int *pen_32;
​
    pen_16 = (unsigned short *)pen_8;
    pen_32 = (unsigned int *)pen_8;
​
    unsigned int red,green,blue;
    switch(info.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("color err\n");
            break;
        }
    }
​
}
​
void show_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++) //遍历行
    {
        byte = dots[i]; // 将每一行存储在byte里
        for(b = 7; b >= 0; b--) // 位移的次数
        {
            if(byte & (1 << b)) //将1位移后与byte相与
            {
                put_pixel(x+7-b,y+i,0xffffff); // 1就显示为白色
                
            }else
            {
                put_pixel(x+7-b,y+i,0x000000); // 0就显示为黑色
            }
        }
    }
}
int main(int argc,char **argv)
{
    fd = open("/dev/fb0",O_RDWR);
    if(fd < 0)
    {   
        printf("open err\n");
        return -1;
    }
​
    if(ioctl(fd,FBIOGET_VSCREENINFO,&info))
​
    {
        printf("ioctl err\n");
        return -1;
    }
    line_width = info.xres * info.bits_per_pixel / 8;
    pixel_width = info.bits_per_pixel / 8;
    screen_size = info.xres * info.yres * info.bits_per_pixel / 8;
    size = (unsigned char *)mmap(NULL,screen_size,PROT_READ | PROT_WRITE,MAP_SHARED,fd,0);
    if(size == (unsigned char *)-1)
    {
        printf("mmap err\n");
        return -1;
    }
    // 将整个屏幕都显示为黑色
    memset(size,0,screen_size);
​
    show_ascii(info.xres/2,info.yres/2,'A'); //显示字符'A'
    munmap(size,screen_size);
    close(fd);
    
    return 0;
}

4.2 显示中文

HZK16文件:每个汉字使用32字节来描述

跟ASCII字库一样,每个字节中每一位用来表示一个像素,位值等于1时表示对 应像素被点亮,位值等于0时表示对应像素被熄灭。

HZK16 中是以GB2312编码值来查找点阵的,以“中”字为例,它的编码值 是“ 0xd6 0xd0”,其中的0xd6表示“区码”,表示在哪一个区:第“0xd6 - 0xa1” 区;其中的0xd0表示“位码”,表示它是这个区里的哪一个字符:第“0xd0 - 0xa1”个。每一个区有94个汉字。区位码从0xa1而不是从0开始,是为了兼容ASCII码。

所以,我们要显示的“中”字,它的GB2312编码是d6d0,它是HZK16里 第“(0xd6-0xa1)*94+(0xd0-0xa1)”个字符。

#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>
#include <sys/ioctl.h>
​
#define FONTDATAMAX 4096
​
static const unsigned char fontdata_8x16[FONTDATAMAX] = {
​
    /* 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 */
    
    ... ...
}
struct fb_var_screeninfo info;
int fd;
unsigned char *size;
int screen_size;
unsigned int line_width;
unsigned int pixel_width;
​
int fd_hzk16;
struct stat hzk_stat;
unsigned char *hzkmem;
​
void put_pixel(int x,int y,unsigned int color)
{
    unsigned char *pen_8 = size + y * line_width + x * pixel_width;
    unsigned short *pen_16;
    unsigned int *pen_32;
​
    pen_16 = (unsigned short *)pen_8;
    pen_32 = (unsigned int *)pen_8;
​
    unsigned int red,green,blue;
    switch(info.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("color err\n");
            break;
        }
    }
​
}
​
void show_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++) //遍历行
    {
        byte = dots[i]; // 将每一行存储在byte里
        for(b = 7; b >= 0; b--) // 位移的次数
        {
            if(byte & (1 << b)) //将1位移后与byte相与
            {
                put_pixel(x+7-b,y+i,0xffffff); // 1就显示为白色
                
            }else
            {
                put_pixel(x+7-b,y+i,0x000000); // 0就显示为黑色
            }
​
        }
    }
​
}
​
void show_chinese(int x,int y,unsigned char *str)
{   
    // 注意:区码和位码都是从0XA1开始的
    unsigned int area  = str[0] - 0xA1; // 区码
    unsigned int where = str[1] - 0xA1; // 位码
    // 获得起始映射地址 乘以32是因为在HZK16中每个字符占32字节
    // 每个区有94个汉字
    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++) //有两个字节
        {
            byte = dots[i*2 + j]; 
            for (b = 7; b >=0; b--) //位移的次数
            {
                if (byte & (1<<b))
                {
                    /* show */
                    put_pixel(x+j*8+7-b, y+i, 0xffffff); /* 白 */
                }
                else
                {
                    /* hide */
                    put_pixel(x+j*8+7-b, y+i, 0); /* 黑 */
                }   
            }
        }
}
int main(int argc,char **argv)
{
    unsigned char str[] = "中";
​
​
    fd = open("/dev/fb0",O_RDWR);
    if(fd < 0)
    {   
        printf("open err\n");
        return -1;
    }
​
    if(ioctl(fd,FBIOGET_VSCREENINFO,&info))
​
    {
        printf("ioctl err\n");
        return -1;
    }
    line_width = info.xres * info.bits_per_pixel / 8;
    pixel_width = info.bits_per_pixel / 8;
    screen_size = info.xres * info.yres * info.bits_per_pixel / 8;
    size = (unsigned char *)mmap(NULL,screen_size,PROT_READ | PROT_WRITE,MAP_SHARED,fd,0);
    if(size == (unsigned char *)-1)
    {
        printf("mmap err\n");
        return -1;
    }
​
    // 已只读方式打开"HZK16"文件
    fd_hzk16 = open("HZK16",O_RDONLY);
    if(fd_hzk16 < 0)
​
    {
        printf("open err\n");
        return -1;
    }
​
​
    // 获取文件状态并存储到hzk_stat结构体里
    if(fstat(fd_hzk16,&hzk_stat))
    {
        printf("fstat err\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("mmap err\n");
        return -1;
    }
    
    // 将整个屏幕都显示为黑色
    memset(size,0,screen_size);
​
    show_ascii(info.xres/2,info.yres/2,'A'); //显示字符'A'
​
    printf("chinese code: %02x %02x\n", str[0], str[1]);
    show_chinese(info.xres/2 + 8,  info.yres/2, str);
    munmap(size,screen_size);
    close(fd);
    
    return 0;
}
交叉编译需要指定编码格式
arm-buildroot-linux-gnueabihf-gcc -fexec-charset=GB2312 -o chinese_show chinese_show.c

  • 11
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值