概述 在嵌入式開發的過程中,由於經常需要下位機與上位機通信,通信之間就需要協議,有協議就需要進行解碼,而產品開發得過程中,協議可能不斷更新,協議更新就需要解碼軟體更新,不斷更新解碼軟體就很麻煩,如果所有人都願意麻煩,那麼我不願意。在這裡就產生了一個通用的解碼類庫,使用者就可以簡單的改一下協議文件,通 ...
概述
在嵌入式開發的過程中,由於經常需要下位機與上位機通信,通信之間就需要協議,有協議就需要進行解碼,而產品開發得過程中,協議可能不斷更新,協議更新就需要解碼軟體更新,不斷更新解碼軟體就很麻煩,如果所有人都願意麻煩,那麼我不願意。在這裡就產生了一個通用的解碼類庫,使用者就可以簡單的改一下協議文件,通過調用這個類庫,就可以實現解碼,不需要再更改解碼演算法了。
class_frame類庫就是這樣的一個很方便的庫件。
類庫簡介
1 #region 程式集 xutopia, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null 2 // D:\workspace\09 UARTTOOL\19\myDll\xutopia\xutopia\bin\Debug\xutopia.dll 3 #endregion 4 5 using System.Collections.Generic; 6 7 namespace xutopia 8 { 9 public class Class_frame 10 { 11 public bool protocolFresh; 12 public string frameMsg; 13 14 public Class_frame(); 15 16 public _decodeDatTimelyStruct DecodeTimely(byte rxdDat); 17 public void Process_protocol_readed(string strPro); 18 public List<_saveDecodeStruct> SaveDecodeDat(List<byte> listRxd); 19 20 public struct _decodeDatTimelyStruct 21 { 22 public byte function; 23 public List<object> listRe; 24 } 25 public struct _saveDecodeStruct 26 { 27 public byte function; 28 public string str; 29 } 30 } 31 }
名稱空間:xutopia;
類的名稱:Class_frame;
屬性:
public bool protocolFresh;
true : 已經正確解析出協議;
false : 沒有協議。
public string frameMsg;
解析出協議的信息。
方法:
public _decodeDatTimelyStruct DecodeTimely(byte rxdDat);
param:
rxdDat:接收到的數據;
retval:
_decodeDatTimelyStruct:解碼的信息;
function : 功能碼;
listRe: 解碼的數據。需要強制類型轉換後才能使用。
public void Process_protocol_readed(string strPro);
param:
strPro:讀取到的協議文件;
public List<_saveDecodeStruct> SaveDecodeDat(List<byte> listRxd);
param:
listRxd:接收到的數據的泛型集合。
retval:
每一種功能碼的解碼數據:
function:功能碼;
str : 需要保存的數據。
驗證類庫
通信協議
下麵進行一個示例:
下位機需要向上位機發送3中數據幀,數據幀以功能碼來識別,每種數據幀的協議如下3個表格所示,上位機需要把這些數據按照協議解碼出來,併進行保存以便分析。
通信協議:
準備協議文件
按照通信協議編寫協議文件
/*
this is a protocol
2019-03-28
正文中不可以出現註釋
e.g. 正文//註釋內容
e.g. 正文
//註釋內容
正文開頭第一行必須是frameType
*/
/*
目前最後一行必須是空行
*/
frameType=header2 function
header1=0xA0
header2=0xA1
body=1
function=0xB1
index=1,type=unsigned char
index=2,type=unsigned short
index=3,type=unsigned int
index=4,type=short
index=5,type=int
index=6,type=float
index=7,type=double
endbody
body=2
function=0xB2
index=1,type=unsigned char
index=2,type=unsigned short
index=3,type=unsigned int
index=4,type=short
index=5,type=int
index=6,type=float
index=7,type=double
endbody
body=3
function=0xB3
index=1,type=unsigned char
index=2,type=unsigned short
index=3,type=unsigned int
index=4,type=short
index=5,type=int
index=6,type=float
index=7,type=double
endbody
check=CRC-CCITT
-----END FILE-----
模擬下位機發送數據
為了方便分析,這裡使用虛擬串口助手在電腦上模擬出兩個串口埠
編寫軟體模擬下位機按照協議發送數據
類庫使用方法
讀取協議文件
1 private void ButtonReadProtocol_Click(object sender, RoutedEventArgs e) 2 { 3 string[] txtRead = new string[2]; 4 5 txtRead = Selected_txt(); 6 if (txtRead == null) 7 return; 8 TextBoxSettingLog.AppendText(txtRead[0] + "\r\n"); 9 s.pro_Read = txtRead[1]; 10 c_f.Process_protocol_readed(s.pro_Read); 11 if (c_f.protocolFresh == true) 12 TextBoxSettingLog.AppendText(c_f.frameMsg); 13 }
保存解碼數據
/// <summary> /// 2019-05-06 /// </summary> private void SaveDecodeDat() { string strPath = Environment.CurrentDirectory; List<Class_frame._saveDecodeStruct> re = new List<Class_frame._saveDecodeStruct>(); re = c_f.SaveDecodeDat(listSpRxdDat); for (int i = 0; i < re.Count; i++) { byte id = re[i].function; string str = re[i].str; string strFile = strPath + "\\DOC\\" + DateTime.Now.ToString("yy-MM-dd-HH.mm.ss") + "dec" + Convert.ToString(id, 16) + ".txt"; if (re[0].str != null) SaveString(str, strFile, FileMode.Create); else MessageBox.Show("null"); } }
實時解碼數據
1 /// <summary> 2 /// 2019-05-07 3 /// </summary> 4 private void Decode_header_function_sum8() 5 { 6 Class_frame._decodeDatTimelyStruct re = new Class_frame._decodeDatTimelyStruct(); 7 int cnt = listSpRxdDat.Count(); 8 9 while (s.dec_lastCnt < cnt) 10 { 11 re = c_f.DecodeTimely(listSpRxdDat[s.dec_lastCnt++]); 12 List<object> l = re.listRe; 13 byte id = re.function; 14 if (l != null) 15 { 16 byte ui8; 17 UInt16 ui16; 18 UInt32 ui32; 19 Int16 i16; 20 Int32 i32; 21 float f; 22 double d; 23 24 switch (id) 25 { 26 case 0xB1: 27 { 28 ui8 = (byte)l[0]; 29 ui16 = (UInt16)l[1]; 30 ui32 = (UInt32)l[2]; 31 i16 = (Int16)l[3]; 32 i32 = (Int32)l[4]; 33 f = (float)l[5]; 34 d = (double)l[6]; 35 TextBoxRxd.AppendText("--------0xB1\r\n"); 36 TextBoxRxd.AppendText(ui8.ToString() + " "); 37 TextBoxRxd.AppendText(ui16.ToString() + " "); 38 TextBoxRxd.AppendText(ui32.ToString() + " "); 39 TextBoxRxd.AppendText(i16.ToString() + " "); 40 TextBoxRxd.AppendText(i32.ToString() + " "); 41 TextBoxRxd.AppendText(f.ToString() + " "); 42 TextBoxRxd.AppendText(d.ToString() + " "); 43 TextBoxRxd.AppendText("\r\n"); 44 } 45 break; 46 case 0xB2: 47 { 48 ui8 = (byte)l[0]; 49 ui16 = (UInt16)l[1]; 50 ui32 = (UInt32)l[2]; 51 i16 = (Int16)l[3]; 52 i32 = (Int32)l[4]; 53 f = (float)l[5]; 54 d = (double)l[6]; 55 TextBoxRxd.AppendText("--------0xB2\r\n"); 56 TextBoxRxd.AppendText(ui8.ToString() + " "); 57 TextBoxRxd.AppendText(ui16.ToString() + " "); 58 TextBoxRxd.AppendText(ui32.ToString() + " "); 59 TextBoxRxd.AppendText(i16.ToString() + " "); 60 TextBoxRxd.AppendText(i32.ToString() + " "); 61 TextBoxRxd.AppendText(f.ToString() + " "); 62 TextBoxRxd.AppendText(d.ToString() + " "); 63 TextBoxRxd.AppendText("\r\n"); 64 } 65 break; 66 case 0xB3: 67 { 68 ui8 = (byte)l[0]; 69 ui16 = (UInt16)l[1]; 70 ui32 = (UInt32)l[2]; 71 i16 = (Int16)l[3]; 72 i32 = (Int32)l[4]; 73 f = (float)l[5]; 74 d = (double)l[6]; 75 TextBoxRxd.AppendText("--------0xB3\r\n"); 76 TextBoxRxd.AppendText(ui8.ToString() + " "); 77 TextBoxRxd.AppendText(ui16.ToString() + " "); 78 TextBoxRxd.AppendText(ui32.ToString() + " "); 79 TextBoxRxd.AppendText(i16.ToString() + " "); 80 TextBoxRxd.AppendText(i32.ToString() + " "); 81 TextBoxRxd.AppendText(f.ToString() + " "); 82 TextBoxRxd.AppendText(d.ToString() + " "); 83 TextBoxRxd.AppendText("\r\n"); 84 } 85 break; 86 default: 87 TextBoxRxd.AppendText("frame id err\r\n"); 88 break; 89 } 90 } 91 } 92 }
在UARTTOOL中使用類庫
讀取協議文件,協議文件的信息會在TextBox框中顯示出來。
如下圖模擬下位機軟體開始向上位機發送數據
UARTTOOL打開串口,點擊保存數據和解碼數據會把原始數據和解碼後的數據保存下來
解碼後的數據如圖,和發送的一致。