汉字点阵与OLED屏显

一、串口传输文件的练习。将两台笔记本电脑,借助 usb转rs232 模块和杜邦线,建立起串口连接。然后用串口助手等工具软件(带文件传输功能)将一台笔记本上的一个大文件(图片、视频和压缩包软件)传输到另外一台电脑,预算文件大小、波特率和传输时间三者之间的关系,并对比实际传输时间。

1. 实验设备

两个USB TO TTL
两台PC机
杜邦线若干
串口助手软件

2.实际电路连接

USB TO TTL 1 USB TO TTL 2
TX RX
RX TX
GND GND

将两个模块的USB接口分别接入两台电脑上

3. 通过串口传输数据

打开串口调试助手,将波特率设置为115200,点击打开串口(两台电脑的串口都要打开)
在这里插入图片描述
选择一个文件进行传输
实际传输对比
开始传输后,发送端与接收端分别显示如下
发送端:
在这里插入图片描述
传输完成后
在这里插入图片描述

4.传输时间对比

计算理论传输时间
在串口助手打开了文件之后,显示文件大小为2220595字节
根据之前给出的计算公式,理论传输时间为216秒

传输时,使用手机同步计时,实际的传输时间为4*60+31=271秒,比理论计算的216秒与系统给出的理论实践200秒都要长,说明实际上通过串口传输的速率没办法达到理论峰值。

二. 学习理解汉字的机内码、区位码编码规则和字形数据存储格式。在Ubuntu下用C/C++(或python) 调用opencv库编程显示一张图片,并打开一个名为"logo.txt"的文本文件(其中只有一行文本文件,包括你自己的名字和学号),按照名字和学号去读取汉字24*24点阵字形字库(压缩包中的文件HZKf2424.hz)中对应字符的字形数据,将名字和学号叠加显示在此图片右下位置。

1、实验准备

一张需要显示的图片,24*24的点阵.hz文件,ASCII码.zf文件,需要显示的文本文件
在这里插入图片描述
请添加图片描述

2、撰写代码

创建一个word.cpp文件,在文件夹下打开终端,输入以下命令

gedit 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="Irene.jpg";//图片的名字
    char* logo_path="logo.txt";//汉字文件的名字
    put_text_to_image(200,350,image_path,logo_path);//change txt place
    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个字节来表示
            */

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


3、编译运行

保存好word.cpp文件

编译指令

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

请添加图片描述

4.运行效果

三. 理解OLED屏显和汉字点阵编码原理,使用STM32F103的SPI或IIC接口实现以下功能:

接线:
在这里插入图片描述

1、显示自己的学号和姓名;

文字取模
用C51格式生成点阵
在这里插入图片描述
a.存储代码

DB 08H 00H 08H 00H 0FH FEH 10H 08H 10H 08H 33H C8H 32H 48H 52H 48H 92H 48H 12H 48H 13H C8H 12H 48H 10H 08H 10H 08H 10H 28H 10H 10H;"何",0
DB 08H 40H 08H 40H 0BH FCH 10H 40H 10H 40H 30H 40H 3FH FEH 50H 00H 90H 40H 10H 40H 13H FCH 10H 40H 10H 40H 10H 40H 1FH FEH 10H 00H;"佳",1
DB 10H 40H 10H 40H 3CH FCH 21H 04H 42H 88H BCH 50H 10H 20H 10H 40H FCH 80H 11H FCH 12H 84H 10H 84H 14H 84H 18H 84H 10H FCH 00H 84H;"铭",2

b.实现显示代码

void TEST_MainPage(void) { 
GUI_ShowCHinese(28,20,16,"何佳铭",1);//中文姓名 
GUI_ShowString(4,48,"632107060601",16,1);//数字详细 
delay_ms(1500); delay_ms(1500); }

c.结果显示
在这里插入图片描述

**

2、显示AHT20的温度和湿度;

**
a.编写bsp_i2c.c中的read_AHT20函数

void read_AHT20(void)
{
	uint8_t   i;
	for(i=0; i<6; i++)
	{
		readByte[i]=0;
	}

	//-------------
	I2C_Start();

	I2C_WriteByte(0x71);
	ack_status = Receive_ACK();
	readByte[0]= I2C_ReadByte();
	Send_ACK();

	readByte[1]= I2C_ReadByte();
	Send_ACK();

	readByte[2]= I2C_ReadByte();
	Send_ACK();

	readByte[3]= I2C_ReadByte();
	Send_ACK();

	readByte[4]= I2C_ReadByte();
	Send_ACK();

	readByte[5]= I2C_ReadByte();
	SendNot_Ack();
	//Send_ACK();

	I2C_Stop();

	//--------------
	if( (readByte[0] & 0x68) == 0x08 )
	{
		H1 = readByte[1];
		H1 = (H1<<8) | readByte[2];
		H1 = (H1<<8) | readByte[3];
		H1 = H1>>4;

		H1 = (H1*1000)/1024/1024;

		T1 = readByte[3];
		T1 = T1 & 0x0000000F;
		T1 = (T1<<8) | readByte[4];
		T1 = (T1<<8) | readByte[5];

		T1 = (T1*2000)/1024/1024 - 500;

		AHT20_OutData[0] = (H1>>8) & 0x000000FF;
		AHT20_OutData[1] = H1 & 0x000000FF;

		AHT20_OutData[2] = (T1>>8) & 0x000000FF;
		AHT20_OutData[3] = T1 & 0x000000FF;
	}
	else
	{
		AHT20_OutData[0] = 0xFF;
		AHT20_OutData[1] = 0xFF;

		AHT20_OutData[2] = 0xFF;
		AHT20_OutData[3] = 0xFF;
		printf("lyy");

	}

	t=T1/10;
	t1=T1%10;
	a=(float)(t+t1*0.1);
	h=H1/10;
	h1=H1%10;
	b=(float)(h+h1*0.1);
	sprintf(strTemp,"%.1f",a);  
    sprintf(strHumi,"%.1f",b);    
	GUI_ShowCHinese(16,00,16,"温湿度",1);
	GUI_ShowCHinese(16,20,16,"温度",1);
	GUI_ShowString(53,20,strTemp,16,1);
	GUI_ShowCHinese(16,38,16,"湿度",1);
	GUI_ShowString(53,38,strHumi,16,1);
	delay_ms(1500);		
	delay_ms(1500);
}

b.编写main.c文件

#include "delay.h"
#include "usart.h"
#include "bsp_i2c.h"
#include "sys.h"

#include "oled.h"
#include "gui.h"
#include "test.h"

int main(void)
{	
	delay_init();	    	        	  
	uart_init(115200);	 
	IIC_Init();
		  
	NVIC_Configuration(); 	  	
	OLED_Init();			        
	OLED_Clear(0); 
	while(1)
	{
		
		read_AHT20_once();
		OLED_Clear(0); 
		delay_ms(1500);
  }
}


c…在oledfont.h文件中输入

    "何",0x08,0x00,0x08,0x00,0x0F,0xFE,0x10,0x08,0x10,0x08,0x33,0xC8,0x32,0x48,0x52,0x48,
0x92,0x48,0x12,0x48,0x13,0xC8,0x12,0x48,0x10,0x08,0x10,0x08,0x10,0x28,0x10,0x10,/*"何",0*/
    "佳",0x08,0x40,0x08,0x40,0x0B,0xFC,0x10,0x40,0x10,0x40,0x30,0x40,0x3F,0xFE,0x50,0x00,
0x90,0x40,0x10,0x40,0x13,0xFC,0x10,0x40,0x10,0x40,0x10,0x40,0x1F,0xFE,0x10,0x00,/*"佳",1*/
    "铭",0x10,0x40,0x10,0x40,0x3C,0xFC,0x21,0x04,0x42,0x88,0xBC,0x50,0x10,0x20,0x10,0x40,
0xFC,0x80,0x11,0xFC,0x12,0x84,0x10,0x84,0x14,0x84,0x18,0x84,0x10,0xFC,0x00,0x84,/*"铭",2*/


d.实物链接
在这里插入图片描述
SCL连接PB6,SDA连接PB7
e.效果
缺少采集模块,故无法实现.

3、上下或左右的滑动显示长字符,比如“Hello,欢迎来到重庆交通大学物联网205实训室!”或者一段歌词或诗词(最好使用硬件刷屏模式)。

a…编写mainc.文件

#include "delay.h"
#include "sys.h"
#include "oled.h"
#include "gui.h"
#include "test.h"
int main(void)
{	
	delay_init();	    	       
	NVIC_Configuration(); 	   
	OLED_Init();			        
	OLED_Clear(0);             
	OLED_WR_Byte(0x2E,OLED_CMD);      
  OLED_WR_Byte(0x27,OLED_CMD);        
  OLED_WR_Byte(0x00,OLED_CMD);        
	OLED_WR_Byte(0x00,OLED_CMD);      
	OLED_WR_Byte(0x07,OLED_CMD);       
	OLED_WR_Byte(0x07,OLED_CMD);        
	OLED_WR_Byte(0x00,OLED_CMD);        
	OLED_WR_Byte(0xFF,OLED_CMD);        
	TEST_MainPage();
	OLED_WR_Byte(0x2F,OLED_CMD);        
	while(1) 
	{	
		
	}
}

b.效果
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值