C#中使用seriport和单片机进行串口长数据收发不全,解决办法
2017-08-13 11:40
513 查看
最近做了一个项目,上位机向单片机要205个字节的报文。每次上位机接收的数据总是分成好几段,不能一次接收205个字节。所以对数据处理造成影响。因此就想着怎么能实现一次接收205字节数据,一次进行处理。试了很多办法,最后终于解决了。
C#中,使用的是serialPort.DataReceived来接收数据。一开始,上位机向单片机发送轮询指令后,单片机按照modbus协议上传205个字节数据。但是每次上位机将数据分成32个字节一段的形式接收。找了半天原因,最终发现,由于计算机速度很快,但是单片机发送205个字节数据是有一个过程的。然而,上位机收到一个字节就会触发serialPort.DataReceived,这时上位机去读接收缓冲区时,时间刚好只能读取32个字节。所以,我在接收一开始进行了延时,使用了 System.Threading.Thread.Sleep(300);延时300后,发现一次能够完整的接收205个字节数据。
分析了一下,原因可能是上位机接收完205个字节需要的时间在300毫秒,如果不延时,直接去读的话,只能读到目前接收的32个字节。具体看程序吧!
/// <summary>
/// 接收数据
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void serialport_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
try
{
//***正在接收状态指示。
IsReceving = true;
//等待所有数据全部进入缓冲区
System.Threading.Thread.Sleep(300);
//读入收到的数据。
int Len = serialport.BytesToRead;
if (Len < 1)
{
//***接收完成状态指示。
IsReceving = false;
return;
}
byte[] data = new byte[Len];
serialport.Read(data, 0, Len);
//字符串处理。
string Str = Encoding.GetEncoding("GB2312").GetString(data);
//数据转十六进制字符串。
string Hex = string.Empty;
for (int i = 0; i < data.Length; i++)
{
string tempstr = Convert.ToString(data[i], 16);
if (tempstr.Length < 2)
{
tempstr = '0' + tempstr;
}
Hex += tempstr + ' ';
}
Hex = Hex.ToUpper();
//使用委托跨线程读取数据。
rtbxRecStr.Invoke(new EventHandler(delegate
{
//***正在处理字符串。
DoingStr = true;
rtbxRecStr.AppendText(Str);
if (chkbxAutoClr.Checked && rtbxRecStr.Text.Length > 10000)
{
rtbxRecStr.Text = string.Empty;
}
//将控件的内容滚动到当前位置。
rtbxRecStr.ScrollToCaret();
//***完成处理字符串。
DoingStr = false;
}
));
// Logger.Debug(string.Format("接收数据: {0}", Str));
rtbxRecHex.Invoke(new EventHandler(delegate
{
//***正在处理十六进制数据。
DoingHex = true;
rtbxRecHex.AppendText(Hex);
if (chkbxAutoClr.Checked && rtbxRecHex.Text.Length > 10000)
{
rtbxRecHex.Text = string.Empty;
}
//将控件的内容滚动到当前位置。
rtbxRecHex.ScrollToCaret();
//***完成处理十六进制数据。
DoingHex = false;
}
));
Logger.Debug(string.Format("接收数据: {0}", Hex));
while (DoingStr || DoingHex)
{
//处理串口接收事件及其它系统消息。
Application.DoEvents();
}
//***接收完成状态指示。
IsReceving = false;
}
catch (Exception Err)
{
MessageBox.Show(Err.Message, "串口调试助手");
}
}
C#中,使用的是serialPort.DataReceived来接收数据。一开始,上位机向单片机发送轮询指令后,单片机按照modbus协议上传205个字节数据。但是每次上位机将数据分成32个字节一段的形式接收。找了半天原因,最终发现,由于计算机速度很快,但是单片机发送205个字节数据是有一个过程的。然而,上位机收到一个字节就会触发serialPort.DataReceived,这时上位机去读接收缓冲区时,时间刚好只能读取32个字节。所以,我在接收一开始进行了延时,使用了 System.Threading.Thread.Sleep(300);延时300后,发现一次能够完整的接收205个字节数据。
分析了一下,原因可能是上位机接收完205个字节需要的时间在300毫秒,如果不延时,直接去读的话,只能读到目前接收的32个字节。具体看程序吧!
/// <summary>
/// 接收数据
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void serialport_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
try
{
//***正在接收状态指示。
IsReceving = true;
//等待所有数据全部进入缓冲区
System.Threading.Thread.Sleep(300);
//读入收到的数据。
int Len = serialport.BytesToRead;
if (Len < 1)
{
//***接收完成状态指示。
IsReceving = false;
return;
}
byte[] data = new byte[Len];
serialport.Read(data, 0, Len);
//字符串处理。
string Str = Encoding.GetEncoding("GB2312").GetString(data);
//数据转十六进制字符串。
string Hex = string.Empty;
for (int i = 0; i < data.Length; i++)
{
string tempstr = Convert.ToString(data[i], 16);
if (tempstr.Length < 2)
{
tempstr = '0' + tempstr;
}
Hex += tempstr + ' ';
}
Hex = Hex.ToUpper();
//使用委托跨线程读取数据。
rtbxRecStr.Invoke(new EventHandler(delegate
{
//***正在处理字符串。
DoingStr = true;
rtbxRecStr.AppendText(Str);
if (chkbxAutoClr.Checked && rtbxRecStr.Text.Length > 10000)
{
rtbxRecStr.Text = string.Empty;
}
//将控件的内容滚动到当前位置。
rtbxRecStr.ScrollToCaret();
//***完成处理字符串。
DoingStr = false;
}
));
// Logger.Debug(string.Format("接收数据: {0}", Str));
rtbxRecHex.Invoke(new EventHandler(delegate
{
//***正在处理十六进制数据。
DoingHex = true;
rtbxRecHex.AppendText(Hex);
if (chkbxAutoClr.Checked && rtbxRecHex.Text.Length > 10000)
{
rtbxRecHex.Text = string.Empty;
}
//将控件的内容滚动到当前位置。
rtbxRecHex.ScrollToCaret();
//***完成处理十六进制数据。
DoingHex = false;
}
));
Logger.Debug(string.Format("接收数据: {0}", Hex));
while (DoingStr || DoingHex)
{
//处理串口接收事件及其它系统消息。
Application.DoEvents();
}
//***接收完成状态指示。
IsReceving = false;
}
catch (Exception Err)
{
MessageBox.Show(Err.Message, "串口调试助手");
}
}
相关文章推荐
- C#:使用ListView动态添加数据一直闪烁的解决办法
- C#使用access数据库,bin下的数据库和工程目录下数据库数据不同步解决办法
- Mysql 使用ibd数据文件进行数据恢复 (以及数据移动) 1067的解决办法
- 解决使用MSComm控件进行串口数据的接收数据不完整
- C#使用ListView更新数据出现闪烁解决办法
- C#使用ListView更新数据出现闪烁解决办法
- 使用asp.net/c# ajax 乱码的解决办法
- 在没有任何数据时进行无效的读取尝试”解决办法
- C#无法对Paradox数据库进行操作的解决办法
- C#与SQL Server之间的数据类型对比及在VS2003+中空值传递的解决办法
- 在网络中使用IO流进行数据收发
- 技术文档-使用C#进行E-Mail的收发操作
- EJB3.0中使用Ant进行编译出错的解决办法
- Delphi:TComPort封装在DLL中,通讯时无法接收串口数据的解决办法
- 关于使用DirectShow架构,传输YUV420数据的Filter与Video Renderer Filter连接问题的解决办法。
- asp.net中GridView绑定数据时进行时间Fromat时不起作用的解决办法
- 关于asp.net网站发布后,使用登录控件和注册控件时出现“数据库只读,无法进行数据更新”的解决方法
- 在使用中文名导出数据到excel文件时文件名出现乱码的解决办法
- Hibernate数据的lazy问题,以及使用spring整合hibernate lazy的解决办法(好文转载)
- 在网络中使用IO流进行数据收发