SerialPort接收函数正确完全接收的问题

jiangnanxiong 2012-07-10 01:48:03
刚刚那个帖子我说的不清楚,现在我新开一个帖子,把我的问题说清楚了,希望大侠们能够很详细的回答我的问题,谢谢;

问题一:
问题如下:
我想把从SerialPort接收到的数放入Textbox中,但总是收不全(比如共10个字节,却总是收了5、6个,后面的就丢了)
我是这么写的(抄了修改的):
void comm_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
int n = comm.BytesToRead;
byte[] buf = new byte[n];//声明一个临时数组存储当前来的串口数据
comm.Read(buf, 0, n);//读取缓冲数据
builder.Length = 0;//清除字符串构造器的内容
//因为要访问ui资源,所以需要使用invoke方式同步ui。
this.Invoke((EventHandler)(delegate
{
//判断是否是显示为16禁止
if (checkBoxhexreceive.Checked)
{
//依次的拼接出16进制字符串
foreach (byte b in buf)
{
builder.Append(b.ToString("X2") + " ");
}
}
else
{
//直接按ASCII规则转换成字符串
builder.Append(Encoding.ASCII.GetString(buf));
}
//追加的形式添加到文本框末端,并滚动到最后。
textBoxreceive.Text += builder.ToString() + "\r\n";
}
}

采用RS485自发自收,每次发送相同的命令,收到在textBoxreceive中的值却不一样,(假如说全的时候是10个字节),有些时候收全了,有些时候只收了8个字节,有些时候只收了6个字节等等等等。。。。

我敢肯定是由于代码的第一行“int n = comm.BytesToRead;”在作怪,应为这里的n就决定了我要读多少字节数。

于是乎我请教了一个人,他告诉我一个方法:
采用ModBUS协议的通讯,可以这样做(比如说收到的数据将是12 34 01 78 90 AB CD):先收第一个数据(判断其是不是12),在收第二个数据(判断其是不是34),在收第三个数据(此处为01);
重点来了:根据ModBus协议来讲,第三位(此处为01)即代表了将要收到的数据时多少位(01:代表了数据为2个字节“78 90”,CRC为2个字节“AB CD”),这样我就知道了在收了第三个数据后还要再收多少个字节了,这样我就不可能丢数据了,这样问题就解决了

上面的思想是好的,但是用代码我根本不会写啊,如果用代码来实现,应该怎么写呢(上面的“先收到第三个数据,判断还要收多少位,从而保证收到的数据是完整的”),应该怎么写呢?

请尽量给代码,谢谢,如果有更好的方法,请指出,谢谢
我已经想了2天了,没有答案;


问题二:
我定义了一个串口接收函数
void comm_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
。。。。。。
}

我想在别的地方调用它,怎么做呢?

比如是在一个控件触发的时候调用它:
private void button1_Click_1(object sender, EventArgs e)
{
“调用DataReceived”函数
}

怎么做啊??
或者说这个不行,换成DataRead(串口读函数),怎么做呢??

请教了!


请高手们不要一笔带过,我是个新手,尽量将详细一点,尽量给代码

谢谢了
...全文
601 8 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
love_521_qian 2013-11-18
  • 打赏
  • 举报
回复
private void SerialPort_DataReceived( object sender , SerialDataReceivedEventArgs e ) { byte rev = (byte)PortHelper.SerialPort.ReadByte (); switch ( PortHelper.RecFlag ) { case 0: { if ( 0x7E == rev ) { Net.RecLen = 0; Net.DataReceiveBuffer[Net.RecLen++] = rev; PortHelper.RecFlag = 1; } else { PortHelper.RecFlag = 0; } break; } case 1: { if ( 0x7E == rev ) { Net.DataReceiveBuffer[Net.RecLen++] = rev; PortHelper.RecFlag = 2; } else { PortHelper.RecFlag = 0; } break; } case 2: { Net.DataReceiveBuffer[Net.RecLen++] = rev; if ( 13 == Net.RecLen ) { Len = (UInt16)( ( Net.DataReceiveBuffer[11] & 0x0F * 0x100 ) + ( Net.DataReceiveBuffer[12] ) ); PortHelper.RecFlag = 3; } break; } case 3: { Net.DataReceiveBuffer[Net.RecLen++] = rev; if ( Len + 17 == Net.RecLen ) { GlobalVariable.TaskFlag = 0x40; PortHelper.RecFlag = 0; } break; } } 这就是方法!不过用的协议不一样!其中包头两个字节,数据长度用的是12位的,也就是Net.DataReceiveBuffer[11] & 0x0F * 0x100 ) + ( Net.DataReceiveBuffer[12] 然后再去判断是否接受完了!再去校验什么的!
love_521_qian 2013-11-18
  • 打赏
  • 举报
回复
private void SerialPort_DataReceived( object sender , SerialDataReceivedEventArgs e ) { byte rev = (byte)PortHelper.SerialPort.ReadByte (); switch ( PortHelper.RecFlag ) { case 0: { if ( 0x7E == rev ) { Net.RecLen = 0; Net.DataReceiveBuffer[Net.RecLen++] = rev; PortHelper.RecFlag = 1; } else { PortHelper.RecFlag = 0; } break; } case 1: { if ( 0x7E == rev ) { Net.DataReceiveBuffer[Net.RecLen++] = rev; PortHelper.RecFlag = 2; } else { PortHelper.RecFlag = 0; } break; } case 2: { Net.DataReceiveBuffer[Net.RecLen++] = rev; if ( 13 == Net.RecLen ) { Len = (UInt16)( ( Net.DataReceiveBuffer[11] & 0x0F * 0x100 ) + ( Net.DataReceiveBuffer[12] ) ); PortHelper.RecFlag = 3; } break; } case 3: { Net.DataReceiveBuffer[Net.RecLen++] = rev; if ( Len + 17 == Net.RecLen ) { GlobalVariable.TaskFlag = 0x40; PortHelper.RecFlag = 0; } break; } }
xiaomingauk 2012-08-08
  • 打赏
  • 举报
回复 1
嘎嘎,串口收数据收不全要等待下再接收,可以用Thread.sleep
jiangnanxiong 2012-07-10
  • 打赏
  • 举报
回复
我试了comm_DataReceived(null,null)
发现如下:
我在原DataReceive函数里定义如下:
void comm_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
byte[] buf = new byte[n];//声明一个临时数组存储当前来的串口数据
comm.Read(buf, 0, n);//读取缓冲数据
}
注:其中的buf是一个全局变量;

调用时用comm_DataReceived(null,null)

我用中断模式调试,发现转去执行DataReceive函数时,buf数组为有数据为正确的;
但是执行完DataReceive函数跳回来时,buf数组就自动清空了,数据全没了!!

这是为何??
缭绕飘渺 2012-07-10
  • 打赏
  • 举报
回复
那你把参数类型改为SerialDataReceivedEventArgs不就完了吗
或者直接comm_DataReceived(null,null)试试
serialport 有个属性ReceivedBytesThreshold = 1;就是串口有1个字节
就触发接收事件进行数据读取,可以根据你的需要设置
jiangnanxiong 2012-07-10
  • 打赏
  • 举报
回复
我说的就是SerialPort的DataReceive事件!!!!!!

我就是不知道怎么能够去断定串口对象要达到多少字节才能触发该事件,应为每次来的数据字节数都是不一样的,要定义的话在哪里定义???

我觉得还是要靠上述的Modbus协议的某位数据来判断串口的接收字节数;可是该怎么写???

另外
我根据mervyn807的回复,用comm_DataReceived(this,EventArgs.Empty)调用该接收函数,爆出错误“无法从System.EventArgs转换为System.IO.Ports.SerialDataReceivedEventArgs)
这是为什么啊?

bdmh 2012-07-10
  • 打赏
  • 举报
回复
seralport就有DataReceived事件啊,你可以动态绑定,也可以在设计期就制定好
缭绕飘渺 2012-07-10
  • 打赏
  • 举报
回复
comm_DataReceived如果你这个是serialport的接收事件的话
他是会自动触发的,要看你的串口对象设置的多少字节触发该事件
你这样读也可以说没有问题,不过串口数据的处理一般是缓存,分析
第二个问题
调用comm_DataReceived(this,EventArgs.empty)

111,093

社区成员

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

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

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