STM32之串口字库更新

news2024/11/22 16:13:26

1.串口通讯介绍

  串口通讯(Serial Communications)是一种通过串口进行数据传输的通讯方式,通过串行口每次传输一个字节的数据,按照约定的协议进行数据的传输和接收。串口通讯的原理是利用串行口的发送和接收线路,将需要传输的数据逐位传输到接收端,然后接收端再将这些数据组合成完整的信息。在传输过程中,数据是按照位(bit)进行发送和接收的,而不是按字节(byte)进行并行传输。

  串口通讯早期就定义了一套标准的串口规约,常见的接口标准包括RS-232、RS-485等。这些标准规定了接口的物理特性、电气特性、信号功能以及传输过程等。其中,RS-232是最常用的标准之一,它规定了使用数据信号线、地线、控制线等进行传输,适用于外设和计算机间的点对点通信。

  在连接方面,串口通讯通常使用DB9(9个引脚)或DB25(25个引脚)等接口进行连接。在这些接口中,GND(地线)、TXD(发送数据)、RXD(接收数据)是最基本的通信线,其他引脚则用于控制信号或握手信号等。

  • 通信参数与模式

  串口通讯需要双方事先约定好通信参数,这些参数包括波特率、数据位、校验位、停止位等。其中,波特率是指每分钟传输二进制的位数,是衡量资料传送速率的指标。数据位则是指一个通信单元发送的有效信息位,一般可选6、7、8、9位。校验位用于检错,有偶校验、奇校验、高校验和低校验等方式。停止位则表示本通信单元结束的标志。

  在通信模式方面,可以是单工、半双工或全双工模式。单工模式的数据传输是单向的,一方固定为发送端,一方固定为接收端。半双工模式则允许数据在两个方向上传输,但在任何时刻只能由其中一方发送数据,另一方接收数据。全双工模式则允许数据同时在两个方向上传输,需要发送设备和接收设备都有独立的接收和发送能力。

  • 特点与应用

  点对点通信:串口通信是一种点对点的通信方式,稳定性高、传输速度快,适用于一些对实时性要求较高的应用场景。

  通信距离短:串口通信的传输距离通常较短,一般在几十米以内,容易受到干扰。不过也有说法认为串口通讯的传输距离较长,可以达到几百米甚至更远(如IEEE488定义的并行通行设备线总长不得超过20米,任意两个设备间的长度不得超过2米,而串口长度可达1200米),这取决于具体的接口标准和传输条件。

  通信速率低:串口通信的传输速率通常较低,一般在几百到几千个比特每秒,难以满足一些高速数据传输的需求。
  硬件接口简单:串口通信使用的是串行接口,接口简单可靠,不需要复杂的硬件支持。

  支持多种通信协议:串口通信可以支持多种通信协议,如RS-232、RS-485、Modbus等,提供了灵活多样的通信方式。

  串口通讯在多个领域中得到广泛应用,包括工业自动化(用于控制和监控机器和生产线)、消费电子产品(如打印机、扫描仪等)、计算机网络(较早的计算机网络中用于连接调制解调器)、科研设备(如示波器、频谱分析器等)以及汽车电子(用于诊断系统)等领域。

2.串口通讯更新字库

  在STM32之LCD屏GBK字库制作与调用中介绍了字库的制作、烧写以及调用方式。但上述使用方法是将字库文件分割为多个数组直接写入。该方法适用于单个字库且字库文件相对较小的情况下进行烧写。本次将介绍利用串口通讯协议,实现串口方式下载更新字库文件。如下图所示:
在这里插入图片描述

2.1 协议介绍

  本协议采用发送–应答方式,每包数据固定4096字节(正文数据),带异或校验;
  协议格式:协议头 + 数据包大小 + 数据标志 + 数据包内容 + 异或校验值。数据均已16进制方式传输;
  协议头:77 62 79 71 --字符串”wbyq”十六进制ASCII值;
  数据包大小:固定两字节,高位在前;
  数据标志:01 —实体内容;
      02 —应答信息;
  数据包内容: 要发送的实际内容,单包数据正文最大4096字节;
  异或校验值:对发送的内容进行异或;
  编码格式:GBK/GB2312

  • 示例1

  • 发送内容:
    在这里插入图片描述

  • 应答信号:
    在这里插入图片描述

  • 示例2

  • 发送内容:
    在这里插入图片描述

  • 应答示例:
    在这里插入图片描述

2.2 协议数据解析示例

  按照文件传输协议格式,解析串口发送的数据内容,通过形参返回解析得到的内容和长度。

/*
串口文件传输数据解析
形参:src --原始内容
      count --src的字节数据
      buffer --保存解析的内容
			buffer_len  --接收的实体内容长度
返回值:0成功,其它值--失败
*/
u8 Usart_DataGet(const u8 *src,u16 count,u8 *buffer,u16 *buffer_len)
{
				/*
				77 62 79 71 0 6 1 31 32 33 34 35 36 7 
			
				77 62 79 71 --协议头
				0 6 --内容长度
				1 --标志符
				31 32 33 34 35 36 --实际内容
				7 --异或校验值
			*/	
	if(count<8)return 1;//长度错误
	if(src[0]!='w' || src[1]!='b' || src[2]!='y' || src[3]!='q')
	{
		return 2;//协议头错误
	}
	u16 len=src[4]<<8|src[5];//数据长度
	if(len<=0 || len>4096)return 3;//数据内容长度错误
	*buffer_len=len;
	u8 xor=0;//保存异或校验值
	if(src[6]!=0x1)return 4;//数据标志位错误
	u16 i=0;
	for(i=0;i<len;i++)
	{
		xor^=src[7+i];
		buffer[i]=src[7+i];
	}
	if(xor!=src[7+i])return 5;//校验出错
	return 0;//数据接收正常
}

2.3 应答发送

/*
发送应答
*/
void Usart_SendAck(u8 stat)
{
	u8 data[10]={0x77,0x62,0x79,0x71,0x0,0x1,0x02};
	u8 xor=0;//保存异或校验值
	data[7]=stat;//应答状态
	xor^=stat;
	data[8]=xor;//异或校验值
	Usartx_SendData(USART1,data,9);//发送应答
}

2.4 字库更新

#include "stm32f10x.h"
#include "sys.h"
#include "beep.h"
#include "delay.h"
#include "led.h"
#include "key.h"
#include "usart.h"
#include "timer.h"
#include "infrared.h"
#include "w25q64.h"
#include "at24c08.h"
#include "nt35310.h"
u8 Usart_DataGet(const u8 *src,u16 count,u8 *buffer,u16 *buffer_len);
void Usart_SendAck(u8 stat);
u8 buffer[4096];
u16 buffer_len;
int main()
{
	u8 key=0;
	Beep_Init();
	Led_Init();
	Key_Init();
	Usartx_Init(USART1,921600,72);
	TIMx_Init(TIM2,72,20*1000);
	printf("USART1初始化完成\r\n");
	u16 id=W25Q64_Init();
	printf("id=%#x\r\n",id);
	I2C_Init();//初始化硬件
	
	NT35310_Init();
	LCD_DisplayStr(100,200,16,"GBK Update:",RED);
	u16 i=0;
	u8 ret;
	u32 addr=0;
	char arr[100];
	while(1)
	{
		if(usart1_flag)
		{
			//usart1_rx_buff[usart1_cnt]='\0';
			//printf("usart1:%s\r\n",usart1_rx_buff);
			/*
				77 62 79 71 0 6 1 31 32 33 34 35 36 7  -->十六进制
			
				77 62 79 71 --协议头
				0 6 --内容长度
				1 --标志符
				31 32 33 34 35 36 --实际内容
				7 --异或校验值
			*/
			ret=Usart_DataGet(usart1_rx_buff,usart1_cnt,buffer,&buffer_len);
			if(ret==0)
			{
				//将字库信息写入到W25Q64
				W25Q64_KuaPageProgram_Erase(GBK_24_ADDR+addr,buffer,buffer_len);
				addr+=buffer_len;
				snprintf(arr,sizeof(arr),"%.1f KB",addr*1.0/1024);
				LCD_DisplayStr(100+11*8,200,16,arr,RED);
				LED1=!LED1;
			}
			Usart_SendAck(ret);
			if(buffer_len<4096)
			{
				printf("字库更新完成\r\n");
				LCD_DisplayStr(10,240,24,"串口字库更新应用示例",RED);
			}
			//printf("ret=%d\n",ret);
			usart1_flag=0;
			usart1_cnt=0;
		}
		
	}
}

2.5 字库更新运行效果

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3 字库合并

  若一次性需要烧写多个字库,则可以将多个字库合并为一个字库文件,代码实现如下:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
//字库合并
int main(int argc,char **argv)
{
	if(argc<3)
	{
		printf("运行格式:./app <字库文件1>、<字库文件2>、<字库文件3>....\n");
		return 0;
	}
	int i=0;
	char  *font_file[5];
	int file_cnt=0;
	unsigned int font_size[5];
	unsigned int font_count=0;
	int ret;
	for(i=1;i<argc;i++)
	{
		font_file[file_cnt]=argv[i];
		struct stat statbuf;
		ret=stat(font_file[file_cnt],&statbuf);//获取文件大小
		if(statbuf.st_size<=0 || ret)//保证能正常获取到文件大小
		{
			continue;
		}
		font_size[file_cnt]=statbuf.st_size;
		printf("字库文件%d:%s\t大小:%d byte\n",i,font_file[file_cnt],font_size[file_cnt]);
		file_cnt++;
	}
	if(file_cnt<2)
	{
		printf("合并文件少于2个,请检查要合并的文件是否正常\n");
		return 0;
	}
	const char *dest_file="font.bin";//合并后的目标文件
	//创建目标文件
	FILE *dest_fp=fopen(dest_file,"w+b");
	if(dest_file==NULL)
	{
		printf("目标文件%s文件创建失败\n",dest_file);
		return 0;
	}
	char buffer[4096];
	int size=0;
	int j=0;
	//打开文件
	for(i=0;i<file_cnt;i++)
	{
		FILE *fp=fopen(font_file[i],"rb");
		if(fp==NULL)
		{
			printf("%s 文件打开失败,请检查文件是否正常\n",font_file[i]);
			return 0;
		}
		printf("字库文件%d正在写入....\n",i+1);
		printf("文件大小:%d\t,写入的起始位置:%d\n",font_size[i],font_count);
		while(1)
		{
			size=fread(buffer,1,sizeof(buffer),fp);//读取源文件内容
			fwrite(buffer,size,1,dest_fp);//将内容写入到新文件中
			font_count+=size;
			if(size!=sizeof(buffer))break;
		}
		if(size%1024)//保证每次写入为1024的倍数
		{
			char data=0;
			//不足1024用0补齐
			for( j=0;j<1024-size%1024;j++)
			{
				fwrite(&data,1,1,dest_fp);
			}
			font_count+=j;
		}
	}
	printf("文件合并完成,合并后的文件为:%s,\t文件大小:%.1f MB\n",dest_file,font_count*1.0/1024/1024);
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2231012.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

立刻解决 gcc: error: unrecognized argument in option ‘-mabi=aapcs-linux’

unrecognized argument in option ‘-mabiaapcs-linux’ Linux 主线支持的硬件较少&#xff0c;一般是第三方开源&#xff08; Linaro/Yocto &#xff09;或者硬件厂商提供定制的嵌入式 Linux 如果确认主线支持自己的硬件&#xff0c;可以从 https://www.kernel.org/ 获取指定…

法律智能助手:开源NLP系统助力法律文件高效审查与检索

一、系统概述 思通数科AI平台是一款融合了自然语言处理和多标签分类技术的开源智能文档分类工具&#xff0c;特别适用于法律行业。平台采用深度学习的BERT模型来进行特征提取与关系抽取&#xff0c;实现了精准的文档分类和检索。用户可以在线训练和标注数据&#xff0c;使系统…

ChatGPT新体验:AI搜索功能与订阅支付指南

就在凌晨&#xff0c;在ChatGPT迎来两周岁生日之际&#xff0c;OpenAI重磅发布了ChatGPT的全新人工智能搜索体验。 期待已久的时刻终于到来&#xff0c; ChatGPT正式转型成为一款革命性的AI搜索引擎! 先来看看ChatGPT搜索&#xff1a;这次不是简单的加个搜索框&#xff0c;而…

【零售和消费品&家居用品】家庭门窗开闭状态安全监控系统源码&数据集全套:改进yolo11-DCNV2

改进yolo11-GhostDynamicConv等200全套创新点大全&#xff1a;家庭门窗开闭状态安全监控系统源码&#xff06;数据集全套 1.图片效果展示 项目来源 人工智能促进会 2024.11.01 注意&#xff1a;由于项目一直在更新迭代&#xff0c;上面“1.图片效果展示”和“2.视频效果展示”…

合并区间 leetcode56

合并区间leetcode 目录一、题目二、踩坑过程三、上官方解答四、含泪体会彩蛋 目录 一、题目 二、踩坑过程 一开始想使用一个数组来标记区间&#xff0c;但是仔细想不好实现&#xff0c;单纯把区间里出现的设置为1&#xff0c;不好体现重叠的概念&#xff0c;如果使用三种状态…

【Linux】- 权限

目录 一、Linux常用热键 &#xff08;1&#xff09;、history&#xff1a; &#xff08;2&#xff09;、单击tab键 / 双击tab键 &#xff08;3&#xff09;、快捷键ctrl c 和 ctrl d 二、关机指令 shutdown 三、window与linux互传文件 四、不同linux系统间互传文件 …

C++(友元、异常机制、静态成员、单例模式)

友元 友元可以访问与其好友关系的类中的私有成员&#xff0c;使用friend关键字进行修饰。&#xff08;友元破坏了类的封装性&#xff09;。 特点 &#xff08;1&#xff09;友元是单向的 &#xff08;2&#xff09;友元不能传递 &#xff08;3&#xff09;友元…

Halcon区域分割之分水岭分割法

现实中我们见到过有山有湖的景象&#xff0c;那么一定是水绕山、山围水的情形。当然可在需要的时候人工构筑分水岭&#xff0c;以防集水盆之间的互相穿透。而区分高山与水的界线以及湖与湖之间的间隔&#xff0c;就是分水岭。 分水岭分割法是一种基于拓扑理论的数学形态…

【python】OpenCV—Tracking(10.4)—Centroid

文章目录 1、任务描述2、人脸检测模型3、完整代码4、结果展示5、涉及到的库函数6、参考 1、任务描述 基于质心实现多目标&#xff08;以人脸为例&#xff09;跟踪 人脸检测采用深度学习的方法 核心步骤&#xff1a; 步骤#1&#xff1a;接受边界框坐标并计算质心 步骤#2&…

使用Jupyter Notebook进行数据科学项目

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 使用Jupyter Notebook进行数据科学项目 Jupyter Notebook 简介 安装 Jupyter Notebook 创建和管理 Notebook 编写和运行代码 示例…

MR30分布式IO:石化行业的智能化革新

在浩瀚的工业领域中&#xff0c;石化行业如同一座巨大的化工厂&#xff0c;将自然界的原始资源转化为人们日常生活中不可或缺的各种产品。然而&#xff0c;随着生产规模的扩大和工艺复杂度的提升&#xff0c;石化行业面临着前所未有的挑战&#xff1a;如何在保证生产效率的同时…

Android 使用ninja加速编译的方法

ninja的简介 随着Android版本的更迭,makefile体系逐渐增多,导致make单编模块的时间越来越长,每次都需要半个小时甚至更长时间,其原因为每次make都会重新加载所有mk文件,再生成ninja编译,此完整过程十分耗时,实际编译代码仅占其中的一小部分。 因此我们可以使用google提…

要在微信小程序中让一个 `view` 元素内部的文字水平垂直居中,可以使用 Flexbox 布局

文章目录 主要特点&#xff1a;基本用法&#xff1a;常用属性&#xff1a; 要在微信小程序中让一个 view 元素内部的文字水平垂直居中&#xff0c;可以使用 Flexbox 布局。以下是如何设置样式的示例&#xff1a; .scan-button {display: flex; /* 启用 Flexbox 布局 */justify…

网关如何传递信息给微服务

前情回顾 上篇我们已经完成了网关对所有微服务请求的拦截以及JWT的登录校验。 客户端和微服务之间的桥梁--网关&#xff08;身份校验&#xff09;https://mp.csdn.net/mp_blog/creation/editor/143425484 问题引入 现在的问题是在一些微服务业务中&#xff0c;需要用到用户…

ubuntu 24.04中安装 Easyconnect,并解决版本与服务器不匹配问题

下载安装包 下载地址 https://software.openkylin.top/openkylin/yangtze/pool/all/ 页面搜索 easyconnect 选择 easyconnect_7.6.7.3.0_amd64.deb安装 sudo dpkg --install easyconnect_7.6.7.3.0_amd64.deb卸载 sudo dpkg --remove easyconnect出现的问题 安装以后第…

Learn QOpenGL 读取obj模型

/* ** File name: OpenGLModelWidget.h ** Author: ** Date: 2024-10-31 ** Brief: 读取模型文件并渲染的OpenGL控件 ** Copyright (C) 1392019713qq.com All rights reserved. */#ifndef OpenGLModelWidget_H #define OpenGLModelWidget_H#include…

C++入门基础知识133—【关于C 库函数 - asctime()】

成长路上不孤单&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a; 【14后&#x1f60a;///C爱好者&#x1f60a;///持续分享所学&#x1f60a;///如有需要欢迎收藏转发///&#x1f60a;】 今日分享关于C 库函数 - asctime()的相关内容&#x…

Java版企电子招标采购系统源业码Spring Cloud + Spring Boot +二次开发+ MybatisPlus + Redis

功能描述 1、门户管理&#xff1a;所有用户可在门户页面查看所有的公告信息及相关的通知信息。主要板块包含&#xff1a;招标公告、非招标公告、系统通知、政策法规。 2、立项管理&#xff1a;企业用户可对需要采购的项目进行立项申请&#xff0c;并提交审批&#xff0c;查看所…

沟通工具选错了,团队效率会下降多少?

沟通工具的选择对团队的工作效率和协作能力有着直接影响。选用不当的沟通工具可能导致信息传递不畅、工作效率低下、团队士气下降等严重后果。具体来说&#xff0c;沟通不畅会造成误解、信息延迟和团队合作困难。例如&#xff0c;使用不适合团队规模和工作流程的工具&#xff0…

ElasticSearch - Bucket Script 使用指南

文章目录 官方文档Bucket Script 官文1. 什么是 ElasticSearch 中的 Bucket Script&#xff1f;2. 适用场景3. Bucket Script 的基本结构4. 关键参数详解5. 示例官方示例&#xff1a;计算每月 T 恤销售额占总销售额的比率百分比示例计算&#xff1a;点击率 (CTR) 6. 注意事项与…