在嵌入式產(chǎn)品開發(fā)中,我們經(jīng)常會(huì)遇到兩個(gè)設(shè)備之間的通信、設(shè)備與服務(wù)器的通信、設(shè)備和上位機(jī)的通信等,很多時(shí)候通信協(xié)議都是自定義的,所以這就涉及到自定義協(xié)議的解析和組包問題。
比如針對下面的這樣一個(gè)協(xié)議:
幀頭1 | 幀頭2 | 字段1 | 字段2 | 校驗(yàn) |
---|---|---|---|---|
固定值:0x55 | 固定值:0xAA | 設(shè)備ID | 電壓值 | 前面所有數(shù)據(jù)異或值 |
char | char | short | float | char |
1字節(jié) | 1字節(jié) | 2字節(jié) | 4字節(jié) | 1字節(jié) |
數(shù)據(jù)在發(fā)送時(shí)涉及到一個(gè)大小端的概念,大小端是針對多字節(jié)數(shù)據(jù)的傳輸,比如上述協(xié)議中字段1,假設(shè)兩字節(jié)內(nèi)容為0x0001,先發(fā)送0x01后發(fā)送0x00,稱為小端模式;先發(fā)送0x00后發(fā)送0x01,稱為大端模式。
假設(shè)字段1內(nèi)容為0x001,字段2內(nèi)容為0x40533333(對應(yīng)為3.3)
假設(shè)按照小端方式發(fā)送,下面是幀數(shù)據(jù):
55 AA 01 00 33 33 53 40 ED
下面來看看如何解析:
若干年前,在第一次面對這種問題時(shí),用的如下傻瓜式的代碼方式實(shí)現(xiàn):
#includeintmain() { unsigned char Rxbuf[9]={0x55,0xAA,0x01,0x00,0x33,0x33,0x53,0x40,0xED}; short DeviceId; floatVoltage; unsigned char check=0; int i; for(i=0;i<8;i++) ????{ ????????check?^=?Rxbuf[i]; ????} ????if(Rxbuf[0]==0x55?&&?Rxbuf[1]==0xAA?&&?Rxbuf[8]==check?) ????{ ????????DeviceId=(Rxbuf[3]<<8)|Rxbuf[2]; ????????Voltage=?*((float?*)&Rxbuf[4]); ????????printf("DeviceId:%d ",DeviceId); ????????printf("Voltage:%f ",Voltage); ????} ????return?0; }

簡單來說就是硬來,按照數(shù)組的先后順序逐個(gè)重組解析,如果協(xié)議比較長,代碼里會(huì)充斥著很多的數(shù)組下標(biāo),一不小心就數(shù)錯(cuò)了。而且如果更改協(xié)議的話,代碼要改動(dòng)很多地方。
后來有人告訴我可以定義個(gè)結(jié)構(gòu)體,然后使用memcpy函數(shù)直接復(fù)制過去就完事了。
#include嗯,的確是方便了很多。不過,該方式僅適合小端傳輸方式。#include #pragma pack(1) struct RxFrame { unsigned char header1; unsigned char header2; short deviceId; floatvoltage; unsigned char check; }; intmain() { unsigned char Rxbuf[9]={0x55,0xAA,0x01,0x00,0x33,0x33,0x53,0x40,0xED}; struct RxFrame RxData; unsigned char check=0; int i; for(i=0;i<8;i++) ????{ ????????check?^=?Rxbuf[i]; ????} ????memcpy(&RxData,Rxbuf,sizeof(Rxbuf)); ????if(Rxbuf[0]==0x55?&&?Rxbuf[1]==0xAA?&&?RxData.check==check?) ????{ ????????printf("DeviceId:%d ",RxData.deviceId); ????????printf("Voltage:%f ",RxData.voltage); ????} ????return?0; }
再后來,又見到有人用如下代碼實(shí)現(xiàn):
#include其中convert.h如下:#include"convert.h" intmain() { unsigned char Rxbuf[9]={0x55,0xAA,0x01,0x00,0x33,0x33,0x53,0x40,0xED}; short DeviceId; floatVoltage; unsigned char check=0; int i; int index=0; for(i=0;i<8;i++) ????{ ????????check?^=?Rxbuf[i]; ????} ????if(Rxbuf[0]==0x55?&&?Rxbuf[1]==0xAA?&&?Rxbuf[8]==check?) ????{ ????????index?+=?2; ????????ByteToShort(Rxbuf,?&index,?&DeviceId); ????????ByteToFloat(Rxbuf,?&index,?&Voltage); ????????printf("DeviceId:%d ",DeviceId); ????????printf("Voltage:%f ",Voltage); ????} ????return?0; }
#ifndef CONVERT_H #define CONVERT_H voidShortToByte(unsigned char*dest,int*index,short value); voidFloatToByte(char*dest,int*index,floatvalue); #endif//CONVERT_Hconvert.c如下:
#include"convert.h" #include#include static bool Endianflag=0; void ByteToShort(const unsigned char*source,int*index,short*result) { int i,len=sizeof(short); char p[len]; memset(p,0,len); if(Endianflag==1) { for(i=0;i 該方法既可以支持小端模式,也可以支持大端模式,使用起來也是比較方便。
除了上述2個(gè)函數(shù),完整的轉(zhuǎn)換包含以下函數(shù),就是將Bytes轉(zhuǎn)換為不同的數(shù)據(jù)類型,以及將不同的數(shù)據(jù)類型轉(zhuǎn)換為Bytes。
#ifndef CONVERT_H #define CONVERT_H voidByteToShort(const unsigned char*source,int*index,short*result); voidByteToInt(unsigned char*source,int*index,int*result); voidByteToLong(char*source,int*index,long long*result); voidByteToFloat(unsigned char*source,int*index,float*result); voidByteToDouble(unsigned char*source,int*index,double*result); voidByteToString(unsigned char*source,int*index,char*result,int length); voidShortToByte(unsigned char*dest,int*index,short value); voidIntToByte(char*dest,int*index,int value); voidLongToByte(char*dest,int*index,long long value); voidFloatToByte(char*dest,int*index,floatvalue); voidDoubleToByte(unsigned char*dest,int*index,double value); voidStringToByte(char*dest,int*index,int length,char*value); #endif//CONVERT_H
組包的過程和解析的過程正好相反,這里不再贅述。你在開發(fā)中遇到這種問題時(shí),又是如何處理的呢?歡迎留言討論!
責(zé)任編輯:彭菁
-
嵌入式
+關(guān)注
關(guān)注
5150文章
19659瀏覽量
317369 -
通信協(xié)議
+關(guān)注
關(guān)注
28文章
1033瀏覽量
41154 -
數(shù)據(jù)
+關(guān)注
關(guān)注
8文章
7255瀏覽量
91816 -
服務(wù)器
+關(guān)注
關(guān)注
13文章
9791瀏覽量
87923 -
嵌入式開發(fā)
+關(guān)注
關(guān)注
18文章
1075瀏覽量
48850
原文標(biāo)題:嵌入式開發(fā)中,自定義協(xié)議的解析與組包
文章出處:【微信號(hào):玩點(diǎn)嵌入式,微信公眾號(hào):玩點(diǎn)嵌入式】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
嵌入式開發(fā)linux awk命令深度詳解
嵌入式開發(fā)入門之旅
淺析基于linux的嵌入式開發(fā)
嵌入式開發(fā)調(diào)試經(jīng)驗(yàn)分享
嵌入式產(chǎn)品的研發(fā)過程是怎樣的
嵌入式開發(fā)中自定義協(xié)議的解析與組包相關(guān)案例分享
嵌入式開發(fā)

嵌入式開發(fā)語言有哪些_最全面嵌入式開發(fā)語言概述

嵌入式開發(fā)(一):嵌入式開發(fā)新手入門

嵌入式開發(fā)前景怎么樣?嵌入式開發(fā)有哪些優(yōu)勢?

嵌入式開發(fā)一般流程

嵌入式開發(fā)資料免費(fèi)分享

嵌入式開發(fā)培訓(xùn)怎么樣?嵌入式開發(fā)培訓(xùn)多少錢

嵌入式開發(fā)過程中的一點(diǎn)調(diào)試經(jīng)驗(yàn)

嵌入式開發(fā)前景怎么樣?

評論