数码相框

声明,文章的内容基本上来自于韦东山老师的F:\010_韦东山Linux_第3期视频_项目实战(适用任意Linux板,111节,6节免费,已完结)\3期视频(含相应的文档与源码)\项目1_文件浏览器_数码相框(33节, 2节免费)\视频,若有侵权请联系作者,我会删除

  1. 数码相框框架:
    socket: 在数码相框中,socket的作用就是把输入进程的事件发送到显示进程。显示的部分十分复杂,只写一个程序,程序里面穿件多个线程,
    一个线程是是专门用来接收的
    总结:
    输入进程:
    1. 主控线程,得到上报的事件,用socket发到显示进程
    2. ts线程,使用tslib读取触摸屏,封装事件,上报
    3. 按键线程,读按键,封装事件,上报
    显示进程:
    1. socket线程,接收数据
    2. 放大线程: 准备好当前图片的放大数据
    3. 缩小线程: 准备好当前图片的缩小数据
    4. 上一幅线程: 准给好上一幅图片
    5. 下一幅线程: 准备好下一幅图片
    6. 当前图片线程: 准备好当前图片
    7. 主控,根据socket线程得到的事件,准备显示哪一个图片
    驱动: 分配五块内存,DMA操作,mmap。其他的驱动程序以前已经写出来了,就不写了。

    为什么使用线程,进程: 想把这些模块独立出来,所以给他们写一个单独的进程。显示进程里面有七个模块,为什么把他们独立出来称之为线程,
    因为从socket得到的数据,这些数据可能放在全局变量里面,同一个进程里面的这些线程可以使用这些全局变量,线程的优点是
    他们可以共享这些资源。
    总结: 使用进程的概念是既可以保持模块独立,使用线程可以共享数据
    使用mmp的作用,是为了让应用程序、线程直接操作内存。

  2. 显示文字
    2.1 文字编码方式
    2.2 英文字母、汉子的点阵显示
    2.3 使用freetype显示任意大小的文字
    2.4 编写一个通用的makefile

    2.1 文字编码方式(字符编码 charset)
    ASCII : 一个字节表示字母
    A 0X41
    a 0X61
    GBK :两个字节表示汉字
    中 D6D0
    BIG5 : 港澳台繁体字表示方法
    繁体民(打不出来,就是竹节头民) D6D0
    对于不同的字符编码,同一个数字解析的字符是不一样的,比如台湾人用BIG字符编码所写的文章,拿到大陆来用GBK来解析就会出现了
    乱码,这就是因为不同的字符编码解析同一个数字出现的结果是不一样的。

    基于上面的情况,全世界弄出一个unicode编码,同样是用数字表示一个字符。目前unicode编码表的容量是0x0000 至0x10FFFF,
    这个编码表实质上只是数字和字符之间的对应关系而已。但是unicode只是规定了字符的二进制代码,但是并没有给出这些字符的
    存储方式,那么怎么表示存储呢?
    最简单的方式是用三个字节表示一个字符,因为unicode的容量已经达到了三个字节了,但是这样会产生很大的浪费,比如英文字母根本
    不需要三个字节来表示。
    所以说这种方式存在着巨大的缺陷,所以就出现了其他的几种方法表示unicode:
    UTF-8
    UTF-16LE
    UTF-16BE
    ......
    分辨UTF-16LE和UTF-16BE的方式是根据前面两个字母:FF FE  //  FE FF
    UTF-16LE的高字节在后面: 61 00 62 00 63 00
    UTF-16BE的高字节在前面:00 61 00 62 00 63
    UTF-8的表示方法: EF BB BF 61 62 63
    
    运用比较多的是UTF-8,这种存储方式是一种变长存储方式。
    http://www.ruanyifeng.com/blog/2007/10/ascii_unicode_and_utf-8.html   //字符编码笔记:ASCII,Unicode 和 UTF-8  阮一峰
    UTF-8 的编码规则很简单,只有二条:
    1)对于单字节的符号,字节的第一位设为0,后面7位为这个符号的 Unicode 码。因此对于英语字母,UTF-8 编码和 ASCII 码是相同的。
    2)对于n字节的符号(n > 1),第一个字节的前n位都设为1,第n + 1位设为0,后面字节的前两位一律设为10。剩下的没有提及的二进
       制位,全部为这个符号的 Unicode 码。
       
       Unicode符号范围     |        UTF-8编码方式
    	(十六进制)        |              (二进制)
    	----------------------+---------------------------------------------
    	0000 0000-0000 007F | 0xxxxxxx
    	0000 0080-0000 07FF | 110xxxxx 10xxxxxx
    	0000 0800-0000 FFFF | 1110xxxx 10xxxxxx 10xxxxxx
    	0001 0000-0010 FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
    	
    UTF-8的优点: 1. 表示英文字母的时候和ASCII是完全一样的,可以做到不浪费。
    			 2. 容错性: 位丢失的时候仅仅导致以后面若干个乱码(一个编码码位),不会导致整个文件乱码。
    			 
    数字   =====    代表什么    ====    显示为什么
    									字体文件: 编码表
    											  字体数据
    开发板上把数字发送到PC串口工具上面,串口工具根据这个数值去字体文件中找到对应的符号,然后将其用点阵显示出来。	
    通过字体文件中的编码表找到对应的字符。例如选择"宋体"字符文件,里面就出现GB2312编码表
    
    源码以不同的编码方式编写,会导致执行结果不一样
    man gcc
    /charset
    解决方式: 编译程序时指定字符集
    -finput-charset=charset  表示源码的编码方式,要是不写的话默认UTF-8来解析,但是gcc容易被骗,需要指定。
    -fexec-charset=charset   表示可执行程序的编码方式,要是不写的话默认UTF-8来解析
    gcc -o ansi ansi.c
    gcc -finput-charset=GBK -fexec-charset=UTF-8 -o utf ansi.c
    因为源码为ansi编码的时候,默认是国标,所以执行程序的时候转换为UTF-8
    但是要是保存的时候用UTF-8来保存的话,就不会有上面的问题了。
    

    2.2 英文字母、汉子的点阵显示
    比如字母A,在f:\linux-2.6.22.6\drivers\video\console\Font_8x16.c中搜索0x41:
    /* 65 0x41 ‘A’ /
    0x00, /
    00000000 /
    0x00, /
    00000000 /
    0x10, /
    00010000 /
    0x38, /
    00111000 /
    0x6c, /
    01101100 /
    0xc6, /
    11000110 /
    0xc6, /
    11000110 /
    0xfe, /
    11111110 /
    0xc6, /
    11000110 /
    0xc6, /
    11000110 /
    0xc6, /
    11000110 /
    0xc6, /
    11000110 /
    0x00, /
    00000000 /
    0x00, /
    00000000 /
    0x00, /
    00000000 /
    0x00, /
    00000000 */

下面是程序: 程序有点问题,以后修改:
#include <sys/mman.h>
#include “stdio.h”

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

#include <linux/font.h>

#include <linux/fb.h>

#include <fcntl.h>

#define FONTDATAMAX 4096

#define DBG_PRINTK printf

static const unsigned char fontdata_8x16[FONTDATAMAX] = {…};
static struct fb_var_screeninfo var;
static struct fb_fix_screeninfo fix;
static int fd_fb;
static int screen_size;
static unsigned char *fb_mem;
static unsigned char str[] = “中”;
static int fd_hzk16;
static struct stat *hzk_stat;
static unsigned char *hzk_mem;
static unsigned line_width;
static unsigned pixel_width;

static void lcd_put_pixel(int x, int y, unsigned int color){
unsigned char *pen_8 = fb_mem + y * line_width + x * pixel_width;
unsigned short *pen_16;
unsigned int pen_32;
unsigned int red, green, blue;/
改为int是担心移位的时候可能会出现一些问题 */

pen_16 = (unsigned short *)pen_8;
pen_32 = (unsigned int *)pen_8;

/* color : 0x00RRGGBB */
switch(var.bits_per_pixel){    /* show_font.c:4661: error: stray '\229' in program,这个是因为之前"{"前面多了个空格 */
	case 8:
	{
		/* 8位的时候需要用到调色板,产生的颜色代表调色板里面的索引值 */
		*pen_8 = color;
		break;
	}

	case 16:
	{
		red = (color >> 16) & 0xff;
		green = (color >> 8) & 0xff;
		blue = color & 0xff;
		color = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3);
		*pen_16 = color;
		break;
	}
	case 32:
	{
		*pen_32 = color;
		break;
	}
	default:
		{
			printf("can't support %dbpp", var.bits_per_pixel);
			break;
		}
	}

}

static void lcd_put_ascii(int x, int y, unsigned char c){
/* 这里注意一下 */
unsigned char dots = (unsigned char )&fontdata_8x16[c16];
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);/
黑色 */
}

}

}
static 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 = hzk_mem + (area * 94 + where) * 32;
unsigned char byte;
int i, j, b;
for(i = 0; i < 16; i++)
for(j = 0; j < 2; j++)
{
//subscripted value is neither array nor pointer,之前的dots是整数,既不是指针, 也不是数组。
byte = dots[i * 2 + j];
for(b = 7; i <= 0; j–)
{
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){

fd_fb = open("/dev/fb0", O_RDWR);
if(fd_fb < 0)
{
	printf("can't open /dev/fb0\n");
	return -1;
}

/* 如果返回值不是0的情况下说明获得不成功,从这个可变信息就可以知道分辨率等参数,可以进var去看看 */
if(ioctl(fd_fb, FBIOGET_VSCREENINFO, &var))
/* fb_info */
{
	printf("can't get var \n");
	return -1;
}

if(ioctl(fd_fb, FBIOGET_VSCREENINFO, &fix))
/* fb_info */
{
	printf("can't get fix \n");
	return -1;
}

/* invalid suffix "_RDWR" on integer constant,这个是未定义,可以man 2 open看看需要什么头文件 */
/*
man指令后面的参数
1、Standard commands (标准命令)
2、System calls (系统调用)
3、Library functions (库函数)
4、Special devices (设备说明)
5、File formats (文件格式)
6、Games and toys (游戏和娱乐)
7、Miscellaneous (杂项)
8、Administrative Commands (管理员命令)
9 其他(Linux特定的), 用来存放内核例行程序的文档。
*/

fd_hzk16 = open("HZK16",O_RDONLY);

if(fd_hzk16 < 0)
{
	printf("can't open HZK16\n");
	return -1;
}

/* lcd提供了一个mmap函数,可以直接映射内存,直接使用framebuffer */
screen_size = var.xres * var.yres * var.bits_per_pixel / 8;
/* 第三个参数是属性,可读可写的意思 */
printf(" %d %d \n ",screen_size,fd_fb);
fb_mem = (unsigned char *)mmap(NULL, screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);
printf("%d\n",fb_mem);
if(fb_mem == (unsigned char *)-1)
{
	printf("can't mmap \n");
	return -1;
}

if(fstat(fd_hzk16, hzk_stat))
{
	printf("can't fstat \n");
	return -1;
}	

/* 第一个参数的意思应该是 */
hzk_mem = (unsigned char *)mmap(NULL, hzk_stat->st_size, PROT_READ, MAP_SHARED, fd_hzk16, 0);

/* 清屏,设置为黑色 */
memset(fb_mem, 0, screen_size);

line_width = var.xres * var.bits_per_pixel / 8;
pixel_width = var.bits_per_pixel / 8;

/* 上面LCD的属性都已经搞清楚了,接下来要做的就是显示 */
lcd_put_ascii(var.xres / 2, var.yres / 2, 'A');
printf("chinese code = %02x %02x\n", str[0], str[1]);
lcd_put_chinese(var.xres / 2 + 8, var.yres / 2, str);

}

freetype的概述:
点阵的缺点就是一旦确定库后,字体的大小就固定死了,但是日程生活中是需要放大缩小的,所以引出了矢量字体文件。
在矢量字体文件中,存储的是若干条曲线的关键点,显示的时候使用贝塞尔数学曲线去描绘连接关键点。
被人已经帮我们处理好了这些数学方面的问题,这个就是freetype理论,从官网上下载稳定版的,freetype2
https://wenku.baidu.com/view/2d24be10cc7931b765ce155b.html //freetype使用方法
glyph字形的轮廓
字体文件除了包括字的关键字外,里面还有charmap,一般来说charmap都会包含有unicode,但是GBK等不一定会有,这些关键点就是glyph

文字的显示方式:
	1. 根据文字显示编码值
	2. 根据编码值在字体文件中找到关键点就是glyph
	3. 设置字体大小
	4. 用某些函数把glyph里的关键点缩放为这个大小
	5. 转换为位图点阵,在LCD上面显示出来
	
那么程序上怎么写代码:
	1. 包含头文件ft2bulid.d
	2. #include FT_FREETYPE_H
	3. 初始化库: FT_Init_Freetype
	4. 加载字体face: 从文件中加载,或者从内存中加载(把文件读到一段内存,从内存中加载文件),主要考虑从文件中加载:
		FT_New_Face(代开字体文件,构造一个face)  unit_per_EM,就是大框的格子
	5. 设置字体的大小(可以显示任意文字的大小,显示之前先设置字体的大小): FT_Set_Char_Size, FT_Set_Pixel_Size
	6. 根据字符的编码值来加载glyph:
		设置选择charmap中的某个编码方式: FT_Select_Charmap
		找到: 获得glyph: glyph_index = FT_Get_Char_Index(face, code)  //face就是字体文件
		获得:加载glyph: FT_Load_Glyph(face, glyph_index, flags)
		转为位图: FT_Render_Glyph
		//上面的三个函数用FT_Load_Char(face, charcode, FT_LOAD_TENDER) //最后一个参数就是直接进行渲染,就是转换为位图
		
		高级用法: 变换,移动,旋转 FT_Set_Transform
		dots: 点也称之为像素
	
1.  英文字母的显示	
	接下来就是看代码: FT_Set_Char_Size里面的参数单位大小什么的,可以去官网上看,太简单了,不行解释了,防止以后忘了,稍微解释下吧
	  FT_EXPORT( FT_Error )
	  FT_Set_Char_Size( FT_Face     face,
						FT_F26Dot6  char_width,
						FT_F26Dot6  char_height,
						FT_UInt     horz_resolution,
						FT_UInt     vert_resolution );
						
	char_width	
	The nominal width, in 26.6 fractional points.
	char_height	
	The nominal height, in 26.6 fractional points.
	horz_resolution	
	The horizontal resolution in dpi.
	vert_resolution	
	The vertical resolution in dpi

	The character widths and heights are specified in 1/64th of points. A point is a physical distance, 
	equaling 1/72th of an inch. Normally, it is not equivalent to a pixel.

	The horizontal and vertical device resolutions are expressed in dots-per-inch, or dpi. Standard values are 72 or 96 dpi 
	for display devices like the screen. The resolution is used to compute the character pixel size from the character point size.

	Value of 0 for the horizontal resolution means ‘same as vertical resolution’, value of 0 for the vertical resolution 
	means ‘same as horizontal resolution’. If both values are zero, 72 dpi is used for both dimensions.

	这个英文文档解释的很清楚了,举个简单的例子:
	  error = FT_Set_Char_Size( face, 50 * 64, 0, 100, 0 );
	  先计算出大小,再计算出这个大小里面有多少个像素,这个就是文字的大小
	  
		像素:是显示器、数字相机或扫描仪可以分辨的最小的点。它是度量数字图像的基本单位。
		点:是打印系统或打印介质所能重现的最小的单位。
		点与像素是有区别的,打印机可以用多个点来打印一个像素。
		pixel和point没有什么直接的联系,由以上可知如果您的图像的ppi为72ppi(pixel per inch)则一个pixel的大小刚好为一个point
		
	  好像解释的不太好,就是说char_width的
	  pixels(像素,dots) =  50 * 64 / 72 / 64 * 100 = 69, 意思就是像素是69, char_height = 0 意思就是char_height = char_width
	  vert_resolution = 0,意思就是vert_resolution = horz_resolution
	 
	 
	很遗憾,对于LCD来说,我们只关心像素pixel的大小,所以上面的讲了半天关系不大,接下来看看FT_Set_Pixel_Size


	修改好代码后就将example和freetype-2.4.10.tar.bz2全部上传,解压,重命名:
		tar xjf freetype-2.4.10.tar.bz2
		mv freetype-2.4.10 freetype-2.4.10_pc
		cd freetype-2.4.10_pc
		./configure   //编译
		make
		sudo make install  //安装,用sudo是因为安装到根目录需要权限
		/usr/bin/install -c -m 644 ./builds/unix/ft2unix.h \
				  /usr/local/include/ft2build.h
		/usr/bin/install -c -m 644 ./builds/unix/ftconfig.h                        \
				  /usr/local/include/freetype2/freetype/config/ftconfig.h
		/usr/bin/install -c -m 644 /work/nfs_root/first_fs/freetype/freetype-2.4.10_pc/objs/ftmodule.h                          \
				  /usr/local/include/freetype2/freetype/config/ftmodule.h    //这里包含各种头文件,freetype
		/usr/bin/install -c -m 755 ./builds/unix/freetype-config \
				  /usr/local/bin/freetype-config
		/usr/bin/install -c -m 644 ./builds/unix/freetype2.m4 \
				  /usr/local/share/aclocal/freetype2.m4
		/usr/bin/install -c -m 644 ./builds/unix/freetype2.pc \
				  /usr/local/lib/pkgconfig/freetype2.pc        //这个就是安装的库的位置	
		book@www.100ask.org:/work/nfs_root/first_fs/freetype/freetype-2.4.10_pc$ ls /usr/local/lib
		libfreetype.a  libfreetype.la  libfreetype.so  libfreetype.so.6  libfreetype.so.6.9.0  pkgconfig  python2.7  python3.5

		book@www.100ask.org:/work/nfs_root/first_fs/freetype/freetype-2.4.10_pc$ cd /usr/local/include/freetype2/freetype/
		book@www.100ask.org:/usr/local/include/freetype2/freetype$ ls
		config      ftbbox.h    ftbzip2.h     ftcid.h     ftgasp.h   ftgzip.h    ftlcdfil.h  ftmac.h     ftmoderr.h  ftpfr.h     ftsnames.h  ftsystem.h  ftwinfnt.h  ttnameid.h  ttunpat.h
		freetype.h  ftbdf.h     ftcache.h     fterrdef.h  ftglyph.h  ftimage.h   ftlist.h    ftmm.h      ftotval.h   ftrender.h  ftstroke.h  fttrigon.h  ftxf86.h    tttables.h
		ftadvanc.h  ftbitmap.h  ftchapters.h  fterrors.h  ftgxval.h  ftincrem.h  ftlzw.h     ftmodapi.h  ftoutln.h   ftsizes.h   ftsynth.h   fttypes.h   t1tables.h  tttags.h	
		
		然后进行编译: gcc -o example1 example1.c
		gcc 是需要针对目标架构设计的。你这两个输出要是一样,你就需要重装 linux 系统了。因为系统已经乱了。
		arm-linux-gcc 是编译到 arm cpu 架构的 gcc直接 gcc 命令,是编译到当前 cpu 架构的 gcc 
		他们不是一个东西,我的机器上有 4 个 gcc ,一个 x86-64 ,一个 mips64el 一个 mipsel ,一个 arm 。完全不冲突。
		编译软件时,需要针对调用即可。调用错误会导致编译出来的程序无法运行。
		一般软件 ./configure 时设置好参数,make 时会自动调用对应的 gcc 。但有的软件在 make 时需要附加参数,比如 kernel 就是这样。
		
		In file included from example1.c:11:0:
		/usr/local/include/ft2build.h:56:38: fatal error: freetype/config/ftheader.h: No such file or directory //找不到路径
		compilation terminated.
		book@www.100ask.org:/work/nfs_root/first_fs/freetype$ ls /usr/local/include/freetype2/freetype/config/ftheader.h
		/usr/local/include/freetype2/freetype/config/ftheader.h   //在上面那个路径可以看见有这个头文件
		book@www.100ask.org:/work/nfs_root/first_fs/freetype$ gcc -o example1 example1.c -I /usr/local/include/freetype2
		example1.c: In function ‘main’:    //所以用-I指定路径
		example1.c:109:3: warning: implicit declaration of function ‘FT_Set_Pixel_Size’ [-Wimplicit-function-declaration]
		   FT_Set_Pixel_Size(face, 24, 0);      //implicit declaration,检查后发现少了s,‘FT_Set_Pixel_Sizes’
		   ^
		/tmp/ccrxR14S.o: In function `main':
		example1.c:(.text+0x26b): undefined reference to `FT_Init_FreeType'   //明明刚刚已经建立库了,所以需要一些参数带上库
		example1.c:(.text+0x294): undefined reference to `FT_New_Face'
		example1.c:(.text+0x2b2): undefined reference to `FT_Set_Pixel_Size'
		example1.c:(.text+0x2d9): undefined reference to `cos'
		example1.c:(.text+0x30a): undefined reference to `sin'
		example1.c:(.text+0x347): undefined reference to `sin'
		example1.c:(.text+0x378): undefined reference to `cos'
		example1.c:(.text+0x3cd): undefined reference to `FT_Set_Transform'
		example1.c:(.text+0x3f5): undefined reference to `FT_Load_Char'
		example1.c:(.text+0x47c): undefined reference to `FT_Done_Face'
		example1.c:(.text+0x488): undefined reference to `FT_Done_FreeType'
		collect2: error: ld returned 1 exit status
		book@www.100ask.org:/work/nfs_root/first_fs/freetype$ ls
		example1.c  freetype-2.4.10_pc  freetype-2.4.10.tar.bz2  freetype????.txt
		book@www.100ask.org:/work/nfs_root/first_fs/freetype$ gcc -o example1 example1.c -I /usr/local/include/freetype2
		/tmp/ccaHtpGn.o: In function `main':
		example1.c:(.text+0x26b): undefined reference to `FT_Init_FreeType'
		example1.c:(.text+0x294): undefined reference to `FT_New_Face'
		example1.c:(.text+0x2ad): undefined reference to `FT_Set_Pixel_Sizes'
		example1.c:(.text+0x2d4): undefined reference to `cos'
		example1.c:(.text+0x305): undefined reference to `sin'
		example1.c:(.text+0x342): undefined reference to `sin'
		example1.c:(.text+0x373): undefined reference to `cos'
		example1.c:(.text+0x3c8): undefined reference to `FT_Set_Transform'
		example1.c:(.text+0x3f0): undefined reference to `FT_Load_Char'
		example1.c:(.text+0x477): undefined reference to `FT_Done_Face'
		example1.c:(.text+0x483): undefined reference to `FT_Done_FreeType'
		collect2: error: ld returned 1 exit status
		book@www.100ask.org:/work/nfs_root/first_fs/freetype$ gcc -o example1 example1.c -I /usr/local/include/freetype2 -lfreetype
		//用-lfreetype带上freetype库
		/tmp/cc26P2Zo.o: In function `main':
		example1.c:(.text+0x2d4): undefined reference to `cos'   //这些数学函数没有定义,再加上-lm  m是math的意思
		example1.c:(.text+0x305): undefined reference to `sin'
		example1.c:(.text+0x342): undefined reference to `sin'
		example1.c:(.text+0x373): undefined reference to `cos'
		collect2: error: ld returned 1 exit status
		book@www.100ask.org:/work/nfs_root/first_fs/freetype$ 
		book@www.100ask.org:/work/nfs_root/first_fs/freetype$ gcc -o example1 example1.c -I /usr/local/include/freetype2 -lfreetype -lm
		./example1
		usage: ./example1 font sample-text
		C:\Windows\Fonts  //随便拷贝一个文件拷贝到服务器上面
		./example1 ./simkai.ttf guangchang  //发现什么都没有,这是因为:
		#define WIDTH   640
		#define HEIGHT  480
		每行里面输出640个字符,crt里面一行只有83个字符,所以根本就看不见字符,这个是韦东山老师的解释,但是我感觉不对,经过实验验证
		我感觉是因为 
		pen.x = 300 * 64;
		pen.y = ( target_height - 200 ) * 64;
		是因为这句话的原因,这句话,老师的界面之所以看不见显示,是因为pen.x的距离设置太大了,超出了显示范围
																																																				
																				 +*+                                              +++++++++    +****+      ++**++        +*+       ++***+        +*+           +
																				 **+                                              ********+   *******+    +******+      +**+      +******+      +**+          +*
																				 **+                                              **+++++++  +**+++***+  +***++***     +***+     +**++++**+    +***+          **
																				 **+                                             +**        +**+   +**+  +**+  +**+   +****+     +*+    **+   +****+         +**
																				 **+                                             +**        +*+     **+  **+    **+   **+**+     +*+    **+   **+**+        +***
			+++  +++                ++++          ++        +++  +++    ++++     **+  ++        ++++          ++        +++  +++ +*+++++            **+ +**+    +**   ++ **+           +**+   ++ **+        **+*
		  +*****+**+ **+    +*+   +******+   **++****+    +*****+**+  +******+   **++****+    +******+   **++****+    +*****+**+ *******++         +**+ +**     +**      **+          +***       **+       +** *
		  ***+***+*+ **+    +**  +********   *****+***+   ***+***+*+ +********   *****+***+  +********   *****+***+   ***+***+*+ ****+****         **+  +**     +**      **+        +****+       **+      +**+ *
		 +**+  **+   **+    +**  +**+  +**   ***+   **+  +**+  **+   ***+  +**+  ***+   **+  +**+  +**   ***+   **+  +**+  **+  +**+   +**+       +**+  +**     +**      **+        +****+       **+     +**+  *
		 +**   **+   **+    +**  +++   +**+  ***    +*+  +**   **+   **+    +*+  ***    +*+  +++   +**+  ***    +*+  +**   **+          **+      +**+   +**     +**      **+          +***+      **+     +**   *
		 +**+  **+   **+    +**   +++*****+  **+    +**  +**+  **+  +**+         **+    +**   +++*****+  **+    +**  +**+  **+          +**     +**+    +**     +**      **+            **+      **+    +**+   *
		  ***+***    **+    +**  +*****+**+  **+    +**   ***+***   +**          **+    +**  +*****+**+  **+    +**   ***+***           +**    +***     +**+    +**      **+            +**      **+    ********
		 +******+    **+    ***  ***+   **+  **+    +**  +******+   +**+    +*+  **+    +**  ***+   **+  **+    +**  +******+   +*+     **+    ***+      **+    **+      **+    +**     +**      **+    ********
		 **++++      **+   +***  **+   +**+  **+    +**  **++++      **+    ***  **+    +**  **+   +**+  **+    +**  **++++     +**    +**+   ***+       +**+  +**+      **+     **+   +**+      **+           *
		 +*****+++   +**+ +****  ***+++***+  **+    +**  +*****+++   +**++++**+  **+    +**  ***+++***+  **+    +**  +*****+++  +***+++***   +**+++++++  +***++***       **+     +**+++***+      **+           *
		 +********+  +******+**  +********+  **+    +**  +********+   +******+   **+    +**  +********+  **+    +**  +********+  +*******+   **********   +******+       **+      +******+       **+           *
		 **+++++***   +***+++*+   +***+++*+  +*+    +*+  **+++++***    +***++    +*+    +*+   +***+++*+  +*+    +*+  **+++++***   ++***+     ++++++++++    ++**++        +++       ++**++        +++           +
		+**     +**                                     +**     +**                                                 +**     +**                                                                                 
		 ***++++**+                                      ***++++**+                                                  ***++++**+                                                                                 
		 ++******+                                       ++******+                                                   ++******+                                                                                  
																																																			
		所以重新设置一下 pen.x和pen.y,另外就是注意一下笛卡尔坐标和lcd屏幕的坐标的问题,另外WIDTH、HEIGHT决定了字符的个数,也就是解析度
		解析度可以简单理解为棋盘上的一个个交叉点,就像上面的输出,不是*就是+ ,实际情况这个是颜色的深浅,为了简单才这样。




2.  汉子的显示
	显示汉子的方式很简单,先新建一个文本文档,然后用unicode方式进行保存,保存后用Hex Editor Neo打开,再修改代码就可以了
	修改代码如下:
	int chinese_str[] = { 0x97e6, 0x4elc, 0x5c71 };
	for ( n = 0; n < 3; n++ )
	error = FT_Load_Char( face, chinese_str[n], FT_LOAD_RENDER );
	
	重新编译一下:
	invalid suffix "lc" on integer constant  //这个是因为把数字1携程了字母l
	执行的时候要带上三个参数,否则会判断错误:
	if ( argc != 3 )
	{
		fprintf ( stderr, "usage: %s font sample-text\n", argv[0] );
		exit( 1 );
	}
	下面是输出结果: 
																	   
			  +++                     ++                                                                                                                                                                    
		  +**+                    +**                                                                                                                                                                   
		   **                     +**                                                                                                                                                                   
		   **                     **+                     +*+                                                                                                                                           
		   **  ++++              +*+  +++++               +**+                                                                                                                                          
		  +*******+            ++*********+                **+                                                                                                                                          
	 ++******++++          +*********++++                  **                                                                                                                                           
	 +++++ *+               ++++**++                       **                                                                                                                                           
		   **+***+             +*+ **+                     **     +                                                                                                                                     
	   +******+++              **  +*+                     **     **+                                                                                                                                   
	   ++++*+   ++++          +*+  +*+++**+                **     +**                                                                                                                                   
		 ++*********+        +**++*********        +++     **     +**                                                                                                                                   
	*********++  +**         ******+*+             +**     **     +*+                                                                                                                                   
	+++++  *+    +*+         *++   +*               **     **     +*+                                                                                                                                   
		   *+    +*+          ++   +*  +++          **     **+++****+                                                                                                                                   
		   *+    **+         +*+   +*  +***+        **+++*******++**+                                                                                                                                   
		   *+ +****         +**+   +*+  +***       +*****+++      **                                                                                                                                    
		   *+  +**+         ***    +*+   +**+      +**++          **                                                                                                                                    
		   *+   ++         +**+    +*+    +*+      ++             **                                                                                                                                    
		   *+              +++  +****                             ++                                                                                                                                    
		   *+                    +***                                                                                                                                                                   
		   +                      +*+     

3.  宽字符的显示
	因为每次去显示中文的汉字的时候都是去获取他的unicode,这个是非常的麻烦,所以引入了宽字符,注意一下,因为汉字和英文字母的
	字节数是不一样的,所以直接用char *str = "gc 光昌"是不行的,需要用到宽字符。
	宽字符中不论是汉字还是字母都是用四个字节来表示
	
	以前用来识别字符的字节数,是使用strlen:   num_chars     = strlen( text );   //这个是前面识别English用的
	现在宽字符使用的方式是:
	man strlen
	string(3), strnlen(3), wcslen(3), wcsnlen(3)  //就是使用这个wcslen
	
	添加这么一行代码:
	wchar_t *wst = L"光昌喜欢小草gc";
	unsigned *p = (wchar_t *)wst;
	int i;
	printf("unicode : \n");
	for(i = 0; i < wcslen(wst); i++)
	{
	printf("ox%x"p[i]);
	}
	printf("\n");
	return 0;
	
	编译结果: 
	ample1.c:86:18: error: converting to execution character set: Invalid or incomplete multibyte or wide character
	wchar_t *wst = L"???????С??gc";
	这个意思是无法转换字符集,所以我们还是需要指定字符集的(方法是前面已经提到了,就不再详述了):
	gcc -finput-charset=GBK -fexec-charset=UTF-8 -o example1 example1.c -I /usr/local/include/freetype2 -lfreetype -lm
	忘了说了,这个可以先用记事本打开example1,另存为,看看他是什么编码方式,是ANSI,也就是GBK,默认就是这样的
	继续编译,下面这个警告应该是缺少头文件:
	example1.c:90:18: warning: implicit declaration of function ‘wcslen’ [-Wimplicit-function-declaration]
	man wcslen
	#include <wchar.h>
	其他的一些小错误就不写了
	输出结果是:
	unicode : 
	ox5149  ox660c  ox559c  ox6b22  ox5c0f  ox8349  ox67  ox63
	用工具查看“光昌喜欢小草gc”这句话的unicode是完全一样的,当用宽字符表示的时候,每个字符都是四字节,里面存放的是unicode
	继续修改代码:
	for(i = 0; i < wcslen(wst); i++)
	  {
		printf("ox%x  ", p[i]);
	  }
	  printf("\n");    
	  //return 0;   //return 0;

	if ( argc != 2 )  //if ( argc != 2 )  目的是为了修改输入参数的个数
	
	  {
		fprintf ( stderr, "usage: %s font\n", argv[0] );
		exit( 1 );
	  }

	  filename      = argv[1];                           /* first argument     */
	  //text          = argv[2];                           /* second argument    */   //修改了参数个数后,这两句
	  //num_chars     = strlen( text );  											  //话就需要去掉,否则会出问题
	for ( n = 0; n < wcslen(wst); n++ )    //for ( n = 0; n < 3; n++ )
	{
	/* set transformation ,这里面要用到刚刚的矩阵,matrix是矩阵的意思 */
	FT_Set_Transform( face, &matrix, &pen );

	/* load glyph image into the slot (erase previous one) */
	error = FT_Load_Char( face, wcslen(wst), FT_LOAD_RENDER ); //error = FT_Load_Char( face, chinese_str[n], FT_LOAD_RENDER );
	继续编译,执行:

在这里插入图片描述
很奇怪的输出,猜测应该是for循环出问题了,修改代码:
error = FT_Load_Char( face, wcslen(wst), FT_LOAD_RENDER )
error = FT_Load_Char( face, wst(n), FT_LOAD_RENDER )
编译执行结果:
不好显示,只好用截图:

在这里插入图片描述今天就到这里了,程序就不附带了,主要是修改别人的文档。

修改后的dot_show.c,只上传部分代码:
*/
static struct fb_var_screeninfo var;
static struct fb_fix_screeninfo fix;
static int fd_fb;
static int screen_size;
static unsigned char *fb_mem;
static unsigned char str[] = “中”;
static int fd_hzk16;
static struct stat hzk_stat;
static unsigned char *hzk_mem;
static unsigned line_width;
static unsigned pixel_width;

static void lcd_put_pixel(int x, int y, unsigned int color){
unsigned char *pen_8 = fb_mem + y * line_width + x * pixel_width;
unsigned short *pen_16;
unsigned int pen_32;
unsigned int red, green, blue;/
改为int是担心移位的时候可能会出现一些问题 */

pen_16 = (unsigned short *)pen_8;
pen_32 = (unsigned int *)pen_8;

/* color : 0x00RRGGBB */
switch(var.bits_per_pixel){    /* show_font.c:4661: error: stray '\229' in program,这个是因为之前"{"前面多了个空格 */
	case 8:
	{
		/* 8位的时候需要用到调色板,产生的颜色代表调色板里面的索引值 */
		*pen_8 = color;
		break;
	}

	case 16:
	{
		red = (color >> 16) & 0xff;
		green = (color >> 8) & 0xff;
		blue = color & 0xff;
		color = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3);
		*pen_16 = color;
		break;
	}
	case 32:
	{
		*pen_32 = color;
		break;
	}
	default:
		{
			printf("can't support %dbpp", var.bits_per_pixel);
			break;
		}
	}

}

static void lcd_put_ascii(int x, int y, unsigned char c){
/* 这里注意一下 */
unsigned char *dots = (unsigned char )&fontdata_8x16[c16];
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);/* 黑色 */
	}

}

}
static 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 = hzk_mem + (area * 94 + where) * 32;
unsigned char byte;
int i, j, b;
for(i = 0; i < 16; i++)
for(j = 0; j < 2; j++)
{

			//subscripted value is neither array nor pointer,之前的dots是整数,既不是指针, 也不是数组。
			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){

fd_fb = open("/dev/fb0", O_RDWR);


if(fd_fb < 0)
{
	printf("can't open /dev/fb0\n");
	return -1;
}

/* 如果返回值不是0的情况下说明获得不成功,从这个可变信息就可以知道分辨率等参数,可以进var去看看 */
if(ioctl(fd_fb, FBIOGET_VSCREENINFO, &var))
/* fb_info */
{
	printf("can't get var \n");
	return -1;
}

if(ioctl(fd_fb, FBIOGET_FSCREENINFO, &fix))      //这儿刚开始写成 了  FBIOGET_VSCREENINFO
/* fb_info */
{
	printf("can't get fix \n");
	return -1;
}

/* invalid suffix "_RDWR" on integer constant,这个是未定义,可以man 2 open看看需要什么头文件 */
/*
man指令后面的参数
1、Standard commands (标准命令)
2、System calls (系统调用)
3、Library functions (库函数)
4、Special devices (设备说明)
5、File formats (文件格式)
6、Games and toys (游戏和娱乐)
7、Miscellaneous (杂项)
8、Administrative Commands (管理员命令)
9 其他(Linux特定的), 用来存放内核例行程序的文档。
*/

fd_hzk16 = open("HZK16",O_RDONLY);

if(fd_hzk16 < 0)
{
	printf("can't open HZK16\n");
	return -1;
}

/* lcd提供了一个mmap函数,可以直接映射内存,直接使用framebuffer */
screen_size = var.xres * var.yres * var.bits_per_pixel / 8;
/* 第三个参数是属性,可读可写的意思 */

fb_mem = (unsigned char *)mmap(NULL, screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);

if(fb_mem == (unsigned char *)-1)
{

	printf("can't mmap \n");
	return -1;
}

if(fstat(fd_hzk16, &hzk_stat))   //这个地方比较奇怪,我定义了static struct stat *hzk_stat;,,然后这儿用参数hzk_stat就出现问题了

{
	printf("can't fstat \n");
	return -1;
}	

/* 第一个参数的意思应该是 */
hzk_mem = (unsigned char *)mmap(NULL, hzk_stat.st_size, PROT_READ, MAP_SHARED, fd_hzk16, 0);

/* 清屏,设置为黑色 */
memset(fb_mem, 0, screen_size);

line_width = var.xres * var.bits_per_pixel / 8;
pixel_width = var.bits_per_pixel / 8;

/* 上面LCD的属性都已经搞清楚了,接下来要做的就是显示 */
lcd_put_ascii(var.xres / 2, var.yres / 2, 'A');

printf("chinese code = %02x %02x\n", str[0], str[1]);

lcd_put_chinese(var.xres / 2 + 8, var.yres / 2, str);

}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值