C#----串口数据接收发送中,发送接收数据已经可以模拟了。
本次YSI实例过程中 主要是:类型转换问题 、计算校验码
一、不同设备不同的规则,本次实例代码如下:
string serialNumber = sn;//Packet Command Payload int i1 = 0x11;//Packet Length Byte int i2 = 0xA5;//Packet Sync Byt[] string[] strarr = new string[32];//命令字符串 strarr[0] = Convert.ToString(i1, 16);//转化固定字符 strarr[1] = Convert.ToString(i2, 16);//转化固定字符 char[] arr = serialNumber.ToCharArray();//字符数组 int[] ii = new int[16];//整形数组,为了计算校验码 ii[0] = i1;//转化固定字符 ii[1] = i2;//转化固定字符 for (int i = 0; i < arr.Length; i++) { strarr[2 + i] = Convert.ToString(arr[i], 16); ii[2 + i] = (int)arr[i]; } //计算校验码 int checksum = 0; for (int i = 0; i < ii.Length; i++) { checksum += ii[i]; if (checksum > 256) checksum = checksum - 256; } strarr[16] = Convert.ToString(checksum, 16);
上述,一是采用强制类型转换 char 类型为 16进制int,然后计算校验码;二是将char转换为16进制形式的string。
这样最后就得出需要发送的字符串数组。
二、发送字符串数据并且接收数据,代码如下:
//计算传输字符串 string[] sendstr = Sendstr(sdstr); //发送字节数组 byte[] wbb = new byte[64]; //转换成16进制字节 for (int i = 0; i < sendstr.Length; i++) { wbb[i] = Convert.ToByte(sendstr[i], 16); } //接收字节数组 byte[] rdb = new byte[64]; //打开新的串行端口连接 sp.Open(); //丢弃来自串行驱动程序的接受缓冲区的数据 sp.DiscardInBuffer(); //丢弃来自串行驱动程序的传输缓冲区的数据 sp.DiscardOutBuffer(); //使用缓冲区的数据将指定数量的字节写入串行端口 sp.Write(wbb, 0, wbb.Length); //当前线程挂起500毫秒 System.Threading.Thread.Sleep(500); //读取数据超时 sp.ReadTimeout = 1000; //读取接收数据 sp.Read(rdb, 0, rdb.Length);
上述,一是需要转换为字节发送,设备要求16进制字节;二是发送数据后,可以挂起线程500毫秒,避免数据冲突的问题。
这样返回字节数组rdb。
三、接收后的字节数组,需要转换解析,代码如下:
//读取记录转换为字符串 string[] rdstr = new string[100]; for (int i = 0; i < rdb.Length; i++) { rdstr[i] = rdb[i].ToString("X2"); }
上述,先转换为16进制字符串。
四、最终需要收集的数据是浮点型数据
网上搜到一个string 与浮点类型相互转换的类,可以直接使用,代码如下:
class stConvertFloat { public static string FloatToStandard(double f, int style) { char[] Num = new char[32];//32为二进制结果加1结束符 if (f < 0) //f为负数 ,符号位Num[0]赋1 { Num[0] = '1'; f = f * (-1); //转换为整数 } else Num[0] = '0'; //求指数 int exponent = 0; if (f >= 1)//指数符号为正情况,即fabs(f)>=1 { while (f >= 2) { exponent++; f = f / 2; } } else//负指数情况 { while (f < 1) { exponent++; f = f * 2; } exponent = (128 - exponent) + 128;//(128-exponent)为补码,+128是指数符号位置1 } exponent += 127;//指数转换为阶码 int i; for (i = 8; i >= 1; i--)//将指数转换为二进制数 { if (exponent % 2 == 0) Num[i] = '0'; else Num[i] = '1'; exponent /= 2; } f = f - 1;//小数转换为标准格式 //求小数部分 double s = 1; for (i = 9; i < 32; i++) { s /= 2; if (f >= s) { //MessageBox.Show(Convert.ToString(s)); f = f - s; Num[i] = '1'; } else Num[i] = '0'; } if (style == 2)//二进制输出 { string tt = new string(Num); return tt; } else //二进制转换为十六进制 { char sum; int j = 0; for (i = 0; i < 32; i = i + 4, j++) { sum = Convert.ToChar((Num[i] - '0') * 8 + (Num[i + 1] - '0') * 4 + (Num[i + 2] - '0') * 2 + (Num[i + 3] - '0')); if (sum > 9) Num[j] = Convert.ToChar((sum - 10) + 'a'); else Num[j] = Convert.ToChar(sum + '0'); } string tt = new string(Num); tt = tt.Substring(0, 8); return tt; } } public static double StandardToFloat(string FNum, int style) { char[] Num = new char[32]; char[] Hex = new char[8]; int i, j, value; if (style == 2)//二进制 { for (i = 0; i < 32; i++) Num[i] = FNum[i]; } else//十六进制转换为二进制 { for (i = 0; i < 8; i++) { Hex[i] = FNum[i]; if (Hex[i] >= '0' && Hex[i] <= '9') value = Hex[i] - '0'; else { Hex[i] = Convert.ToChar(Hex[i] | 0x20); //统一转换为小写 value = Hex[i] - 'a' + 10; } for (j = 3; j >= 0; j--) { Num[i * 4 + j] = Convert.ToChar((value % 2) + '0'); value /= 2; } } } double f = 1;//f为最终浮点数结果,标准浮点格式隐含小数点前的1 double s = 1;//s为小数各个位代表的权值 for (i = 9; i < 32; i++)//转换小数部分 { s /= 2; if (Num[i] == '1') { f += s; //MessageBox.Show(Convert.ToString(s)); } } int exponent = 0;//指数部分 int d = 1;//d代表指数部分各位的权值 for (i = 8; i >= 1; i--)//此时计算的是阶码 { if (Num[i] == '1') exponent += d; d *= 2; } if (exponent >= 127) exponent -= 127;//将阶码转换为指数 else { exponent += 256;//补上指数变阶码溢出的最高位 exponent -= 127;//阶码变指数,指数为补码 exponent = 128 - (exponent - 128);//(exponent-128)去符号位,在讲补码变为指数绝对值 exponent = exponent * (-1);//最终指数部分 } if (Num[0] == '1')//浮点数符号位为1,说明为负数 f = f * (-1); f = f * Math.Pow(2, exponent);//将小数部分和浮点部分组合 return f; } }
综上:串口数据发送接收是比较简单的,难点在于数据类型转换。
需要怎么转换成字节发送出去,再如何接收字节转换成所需数据。