第六章:文件显示

6.3 中文字符的点阵显示

修改 lcd_put_chinese 函数,可以指定字符颜色。
实现 lcd_put_str 函数, 可以输出混合的中英文字符,比如“中国  china”,支持自动换行。
效果:读取指定文件中英文数据到lcd显示

image

文件:show_chinses.c

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

extern const unsigned char fontdata_8x16[];  // fontdata_8x16 单独在 fontdata.c

static int fd_fb                    = 0;
static unsigned char *fb_base       = NULL;
static struct fb_var_screeninfo var = {0};
static int screen_size              = 0;
static int line_width               = 0;
static int pixel_width              = 0;

static int fd_hzk16;
static struct stat hzk_stat  = {0};
static unsigned char *hzkmem = {0};

void lcd_put_pixel(int x, int y, unsigned int color)
{
    unsigned char *pen_8   = fb_base + y * line_width + x * pixel_width;
    unsigned short *pen_16 = (unsigned short*)(pen_8);
    unsigned int *pen_32   = (unsigned int*)(pen_8);

    unsigned int red   = 0;
    unsigned int green = 0;
    unsigned int blue  = 0;

    switch (var.bits_per_pixel)
    {
        case 8:
            *pen_8 = color;
            break;

        case 16:
            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 open %dbpp\n", var.bits_per_pixel);
            break;
    }
}

void lcd_put_ascii(int x, int y, char c, unsigned int color)
{
    unsigned char *dots = (unsigned char*)(&fontdata_8x16[c * 16]);
    int i = 0;
    int b = 0;

    for (i=0; i<16; ++i)
    {
        for (b=7; b>=0; --b)
        {
            if (dots[i] & (1 << b))
                lcd_put_pixel(x+7-b, y+i, color);
            else
                lcd_put_pixel(x+7-b, y+i, 0xffffff);
        }
    }
}

void lcd_put_ascii_str(int x, int y, const unsigned char *str, unsigned int color)
{
    unsigned int index = 0;

    while(*str)
    {
        if (*str == '\r' || *str == '\n')
        {
            y += 16;
            index = 0;
        }
        else
        {
            lcd_put_ascii(x + index, y, *str, color);
            index += 8;
        }

        ++str;
    }
}

void lcd_put_chinese(int x, int y, const unsigned char *str, unsigned int color)
{
    unsigned int area   = str[0] - 0xa1;
    unsigned int where  = str[1] - 0xa1;
    unsigned char *dots = hzkmem + (area * 94 + where) * 32;
    unsigned char byte  = 0;

    int i = 0;
    int j = 0; 
    int b = 0;

    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))
                    lcd_put_pixel(x+j*8+7-b, y+i, color);
                else
                    lcd_put_pixel(x+j*8+7-b, y+i, 0xffffff);
            }
        }
    }
}

void lcd_put_str(int x, int y, const unsigned char*str, unsigned int color)
{
    unsigned int index = 0;

    while (*str)
    {
        if (*str <= 0xa1)
        {
            if (*str == '\r' || *str == '\n')
            {
                y += 16;
                index = 0;
            }
            else
            {
                lcd_put_ascii(x + index, y, *str, color);
                index += 8;
            }
            str++;
        }
        else
        {
            lcd_put_chinese(x + index, y, str, color);
            index += 16;
            str+=2;
        }
    }
}

int test_show(const unsigned char *path)
{
    int fd_src = 0;
    unsigned char *srcmem = NULL;
    struct stat src_stat  = {0};

    fd_src = open(path, O_RDONLY);
    if (fd_src < 0)
    {
        printf("can't open %s\n", path);
        return -1;    
    }

    if(fstat(fd_src, &src_stat))
    {
        printf("can't get src_stat\n");
        return -1;
    }

    srcmem = (unsigned char*)mmap(NULL, src_stat.st_size, PROT_READ, MAP_SHARED, fd_src, 0);
    if (srcmem == (void*)-1)
    {
        printf("can't mmap for srcmem\n");
        return -1;
    }

    lcd_put_str(10, 10, srcmem, 0x11ee88);

    munmap(srcmem, src_stat.st_size);
    close(fd_src);
    
}

int main(int argc, char **argv)
{
    int i = 0;

    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 == (void*)-1)
    {
        printf("can't mmap for hzkmem\n");
        return -1;
    }

    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 fd_fb var\n");
        return -1;
    }
    
    screen_size = var.xres * var.yres * var.bits_per_pixel / 8;
    pixel_width = var.bits_per_pixel / 8;
    line_width = var.xres * var.bits_per_pixel / 8;

    fb_base = mmap(NULL, screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);
    if (fb_base == (void*)-1)
    {
        printf("cant mmap for fb_base\n");
        return -1;
    }

    memset(fb_base, 0xff, screen_size);

    //====================================================

    if (argc == 1)
    {
        // lcd_put_ascii(100, 100, 'A', 0);
        // lcd_put_ascii_str(100, 100, "Hello word\nHow are you", 0x567894);
        // lcd_put_chinese(200, 200, "中", 0x123456);
        lcd_put_str(100, 100, "A中A\nhahah", 0x11ee88);
    }
    else
    {
        test_show(argv[1]) ;    
    }

    //====================================================

    munmap(fb_base, screen_size);
    munmap(hzkmem, hzk_stat.st_size);

    close(fd_fb);
    close(fd_hzk16);

    return 0;
}

编译运行:

ubutun 编译        -> arm-linux-gnueabihf-gcc -fexec-charset=GB2312 fontdata.c show_chinese.c 
ubutun 拷贝文件    -> cp ./a.out ~/nfs_rootfs/
                  -> cp ./source.txt ~/nfs_rootfs/ 
                  -> cp ./HZK16 ~/nfs_rootfs/
                  
开发板执行         -> ./a.out source.txt

文件:source.txt [请以GB2312保存]

If I could,I surely would. 
如果可以,我绝对愿意!

May there be enough clouds in your life to make a beautiful sunset.
愿你的生命中有足够的云翳,来造成一个美丽的黄昏。

The worst way to miss someone is to be sitting right beside them knowing you can’t have them.
失去某人,最糟糕的莫过于,他近在身旁,却犹如远在天边。

You must always have faith in who you are!
相信自己 坚持自己!

The longest day has an end.
最难过的日子也有尽头。

Dont’t cry because it is over, smile because it happened.
不要因为结束而哭泣.微笑吧,为你的曾经拥有。

Happineis good health and a bad memory.
幸福是良好的健康加上糟糕的记性。

第七章:输入系统应用编程

7.3 不使用库的应用程序实例

使用 select 函数实现LCD输入信息获取
#include <stdio.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <linux/input.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/select.h>

int main(int argc, char **argv)
{
    int fd = 0;
    int len = 0;
    int i = 0;
    int ret = 0;
    struct input_id id = {0};
    struct input_event event = {0};    
    unsigned char byte = 0;
    unsigned char bit = 0;
    unsigned int evbit[2] = {0};
    int nfds;
    fd_set readfds;
    struct timeval tv;
    
    const char *ev_names[] = {
        "EV_SYN ",
        "EV_KEY ",
        "EV_REL ",
        "EV_ABS ",
        "EV_MSC ",
        "EV_SW    ",
        "NULL ",
        "NULL ",
        "NULL ",
        "NULL ",
        "NULL ",
        "NULL ",
        "NULL ",
        "NULL ",
        "NULL ",
        "NULL ",
        "NULL ",
        "EV_LED ",
        "EV_SND ",
        "NULL ",
        "EV_REP ",
        "EV_FF    ",
        "EV_PWR ",
    };

    if (argc <2)
    {
        printf("Usage: %s <dev>\n", argv[0]);
        return -1;
    }

    fd = open(argv[1], O_RDWR | O_NONBLOCK);
    if (fd < 0)
    {
        printf("can not open %s\n", argv[1]);
        return -1;
    }
    
    if (!ioctl(fd, EVIOCGID, &id))    
    {
        printf("bustype = 0x%x\n", id.bustype);
        printf("vendor  = 0x%x\n", id.vendor);
        printf("product = 0x%x\n", id.product);
        printf("version = 0x%x\n", id.version);
    }

    len = ioctl(fd, EVIOCGBIT(0, sizeof(evbit)), &evbit);    
    if (len > 0 && len <= sizeof(evbit))
    {
        printf("support ev type: ");
        for (i=0; i<len; ++i)
        {
            byte = ((unsigned char*)evbit)[i];
            for (bit=0; bit<8; ++bit)
            {
                if (byte & (1 << bit))
                    printf("%s ", ev_names[i * 8 + bit]);    // 这里的下标和 ev_names 填充 "NULL" 一起理解
            }
        }
        printf("\n");
    }

    while (1)
    {
        FD_ZERO(&readfds);
        FD_SET(fd, &readfds);
        tv.tv_sec  = 5;
         tv.tv_usec = 0;
        nfds = fd + 1;
        ret = select(nfds, &readfds, NULL, NULL, &tv);
        if (ret > 0)
        {
            if (FD_ISSET(fd, &readfds))
                while (read(fd, &event, sizeof(event)) == sizeof(event))
                    printf("get event: type = 0x%x, code = 0x%x, value = 0x%x\n", event.type, event.code, event.value);
        }
        else if (ret == 0)
        {
            printf("time out\n");
        }
        else
        {
            printf("select err\n");
        }
        
    }

    close(fd);

    return 0;
}

TianSong
737 声望139 粉丝

阿里山神木的种子在3000年前已经埋下,今天不过是看到当年注定的结果,为了未来的自己,今天就埋下一颗好种子吧