两台PC实现串口通信以及点阵字模读写

目录

一、PC串口通信

1. 连线设置

2.打开调试助手

2.1 加载图片

 2.2 设置波特率为115200

 2.3 点击发送文件

3.将波特率设为2000000

4. 结果分析

 二、点阵汉字读取与打印

1. 点阵汉字知识点

1.1 汉字编码

1.2 点阵字库结构

1.3 汉字点阵获取

2. 编程实现

2.1 创建文本文档

2.2 打开Ubuntu 

2.3 运行结果

 三、总结


一、PC串口通信

1. 连线设置

注意将一个串口的TXD连接另一个串口的RXD,接电源和接地连一起即可。

2.打开调试助手

2.1 加载图片

 2.2 设置波特率为115200

 2.3 点击发送文件

 预计时间为15s,但是在实际测试过程中用了21s

3.将波特率设为2000000

可见此时预测时间为0.6s,可是实际的传输时间为11s。

4. 结果分析

因为传输时延=文件大小/波特率,因为随着波特率的升高,丢包率会更高,因此实际时间与预测时间差别很大。

 二、点阵汉字读取与打印

1. 点阵汉字知识点

1.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。

1.2 点阵字库结构

  • 点阵字库存储

        在汉字的点阵字库中,每个字节的每个位都代表一个汉字的一个点,每个汉
字都是由一个矩形的点阵组成,0 代表没有,1 代表有点,将 0 和 1 分别用不同颜色画出,就形成了一个汉字,常用的点阵矩阵有 12 * 12, 14 * 14, 16 * 16 三 种字库。 字库根据字节所表示点的不同有分为横向矩阵和纵向矩阵,目前多数的字库都是横向矩阵的存储方式(用得最多的应该是早期 UCDOS 库),纵向矩阵一 般是因为有某些液晶是采用纵向扫描显示法,为了提高显示速度,于是便把字库 矩阵做成纵向,省得在显示时还要做矩阵转换。我们接下去所描述的都是指横向矩阵字库。

  • 16 * 16 点阵字库

        对于 16 * 16 的矩阵来说,它所需要的位数共是 16 * 16=256 个位,每个字节为 8 位,因此,每个汉字都需要用 256/8=32 个字节来表示。即每两个字节代表一行的 16 个点,共需要 16 行,显示汉字时,只需一次性读取 32 个字节,并将每两个字节为一行打印出来,即可形成一个汉字。

  • 14 * 14 与 12 * 12 点阵字库

        对于 14 * 14 和 12 * 12 的字库,理论上计算,它们所需要的点阵分别为(14 * 14/8)=25, (12 * 12/8)=18 个字节,但是,如果按这种方式来存储,那么取 点阵和显示时,由于它们每一行都不是 8 的整位数,因此,就会涉到点阵的计算处理问题,会增加程序的复杂度,降低程序的效率。
为了解决这个问题,有些点阵字库会将 14 * 14 和 12 * 12 的字库按 16*14和16 * 12 来存储,即,每行还是按两个字节来存储,但是 14 * 14 的字库,每两个字节的最后两位是没有使用,12 * 12 的字节,每两字节的最后 4 位是没有 使用,这个根据不同的字库会有不同的处理方式,所以在使用字库时要注意这个 问题,特别是 14 * 14 的字库。


1.3 汉字点阵获取

  • 利用区位码获取汉字

        汉字点阵字库是根据区位码的顺序进行存储的,因此,我们可以根据区位来
获取一个字库的点阵,它的计算公式如下:
点阵起始位置 = ((区码- 1)*94 + (位码 – 1)) * 汉字点阵字节数
获取点阵起始位置后,我们就可以从这个位置开始,读取出一个汉字的点阵。

  • 利用汉字机内码获取汉字

前面我们己经讲过,汉字的区位码和机内码的关系如下:
        机内码高位字节 = 区码 + 20H + 80H(或区码 + A0H)
        机内码低位字节 = 位码 + 20H + 80H(或位码 + AOH)

反过来说,我们也可以根据机内码来获得区位码:
        区码 = 机内码高位字节 - A0H
        位码 = 机内码低位字节 - AOH

将这个公式与获取汉字点阵的公式进行合并计就可以得到汉字的点阵位置。

2. 编程实现

2.1 创建文本文档

 创建文本文档并保存为ANSI格式

  • ANSI通常使用 0x80~0xFF 范围的 2 个字节来表示 1 个字符。Unicode字符分为17组编排,   UTF-8用1到6个字节编码UNICODE字符。
  • ANSI是一种字符代码,为使计算机支持更多语言,通常使用 0x80~0xFF 范围的 2 个字节来表示 1 个字符。表示英文字符时用一个字节,表示中文用两个或四个字节。
  • UTF-8(8-bit Unicode Transformation Format)是一种针对Unicode的可变长度字符编码,又称万国码。由Ken Thompson于1992年创建。现在已经标准化为RFC 3629。

可用ultraEdit查看文本中的十六进制编码

链接:https://pan.baidu.com/s/1R6t4u8KrAAuf0GCRRpivEQ 
提取码:qwer

可以看到宋健鑫对应的编码为CB  CE BD A1 F6 CE

2.2 打开Ubuntu 

  • 首先用cd命令到在ubuntu上安装的opencv的路径下

  • 编写addtext.cpp文件
#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="test.png";

char* logo_path="logo1.txt";

put_text_to_image(700,700,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;

 //存放ascii字膜

char buff[16];           

//打开ascii字库文件

FILE *ASCII;

if ((ASCII = fopen("Asci0816.zf", "rb")) == NULL){

	printf("Can't open ascii.zf,Please check the path!");

	//getch();

	exit(0);

}

fseek(ASCII, offset, SEEK_SET);

fread(buff, 16, 1, ASCII);

int i, j;

Point p1 = p;

for (i = 0; i<16; i++)                  //十六个char

{

	p.x = x_offset;

	for (j = 0; j < 8; j++)              //一个char八个bit

	{

		p1 = p;

		if (buff[i] & (0x80 >> j))    /*测试当前位是否为1*/

		{

			/*

				由于原本ascii字膜是8*16的,不够大,

				所以原本的一个像素点用4个像素点替换,

				替换后就有16*32个像素点

				ps:感觉这样写代码多余了,但目前暂时只想到了这种方法

			*/

			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;            //原来的一个像素点变为四个像素点,所以x和y都应该+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];//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);/*从偏移量的位置读取72个字节,每个汉字占72个字节*/

bool mat[24][24];//定义一个新的矩阵存放转置后的文字字膜

int i,j,k;

for (i = 0; i<24; i++)                 /*24x24点阵汉字,一共有24行*/

{

	for (j = 0; j<3; j++)                /*横向有3个字节,循环判断每个字节的*/

		for (k = 0; k<8; k++)              /*每个字节有8位,循环判断每位是否为1*/

			if (buff[i * 3 + j] & (0x80 >> k))    /*测试当前位是否为1*/

			{

				mat[j * 8 + k][i] = true;          /*为1的存入新的字膜中*/

			}

			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){//将汉字弄上图片
//x和y就是第一个字在图片上的起始坐标
//通过图片路径获取图片

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!");

	//getch();

	exit(0);

}

fseek(file_logo, 0, SEEK_SET);

fread(hexcode, length, 1, file_logo);

int x =x_offset,y = y_offset;//x,y:在图片上绘制文字的起始坐标

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);

        /*

        计算在汉字库中的偏移量

        对于每个汉字,使用24*24的点阵来表示的

        一行有三个字节,一共24行,所以需要72个字节来表示



        d5-af=38(十进制),因为是从汉字啊开始的,所以减去的是af而不是a0,38+15等于53与区码相对应

        d4-a0=52

        */

        m=m+2;//一个汉字的机内码占两个字节,

        x+=24;//一个汉字为24*24个像素点,由于是水平放置,所以是向右移动24个像素点

    }

    else{//当读取的字符为ASCII码时

    wh=hexcode[m];

    offset=wh*16l;//计算英文字符的偏移量

    paint_ascii(image,x,y,offset);

    m++;//英文字符在文件里表示只占一个字节,所以往后移一位就行了

    x+=16;

    }



}

cv::imshow("image", image);

cv::waitKey();

}

将需要的文本文档,汉字库,ASCII字库,拖进ubuntu的

Asci0816.zf和HZKf2424.hz可以用FONTSHOW查看

链接:https://pan.baidu.com/s/13HoayHz_QBeq5m3B05ddIg 
提取码:qwer

利用g++命令,编译生成执行文件

g++ addtext.cpp -o test `pkg-config --cflags --libs opencv`

输入

./test

运行程序

2.3 运行结果

 三、总结

        通过对点阵汉字的学习,明白了除了ASCII能编码英文之外,中文也能够进行编码,不过需要两位,为了与ASCII不冲突,引入了区位码和机内码。opencv的作用就是根据点阵图利用circle函数画实心圆代替像素点来绘字和字符。

参考文献:

汉字点阵字库原理.pdf

addtext(汉字叠加代码-函数模块化,非常灵活)-计科1503班-孙西从) (1)文件提取码qwer
 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值