目录
2.学习理解汉字的机内码、区位码编码规则和字形数据存储格式。在Ubuntu下用C/C++(或python) 调用opencv库编程显示一张图片,并打开一个名为"logo.txt"的文本文件(其中只有一行文本文件,包括你自己的名字和学号),按照名字和学号去读取汉字24*24点阵字形字库(压缩包中的文件HZKf2424.hz)中对应字符的字形数据,将名字和学号叠加显示在此图片右下位置。
3.理解OLED屏显和汉字点阵编码原理,使用STM32F103的SPI或IIC接口实现以下功能: 1) 显示自己的学号和姓名; 2) 显示AHT20的温度和湿度; 3) 上下或左右的滑动显示长字符,比如“Hello,欢迎来到重庆交通大学物联网205实训室!”或者一段歌词或诗词(最好使用硬件刷屏模式)。
1. 串口传输文件的练习。将两台笔记本电脑,借助 usb转rs232 模块和杜邦线,建立起串口连接。然后用串口助手等工具软件(带文件传输功能)将一台笔记本上的一个大文件(图片、视频和压缩包软件)传输到另外一台电脑,预算文件大小、波特率和传输时间三者之间的关系,并对比实际传输时间。
串口传输文件是一种传统的数据传输方式,在某些场景下仍然被使用。在练习中,我们需要完成以下步骤:
-
准备材料:两台笔记本电脑、USB转RS232模块、杜邦线。
-
连接设备:将USB转RS232模块的USB端连接到一台笔记本电脑的USB接口上,然后将杜邦线连接至模块的RS232端口和另一台笔记本电脑的串口(通常为DB9接口)。
-
配置串口:打开计算机的设备管理器,找到串口设备,并设置波特率、数据位、停止位等参数。确保两台电脑的串口参数一致。
-
安装串口助手软件:在两台电脑上都安装串口助手或类似的工具软件,以实现串口通信和文件传输功能。
-
选择文件并传输:在源电脑上选择您要传输的文件(如图片、视频或压缩包),通过串口助手软件的文件传输功能发送该文件。在目标电脑上,使用串口助手接收并保存传输的文件。
-
记录传输时间:在传输过程中记录传输的时间,可以使用计时工具或手动记录开始和结束时间。根据传输所花费的时间,计算传输速率。
-
比较实际传输时间:比较实际传输时间与预估的文件大小和波特率的关系,观察它们之间的相关性。
2. 学习理解汉字的机内码、区位码编码规则和字形数据存储格式。在Ubuntu下用C/C++(或python) 调用opencv库编程显示一张图片,并打开一个名为"logo.txt"的文本文件(其中只有一行文本文件,包括你自己的名字和学号),按照名字和学号去读取汉字24*24点阵字形字库(压缩包中的文件HZKf2424.hz)中对应字符的字形数据,将名字和学号叠加显示在此图片右下位置。
汉字的机内码、区位码编码规则和字形数据存储格式是汉字计算机处理的重要基础,这里简单介绍一下。
机内码是指计算机内部用来表示一个字符的二进制编码。在GB2312和GBK国家标准中,一个汉字使用两个字节的16进制数表示。第一字节,即高字节的范围是0xB0-0xF7(对应176-247),第二字节,即低字节的范围是0xA1-0xFE(对应161-254)。两个字节的二进制形式一共可以表示216 * 94 = 17,664个汉字。
区位码则是指将一个汉字的Unicode编号,即字符的十进制或十六进制表示,转换为区码和位码分别表示高低字节。例如“工”字的Unicode编号是0x5DE5,对应的区码=0x5D(93),位码=0xE5(229)。
字形数据存储格式指的是将一个汉字的字形图像按照行列顺序排列成点阵数据,然后采用不同的方式存储在文件中。有些字形点阵数据文件采用写满一行后再换行的方式存储,有些则采用跨行存储的方式。在本题中,您需要使用HZKf2424.hz字库文件,该字库中汉字的点阵数据编码方式是行列式排列,3660个汉字(GB2312字符集的全部字符)以连续的形式存储在文件中。
简单示例代码如下:
#include <iostream>
#include <fstream>
#include "opencv2/opencv.hpp"
using namespace std;
using namespace cv;
#define HZK_SIZE 24 //字库点阵大小
#define HZK_NUM 3761 //字库中的汉字数目
int main(int argc, char *argv[])
{
const char* textFile = "logo.txt";
const char* hzkFile = "HZKf2424.hzk";
char name[20];
char id[20];
// 读取姓名和学号
ifstream fin(textFile);
fin >> name >> id;
fin.close();
// 打开字库文件
FILE *fp = fopen(hzkFile, "rb");
if (fp == NULL)
{
printf("Failed to open the hzk file: %s", hzkFile);
return -1;
}
// 加载图片
Mat img = imread("image.jpg");
if (img.empty())
{
printf("Failed to load image file.");
return -1;
}
// 创建一个24*24的中间模板
Mat hzkTemp(HZK_SIZE, HZK_SIZE, CV_8U);
// 在图片右下位置绘制姓名和学号
int x = img.cols - (strlen(name) + strlen(id)) * HZK_SIZE;
int y = img.rows - HZK_SIZE;
for (int i = 0; i < strlen(name); i++)
{
// 获取汉字的区位码
unsigned char q = (unsigned char)name[i] - 0xA0;
unsigned char w = (unsigned char)name[i + 1] - 0xA0;
// 计算偏移量
unsigned int offset = (94 * (q - 1) + (w - 1)) * HZK_SIZE * HZK_SIZE;
// 读取点阵数据
fseek(fp, offset, SEEK_SET);
fread(hzkTemp.data, 1, HZK_SIZE * HZK_SIZE, fp);
// 在图像中绘制字形
Mat roi = img(Rect(x, y, HZK_SIZE, HZK_SIZE));
hzkTemp.copyTo(roi);
x += HZK_SIZE;
i++;
}
for (int i = 0; i < strlen(id); i++)
{
// 获取汉字的区位码
unsigned char q = (unsigned char)id[i] - 0xA0;
unsigned char w = (unsigned char)id[i + 1] - 0xA0;
// 计算偏移量
unsigned int offset = (94 * (q - 1) + (w - 1)) * HZK_SIZE * HZK_SIZE;
// 读取点阵数据
fseek(fp, offset, SEEK_SET);
fread(hzkTemp.data, 1, HZK_SIZE * HZK_SIZE, fp);
// 在图像中绘制字形
Mat roi = img(Rect(x, y, HZK_SIZE, HZK_SIZE));
hzkTemp.copyTo(roi);
x += HZK_SIZE;
i++;
}
//释放资源
fclose(fp);
hzkTemp.release();
// 显示图像
namedWindow("Image", WINDOW_NORMAL);
imshow("Image", img);
waitKey(0);
return 0;
在此程序中,我们首先读取文本文件“logo.txt”中的姓名和学号,打开HZKf2424.hz字库文件,在图片的右下位置绘制姓名和学号对应的汉字。最后,将结果图像显示在窗口中,等待用户按下键盘。 需要注意的是,在运行此程序之前,您需要先把“image.jpg”图片文件和“HZKf2424.hz”字库文件放在同一目录下,并且确保您的计算机上已经正确安装了OpenCV库。
代码的功能:
// 打开HZK字库文件
FILE* fp = fopen("HZKf2424.hz", "rb");
// 若文件打开失败,则退出程序
if (!fp) {
cout << "Can't open hzk file!" << endl;
return -1;
}
这段代码打开了HZK字库文件,使用了C语言标准库中的“fopen”函数。如果打开文件失败,则程序将输出一条错误信息并退出运行。
// 循环读取每一个汉字
for (int i = 0; i < strlen(id); i++) {
unsigned char q = (unsigned char)id[i] - 0xA0;
// 若此汉字是全角字符,则解析双字节编码
if (q >= 0 && q <= 15) { // 确认是否为汉字,为16进制00-0Fh范围内
unsigned char w = (unsigned char)id[i + 1] - 0xA0;
// 计算偏移量
unsigned int offset = (94 * (q - 1) + (w - 1)) * HZK_SIZE * HZK_SIZE;
// 读取点阵数据
fseek(fp, offset, SEEK_SET);
fread(hzkTemp.data, 1, HZK_SIZE * HZK_SIZE, fp);
// 在图像中绘制字形
Mat roi = img(Rect(x, y, HZK_SIZE, HZK_SIZE));
hzkTemp.copyTo(roi);
x += HZK_SIZE;
i++;
}
else { // 若不是汉字,使用英文字符代替
putText(img, string(1, id[i]), Point(x, y), FONT_HERSHEY_SIMPLEX, 1, Scalar(0, 0, 255), 2);
x += 20;
}
}
这段代码是主要的绘图逻辑,先通过循环读取名字中的每个汉字。如果当前汉字是全角字符,则解析双字节编码,计算出该汉字在HZK字库文件中的偏移量,然后从文件中读取该汉字的点阵数据,再在图像中绘制该汉字。若此字符不是汉字,那么我们就用英文字符来代替。
// 释放资源
fclose(fp);
hzkTemp.release();
// 显示图像
namedWindow("Image", WINDOW_NORMAL);
imshow("Image", img);
waitKey(0);
return 0;
最后,我们释放文件指针和临时图像变量的内存,再将结果图像显示在窗口中,并等待用户按下键盘才退出。
3. 理解OLED屏显和汉字点阵编码原理,使用STM32F103的SPI或IIC接口实现以下功能: 1) 显示自己的学号和姓名; 2) 显示AHT20的温度和湿度; 3) 上下或左右的滑动显示长字符,比如“Hello,欢迎来到重庆交通大学物联网205实训室!”或者一段歌词或诗词(最好使用硬件刷屏模式)。
这是一个比较复杂的任务,需要使用STM32F103的SPI或IIC接口连接到OLED屏幕,并实现涉及到的功能。以下是实现这些功能的基本步骤:
-
首先需要选择合适的OLED屏幕,根据屏幕的驱动器芯片来确定需要使用的接口。
-
在STM32F103上初始化SPI或IIC接口,以便与OLED屏幕通信。需要注意的是,不同的OLED屏幕厂家、型号和接口实现可能需要不同的初始化设置。
-
对汉字进行点阵编码,将学号和姓名编码为汉字点阵数据。需要注意的是,点阵大小是16x16或24x24,通常按16位或24位分为两个字节。编码可以参考GB2312、GB18030、Unicode等编码体系。
-
在OLED屏幕上显示学号和姓名。这可以通过向屏幕发送点阵数据的方式来实现。需要按照屏幕的显示规格将点阵数据进行适当调整和填充。
-
连接AHT20温湿度传感器,读取传感器数据。可以使用IIC或SPI接口与传感器通信,读取传感器输出的数字化数据。
-
将AHT20返回的温度和湿度数据转换为可以显示的信息,如需要将温度和湿度显示为字符串的形式。
-
在OLED屏幕上显示温度和湿度。这可以通过向屏幕发送字符串的方式来实现。需要按照屏幕的显示规格将字符串进行适当调整和填充。
-
编写一个函数来实现上下或左右滑动显示较长的文本。该函数需要将文字分成多个屏幕页、按行排列,并在每个屏幕页中绘制文本。需要注意的是,在绘制文本时应根据OLED屏幕的显示规格进行字体大小和行距的适当调整。
-
将滑动显示文本的函数与OLED屏幕的SPI或IIC接口结合起来,以便在屏幕上显示长文本。
-
在主程序中,调用以上函数来实现显示所有信息。在实现过程中需要注意时间延迟的问题,以免芯片和OLED屏幕之间的通信出现错误。
以下是一个使用STM32F103系列微控制器和SPI接口驱动OLED SSD1306屏幕显示学号和姓名的示例代码:
#include "stm32f10x.h"
#include "ssd1306.h" // SSD1306屏幕驱动库
#define OLED_SPI_PORT SPI1 // 使用SPI1接口
#define OLED_CS_PIN GPIO_Pin_4 // OLED屏幕的片选引脚
#define OLED_DC_PIN GPIO_Pin_5 // OLED屏幕的数据/命令选择引脚
// 像素缓冲区,用于存储8x16的汉字点阵数据
uint8_t buffer[16];
// 学号和姓名
char* studentID = "1234567890";
char* studentName = "John Doe";
// OLED屏幕初始化
void OLED_Init() {
// ... 初始化SPI1接口、GPIO引脚等 ...
// 具体的初始化步骤可以参考SSD1306屏幕的驱动库
// 例如,设置SPI为主机模式,使能SPI时钟,配置GPIO引脚等
// 调用相关的硬件初始化函数
}
// 将汉字字符绘制在OLED屏幕上
void OLED_DrawChinese(uint8_t x, uint8_t y, uint16_t code) {
// code为汉字字符的编码,参考GB2312或Unicode编码表
// 从字库或字模文件中读取相应的点阵数据,并填充到buffer中
// 然后调用OLED屏幕绘制函数将buffer中的点阵数据显示在指定位置
// 需要根据OLED屏幕实际显示规格来确定点阵数据的填充方式和显示位置
}
// 在OLED屏幕上显示学号和姓名
void OLED_DisplayInfo() {
// 清空屏幕
OLED_Clear();
// 设置字体大小和显示位置
OLED_SetFontSize(16, 16);
OLED_SetCursor(0, 0);
// 显示学号
OLED_DrawString(studentID);
// 设置字体大小和显示位置
OLED_SetFontSize(16, 16);
OLED_SetCursor(0, 16);
// 显示姓名
OLED_DrawString(studentName);
// 刷新屏幕,使绘制的图像显示在屏幕上
OLED_Refresh();
}
int main() {
// 初始化OLED屏幕和SPI接口
OLED_Init();
// 显示学号和姓名
OLED_DisplayInfo();
while (1) {
// 其他功能逻辑或操作
}
}
以上示例代码只是一个简单的框架,仅包含部分关键函数和变量的示例。