c# 串口通信serialport,循环发送问题,求大神赐教

cyclss 2018-06-21 07:03:07
我要做一个实时数据采集通讯,想法是吧串口通讯做成一个线程,通过while循环不断的发送报文,再由serialPort1_DataReceived事件接受,为了保证发一帧采集一帧,我在while循环里加个判断(当接受缓冲区被清空,serialport.BytesToRead==0,的条件下才发报文),等serialPort1_DataReceived事件接受完事件清空缓冲区,这个逻辑判断应该没有问题啊,但是运行起来,接受的数据正确的也有,丢失的也有,丢失完采集不到的也有,停止采集的也有,请教是什么情况,有没有其他号的思路
     public Form1()
{
InitializeComponent();
}
SerialPort MyCom = new SerialPort();
public void OpenMyCom()
{
if (MyCom.IsOpen == true)
{
MyCom.Close();
}
MyCom.BaudRate = 9600;//波特率
MyCom.PortName = "COM7";//端口号
MyCom.DataBits = 8;//数据位
MyCom.Parity = Parity.None;
MyCom.StopBits = StopBits.One;
MyCom.ReceivedBytesThreshold = 1;
MyCom.DataReceived += new SerialDataReceivedEventHandler(serialPort1_DataReceived);
MyCom.Open();
}
...全文
587 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
sp1234_maJia 2018-07-21
  • 打赏
  • 举报
回复
当你想打印“消息”内容时,你可能应该写
this.label1.Text += s;
来查看和调试累积收到的内容,而不是想当然地以为 s 中就是一个完整的消息。

另外我不知道谁教你写 DiscardInBuffer 这种语句的。这种语句只有当你想丢弃当前所有数据(重新开始接收后续数据)时你才应该写它,你写这个干什么?????是从哪一个坑的博客上看到的????
  • 打赏
  • 举报
回复
什么线程、队列、阻塞式 receive 语句等等,都不是本质原因,都会造成你盲目乱“试”,用大堆无关的东西来(貌似)“弥补”你的bug,结果就是越改越乱越复杂。学点原理才能忘记那些死记硬背的东西,解决问题。
  • 打赏
  • 举报
回复
只有数据库块通讯才不会分包粘包 --> 只有数据块儿通讯才不会分包粘包

这是一个基本常识。你收到数据,应该累计起来,判断有没有收到消息结束标志。当累积的字节中包含消息结束标志时,取出发现的消息内容(但是必须保留后续消息的粘包内容),才来解析处理。这个解析处理通常也是异步的,以便迅速释放 I/O 线程来保证 serialPort1_DataReceived 去及时接收下一个消息。


凡是看这类数据流接收消息代码,如果你看到针对的是流式数据 Receive,但是连分包和粘包的概念都没有那就不是真正懂通讯程序设计。然后看信令设计,如果信令设计不能很好地并发多消息异步处理(只能强迫处理程序顺序处理)那也是相当于还没有怎么设计过实用的通讯程序的。这两种情况,都是刚学编程的人才犯的错误,就好像写不好网络小说怪电脑不好使,这是初学的习惯。
  • 打赏
  • 举报
回复
你自己看看你的 serialPort1_DataReceived 代码!数据流式通讯,自然是有粘包和分包的情况的(只有数据库块通讯才不会分包粘包)。你处理分包和粘包情况了吗?

你写的 serialPort1_DataReceived 完全是错误的!!
情似生活 2018-07-20
  • 打赏
  • 举报
回复
你可以用两个线程,一个线程接收数据,一个线程处理数据(包括发送),接收线程读到的数据用队列来存储。再从队列里去取数据来处理。
fudashouyao 2018-07-04
  • 打赏
  • 举报
回复
1 ,2,1,2,1,2 那你在1中调用2,2中调用1 不就好了,然后开启你让1先跑还是2先跑就好了。我建议你用队列。所有的处理都去操作队列。独立性更强。
funkf 2018-07-04
  • 打赏
  • 举报
回复
不要用serialPort1_DataReceived事件去接收数据,自己写一个接收方法放到发送方法后面,即 MyCom.Write(SendCom, 0, 8);
System.Threading.Thread.Sleep(30); 这后面+接收方法
just59277 2018-06-27
  • 打赏
  • 举报
回复
先不管下位机能不能承受,有的模块确实是支持毫秒级的采集,你可以按6楼的,自己写个Received,这样也方便调试。
qq_25731181 2018-06-26
  • 打赏
  • 举报
回复
下位机承受不起这个频率吗
Bridge_go 2018-06-26
  • 打赏
  • 举报
回复
不要用这个事件,直接读试试
Laplace_Primitives 2018-06-26
  • 打赏
  • 举报
回复
一个是发的太快了,再就有可能下位机回复的时候两个字节之间间隔时间太长,判断为接收完了,其实就接收了一部分可以放接收事件里再等待判断一下确实不回了再处理数据
cyclss 2018-06-21
  • 打赏
  • 举报
回复
引用 3 楼 yuankaiwsl 的回复:
这样会不会把下位机发死

下位机承受不起这个频率吗
巴士上的邂逅 2018-06-21
  • 打赏
  • 举报
回复
这样会不会把下位机发死
cyclss 2018-06-21
  • 打赏
  • 举报
回复
      public void WriteUtr()
{
byte[] SendCom = { 0x01, 0x03, 0x05, 0x20, 0x00, 0x02, 0xC5, 0x0D };//报文

while (true)
{
if (MyCom.BytesToRead == 0)//加判断,只有在缓冲区没有数据才发报文
{
MyCom.Write(SendCom, 0, 8);
System.Threading.Thread.Sleep(30);
}
else
{
return;
}
}
}
cyclss 2018-06-21
  • 打赏
  • 举报
回复
 private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
int len = MyCom.BytesToRead;
byte[] buff = new byte[len];
MyCom.Read(buff, 0, len);
string str = "";
for (int i = 0; i < len - 1; i++)
{
str = str + " " + buff[i].ToString();

}
if (this.label1.InvokeRequired)
{
this.label1.Invoke(new Action<string>(s => { this.label1.Text = s; }), str);
}

MyCom.DiscardInBuffer();//清输入缓冲区
}

private void button2_Click(object sender, EventArgs e)
{
Thread th1 = new Thread(WriteUtr);
th1.Start();
th1.IsBackground = true;
}

public void WriteUtr()
{
byte[] SendCom = { 0x01, 0x03, 0x05, 0x20, 0x00, 0x02, 0xC5, 0x0D };//报文

while (tr

110,566

社区成员

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

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

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