一、 控制示意图
控制器发送自定义的协议给对靶系统,对靶系统也返回对应的帧。
1.1 控制器—>对靶装置
这是控制器发送到对靶装置的协议格式:
1.2 对靶装置—>控制器
这是对靶装置发给控制器的协议格式:
二、命令格式具体参数意义
2.1登入命令
2.1.1 控制器作为客户端发送命令
完整的数据包(16进制):02734C442003
代码如下:
byte[] login ={ 0x02, 0x73, 0x4C, 0x44,0x20,0x03 }; //登录指令
clientStream.Write(loginlidar, 0, loginlidar.Length); //发送登录指令
if (clientStream.CanRead)
{
byte[] loginanswer = new byte[1024]; //开辟缓存区
StringBuilder myCompleteMessage = new StringBuilder(); //接收结果变量
int numberOfBytesRead = 0;
do
{
numberofBytesRead = clientStream.Read(loginanswer, 0, loginanswer.Length);
//读出 TCPIP 通信接收缓存区
myCompleteMessage.AppendFormat("{0}",Encoding.ASCII.GetString(myReadBuffer, 0,
numberOfBytesRead));
//将网口读到的所有信息堆栈写入接收结果变量
}
while (clientStream.DataAvailable); //若数据没到达则循环接收
//可以继续操作 myCompleteMessage 中的接受信息以确定进一步操作, 下面继续简单提取了关键指令信息, 其中可能包含了 ETX, STX, 您需要进一步精细的进行处理
string result = myCompleteMessage.ToString();
string[] split = result.Split(new char[] { ' ' });//用空格将接收字符串分割成 N 个字符串数组 。
loginresult.Text = split[3];//第 3 部分为设备登录结果信息+ETX , 首字节为登录结果信息
2.1.2 对靶装置接收到登入命令的返回值
完整的数据包(16进制,失败):02734C44203131602003
控制器的代码:
#define PIN 2
volatile long count =0;
volatile int flag = 0;
volatile int mode_flag =0 ;
volatile long maxnum;
byte comdata[8]={0};
char numdata[8]={0,0,0,0};
#define A0_Command 0x10 #可用模式选择
#define A1_Command 0x11
#define A2_Command 0x20
#define A3_Command 0x21
void receive_data(void);
void test_do_data(void);
void setup() {
Serial.begin(9600);
Serial3.begin(9600);
pinMode(PIN,INPUT);
pinMode(13,OUTPUT);
pinMode(8,OUTPUT);
attachInterrupt(0,blinkA,FALLING);
}
void loop() {
if(Serial3.available()>0)
{
receive_data();
test_do_data();
}
delay(100); //自己发出脉冲信号测试
digitalWrite(8,HIGH);
digitalWrite(8,LOW);
}
void receive_data() #数据接收
{
int i;
for(i=0;i<8;i++)
{
comdata[i]= Serial3.read();
delay(2);
}
for(i=0;i<4;i++)
{
numdata[i]= char(Serial3.read());
delay(2);
}
}
void test_do_data(void)
{
int x;
if(comdata[0] == 0x02) // 帧头
{
Serial.println("head is ok");
if (comdata[1]==0x73 && comdata[2]==0x4c && comdata[3]==0x44) //下位机登入对靶系统
{
Serial.println("LIGIN DEVICE");
switch(comdata[5]){
case 0x30:
Serial.println("Ligin Successful");
break;
case 0x31:
Serial.println("Ligin failed");
break;
}
}
for(x=0;x<8;x++)
maxnum=(maxnum*10+long(numdata[x]-'0'));
}
}
void blinkA()
{
count++;
if(count>=maxnum)
{
if(flag==0)
digitalWrite(13,HIGH);
else
digitalWrite(13,LOW);
flag=~flag;
count=0;
}
}
由于对靶系统的接收和发送程序还没调试好,在此用Arduino的两个串口来测试控制器接收到返回值,对应操作。
通过串口发送hex数据给控制器mage2560,执行结果:
2.2 设备同步指令
2.2.1 控制器作为客户端发送命令
代码如下:
byte[] login ={ 0x02, 0x73, 0x54, 0x4D,0x20,0x03 }; //调整指令
clientStream.Write(loginlidar, 0, loginlidar.Length); //发送调整指令
if (clientStream.CanRead)
{
byte[] loginanswer = new byte[1024]; //开辟缓存区
StringBuilder myCompleteMessage = new StringBuilder(); //接收结果变量
int numberOfBytesRead = 0;
do
{
numberofBytesRead = clientStream.Read(loginanswer, 0, loginanswer.Length);
//读出 TCPIP 通信接收缓存区
myCompleteMessage.AppendFormat("{0}",Encoding.ASCII.GetString(myReadBuffer, 0,
numberOfBytesRead));
//将网口读到的所有信息堆栈写入接收结果变量
}
while (clientStream.DataAvailable); //若数据没到达则循环接收
//可以继续操作 myCompleteMessage 中的接受信息以确定进一步操作, 下面继续简单提取了关键指令信息, 其中可能包含了 ETX, STX, 您需要进一步精细的进行处理
string result = myCompleteMessage.ToString();
string[] split = result.Split(new char[] { ' ' });//用空格将接收字符串分割成 N 个字符串数组 。
loginresult.Text = split[3];//第 3 部分为设备登录结果信息+ETX , 首字节为登录结果信息
2.2.2 对靶装置接收到模式设置命令的返回值
完整数据包(16进制,进入调试模式):0273544D3030203030502003
控制解析返回值代码如下:
#define PIN 2
volatile long count =0;
volatile int flag = 0;
volatile int mode_flag =0 ;
volatile long maxnum;
byte comdata[8]={0};
char numdata[8]={0,0,0,0};
#define A0_Command 0x10 #可用模式选择
#define A1_Command 0x11
#define A2_Command 0x20
#define A3_Command 0x21
void receive_data(void);
void test_do_data(void);
void setup() {
Serial.begin(9600);
Serial3.begin(9600);
pinMode(PIN,INPUT);
pinMode(13,OUTPUT);
pinMode(8,OUTPUT);
attachInterrupt(0,blinkA,FALLING);
}
void loop() {
if(Serial3.available()>0)
{
receive_data();
test_do_data();
}
delay(100); //自己发出脉冲信号测试
digitalWrite(8,HIGH);
digitalWrite(8,LOW);
}
void receive_data() #数据接收
{
int i;
for(i=0;i<8;i++)
{
comdata[i]= Serial3.read();
delay(2);
}
for(i=0;i<4;i++)
{
numdata[i]= char(Serial3.read());
delay(2);
}
}
void test_do_data(void)
{
int x;
if(comdata[0] == 0x02) // 帧头
{
Serial.println("head is ok");
if(comdata[1]==0x73 && comdata[2]==0x54 && comdata[3]==0x4D){ //模式设置
Serial.println("Setting mode");
switch(comdata[5]){
case 0x31:
Serial.println("Mode one");
break;
case 0x32:
Serial.println("Mode two");
break;
}
}
for(x=0;x<8;x++)
maxnum=(maxnum*10+long(numdata[x]-'0'));
}
}
void blinkA()
{
count++;
if(count>=maxnum)
{
if(flag==0)
digitalWrite(13,HIGH);
else
digitalWrite(13,LOW);
flag=~flag;
count=0;
}
}
执行结果:
2.3设备索引指令
2.3.1 控制器发送指令到对靶系统
代码基本同上。
2.3.2 控制器得到返回值解析
代码如下:
#define PIN 2
volatile long count =0;
volatile int flag = 0;
volatile int mode_flag =0 ;
volatile long maxnum;
byte comdata[6]={0};
char numdata[4]={0,0,0,0};
#define A0_Command 0x10
#define A1_Command 0x11
#define A2_Command 0x20
#define A3_Command 0x21
void receive_data(void);
void test_do_data(void);
void setup() {
Serial.begin(9600);
Serial3.begin(9600);
pinMode(PIN,INPUT);
pinMode(13,OUTPUT);
pinMode(8,OUTPUT);
attachInterrupt(0,blinkA,FALLING);
}
void loop() {
if(Serial3.available()>0)
{
receive_data();
test_do_data();
}
delay(100); //自己发出脉冲信号测试
digitalWrite(8,HIGH);
digitalWrite(8,LOW);
}
void receive_data()
{
int i;
for(i=0;i<6;i++)
{
comdata[i]= Serial3.read();
delay(2);
}
for(i=0;i<4;i++)
{
numdata[i]= char(Serial3.read());
delay(2);
}
}
void test_do_data(void)
{
int x;
if(comdata[0] == 0x02) // 头
{
Serial.println("head is ok");
if (comdata[1]==0x73 && comdata[2]==0x4c && comdata[3]==0x44) //模式选择
{
Serial.println("LIGIN DEVICE");
switch(comdata[5]){
case 0x30:
Serial.println("Login Successful");
break;
case 0x31:
Serial.println("Login failed");
break;
}
}
if(comdata[1]==0x73 && comdata[2]==0x54 && comdata[3]==0x4D){
Serial.println("Setting mode");
switch(comdata[5]){
case 0x30:
Serial.println("Mode one");
break;
case 0x31:
Serial.println("Mode two");
break;
}
}
if (comdata[1]==0x73 && comdata[2]==0x52 && comdata[3]==0x44) //设备索引
{
Serial.println("Device index");
if(numdata[1]==0x53 &&numdata[1]==0x43&& numdata[1]==x41&& numdata[1]==0x55)
Serial.println("SCAU");
}
if (comdata[1]==0x73 && comdata[2]==0x54 && comdata[3]==0x49) //对靶装置设定
Serial.println("Device index");
}
for(x=0;x<4;x++)
maxnum=(maxnum*10+long(numdata[x]-'0'));
}
void blinkA()
{
count++;
if(count>=maxnum)
{
if(flag==0)
digitalWrite(13,HIGH);
else
digitalWrite(13,LOW);
flag=~flag;
count=0;
}
}
2.3 注销命令
2.3.1控制器登出对靶装置
完整数据包(16进制):02734C4F2003
代码如下:
byte[] logout ={ 0x02, 0x73, 0x4C, 0x4f,0x20,0x03 }; //调整指令
clientStream.Write(loginlidar, 0, loginlidar.Length); //发送调整指令
if (clientStream.CanRead)
{
byte[] loginanswer = new byte[1024]; //开辟缓存区
StringBuilder myCompleteMessage = new StringBuilder(); //接收结果变量
int numberOfBytesRead = 0;
do
{
numberofBytesRead = clientStream.Read(loginanswer, 0, loginanswer.Length);
//读出 TCPIP 通信接收缓存区
myCompleteMessage.AppendFormat("{0}",Encoding.ASCII.GetString(myReadBuffer, 0,
numberOfBytesRead));
//将网口读到的所有信息堆栈写入接收结果变量
}
while (clientStream.DataAvailable); //若数据没到达则循环接收
//可以继续操作 myCompleteMessage 中的接受信息以确定进一步操作, 下面继续简单提取了关键指令信息, 其中可能包含了 ETX, STX, 您需要进一步精细的进行处理
string result = myCompleteMessage.ToString();
string[] split = result.Split(new char[] { ' ' });//用空格将接收字符串分割成 N 个字符串数组 。
loginresult.Text = split[3];//第 3 部分为设备登录结果信息+ETX , 首字节为登录结果信息
2.3.2控制器对对靶装置返回值的处理
完整数据包(16进制):02734C4F203030502003
代码如下:
#define PIN 2
volatile long count =0;
volatile int flag = 0;
volatile int mode_flag =0 ;
volatile long maxnum;
byte comdata[6]={0};
char numdata[4]={0,0,0,0};
#define A0_Command 0x10
#define A1_Command 0x11
#define A2_Command 0x20
#define A3_Command 0x21
void receive_data(void);
void test_do_data(void);
void setup() {
Serial.begin(9600);
Serial3.begin(9600);
pinMode(PIN,INPUT);
pinMode(13,OUTPUT);
pinMode(8,OUTPUT);
attachInterrupt(0,blinkA,FALLING);
}
void loop() {
if(Serial3.available()>0)
{
receive_data();
test_do_data();
}
delay(100); //自己发出脉冲信号测试
digitalWrite(8,HIGH);
digitalWrite(8,LOW);
}
void receive_data()
{
int i;
for(i=0;i<6;i++)
{
comdata[i]= Serial3.read();
delay(2);
}
for(i=0;i<4;i++)
{
numdata[i]= char(Serial3.read());
delay(2);
}
}
void test_do_data(void)
{
int x;
if(comdata[0] == 0x02) // 头
{
Serial.println("head is ok");
if (comdata[1]==0x73 && comdata[2]==0x4c && comdata[3]==0x44) //登入解析
{
Serial.println("LIGIN DEVICE");
switch(comdata[5]){
case 0x30:
Serial.println("Login Successful");
break;
case 0x31:
Serial.println("Login failed");
break;
}
}
if(comdata[1]==0x73 && comdata[2]==0x54 && comdata[3]==0x4D){ //模式选择
Serial.println("Setting mode");
switch(comdata[5]){
case 0x30:
Serial.println("Mode one");
break;
case 0x31:
Serial.println("Mode two");
break;
}
}
if (comdata[1]==0x73 && comdata[2]==0x52 && comdata[3]==0x44) //设备索引
{
Serial.println("Device index");
if(numdata[1]==0x53 &&numdata[1]==0x43&& numdata[1]==0x41&& numdata[1]==0x55)
Serial.println("SCAU");
}
if (comdata[1]==0x73 && comdata[2]==0x4C && comdata[3]==0x4f) //对靶装置设定
Serial.println("Logout");
switch(comdata[5]){
case 0x30:
Serial.println("Logout successful");
break;
case 0x31:
Serial.println("Logout failed");
break;
}
}
for(x=0;x<4;x++)
maxnum=(maxnum*10+long(numdata[x]-'0'));
}
void blinkA() //做执行操作
{
count++;
if(count>=maxnum)
{
if(flag==0)
digitalWrite(13,HIGH);
else
digitalWrite(13,LOW);
flag=~flag;
count=0;
}
}
执行结果:
2.4 关闭对靶系统命令
2.4.1 控制器关闭对靶装置
协议的具体形式
代码与上相似
2.4.2 控制器对返回值处理
代码与上相似。
2.5控制器对对靶装置设置参数
后续补充
2.6 控制请求数据(单次)
后续补充
2.7 控制器请求数据(多次)
后续补充
总结
在这个自定义的协议中,发送给对靶装置的指令数据包是固定长度6个长度,对靶装置的返数据包是不固定,有的没有包括数据包,有的包括数据字段,使其数据包要单独提出来分析。
有几个问题:
(1)在数据接收部分,校验部分代码没有实现,只是接收保存。
(2)在数据解析部分是对指令解析了,但是没有对数据段内容具体解析。
(3)不固定数据长度的怎么接收处理。