点阵显示


title: 点阵显示
date: 2019/2/27 19:32:07
toc: true

点阵显示

linux内核中存在着ASCII的字符点阵文件,这里我们挑选8*16的,也就是8列16行来测试显示英文.

mark

汉字的话我们需要自己寻找点阵,这里选取了hzk16,也就是16*16的,这也是为什么我们英文选取8*16的原因,一个中文占据两个英文空间

具体关于汉字库的使用,参考这里

gbk转uft8

linux下默认都是utf-8编码的,终端的输入都是utf-8的,所以这里我们需要将输入的utf8转换为gbk才能使用hzk这个点阵

PC显示点阵

这里直接都是使用utf8编码的

#include <stdio.h>
#include <stdlib.h>

#include <iconv.h>  

#include <unistd.h>  
#include <fcntl.h>  
#include <string.h>  
#include <sys/stat.h>  
int code_convert(char *from_charset, char *to_charset, char *inbuf, size_t inlen,  
        char *outbuf, size_t outlen) {  
    iconv_t cd;  
    char **pin = &inbuf;  
    char **pout = &outbuf;  
  
    cd = iconv_open(to_charset, from_charset);  
    if (cd == 0)  
        return -1;  
    memset(outbuf, 0, outlen);  
    if (iconv(cd, pin, &inlen, pout, &outlen) == -1)  
        return -1;  
    iconv_close(cd);  
    *pout = '';  
  
    return 0;  
}  
  
int u2g(char *inbuf, size_t inlen, char *outbuf, size_t outlen) {  
    return code_convert("utf-8", "gb2312", inbuf, inlen, outbuf, outlen);  
}  
  
int g2u(char *inbuf, size_t inlen, char *outbuf, size_t outlen) {  
    return code_convert("gb2312", "utf-8", inbuf, inlen, outbuf, outlen);  
}



int main(void)
{
    FILE* fphzk = NULL;
    int i, j, k, offset;
    int flag;
    unsigned char buffer[32];
    unsigned char word[5];
	unsigned char utf[5];
    unsigned char key[8] = {
        0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01
    };
    fphzk = fopen("hzk16", "rb");
    if(fphzk == NULL){
        fprintf(stderr, "error hzk16
");
        return 1;
    }
    while(1){
        printf("输入要生成字模的汉字(多个):");
        for(;;){
            fgets((char*)utf, 4, stdin);//这里是读取3个字符,然后补上一个结束
			
			printf("raw char[] is :");
			for(i=0;i<10;i++)
				printf("%x ",(*(utf+i)&0xFF));
			
			u2g(utf, 3, word, sizeof(word)); 
			
			printf("
 change char[] is :");
			for(i=0;i<3;i++)
				printf("%x ",(*(word+i)&0xFF));
			
            if(*word == '
') 
                break;
            offset = (94*(unsigned int)(word[0]-0xa0-1)+(word[1]-0xa0-1))*32;
            fseek(fphzk, offset, SEEK_SET);
            fread(buffer, 1, 32, fphzk);
            for(k=0; k<16; k++){
                for(j=0; j<2; j++){
                    for(i=0; i<8; i++){
                        flag = buffer[k*2+j]&key[i];
                        printf("%s", flag?".":" ");
                    }
                }
                printf("
");
            }
            printf("uchar code key[32] = {");
            for(k=0; k<31; k++){
                printf("0x%02X,", buffer[k]);
            }
            printf("0x%02X};
", buffer[31]);
            printf("
");
        }
    }
    fclose(fphzk);
    fphzk = NULL;
    return 0;
}

mark

关键函数

LCD操作相关

  • ioctl(fd_fb, FBIOGET_VSCREENINFO, &var)获取到lcd可变信息:xy分辨率,像素位数
  • ioctl(fd_fb, FBIOGET_FSCREENINFO, &fix),获取固定信息,缓存地址,每行字节数

内存映射

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

文件大小查看

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

怎么查看函数的使用,直接man xxx,然后使用/ fun_name 即可

编译错误排查

find -name "fb.h"  #寻找头文件路径,在交叉工具链中搜索
open 函数中找不到 O_RDWR的宏定义,使用 man 2 open 找到对应头文件

详细代码

具体代码如下,没什么好分析的了

#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




// 这里是英文点阵

int fd_fb;
struct fb_var_screeninfo var;	/* Current var */
struct fb_fix_screeninfo fix;	/* Current fix */
int screen_size;
unsigned char *fbmem;
unsigned int line_width;
unsigned int pixel_width;

int fd_hzk16;
struct stat hzk_stat;
unsigned char *hzkmem;



/* color : 0x00RRGGBB */
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
", var.bits_per_pixel);
			break;
		}
	}
}

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++)
	{
		byte = dots[i];
		for (b = 7; b >= 0; b--)
		{
			if (byte & (1<<b))
			{
				/* show */
				lcd_put_pixel(x+7-b, y+i, 0xffffff); /* 白 */
			}
			else
			{
				/* hide */
				lcd_put_pixel(x+7-b, y+i, 0); /* 黑 */
			}
		}
	}
}

void lcd_put_chinese(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, 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 */
					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
");
		return -1;
	}

	if (ioctl(fd_fb, FBIOGET_VSCREENINFO, &var))
	{
		printf("can't get var
");
		return -1;
	}

	if (ioctl(fd_fb, FBIOGET_FSCREENINFO, &fix))
	{
		printf("can't get fix
");
		return -1;
	}

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

	fd_hzk16 = open("HZK16", O_RDONLY);
	if (fd_hzk16 < 0)
	{
		printf("can't open HZK16
");
		return -1;
	}
	if(fstat(fd_hzk16, &hzk_stat))
	{
		printf("can't get fstat
");
		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
");
		return -1;
	}

	/* 清屏: 全部设为黑色 */
	memset(fbmem, 0, screen_size);

	lcd_put_ascii(var.xres/2, var.yres/2, 'A');

	printf("chinese code: %02x %02x
", str[0], str[1]);
	lcd_put_chinese(var.xres/2 + 8,  var.yres/2, str);

	return 0;	
}

内核设置

内核需要加入对lcd的驱动支持,具体在

  │ Symbol: FB_S3C2410 [=y]                                                                                                    │
  │ Type  : tristate                                                                                                           │
  │ Prompt: S3C2410 LCD framebuffer support                                                                                    │
  │   Defined at drivers/video/Kconfig:2062                                                                                    │
  │   Depends on: HAS_IOMEM [=y] && FB [=y] && ARCH_S3C24XX [=y]                                                               │
  │   Location:                                                                                                                │
  │     -> Device Drivers                                                                                                      │
  │       -> Graphics support                                                                                                  │
  │         -> Support for frame buffer devices (FB [=y])                                                                      │
  │   Selects: FB_CFB_FILLRECT [=y] && FB_CFB_COPYAREA [=y] && FB_CFB_IMAGEBLIT [=y]  

后续

测试发现,从终端输入到串口,linux读取到的编码是utf-8的,参考这里写个程序输入字符,然后显示到液晶,这里还需要做一个utf8转gbk的函数,实际上这个函数在板子上不行,iconv_open返回成功,下面的转换就返回失败


#include <stdio.h>
#include <stdlib.h>

#include <iconv.h>  

#include <unistd.h>  
#include <fcntl.h>  
#include <string.h>  
#include <sys/stat.h>  
int code_convert(char *from_charset, char *to_charset, char *inbuf, size_t inlen,  
        char *outbuf, size_t outlen) {  
    iconv_t cd;  
    char **pin = &inbuf;  
    char **pout = &outbuf;  
  
    cd = iconv_open(to_charset, from_charset);  
    if (cd == 0)  
        return -1;  
    memset(outbuf, 0, outlen);  
    if (iconv(cd, pin, &inlen, pout, &outlen) == -1)    //这里失败了
        return -1;  
    iconv_close(cd);  
    *pout = '';  
  
    return 0;  
}  
  
int u2g(char *inbuf, size_t inlen, char *outbuf, size_t outlen) {  
    return code_convert("utf-8", "gb2312", inbuf, inlen, outbuf, outlen);  
}  
  
int g2u(char *inbuf, size_t inlen, char *outbuf, size_t outlen) {  
    return code_convert("gb2312", "utf-8", inbuf, inlen, outbuf, outlen);  
}



int main(void)
{
    FILE* fphzk = NULL;
    int i, j, k, offset;
    int flag;
    unsigned char buffer[32];
    unsigned char word[5];
	unsigned char utf[5];
    unsigned char key[8] = {
        0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01
    };
    fphzk = fopen("hzk16", "rb");
    if(fphzk == NULL){
        fprintf(stderr, "error hzk16
");
        return 1;
    }
    while(1){
        printf("输入要生成字模的汉字(多个):");
        for(;;){
            fgets((char*)utf, 4, stdin);//这里是读取3个字符,然后补上一个结束
			
			printf("raw char[] is :");
			for(i=0;i<10;i++)
				printf("%x ",(*(utf+i)&0xFF));
			
			u2g(utf, 3, word, sizeof(word)); 
			
			printf("
 change char[] is :");
			for(i=0;i<3;i++)
				printf("%x ",(*(word+i)&0xFF));
			
            if(*word == '
') 
                break;
            offset = (94*(unsigned int)(word[0]-0xa0-1)+(word[1]-0xa0-1))*32;
            fseek(fphzk, offset, SEEK_SET);
            fread(buffer, 1, 32, fphzk);
            for(k=0; k<16; k++){
                for(j=0; j<2; j++){
                    for(i=0; i<8; i++){
                        flag = buffer[k*2+j]&key[i];
                        printf("%s", flag?".":" ");
                    }
                }
                printf("
");
            }
            printf("uchar code key[32] = {");
            for(k=0; k<31; k++){
                printf("0x%02X,", buffer[k]);
            }
            printf("0x%02X};
", buffer[31]);
            printf("
");
        }
    }
    fclose(fphzk);
    fphzk = NULL;
    return 0;
}
原文地址:https://www.cnblogs.com/zongzi10010/p/10492453.html