【开源】libserial_protocol:适用于单片机的串口通信协议基础库
借助五一假期,写了一个串口通信协议基础库,虽然写着适用于单片机,但实际上并不限制具体的硬件平台。
特点如下:
- 不涉及到具体硬件,libserial_protocol 纯软件协议,与具体硬件分离。
- 内存空间占用可控,libserial_protocol 支持动静态内存,内存空间可控。
- 接口简单容易复用,libserial_protocol 采用面向对象方式实现,提供大小数据量解码方式。
源码仓库:
gitee: libserial_protocol: 适用于单片机的串口通信协议基础库
github: https://github.com/lovemengx/libserial_protocol
一、接口定义
// 缓存数据结构(编解码不能同时使用同一块缓存)
typedef struct{
unsigned char *buf; // 缓存位置, 由用户指向一块可用的内存空间
unsigned int total; // 缓存大小, 标明该内存空间的总长度
}libserial_protocol_buf_t;
/*---------------------------------------------------------------------
* 函数: libserial_protocol_create
* 功能: 使用接口内部申请指定可用大小的空间
* 参数: size: 申请可用缓冲区大小
* 返回: NULL: 申请内存空间失败 >0: 申请成功
* 备注: 接口内部会多申请内部数据结构所需的空间大小
*---------------------------------------------------------------------*/
libserial_protocol_buf_t *libserial_protocol_create(unsigned int size);
/*---------------------------------------------------------------------
* 函数: libserial_protocol_release
* 功能: 释放接口内部申请的内存空间
* 参数: splbuf: 由 libserial_protocol_create() 创建的内存空间
* 返回: 0: 不满足最小长度要求 >0: 可供用户使用的大小
*---------------------------------------------------------------------*/
void libserial_protocol_release(libserial_protocol_buf_t *splbuf);
/*---------------------------------------------------------------------
* 函数: libserial_protocol_internal_size
* 功能: 返回内部数据结构占用字节数
* 参数:
* 返回: 返回内部数据结构占用字节数
*---------------------------------------------------------------------*/
unsigned int libserial_protocol_internal_size();
/*---------------------------------------------------------------------
* 函数: libserial_protocol_init
* 功能: 使用用户提供的或创建接口的缓冲区, 初始化内部数据结构
* 参数: splbuf: 缓冲区 size: 缓冲区大小
* 返回: 0: 不满足最小长度要求 >0: 可供用户使用的大小
*---------------------------------------------------------------------*/
unsigned int libserial_protocol_init(libserial_protocol_buf_t *splbuf);
/*---------------------------------------------------------------------
* 函数: libserial_protocol_reset
* 功能: 重置解码器
* 参数: splbuf: 缓冲区
* 返回: 无返回值
*---------------------------------------------------------------------*/
void libserial_protocol_decode_reset(libserial_protocol_buf_t *splbuf);
/*---------------------------------------------------------------------
* 函数: libserial_protocol_decode
* 功能: 解码数据
* 参数: splbuf: 缓冲区 indata: 输入数据 dalen: 解成功的数据长度
* 返回: 0: 正在解码 1:解码成功 -1: 校验失败
*---------------------------------------------------------------------*/
int libserial_protocol_decode(libserial_protocol_buf_t *splbuf, unsigned char indata, unsigned int *dalen);
/*---------------------------------------------------------------------
* 函数: libserial_protocol_decode_find
* 功能: 寻找数据区域(适合较大数据量)
* 参数: splbuf: 缓冲区 indata: 输入数据
* 返回: 0: 正在寻找 >0: 数据区域长度
*---------------------------------------------------------------------*/
unsigned int libserial_protocol_decode_find(libserial_protocol_buf_t *splbuf, unsigned char indata);
/*---------------------------------------------------------------------
* 函数: libserial_protocol_decode_copy
* 功能: 拷贝数据区域(适合较大数据量)
* 参数: splbuf: 缓冲区 indata: 输入数据 dalen: 输入的数据长度
* 返回: 0: 完成拷贝 -1: 校验失败 -2: 数据长度或解码状态错误
*---------------------------------------------------------------------*/
int libserial_protocol_decode_copy(libserial_protocol_buf_t *splbuf, unsigned char *indata, unsigned int len);
/*---------------------------------------------------------------------
* 函数: libserial_protocol_encode
* 功能: 数据编码
* 参数: splbuf: 缓冲区 indata: 输入数据 dalen: 输入的数据长度
* 返回: 0: 数据长度不合法 >0: 编码后的数据长度
*---------------------------------------------------------------------*/
unsigned int libserial_protocol_encode(libserial_protocol_buf_t *splbuf, const void *indata, unsigned int dalen);
二、示例代码
#include <stdio.h>
#include "libserial_protocol.h"
#define iprintf(format,...) printf("[inf]%s():%05d " format , __func__, __LINE__,##__VA_ARGS__)
/*---------------------------------------------------------------------
* 函数: static_libserial_protocol
* 功能: 演示采用静态内存方式进行两种方法解码
*---------------------------------------------------------------------*/
void static_libserial_protocol(const char *data, unsigned int length)
{
int result = 0;
unsigned int i = 0;
unsigned char buf1[512], buf2[512];
libserial_protocol_buf_t splbuf1, splbuf2;
// 使用静态内存
splbuf1.buf = buf1;
splbuf2.buf = buf2;
splbuf1.total = sizeof(buf1);
splbuf2.total = sizeof(buf2);
// 初始化内部数据结构
unsigned int avail1 = libserial_protocol_init(&splbuf1);
unsigned int avail2 = libserial_protocol_init(&splbuf2);
iprintf("avail1:%d avail2:%d\n", avail1, avail2);
// 对数据进行编码
unsigned int enbyte = libserial_protocol_encode(&splbuf1, data, length);
iprintf("enbyte:%d datalen:%d\n", enbyte, length);
// 使用最简单的方式解码, 适合小数据量
unsigned int debyte = 0x00;
for (i = 0; i < enbyte; i++) {
if ((result = libserial_protocol_decode(&splbuf2, splbuf1.buf[i], &debyte)) == 1) {
iprintf("simple mode: decode success debyte:%d data:[%s]\n", debyte, splbuf2.buf);
break;
}
}
// 使用较高性能方式解码, 适合大数据量
for (i = 0; i < enbyte; i++){
if ((debyte = libserial_protocol_decode_find(&splbuf2, splbuf1.buf[i])) > 0) {
if (libserial_protocol_decode_copy(&splbuf2, splbuf1.buf + i + 1, debyte) == 0) {
iprintf("comple mode: decode success debyte:%d data:[%s]\n", debyte, splbuf2.buf);
}
break;
}
}
iprintf("static run done...\n\n");
return;
}
/*---------------------------------------------------------------------
* 函数: static_libserial_protocol
* 功能: 演示采用动态内存方式进行两种方法解码
*---------------------------------------------------------------------*/
void dynamic_libserial_protocol(const char* data, unsigned int length)
{
int result = 0;
unsigned int i = 0;
libserial_protocol_buf_t* splbuf1, * splbuf2;
// 使用动态内存
splbuf1 = libserial_protocol_create(512);
splbuf2 = libserial_protocol_create(512);
if (!splbuf1 || !splbuf2) {
iprintf("create dynamic failed.\n");
libserial_protocol_release(splbuf1);
libserial_protocol_release(splbuf2);
return ;
}
// 初始化内部数据结构
unsigned int avail1 = libserial_protocol_init(splbuf1);
unsigned int avail2 = libserial_protocol_init(splbuf2);
iprintf("avail1:%d avail2:%d\n", avail1, avail2);
// 对数据进行编码
unsigned int enbyte = libserial_protocol_encode(splbuf1, data, length);
iprintf("enbyte:%d datalen:%d\n", enbyte, length);
// 使用最简单的方式解码, 适合小数据量
unsigned int debyte = 0x00;
for (i = 0; i < enbyte; i++) {
if ((result = libserial_protocol_decode(splbuf2, splbuf1->buf[i], &debyte)) == 1) {
iprintf("simple mode: decode success debyte:%d data:[%s]\n", debyte, splbuf2->buf);
break;
}
}
// 使用较高性能方式解码, 适合大数据量
for (i = 0; i < enbyte; i++) {
if ((debyte = libserial_protocol_decode_find(splbuf2, splbuf1->buf[i])) > 0) {
if (libserial_protocol_decode_copy(splbuf2, splbuf1->buf + i + 1, debyte) == 0) {
iprintf("comple mode: decode success debyte:%d data:[%s]\n", debyte, splbuf2->buf);
}
break;
}
}
// 释放内存空间
libserial_protocol_release(splbuf1);
libserial_protocol_release(splbuf2);
iprintf("dynamic run done...\n\n");
return;
}
int main(int argc, char* argv[])
{
char data[256] = { 0 };
// 填充数据, 最后一字节存储 '\0'
for (unsigned int i = 0, j = 0; i < sizeof(data) - 1; i++) {
data[i] = '0' + j;
j = '9' == data[i] ? 0 : j + 1;
}
static_libserial_protocol(data, sizeof(data));
dynamic_libserial_protocol(data, sizeof(data));
return 0;
}
三、代码运行结果

【开源】libserial_protocol:适用于单片机的串口通信协议基础库的更多相关文章
- 单片机modebus RTU通信实现,采用C语言,可适用于单片机,VC,安卓等(转)
源:单片机modebus RTU通信实现,采用C语言,可适用于单片机,VC,安卓等 //modebus_rtu.c /***************************************** ...
- 基于STM32之UART串口通信协议(一)详解
一.前言 1.简介 写的这篇博客,是为了简单讲解一下UART通信协议,以及UART能够实现的一些功能,还有有关使用STM32CubeMX来配置芯片的一些操作,在后面我会以我使用的STM32F429开发 ...
- 基于STM32之UART串口通信协议(三)接收
一.前言 1.简介 回顾上一篇UART发送当中,已经讲解了如何实现UART的发送操作了,接下来这一篇将会继续讲解如何实现UART的接收操作. 2.UART简介 嵌入式开发中,UART串口通信协议是我们 ...
- [51单片机] HC-SR04超声波测距仪 基础代码
>_<:超声波测距仪模块: >_<:51单片机,11.0592MHz晶振,将采集数据发送到串口的基础例子: >_<:代码: /******************* ...
- 自制单片机之十七……PC与单片机RS-232串口的通讯和控制
这次我们来试着一步步的去掌握PC与单片机通过RS-232进行通讯和控制. 先说说我硬件的情况.我用的PC是个二手的IBM240小本本,十寸屏,赛扬400,机子很老了.但也有它的优点:1.串口,并口,P ...
- UART串口协议基础1
Louis kaly.liu@163.com 串口协议基础 1 串口概述 串口由收发器组成.发送器是通过TxD引脚发送串行数据,接收器是通过RxD引脚接收串行数据. 发送器和接收器都利用了一个移位寄存 ...
- 基于STM32之UART串口通信协议(四)Printf发送
一.前言 1.简介 前面在UART发送中已经讲解过如何调用HAL库的HAL_UART_Transmit函数来实现串口发送,而在调用这个函数来实现串口发送的话,但是在发送数据或者字符的时候,需要将数据或 ...
- 基于STM32之UART串口通信协议(二)发送
一.前言 1.简介 在上一篇UART详解中,已经有了关于UART的详细介绍了,也有关于如何使用STM32CubeMX来配置UART的操作了,而在该篇博客,主要会讲解一下如何实现UART串口的发送功能. ...
- YARN底层基础库
YARN基础库是其他一切模块的基础,它的设计直接决定了YARN的稳定性和扩展性,YARN借用了MRV1的一些底层基础库,比如RPC库等,但因为引入了很多新的软件设计方式,所以它的基础库更多,包括直 ...
- ESP8266开发之旅 网络篇⑥ ESP8266WiFiGeneric——基础库
1. 前言 在前面的博文中,博主介绍到ESP8266WiFi库是包含了很多功能的一个超级库.ESP8266WiFi库不仅仅局限于 ESP8266WiFi.h 和 ESP8266WiFi.cpp ...
随机推荐
- 关系抽取--Relation Extraction: Perspective from Convolutional Neural Networks
一种使用CNN来提取特征的模型,通过CNN的filter的大小来获得不同的n-gram的信息,模型的结构如下所示: 输入 输入使用word2vec的50维词向量,加上 position embeddi ...
- 安装nvm 和 yarn
安装nvm curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash 执行上面的命令 如果出现问题 ...
- day09-Tomcat01
Tomcat01 1.WEB开发介绍 WEB,在英文中WEB表示网/网络资源,它用于表示WEB服务器(主机)供浏览器访问的资源 WEB服务器(主机)上供外界访问的Web资源为: 静态web资源(如ht ...
- C#设置picturebox滚动条来实现查看大图片
要给PictureBox添加滚动条需要以下步骤: (1)将picturebox放在panel上: ( 2)将panel的AutoScroll设置为ture: (3)将picturebo ...
- vue 3.0 常用api 的简介
vue3.0 生命周期 写法一 和vue2.x 一致 区别在于(beforeUnmount.unmount)名称不一样 写法二 在setup 中使用, 需要引用 如: import { onBefor ...
- 关于Wegame页面空白的问题解决
前言 前几天帮亲戚家装电脑系统,装好后发现 wegame 所有页面都不能正确加载(全部是空白页面),很神奇,在网上找了很多种解决办法都没有效果,后来不过细心的我发现360浏览器一直提示我证书不安全过期 ...
- c++学习笔记(入门)
1 struct和class的区别 struct成员变量(成员函数)的访问属性缺省的情况下默认为public. class成员变量(成员函数)的访问属性缺省的情况下默认为private. 2 初始化列 ...
- java 运用jxl 读取和输出Excel
文章结尾源码以及jxl包 1.输出excel: package JmExcel; import java.io.File; import java.io.FileOutputStream; impor ...
- VulnHub靶场渗透实战8-DarkHole: 2
靶场地址:DarkHole: 2 ~ VulnHub DescriptionBack to the Top Difficulty:Hard This works better with VMware ...
- JUC源码学习笔记6——ReentrantReadWriteLock
系列文章目录和关于我 阅读此文需要有AQS独占和AQS共享的源码功底,推荐阅读: 1.JUC源码学习笔记1--AQS独占模式和ReentrantLock 2.JUC源码学习笔记2--AQS共享和Sem ...