int n = comm.BytesToRead;//先记录下来,避免某种原因,人为的原因,操作几次之间时间长,缓存不一致 byte[] buf = new byte[n];//声明一个临时数组存储当前来的串口数据
comm.Read(buf, 0, n);//读取缓冲数据 buffer.AddRange(buf); if (buffer.Count==9) { byte[] binary_data_1 = new byte[9]; buffer.CopyTo(0, binary_data_1, 0, 9); buffer.Clear(); string data = binary_data_1[3].ToString("X2") + binary_data_1[4].ToString("X2") + binary_data_1[5].ToString("X2") + binary_data_1[6].ToString("X2"); int hex = Convert.ToInt32(data, 16); this.Invoke((EventHandler)(delegate { this.textBox2.AppendText(hex.ToString()); })); }第二个问题 这样改就好了。加上 buffer.Clear(); 我都不知道为啥。
DataRecevied 每次收到的数据可能不一样长,说具体一点就是你认为“ 每次收到的都是9个字节的数据。”其实不是(可能大于也可能小于),不信你在这个代码( int n = comm.BytesToRead;)前面sleep几秒钟试下。还有我以前接触的单片机是,下面给你会数据的时候,你在向串口写数据,人家不会理你的。(就是你快速(没有sleep)的给人家发10桢数据,人家可能给你只回5桢)第一个解决方法,你自己控制收发时间,能保证每次都是收到完整的一帧(数据)没有多收也没有少收。可以定义一个信号变量,第一条收完了在发第二条。第二个解决方法,自己创建一个全局的buffer,每次comm_DataReceived 收到的数据只管往 全局的buffer里面填 然后在去遍历截取里面完整的一帧帧数据(取出来就remove全部buffer的数据)。然后在去操作取出来的每一帧。
是标准的ModBus RTU吧。收发都是十六进制的。 如果每次都是读同一个寄存器,接受到的数据长度应该不会变,主要是判断一下是否有干扰。(用CRC校验来判断) 思路是这样: if (buffer.Count==9) 改为 if (buffer[0]==0x02&&buffer[1]==0x03) 然后 计算 buffer[0],buffer[1],buffer[2],buffer[3],buffer[4],buffer[5],buffer[6]的crc校验是否为 buffer[7]buffer[8],(要分清高位和低位,有次我没注意,一直无法正确校验)。 如果校验匹配,则 buffer.CopyTo(0, data_1, 0, 9); 否则 buffer.clear();
int n = comm.BytesToRead;//先记录下来,避免某种原因,人为的原因,操作几次之间时间长,缓存不一致
byte[] buf = new byte[n];//声明一个临时数组存储当前来的串口数据
comm.Read(buf, 0, n);//读取缓冲数据
buffer.AddRange(buf);
if (buffer.Count==9)
{
byte[] binary_data_1 = new byte[9];
buffer.CopyTo(0, binary_data_1, 0, 9);
buffer.Clear(); string data = binary_data_1[3].ToString("X2") + binary_data_1[4].ToString("X2") + binary_data_1[5].ToString("X2") + binary_data_1[6].ToString("X2"); int hex = Convert.ToInt32(data, 16); this.Invoke((EventHandler)(delegate { this.textBox2.AppendText(hex.ToString()); })); }第二个问题 这样改就好了。加上 buffer.Clear();
我都不知道为啥。
然后在去遍历截取里面完整的一帧帧数据(取出来就remove全部buffer的数据)。然后在去操作取出来的每一帧。
如果每次都是读同一个寄存器,接受到的数据长度应该不会变,主要是判断一下是否有干扰。(用CRC校验来判断)
思路是这样:
if (buffer.Count==9) 改为 if (buffer[0]==0x02&&buffer[1]==0x03)
然后 计算 buffer[0],buffer[1],buffer[2],buffer[3],buffer[4],buffer[5],buffer[6]的crc校验是否为 buffer[7]buffer[8],(要分清高位和低位,有次我没注意,一直无法正确校验)。
如果校验匹配,则 buffer.CopyTo(0, data_1, 0, 9);
否则 buffer.clear();
public byte[] CRC16(byte[] data)
{
byte CRC16Lo;
byte CRC16Hi; //CRC寄存器
byte CL; byte CH; //多项式码&HA001
byte SaveHi; byte SaveLo;
byte[] tmpData;
int Flag;
CRC16Lo = 0xFF;
CRC16Hi = 0xFF;
CL = 0x01;
CH = 0xA0;
tmpData = data;
for (int i = 0; i < tmpData.Length; i++)
{
CRC16Lo = (byte)(CRC16Lo ^ tmpData[i]); //每一个数据与CRC寄存器进行异或
for (Flag = 0; Flag <= 7; Flag++)
{
SaveHi = CRC16Hi;
SaveLo = CRC16Lo;
CRC16Hi = (byte)(CRC16Hi >> 1); //高位右移一位
CRC16Lo = (byte)(CRC16Lo >> 1); //低位右移一位
if ((SaveHi & 0x01) == 0x01) //如果高位字节最后一位为1
{
CRC16Lo = (byte)(CRC16Lo | 0x80); //则低位字节右移后前面补1
} //否则自动补0
if ((SaveLo & 0x01) == 0x01) //如果LSB为1,则与多项式码进行异或
{
CRC16Hi = (byte)(CRC16Hi ^ CH);
CRC16Lo = (byte)(CRC16Lo ^ CL);
}
}
}
byte[] ReturnData = new byte[2];
ReturnData[0] = CRC16Hi; //CRC高位
ReturnData[1] = CRC16Lo; //CRC低位
return ReturnData;
}
给你个crc校验函数。刚测试过,可以的哦。02 03 00 00 00 02 ,计算完就是C4 38