.net 2.0 串口通讯的问题,SerialPort的ReadBufferSize到底有什么用?

hwyqy 2009-09-08 05:16:10
我的程序和一台医疗仪器通讯。通讯建立后,该医疗仪器每次发送一行数据(但我也不确定一行数据是分次发还是一次性发,因为这个程序不是我写的,但从结果上判断,应该是一次性发送的)。结果我的程序一般情况下先收200字节,然后再收48字节(偶尔也会一次性收248字节,所以我判断医疗仪器是一次性发送一行数据)。
我的程序是在ReveiveData事件中接收数据的,另外,ReceivedBytesThreshold属性设置为1。我的程序已经依靠数据侦的首尾标志解决分段接收的问题,但以下疑问在心中,仍无法得到答案

但为什么我的程序是先收200字节,再收48字节?我的ReadBufferSize已经设置为1M了,为何没有效果?还请高手解答。

另:还有没有其它数据接收方式,能够一次性接收完对方一次性发送过来的数据?
...全文
1677 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
jhdxhj 2009-09-21
  • 打赏
  • 举报
回复
ding
灯火斑斓 2009-09-21
  • 打赏
  • 举报
回复
请参考一下下面的方法。
技术要点:
(1).首先,SerialPort的ReceivedBytesThreshold先设置成1,表示只要有1个字符送达端口时便触发DataReceived事件
(2).当DataReceived触发时,先把ReceivedBytesThreshold设置成一个比较大的值,达到读取本次端口数据时,不再触发DataReceived.
(3).循环读取端口中的数据,直至读完。
(4).移除读取数据中的非法字符。
(5).触发一个后台线程处理收到的数据。
(6).在finally中把ReceivedBytesThreshold重置回1

private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
if (sender.GetType() != typeof(System.IO.Ports.SerialPort))
{
return;
}
string strReceive = string.Empty;
string strCollect = string.Empty;
System.IO.Ports.SerialPort comPort = (System.IO.Ports.SerialPort)sender;

try
{
comPort.ReceivedBytesThreshold = comPort.ReadBufferSize;
while (true)
{
strReceive = comPort.ReadExisting();
if (string.Equals(strReceive, string.Empty))
{
break;
}
else
{
strCollect += strReceive;
Application.DoEvents();
Thread.Sleep(100);
}
}
strCollect = strCollect.Replace("\0", string.Empty);
strCollect = strCollect.Replace("\r\n", string.Empty);
strCollect = strCollect.Replace("\r", string.Empty);
strCollect = strCollect.Replace("\n", string.Empty);

if (!this.bIsHandleCom)
{
this.bIsHandleCom = true;
mReceiveData = strCollect;
if (ReceiveDataParserEvent != null)
ReceiveDataParserEvent(mReceiveData);
if (ThreadReceiveParser != null && !ThreadReceiveParser.IsAlive)
{
ThreadReceiveParser.Start();
}
}

}
catch (Exception ex)
{
MessageBox.Show(this, ex.ToString(), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
comPort.ReceivedBytesThreshold = 1;
}
}
wzuomin 2009-09-18
  • 打赏
  • 举报
回复
mark
mozhaodi 2009-09-18
  • 打赏
  • 举报
回复
read事件不太好用,你定义100字节触发,但是串口接受的数据不是1个字节一个字节来的,有可能一下来两个,有可能就超过了100个字节,所以就不准了。
ttianqq 2009-09-14
  • 打赏
  • 举报
回复
我的意见是不用ReveiveData这个事件,我在做串口程序的时候也遇到了这样的问题的,一次性发送的内容却莫名其妙的分了两次接收
你可以自己开一个线程来处理就好了,如果发送的命令含有固定的结束符,可以用ReadTo函数,如果没有可以用Read或者ReadExist等等
jhdxhj 2009-09-14
  • 打赏
  • 举报
回复
ding
hwyqy 2009-09-14
  • 打赏
  • 举报
回复
代码sp即为串口,其中ReceivedBytesThreshold=1。因为上位机有多种,而且程序不是我写的,所以我无法定义数据桢的格式。我也知道ReceivedBytesThreshold=200,就会收到>=200字节后才激发事件,但由于上位机程序有多种,发送的字节数有时候一次仅一个(如开始标志或结束标志),所以只能将ReceivedBytesThreshold设置为1。大家帮我看看程序,这种接收方法是不是有什么问题。
现在最关键的是,我总怀疑上位机是一次性发了一条数据(约300-500字节),而我的程序却分了N次接收后再合并的。现在有没有方法能够做到对方发送一条数据,而我这边也仅只要收一次。ReadExisting()方法不能用,因为它返回字符串,而我的数据还需要分析二进制后再解码的。有兄弟说用sleep,不知道能不能行,还没试。

protected void ReceiveBySubsection()
{
byte[] readBuffer = new byte[BUFFERSIZE];
//关键就在此方法上,是不是read方法不能一次性把缓冲区中的所有数据都读完?
//我也怀疑是ReceivedBytesThreshold=1导致频繁激发Receive事件,但仅是怀疑
int count = sp.Read(readBuffer, 0, readBuffer.Length);

//接收到新数据,清空原有数据,StartWithFlag为自己编写的方法

if (StartWithFlag(readBuffer))
{
datas = new List<byte>();
}
if (datas == null)
{
OnErrorReceived(new ErrorReceiveEventArgs("一次性分段接收数据出错,未接收到起始标志。", true));
return;
}
//CopyDataToList将数据追加到List集合,是自定义的方法
CopyDataToList(datas, readBuffer, count);
//判断有没有收到结束标志
if (EndWithFlag(readBuffer))
{
//进行下一步的解码和分析数据的操作
DecodeAndAnalyse(datas);
}
}
freeboy827 2009-09-14
  • 打赏
  • 举报
回复
ReceivedBytesThreshold 这个属性不用改,默认就是1
freeboy827 2009-09-14
  • 打赏
  • 举报
回复

Thread.Sleep(50);

if (p.BytesToRead > 0)
{
//循环接收
string strData = p.ReadExisting();

}

这样试试
jhdxhj 2009-09-14
  • 打赏
  • 举报
回复
ding
风之影子 2009-09-10
  • 打赏
  • 举报
回复
byte[] data = new byte[this.serialPort1.BytesToRead];
selMonitor.Read(data, 0, data.Length);


如果你不设置一次读取的大小,程序会一次完整把缓存里的数据全部提走.
上面的就可以.(尽量用线程来读)
silentwins 2009-09-10
  • 打赏
  • 举报
回复
ReceivedBytesThreshold 才是触发缓存区字节的大小吧
你把他设置成200看看……
mozhaodi 2009-09-10
  • 打赏
  • 举报
回复
你的一个数据帧是多少啊,我的数据包是固定的,就是208个字节。所以
我在接收事件里用byte[] data=new int[208];
for (int i = 0; i < 208; i++)
{
data[i] = Convert.ToByte(serialPort1.ReadByte());
}
处理完之后再用serialport1.discadinbuffer();
ZhengZhiRen 2009-09-08
  • 打赏
  • 举报
回复
ReceivedBytesThreshold获取或设置 DataReceived 事件发生前内部输入缓冲区中的字节数

读取当前缓冲区中的所有数据可用ReadExisting(),有时可以加个thread.sleep()待串口上数据发完
yczf1836 2009-09-08
  • 打赏
  • 举报
回复
贴代码出来看看
CopperBell 2009-09-08
  • 打赏
  • 举报
回复
友情up
柳晛 2009-09-08
  • 打赏
  • 举报
回复
.

111,086

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • AIGC Browser
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧