02.点阵显示中文汉字
1.环境
- 官方给的内核文件(linux3.4)和根文件系统、linux2.6和配套根文件系统
- 不同的内核文件编译时用的交叉编译器不同,linux3.4用4.x的编译器,linux2.6用3.x的编译器,否则不能运行
- !!注意:在写代码时要用GB2312编码写,否则程序中的"中"是UTF-8,显示出来就是"涓"字
2.架构思路
- 打开屏所对应的文件,调用fctl函数使可以用地址来操作文件
- 获得屏的一些信息(如:屏幕一个像素点占用的位数,屏的分辨率等等)
- 打开汉字库文件,调用fctl函数使可以用地址来操作文件
- 获得汉字库文件的一些信息(如大小)
- 清屏
- 写ascii字符和汉字
3.知识点
LCD设备fb0的file_operations是fb_fops(位于fbmem.c)
fb_fops的write成员是fb_write()函数.
发现write()函数直接是对显存地址写数据, 所以使用echo “hello”> /dev/fb0时会直接出现乱码(没有点阵信息)
ioctl函数
octl是设备驱动程序中对设备的I/O通道进行管理的函数。所谓对I/O通道进行管理,就是对设备的一些特性进行控制,例如串口的传输波特率、马达的转速等等。它的参数个数如下:int ioctl(int fd, int cmd, …);其中fd就是用户程序打开设备时使用open函数返回的文件标示符,cmd就是用户程序对设备的控制命令,至于后面的省略号,那是一些补充参数,一般最多一个,有或没有是和cmd的意义相关的。
ioctl获取屏幕的信息:ioctl(fd_fb , FBIOGET_FSCREENINFO, &fix)
FBIOGET_VSCREENINFO:获取fb_info-> var成员(可变信息:xy分辨率,像素位数等)
FBIOGET_FSCREENINFO:获取fb_info-> fix成员(固定信息:缓存地址,每行字节数,)
- mmap函数
mmap()函数:申请一段用户空间的内存区域,并映射到内核空间某个内存区域.
申请一块内存映射到某一个文件,然后应用程序直接向内存写数据,即可直接写入这个文件
即:通过mmap函数可以实现用指针对文件操作
void* mmap(void* start,size_t length,int prot,int flags,int fd,off_t offset);
返回值:失败返回-1,并设置errno值.成功,返回映射的地址指针.若指定start则返回0
start:需要映射的内存起始地址,通常填NULL,表示让系统自动映射,映射成功后返回该地址.
length:映射地址的大小,填LCD显存字节数即可,因为2440一个地址存8位.
prot:对映射地址的保护(protect)方式,常用组合如下:
PROT_EXEC 映射区域可被执行
PROT_READ 映射区域可被读取
PROT_WRITE 映射区域可被写入
PROT_NONE 映射区域不可访问
flag:填MAP_SHARED即可,表示共享此映射,对其它进程可见.
fd:需要将内存映射到哪个文件描述符(以后便可以直接通过内存来直接操作该文件)
offset:映射偏移值,填0即可.
- ASCII码字库文件使用
在linux工程文件中搜索font,内核有很多font文件,我们使用font_8*16.c,这里面就存着字符对应的点阵信息。
数组的下标就是字符对应的ascii码
- HZK16汉字库文件使用
(1)HZK16是按分区表排列的点阵文件,由于每个汉字是2字节,每个字节的点阵是8x16,所以HZK16里的每个汉字点阵大。小:2816=32字节.
(2)然后还要将编码转为点阵码,我们以"中"为例:
“中” 的GBK编码为D6 D0.
转为分区表(每字节减去A1): 35 2F
所以中的点阵位于:(35*94+2F)32~(3594+2F)*32+31
注意!!
注意编写程序的软件的编码方式是什么,HZK16使用的是GBK的编码,所以如果编辑器的编码方式不是ANSI的,那么就需要在编译的时候加上
gcc -finput-charset=UTF-8 -fexec-charset=GBK -o ansi ansi.c
附录:源码
#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
static const unsigned char fontdata_8x16[FONTDATAMAX] = {... /*asic编码*/
}
int fd_fb; //屏的文件描述符
int fd_hzk16; //汉字库文件的描述符
struct fb_var_screeninfo var; //用来存屏的可变信息的,对应驱动
struct fb_fix_screeninfo fix; //用来存屏不可变信息的
int screen_size; //屏幕大小
unsigned char *fbmem; //屏的framebufferstruct stat hzk_stat; //汉字文件的属性
unsigned char *hzkmem; //汉字文件的指针,可以直接用这个指针去操作那个文件unsigned int line_width; //一行有多少个字节
unsigned int pixel_width; //一行有多少个字节//color : 0x00RRGGBB
//板子驱动上是每个像素16位
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; //这里用int不用char,是因为在给color赋值时需要左移11位,如果是char可能会出错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 &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 %d bpp\n",var.bits_per_pixel);break; //不能支持这种像素}
}void lcd_put_ascii(int x, int y, unsigned char c)
{//存放字符c的点阵的首地址//每个字符需要16个字节存放,所以第c个字符就是c*16unsigned char *dots = (unsigned char *)&fontdata_8x16[c*16];int i,b;unsigned char byte;for(i = 0; i < 16; i++){byte = *(dots+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; //这个汉字所在的区,汉字的第一个字符-0xa1unsigned int where = str[1] - 0xA1; //这个汉字在这个区的什么地方,汉字的第二个字符-0xa1unsigned char *dots =(unsigned char *)(hzkmem + (area*94 + where)*32) ; //一个区有94个字符,一个字符占用32字节(16*16/8) unsigned char byte;int i,j,b;for(i = 0; i < 16; i++){for(j = 0; j < 2; j++){byte = dots[i*2 + j]; //一个汉字占用两个8*16的地方,地址是横着算的,不是先竖着弄完一个8*16,然后再接着另外一个8*16for(b =7; b >=0; b--){if(byte & (1<<b)){/*show*/lcd_put_pixel(x + j*8 + 7-b , y + i , 0xffffff);}else{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\n");}//首先获得LCD的一些参数,如每个点用多少位来显示,XY的分辨率是多少//这些信息在写LCD驱动的时候,都放在了一个fb_info的结构体中//可以返回去驱看当时的驱动,在lcd_init函数里if(ioctl(fd_fb , FBIOGET_VSCREENINFO, &var)) //可变信息:分辨率、RBG谁在高位、每一个点需要几位数据{printf("can't get var\n");return -1;}if(ioctl(fd_fb , FBIOGET_FSCREENINFO, &fix)) //不可变数据:显存长度、设备名、一行的长度等{printf("can't get fix\n");return -1;}screen_size = var.xres * var.yres *var.bits_per_pixel /8; //算出一屏有多大,x*y*每个像素的位数/8 (Bytes)pixel_width = var.bits_per_pixel / 8; //每个像素占多少字节:每个像素占多少位/8line_width = var.xres * pixel_width; //一行多少个像素乘以每个像素多少字节//这个是把文件当作指针来操作,就不用对文件描述符来操作了//对那个文件描述符操作,就是对framebuffer操作//void *mmap(void *addr, size_t length, int prot, int flags,int fd, 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");}//汉字库初始化fd_hzk16 = open("HZK16",O_RDONLY);if(fd_hzk16 < 0){printf("can't open HZK16\n");return -1;}//int fstat(int fd, struct stat *buf); 获得这个文件的一些信息if(fstat(fd_hzk16 , &hzk_stat)){printf("can't get HZK16\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("can't mmap\n");}/*清屏:全部设为黑色*/memset(fbmem, 0 ,screen_size);lcd_put_ascii(var.xres/2 , var.yres/2 ,'A');printf("chines code: %02x %02x \n",str[0] , str[1]);lcd_put_chinese(var.xres/2+8,var.yres/2,str);}
02.点阵显示中文汉字相关推荐
- OpenCV显示中文汉字,未使用CvxText和FreeType库
OpenCV显示中文汉字,未使用CvxText和FreeType库 采用windows的GDI显示系统的TrueType字体,没有封装,就两个函数,分成了h和cpp文件,可以自己编辑文件名和函数名,亦 ...
- 总结一下嵌入式OLED显示屏显示中文汉字的办法
为什么80%的码农都做不了架构师?>>> 这个问题以为很简单,但最后花很多功夫才能完成,所以总结一下分享给大家. 解决思路 UTF-8->Unicode->GB23 ...
- android 只能输入汉字,EditText限制输入的几种方式及只显示中文汉字的做法
前段时间项目中有个需求是要求只能输入汉字,并且不能输入偏旁部首,于是总结了下EditText限制输入的几种方式,但是对于语音输入的还没找到好的解决方案: 通过设置EditText的inputType来 ...
- jetson nano 在opencv拉流的视频上显示中文汉字(含c++完整源码)
目录 问题 解决方案 步骤一:生成中文图片 步骤二:中文图片蒙皮到视频帧,形成中文显示效果 问题 在jetson nano这样的嵌入式设备上,用opencv拉流,并在实时视频上面,显示汉字. 关于使用 ...
- 51单片机教程:51单片机驱动四个8*8点阵,拼凑16*16点阵显示标准汉字。
看此篇博文之前建议先看博主的上一篇博文: 51单片机教程:8*8 点阵显示字符.数字.简单汉字 取走点赞哦~ 教你如何用4个8乘8点阵拼成一个16乘16点阵 资料链接:点阵16乘16.rar 一.点阵 ...
- 单片机8×8点阵显示简单汉字的程序_LED显示屏的显示原理原来是这样,科技实现梦想...
从图上看,8X8 点阵共需要64 个发光二极管组成,且每个发光二极管是放置在行线和列线的交叉点上,当对应的某一行置高电平,某一列置低电平时,则相应的二极管就亮. 将许多这样的模块组合在一起,就是我们通 ...
- STM32F29显示中文汉字
以下资料为网络搜集,发现很多都为"原创",无法判断作者了. 自己理解后整理,看官自己另行查找详源 . 也可以参考一下这文章 : STM32F429 之 LTDC汉字显示_ 开发效果 ...
- 单片机8×8点阵显示简单汉字的程序_干货 | 浅析单片机制作贪吃蛇游戏
为了让大家更深入地了解底层的原理,在讲解时特意选择了51单片机(而非STM系列),另外16*16点阵由译码器和移位缓存器直接驱动(而非MAX系列芯片),摇杆也利用ADC功能判断方向. 那如何让单片机驱 ...
- opencv学习笔记六十八:显示中文汉字
opencv中putText只能显示英文,如果在某个程序中你想显示汉字,可在该项目上新建一个头文件项putText.h和一个putText.cpp即可. putText.h #ifndef PUTTE ...
最新文章
- 自己动手安装ARM交叉编译工具链
- 众人评说《我们在微软怎样开发(英文版)》
- Android 图片的帧动画
- 如何在Django中以GROUP BY查询?
- 交换与路由技术课程期末上机测试题目一
- Nginx设置本地浏览器缓存
- linux ssh应用
- mysql 实现表值函数,SQL SERVER 的 CLR表值函数
- 《编码规范和测试方法——C/C++版》学习笔记 ·001
- Jenkins+Github(Robotframework代码)
- BGP路径属性分类与实验(华为设备)
- atitit.提高开发效率---mda 革命性的软件开发方法
- Android Button设置
- 抽象代数 01.06 变换群与置换群
- SNOWNLP情感分析报错解决
- Android dropbox介绍
- Android有效解决加载大图片内存溢出问题及优化虚拟机内存
- 高通MTK麒麟 手机平台USB3.0方案对比
- fttp项目下载和上传
- 升腾c10,华为ct3100安装nextcloud,KodExplorer网盘
热门文章
- 对接支付宝支付通道接口
- 大华与巴斯勒相机实现单拍的不同
- C语言程序设计实训教程-张玉生 张书月 朱苗苗/主编—实验14.4
- springboot网上图书商城
- 巨杉2017行业认可盘点
- OpenLDAP中如何禁用账户,启用账户
- 【C#】最全单据打印(打印模板、条形码二维码、字体样式、项目源码)
- SWAN之ikev2协议farp配置测试
- 递归实现斐波那契数列 一个人赶着鸭子去每个村庄卖,每经过一个 村子卖去所赶鸭子的一半又一只。 这样他经过了 七个村子后还剩 两只鸭子,问问他出发时共赶多少只鸭子?经过每个村子卖出多少只鸭子?
- 中法计算机专业,中法计算机大一新生的专业课课程表