STM32 | 分享自定义协议的一些典型例子

发布者:滁州鱼儿最新更新时间:2021-08-10 来源: eefocus关键字:STM32  自定义协议 手机看文章 扫描二维码
随时随地手机看文章

上次分享的《分享一个很酷的上位机软件》中,有如下协议:

有位读者朋友问数据为什么要按这样的格式来发。其实这是个自定义协议,这是上位机开发者定义的一个数据交互协议。


我们下位机往伏特加上位机发送数据需要遵循这样的协议数据,才能保证上位机能正确识别这些数据。


关于自定义协议,对于会的人很简单,对于不会的人就摸不着头脑。下面分享一些关于自定义协议的笔记,希望能对初学者有帮助,也希望大神们能多多指出不足。


什么是协议?

协议这个概念我觉得挺杂的。就像嵌入式的概念一样,说法不一,比如大家常常争论FPGA是不是嵌入式、单片机是不是属于嵌入式等等。下面简单看一下嵌入式中协议这个概念。


在互联网领域,协议常常指的是网络协议。


在嵌入式中,协议按大类分主要可分为底层协议(硬件层协议/物理层协议)与上层协议(用户层协议/应用层协议),根据实际还可细分成很多层。


底层协议如串口、SPI、I2C等,底层协议决定着数据传输的方式(传输数据需要多少条信号线,传输数据的时序是怎样的)。上层协议决定着这些数据是拿来干什么用的。太难解释了。。看实例吧:

这是多功能电能表的协议通讯协议,其中底层协议是485通讯,上层协议有很多条,但格式基本都统一:

每一帧(包)数据的格式都类似是这样子的格式,例如读数据协议:

主站往从站发送数据(控制器->智能电表):

从站往主站发送数据(智能电表->控制器):

明确了协议之后,该发什么数据、收到的数据是怎么样我们都心里有数,那么这个通信的过程就很明朗了。


一般控制器往外发送协议数据都比较简单,重点是返回数据的处理(解析),解析方式根据协议的不同而有不同的方法。


协议(上层协议)按照通用性来分可以分为专有协议与自定义协议,例如上面电表的协议其实是专有协议(具有一些标准的协议):

自定义协议就是我们开发者可以针对一些应用、一些需求自己制定的一些协议。下面来分享一些常见的自定义协议:


常见的自定义协议

在我们嵌入式开发中,自定义协议的应用很多。例如上下位机之间的通讯、控制器与控制器之间的通讯、服务器与设备终端之间的通讯等。


自定义协议也没有什么特定的规范、标准,可以很灵活地制定,只要能满足开发需要即可。下面依旧以实例来做分享:


例子一(典型):

之前有个物联网项目,服务器往我们终端设备发送的协议数据类似于:

我们设备终端需要用到协议数据中字段的实际数据,整个数据包是字符串的形式,这时候可以用sscanf函数来做解析:


char tmpBuf[TMP_BUF_LEN];

char *cmd_str = tmpBuf;

uint16_t num = 0;

uint16_t devid = 0;


if (sscanf(buf, "Data=%s,%d,%d", cmd_str, &num, &devid)!=3 )

{

    return -1;

}


关于sscanf函数就不做解释了,不会的朋友自行百度。sscanf函数在做类似的解析非常好用,很多时候都可以使用。如:

因为是两端通讯,当然要确保通讯的正确性。比如服务器往设备发送数据,怎么知道有没有发送,这就得设备端在收到数据的同时回应相应的数据包。


可以使用与sscanf函数相对应的sprintf函数做组包操作。比如(这个sprintf例子与上例无关,只是为了说明一下sprintf的用法):

一端给另一端发送数据一般有两种,以设备端在往服务端发送数据为例:

(1)当设备收到服务端的数据时,会回应与之对应的数据,这称为被动应答。

(2)设备主动给服务端发送数据,例如设备常常定时、主动地给服务端发送一些时间戳信息等(俗称心跳包),这样服务端就知道设备是在正常工作的(活着的状态)。这称为主动发送或主动申请。


在处理这些字符串形式的协议数据的时候用sscanf、sprintf、strcmp、strstr、strcat等函数非常方便,有时候可以搭配正则表达式来做匹配。


例子二(典型):

之前有个项目需要从控制板显示主控制板的运行状态,两控制板之间使用的底层协议为485协议。上层协议(从控板接收数据协议)如:

这里省略的部分为其他信息,比如整个数据包的长度等。

解析函数如:

这里的应用比较简单,只是解析一个报警信息来显示。有时候需要用到整个数据包里的数据,这时候我们可以建立一个结构体来保存所有我们需要的数据,这样方便我们清晰、有条理地对数据进行处理。例如:

例子三(其它):

上面的两个例子中的自定义协议是比较典型的、用得比较多的。

下面也分享其它我自己的一些例子,很多时候为了满足我们自己通讯应用的需要,我们也会自己建立一些自己的小协议来满足我们的需求。


(1)例子一

之前使用串口屏与STM32通讯的时候,我有制定一些的协议。

为了让STM32能识别我串口屏不同页面发送的数据,必须要制定一条协议来识别页面:

这样,每切换至不同的页面时,就会往STM32发送关于页面的协议数据,这样我们就可以知道当前处于哪个界面。


为了让STM32能接收到正确的WiFi设置信息(如何区分WiFi名与密码),必须要给WiFi信息添加一些辅助协议数据,如:

相应的解析处理函数:

(2)例子二

之前在一个单相用电器监测的应用中,有用到zigbee无线通讯,即其中一块控制板做采集板,另一块控制板做显示板。


有些朋友可能会有疑问为什么不做在同一块板上?其实这是一道全国大学生电赛题(《省电赛一等奖作品:单相用电器分析监测装置》),我们只是根据题目要求来做的:

我们当时在做这个通讯时也是有制定一个简单的协议,在数据前面加个标识,就像JSON格式数据的键值对。关于JSON数据可阅读:

  • 《基于Linux、C、JOSN、Socket的编程实例(附代码)》

  • 《一个超轻量级的JSON解析器》

  • 《JSON的简单认识》

我们制定的协议如:

相应的解析及结果:

类似这样子的协议解析实际上是有套路的,摸清楚这些套路之后以后在做类似应用的时候其实就很简单了。


重点掌握sscanf、sprintf、strcmp、strstr、strcat等函数以及上面的两种典型例子。

小编在三个地方搬过砖,每个地方都有用到类似的自定义协议,而且都形成专门的协议文档,每次做类似通讯类的应用的时候,都会按照这样已份协议文档来修改以适应不同的项目。

关键字:STM32  自定义协议 引用地址:STM32 | 分享自定义协议的一些典型例子

上一篇:STM32 | MCU错误代码自动追踪库的使用经验分享
下一篇:STM32 | map文件详解

推荐阅读最新更新时间:2024-11-13 10:20

STM32的NVIC_PriorityGroupConfig使用及优先级分组方式理解
STM32有43个channel的settable的中断源;AIRC(Application Interrupt and Reset Register)寄存器中有用于指定优先级的4 bits。这4个bits用于分配preemption优先级和sub优先级,在STM32的固件库中定义如下 /* Preemption Priority Group -------------------------------------------------*/ #define NVIC_PriorityGroup_0 ((u32)0x700) /* 0 bits for pre-emption priority
[单片机]
STM32蜂鸣器-库函数
需要注意的是,使用了库函数的模板就不能胡乱套用寄存器的操作,之前还想放个大招结果出丑了,这里的实验要求是绿灯亮,蜂鸣器响,红灯亮,蜂鸣器停止,蜂鸣器响起间隔半秒,led的文件我这里就不给出了,主要放出beep的文件吧,这里操作的是PF8口。 1.beep.h #ifndef __BEEP_H #define __BEEP_H #include sys.h #define BEEP PFout(8) void beep_init(void); #endif 2.beep.c #include beep.h void beep_init() { GPIO_InitTypeDef GPIO_I
[单片机]
JSP向Servlet传递数据以及与STM32、ESP8266通信过程
工作流程: login.jsp- ValidateTest.java- ControlTest.jsp和SocketTest.java- Control.java- 8266- STM32 以上文件中后缀名为.jsp的就是JSP文件,Control.java和ValidateTest.java就是所谓的Servlet文件,SocketTest.java就是普通的Java Class文件。即只要是和JSP文件有数据传递关系的都得创建Servlet文件,而不是创建Class文件,当然了,你创建Class文件也行,只不过里面还是都得有Servlet文件所必须的doPost之类的方法。 Servlet是用来和JSP进行通信的文件,
[单片机]
JSP向Servlet传递数据以及与<font color='red'>STM32</font>、ESP8266通信过程
STM32位带操作的详解
1. 什么是位带操作以及STM32中位带操作的区域 什么是位带操作?简单来说就是通过宏定义封装一些操作,让你可以像51单片机上去操作IO口,从而不用麻烦的去配置各种寄存器,在STM32中有两个地方实现了位带。其中一个是 SRAM 区的最低 1MB 范围,第二个则是片内外设区的最低 1MB 范围。这两个区中的地址除了可以像普通的 RAM 一样使用外,它们还都有自己的“位带别名区”,位带别名区把每个比特膨胀成一个 32 位的字。当你通过位带别名区访问这些字时,就可以达到访问原始比特的目的。 下图就是STM32中可以用于位带操作的区域了,片上SRAM的0x2000 0000到0x2010 0000和片上外设的0x4000 0000到
[单片机]
<font color='red'>STM32</font>位带操作的详解
STM32窗口看门狗详解
本文将介绍窗口看门狗,并通过按键模拟触发程序死机、进而触发提前唤醒中断、并复位程序。 ①窗口看门狗介绍 ②STM32CUBEMX配置工程文件 ③代码实现 ①窗口看门狗介绍 窗口看门狗用来监测由于不可预知的因素或者不可预知的逻辑条件导致程序脱离正常运行序列的软件故障。 窗口看门狗介绍之工作原理框图: 窗口看门狗介绍之配置寄存器: 预分频器用于将RCC传来的PCLK1时钟进行分频,配置寄存器中第7位第8位用来存放预分频器的预分频值,第0位至第6位用于存放窗口看门狗的窗口值,当计数器的值大于窗口值时喂狗会触发复位、即只有计数器的值在0x40与窗口值之间时喂狗不会触发程序复位;所以窗口值需要大于0x40、小于0x7f,否则窗口没有
[单片机]
<font color='red'>STM32</font>窗口看门狗详解
【菜鸟入门】stm32 之 实时时钟
经过这么10天的瞎搞,我的库已经初具规模了,于是,不用每次都把所有的文件copy过去,直接在Option里面把path给加上就ok了。 RTC的时钟配置,RTC的时间寄存器是2个32位的寄存器,无非就是一个计数器,大概可以这样理解吧,我们先看看时钟吧 RTC的时钟可以从这3路来,我们需要PTCSEL寄存器来进行设置, 上面这个图是摘自李想老师的课件里面的,我觉得这个是做的相对好的! 位了保证RTC正常工作,我们需要在系统断电时,RTC不受影响,当然我们一般都需要接一个Battery,作为rtc的后备电源,这里设计到电源管理,我们先来看看电源管理里面关于rtc的 只要我们把第八位置1我们就可以对其进行正常供电,我
[单片机]
【菜鸟入门】<font color='red'>stm32</font> 之 实时时钟
STM32单片机引脚介绍及功能 STM32单片机的工作原理和基本组成
一、STM32单片机引脚介绍及功能 STM32单片机引脚分为两种类型:GPIO引脚和其他引脚。其中GPIO引脚可以作为通用输入输出引脚,也可以通过软件控制来使用特定功能。其他引脚则是供其他模块使用的,如时钟引脚、中断引脚等。 1.GPIO引脚 GPIO引脚是单片机最常用的引脚类型,用于通信、控制、数据传输等。在STM32单片机中,GPIO引脚包含多个不同的功能区,每个区域有一个或多个引脚。 每个GPIO引脚可配置为输入或输出格式,并根据需要在软件中进行控制。GPIO引脚通常被用于与外围设备进行数据传输、控制和通信。 2.其他引脚 (1) 时钟引脚 时钟引脚是STM32单片机中最重要的引脚类型之一,它们控制单片机系统的时钟周期。
[单片机]
STM32程序添加printf后无法运行的解决方法
标准库函数的默认输出设备是显示器,要实现在串口或LCD输出,必须重定义标准库函数里调用的与输出设备相关的函数. 例如:printf输出到串口,需要将fputc里面的输出指向串口(重定向),方法如下: #ifdef __GNUC__ /* With GCC/RAISONANCE, small printf (option LD Linker- Libraries- Small printf set to 'Yes') calls __io_putchar() */ #define PUTCHAR_PROTOTYPE int __io_putchar(int ch) #else #define PUTCHAR_P
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
更多往期活动
随便看看

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved