软件功能是要读取一个光纤传感器返回的数值,先发送一个6字节的代码确认传感器已经准备好,传感器返回6个字节响应;接着上位机在发送6个字节读取数据,传感器会周期性的返回126个字节来响应。
原因是接收数据的长度有多种,所以本人用一个统一的响应函数里面的一个case语句来通过某一返回字段来判断返回数据,再执行发送的命令的响应函数。
但是问题就出在,当本人发送读数据的6个波长之后,返回的数据经常达不到126个字节,,,希望高手能帮本人解惑,最好能给出帮本人解决问题的语句。下面贴代码
原因是接收数据的长度有多种,所以本人用一个统一的响应函数里面的一个case语句来通过某一返回字段来判断返回数据,再执行发送的命令的响应函数。
但是问题就出在,当本人发送读数据的6个波长之后,返回的数据经常达不到126个字节,,,希望高手能帮本人解惑,最好能给出帮本人解决问题的语句。下面贴代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;
using PortsThirdTry.usefulFun;
using System.Threading;
namespace PortsThirdTry
{
public partial class Form1 : Form
{
//全局预处理:创建实例,定义变量
PortsThirdTry.usefulFun.ClassCrc16 classCrc16 = new PortsThirdTry.usefulFun.ClassCrc16();
LittleFun littleFun = new LittleFun();
SerialPort comm = new SerialPort();
byte crcHi = 0x00;//crc高位
byte crcLo = 0x00;//crc低位
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
//初始化下拉框参数
string[] ports = SerialPort.GetPortNames();
Array.Sort(ports); //冒泡程序对串口进行排序
comboPortName.Items.AddRange(ports);
comboPortName.SelectedIndex = comboPortName.Items.Count > 0 ? 0 : -1; //默认串口
comboBaudRate.SelectedIndex = comboBaudRate.Items.IndexOf("115200"); //默认波特率
comboDataBits.SelectedIndex = comboDataBits.Items.IndexOf("8");//默认数据位数
comboStopBits.SelectedIndex = comboStopBits.Items.IndexOf("1");//默认停止位数
comboParityBits.SelectedIndex = comboParityBits.Items.IndexOf("无");//默认校验方式
comm.ReadTimeout = 2000;//超时时间,2s
comm.DataReceived += choice;
}
#region 串口打开按钮
private void btnOpenPort_Click(object sender, EventArgs e)
{
//根据当前串口对象,来判断操作
if (comm.IsOpen)
{
comm.Close(); //打开时点击,则关闭串口
}
else//关闭时点击,则设置好端口,波特率后打开
{
comm.PortName = comboPortName.Text;
comm.BaudRate = int.Parse(comboBaudRate.Text);
comm.DataBits = int.Parse(comboDataBits.Text);
switch (comboStopBits.Text)//设置停止位数
{
case "1":
comm.StopBits = StopBits.One;
break;
case "1.5":
comm.StopBits = StopBits.OnePointFive;
break;
case "2":
comm.StopBits = StopBits.Two;
break;
case "无":
comm.StopBits = StopBits.None;
break;
default:
break;
}
switch (comboParityBits.Text)
{
case "无":
comm.Parity = Parity.None;
break;
case "奇校验":
comm.Parity = Parity.Odd;
break;
case "偶校验":
comm.Parity = Parity.Even;
break;
default:
break;
}
try
{
comm.Open();
}
catch (Exception)
{
//捕获到异常信息,创建一个新的comm对象,之前的不能用了。
comm = new SerialPort();
//现实异常信息给客户。
MessageBox.Show("该串口被占用,请更换其他串口");
}
}
//设置按钮的状态
btnOpenPort.Text = comm.IsOpen ? "关闭串口" : "打开串口";
if (btnOpenPort.Text == "关闭串口")
{
comboPortName.Enabled = false;
comboBaudRate.Enabled = false;
comboDataBits.Enabled = false;
comboStopBits.Enabled = false;
comboParityBits.Enabled = false;
}
else
{
comboPortName.Enabled = true;
comboBaudRate.Enabled = true;
comboDataBits.Enabled = true;
comboStopBits.Enabled = true;
comboParityBits.Enabled = true;
}
}
#endregion
#region 主机查询命令
# region 设置扫描步长
#region 开始扫描指令
#region 读取波长数据
int[] allWave = new int[30];//定义一个数组来存储波长数据
private void btnGetWaveLength_Click(object sender, EventArgs e)
{
Byte ScanLength = Convert.ToByte(comboGetChannels.Text);
byte[] sendGetWaveLengthData = new byte[4] { 0x10, 0x01, 0x06, ScanLength };//将要发送的数据组
byte[] sendGetWaveLengthCrc = classCrc16.Crc16(sendGetWaveLengthData, out crcHi, out crcLo);//将要发送的crc
byte[] sendGetWaveLength = new byte[sendGetWaveLengthData.Length + sendGetWaveLengthCrc.Length];//将要发送的完整数组
sendGetWaveLengthData.CopyTo(sendGetWaveLength, 0);
sendGetWaveLengthCrc.CopyTo(sendGetWaveLength, sendGetWaveLengthData.Length);
comm.Write(sendGetWaveLength, 0, sendGetWaveLength.Length);//发送扫描数据
//comm.DataReceived += comm_GetWaveLength;
//comm.ReceivedBytesThreshold = 126;//设置接收的缓冲字节数
}
void comm_GetWaveLength(List<byte> a)//
{
byte[] receiveGetWaveLength = (byte[]) a.ToArray();
int n = receiveGetWaveLength.Length;//comm.Read(receiveGetWaveLength, 0, n);
while (n < 126)
{
Thread.Sleep(50);
}
byte[] receiveGetWaveLengthData = new byte[n-2];//将收到的数据中的crc以外的部分去掉,用于校验对比
byte[] receiveGetWaveLengthCrc = new byte[2];
Array.Copy(receiveGetWaveLength, 0, receiveGetWaveLengthData, 0, n-2);
Array.Copy(receiveGetWaveLength, n-2, receiveGetWaveLengthCrc, 0, 2);
byte[] receiveGetWaveLengthCrc2 = classCrc16.Crc16(receiveGetWaveLengthData, out crcHi, out crcLo);
this.Invoke((EventHandler)(delegate //用invoke更新界面
{
if (!littleFun.equalOrNot(receiveGetWaveLengthCrc2, receiveGetWaveLengthCrc))
{
MessageBox.Show("扫描波长数据错误,请重新设置");
}
else
{
//写一个循环程序迭代光栅编号
for (int j = 3; j < 126; j++)
{
txtDataMessage.Text = "波长数据为:" + " ";
if ((j - 4) % 4 == 0)
{
int text = ((int)receiveGetWaveLength[j + 1] * 65536 + (int)receiveGetWaveLength[j + 2] * 256 + (int)receiveGetWaveLength[j + 3]) / 10000;
int x = (j - 4) / 4;
allWave[x] = text;
txtDataMessage.Text += allWave[x];
}
else
{
}
}
}
}));
}
#endregion
#region 峰值功率数据
#region 读取AD数据
#region 查询当前阈值
private void btnClose_Click(object sender, EventArgs e)
{
Close();
}
#region 手动设定阈值
void choice(object sender, SerialDataReceivedEventArgs e)
{
int n = comm.BytesToRead;
byte[] receiveData = new byte[n];
comm.Read(receiveData, 0, n);
int Data = receiveData[1];
List<byte> sendData = new List<byte>();
foreach (byte i in receiveData)
{
sendData.Add(i);
}
switch (Data)
{
case 3:
comm_receiveMachineSearchFun(sendData);
break;
case 4:
comm_ScanLengthFun(sendData);
break;
case 32:
comm_receiveBeginScanFun(sendData);
break;
case 1://表示需要执行读波长函数
comm_GetWaveLength(sendData);
break;
case 2:
comm_PeakRate(sendData);
break;
case 5:
break;
case 6:
if ((receiveData[6] & receiveData[4] & receiveData[5] & receiveData[7]) == 0)
{
comm_receiveGetThreshold(sendData);
}
else
{
comm_SetThreshold(sendData);
}
break;
}
}
}
}
解决方案
15
基本上,看到
while (n < 126)
{
Thread.Sleep(50);
}
这类代码,你就应该清理这类垃圾。重新理解和设计流程。
之所以“死循环+阻塞”,而且是给出了一个既不足够长也不足够短的数值——50,这个完全瞎猜的数值,之所以这样设计,就是原因是这类通讯程序设计根本的理念就错误了。
10
有一点建议,先把数据接收和数据解析分离
数据解析会影响数据接收的
数据解析会影响数据接收的
5
List<byte> sendData = new List<byte>(); 这句代码放在方法的外面
参考下这个你就明白了。
http://bbs.csdn.net/topics/391975233#post-401292623
5
你这个问题问的有歧义..
是他发不到126还是你收不到126?..
假如是前者 可能这个模块有问题.
假如是后者 为啥你不判断126之后 组成一个”合法”的数据呢
10
即便是串口通讯,双方也应该定义一个通信协议,怎么能随随便便说收几个就收几个呢?
本人建议你先用串口调试助手先确定一下,是下位机没有发送预期的数据,还是人家发了你没有收到。假如是后者,你就观察一下下位机什么时候把126个字节全部发给你的,你可以等待这么久时间后一次性收上来,当然这很非常不专业的做法。正确的做法是在协议中指定一个剩余字节长度,然后按照这个协议中指定的长度去接受剩下的内容,还需要设计一个超时,这取决于上下位机之间的最长响应时延。接着说,假如你按照协议指定长度接收完毕,那么你收到的内容必定是双方约定的预期的内容,假如没收完就超时,说明下位机没法或超时时间太短了。
本人建议你先用串口调试助手先确定一下,是下位机没有发送预期的数据,还是人家发了你没有收到。假如是后者,你就观察一下下位机什么时候把126个字节全部发给你的,你可以等待这么久时间后一次性收上来,当然这很非常不专业的做法。正确的做法是在协议中指定一个剩余字节长度,然后按照这个协议中指定的长度去接受剩下的内容,还需要设计一个超时,这取决于上下位机之间的最长响应时延。接着说,假如你按照协议指定长度接收完毕,那么你收到的内容必定是双方约定的预期的内容,假如没收完就超时,说明下位机没法或超时时间太短了。
10
本人也遇到相似于你的问题,假设本人一次发送一帧十字节的数据,接受到的也的确是十字节 但是他们可能不是一帧了 而是在大于一帧小于十帧之间,字节和字节之间被断开单独算一帧了,而且单独算一帧的字节数还不确定