一、串口传输文件
1.题目要求
串口传输文件的练习。将两台笔记本电脑,借助 usb转rs232 模块和杜邦线,建立起串口连接。然后用串口助手等工具软件(带文件传输功能)将一台笔记本上的一个大文件(图片、视频和压缩包软件)传输到另外一台电脑,预算文件大小、波特率和传输时间三者之间的关系,并对比实际传输时间。
2.实验过程
①连接好两台电脑 两个串口的连线方式为: 3v3——3v3 GND——GND TXD——RXD RXD——TXD
②传输文件 设置波特率为115200,打开串口,打开文件,发送文件。 发送完成后,接收端如下: 传输成功。 ③理论时间与实际时间 理论时间=(文件大小*8)/波特率 所以理论时间为:122.57秒 实际时间为:159.89秒 可以看到实际时间比理论时间稍长,可能是传输中延时累加起来,导致了超时。
二、汉字点阵原理
1.汉字编码
①区位码 在国标 GD2312—80 中规定,所有的国标汉字及符号分配在一个 94 行、94 列的方阵中,方阵的每一行称为一个“区”,编号为 01 区到 94 区,每一列称为一个“位”,编号为 01 位到 94 位,方阵中的每一个汉字和符号所在的区号和位号组合在一起形成的四个阿拉伯数字就是它们的“区位码”。区位码的前两位是它的区号,后两位是它的位号。用区位码就可以唯一地确定一个汉字或符号,反过来说,任何一个汉字或符号也都对应着一个唯一的区位码。汉字“母”字的区位码是 3624,表明它在方阵的 36 区 24 位,问号“?”的区位码为0331,则它在 03 区 3l 位。
②机内码 汉字的机内码是指在计算机中表示一个汉字的编码。机内码与区位码稍有区别。如上所述,汉字区位码的区码和位码的取值均在 1~94 之间,如直接用区位码作为机内码,就会与基本 ASCII 码混淆。为了避免机内码与基本 ASCII 码的冲突,需要避开基本 ASCII 码中的控制码(00H~1FH),还需与基本 ASCII 码中的字符相区别。为了实现这两点,可以先在区码和位码分别加上 20H,在此基础上再加 80H(此处“H”表示前两位数字为十六进制数)。经过这些处理,用机内码表示一个汉字需要占两个字节,分别 称为高位字节和低位字节,这两位字节的机内码按如下规则表示: 高位字节 = 区码 + 20H + 80H(或区码 + A0H) 低位字节 = 位码 + 20H + 80H(或位码 + AOH) 由于汉字的区码与位码的取值范围的十六进制数均为 01H~5EH(即十进制的 01~94),所以汉字的高位字节与低位字节的取值范围则为 A1H~FEH(即十进制的 161~254)。 例如,汉字“啊”的区位码为 1601,区码和位码分别用十六进制表示即为 1001H,它的机内码的高位字节为 B0H,低位字节为 A1H,机内码就是 B0A1H。
2.点库字库结构
①点阵字库存储 在汉字的点阵字库中,每个字节的每个位都代表一个汉字的一个点,每个汉 字都是由一个矩形的点阵组成,0 代表没有,1 代表有点,将 0 和 1 分别用不同颜色画出,就形成了一个汉字,常用的点阵矩阵有 1212, 1414, 16*16 三种字库。 字库根据字节所表示点的不同有分为横向矩阵和纵向矩阵,目前多数的字库 都是横向矩阵的存储方式(用得最多的应该是早期 UCDOS 字库),纵向矩阵一般是因为有某些液晶是采用纵向扫描显示法,为了提高显示速度,于是便把字库矩阵做成纵向,省得在显示时还要做矩阵转换。我们接下去所描述的都是指横向矩阵字库。
②1616 点阵字库 对于 1616 的矩阵来说,它所需要的位数共是 1616=256 个位,每个字 节为 8 位,因此,每个汉字都需要用 256/8=32 个字节来表示。 即每两个字节代表一行的 16 个点,共需要 16 行,显示汉字时,只需一次 性读取 32 个字节,并将每两个字节为一行打印出来,即可形成一个汉字。 点阵结构如下图所示: ③1414 与 1212 点阵字库 对于 1414 和 1212 的字库,理论上计算,它们所需要的点阵分别为(14 14/8)=25, (1212/8)=18 个字节,但是,如果按这种方式来存储,那么取 点阵和显示时,由于它们每一行都不是 8 的整位数,因此,就会涉到点阵的计算处理问题,会增加程序的复杂度,降低程序的效率。 为了解决这个问题,有些点阵字库会将 1414 和 1212 的字库按 1614 和 1612 来存储,即,每行还是按两个字节来存储,但是 1414 的字库,每 两个字节的最后两位是没有使用,1212 的字节,每两字节的最后 4 位是没有使用,这个根据不同的字库会有不同的处理方式,所以在使用字库时要注意这个问题,特别是 1414 的字库。
3.汉字点阵获取
①利用区位码获取汉字 汉字点阵字库是根据区位码的顺序进行存储的,因此,我们可以根据区位来 获取一个字库的点阵,它的计算公式如下: 点阵起始位置 = ((区码- 1)*94 + (位码 – 1)) * 汉字点阵字节数获取点阵起始位置后,我们就可以从这个位置开始,读取出一个汉字的点阵。
②利用汉字机内码获取汉字 前面我们己经讲过,汉字的区位码和机内码的关系如下: 机内码高位字节 = 区码 + 20H + 80H(或区码 + A0H) 机内码低位字节 = 位码 + 20H + 80H(或位码 + AOH) 反过来说,我们也可以根据机内码来获得区位码: 区码 = 机内码高位字节 - A0H 位码 = 机内码低位字节 - AOH 将这个公式与获取汉字点阵的公式进行合并计就可以得到汉字的点阵位置。
三、Ubuntu下显示图片和文字
1.实验要求
在Ubuntu下用C/C++(或python) 调用opencv库编程显示一张图片,并打开一个名为"logo.txt"的文本文件(其中只有一行文本文件,包括你自己的名字和学号),按照名字和学号去读取汉字24*24点阵字形字库(压缩包中的文件HZKf2424.hz)中对应字符的字形数据,将名字和学号叠加显示在此图片右下位置。
2.实验准备
①一张图片 ②24*24点阵的文件和ASCll码文件 ③想要显示的文字
3.编写代码
打开终端输入指令 gedit word.cpp 来创建 word.cpp 文件,再输入代码:
#include<iostream>
#include<opencv/cv.h>
#include"opencv2/opencv.hpp"
#include<opencv/cxcore.h>
#include<opencv/highgui.h>
#include<math.h>
using namespace cv;
using namespace std;
void paint_chinese(Mat& image,int x_offset,int y_offset,unsigned long offset);
void paint_ascii(Mat& image,int x_offset,int y_offset,unsigned long offset);
void put_text_to_image(int x_offset,int y_offset,String image_path,char* logo_path);
int main(){
String image_path="bird.jpg";
char* logo_path="logo.txt";
put_text_to_image(200,350,image_path,logo_path);
return 0;
}
void paint_ascii(Mat& image,int x_offset,int y_offset,unsigned long offset){
Point p;
p.x = x_offset;
p.y = y_offset;
char buff[16];
FILE *ASCII;
if ((ASCII = fopen("Asci0816.zf", "rb")) == NULL){
printf("Can't open ascii.zf,Please check the path!");
exit(0);
}
fseek(ASCII, offset, SEEK_SET);
fread(buff, 16, 1, ASCII);
int i, j;
Point p1 = p;
for (i = 0; i<16; i++)
{
p.x = x_offset;
for (j = 0; j < 8; j++)
{
p1 = p;
if (buff[i] & (0x80 >> j))
{
circle(image, p1, 0, Scalar(0, 0, 255), -1);
p1.x++;
circle(image, p1, 0, Scalar(0, 0, 255), -1);
p1.y++;
circle(image, p1, 0, Scalar(0, 0, 255), -1);
p1.x--;
circle(image, p1, 0, Scalar(0, 0, 255), -1);
}
p.x+=2;
}
p.y+=2;
}
}
void paint_chinese(Mat& image,int x_offset,int y_offset,unsigned long offset){
Point p;
p.x=x_offset;
p.y=y_offset;
FILE *HZK;
char buff[72];
if((HZK=fopen("HZKf2424.hz","rb"))==NULL){
printf("Can't open HZKf2424.hz,Please check the path!");
exit(0);
}
fseek(HZK, offset, SEEK_SET);
fread(buff, 72, 1, HZK);
bool mat[24][24];
int i,j,k;
for (i = 0; i<24; i++)
{
for (j = 0; j<3; j++)
for (k = 0; k<8; k++)
if (buff[i * 3 + j] & (0x80 >> k))
{
mat[j * 8 + k][i] = true;
}
else {
mat[j * 8 + k][i] = false;
}
}
for (i = 0; i < 24; i++)
{
p.x = x_offset;
for (j = 0; j < 24; j++)
{
if (mat[i][j])
circle(image, p, 1, Scalar(255, 0, 0), -1);
p.x++;
}
p.y++;
}
}
void put_text_to_image(int x_offset,int y_offset,String image_path,char* logo_path){
Mat image=imread(image_path);
int length=19;
unsigned char qh,wh;
unsigned long offset;
unsigned char hexcode[30];
FILE* file_logo;
if ((file_logo = fopen(logo_path, "rb")) == NULL){
printf("Can't open txtfile,Please check the path!");
exit(0);
}
fseek(file_logo, 0, SEEK_SET);
fread(hexcode, length, 1, file_logo);
int x =x_offset,y = y_offset;
for(int m=0;m<length;){
if(hexcode[m]==0x23){
break;
}
else if(hexcode[m]>0xaf){
qh=hexcode[m]-0xaf;
wh=hexcode[m+1] - 0xa0;
offset=(94*(qh-1)+(wh-1))*72L;
paint_chinese(image,x,y,offset);
m=m+2;
x+=24;
}
else{
wh=hexcode[m];
offset=wh*16l;
paint_ascii(image,x,y,offset);
m++;
x+=16;
}
}
cv::imshow("image", image);
cv::waitKey();
}
可以根据自身情况修改代码达到想要的效果:
第16行:修改为自己的图片文件名字。 第18行:修改符合自己图片尺寸的显示位置。 第115行:修改为自己需要打印的字符长度。
4.编译运行
输入编译指令:
g++ word.cpp -o word `pkg-config --cflags --libs opencv`
编译没错后,输入指令:
./word
开始运行。 运行结果如下: 实验成功。
四、总结
本次实验相比之前比较简单,参考了大神的代码,看懂以后修改了需要的部分就做出来了。整体不是很难,也是对点阵汉字的第一次接触,很感兴趣。
五、参考资料
点阵汉字的字模读取与显示
|