c#中,确保数据接收完整的串口处理程序
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
c#中,确保数据接收完整的串⼝处理程序
:
如果⼀些⼚家⽐较懒的话,没有提供相应的dll,我们只能对它进⾏串⼝通信编程了。
以前从没接触过串⼝编程,最近在⼀个项⽬中有⼏个地⽅都需要采⽤串⼝通信,跟公司⼀个⽼
⼿请教后,感觉学到了很多东西,特在此做个总结:
⼀:⾸先我们来认识下什么是串⼝:
我们可以看到该串⼝的属性,在C#中我们使⽤SerialPort类来表⽰串⼝
⼆:串⼝调试⼯具:
在对串⼝进⾏编程时候,我们要向串⼝发送指令,然后我们解析串⼝返回的指令。
在这⾥向⼤家推荐⼀款⼯具。
void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
//接收数据
string str = "";
do
{
int count = serialPort.BytesToRead;
if (count <= 0)
break;
byte[] readBuffer = new byte[count];
Application.DoEvents();
serialPort.Read(readBuffer, 0, count);
str += System.Text.Encoding.Default.GetString(readBuffer);
} while (serialPort.BytesToRead > 0);
listBox1.Items.Add(str);
}
如果,翻看我之前的博客,会找到⼀篇⽤I/O模拟IIC通信的程序⽂章。
好吧,如果找不到可以点击,这⾥就不在赘述了,系统也已经完全调试通过了。
今天的任务是,把测试得到的数据在上位机的界⾯上显⽰出来,于是键盘⼿花了两天的时间模仿着巨⼈的肩膀通过了⽤C#编写的界⾯程序,界⾯很简单就像下⾯显⽰的⼀样。
c#串⼝系列⽂章:
第⼀个串⼝打开的时候你是要TRY CATCH的不然会异常
第⼆个尽量使⽤READ和WRITE不要⽤WRITELINE和READLINE,后两个是要读换⾏符的
第三个查看你的串⼝初始化是否初始化好了
为什么我按发送界⾯就卡住了啊,
程序就不往下执⾏了。
为什么啊?
没弄明⽩,请⾼⼿指点
如果你只知道编写同步操作代码,就不可能做出专业的产品,⽽只是知道.net有那些语句⽽已。
GSM Modem
⼀直在csdn上回关于gsm modem⽅⾯的AT指令问题,之前花了不少时间,想想还是补上整理后的内容
在C#中使⽤SerialPort类实现串⼝通信遇到多线程问题
4...添加数据接收的事件
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
使⽤中的⼀些常见问题
C#中SerialPort类中DataReceived事件GUI实时处理⽅法(来⾃wanglei_wan@ 的看法)
MSDN:从 SerialPort 对象接收数据时,将在辅助线程上引发 DataReceived 事件。
由于此事件在辅助线程⽽⾮主线程上引发,因此尝试修改主线程中的⼀些元素(如 UI 元素)时会引发线程异常。
如果有必要修改主 Form 或 Control 中的元素,必须下⾯是代码实例:
private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
int SDateTemp = this.serialPort1.ReadByte();
//读取串⼝中⼀个字节的数据
this.tB_ReceiveDate.Invoke(
//在拥有此控件的基础窗⼝句柄的线程上执⾏委托Invoke(Delegate)
//即在textBox_ReceiveDate控件的⽗窗⼝form中执⾏委托.
new MethodInvoker(
/*表⽰⼀个委托,该委托可执⾏托管代码中声明为 void 且不接受任何参数的任何⽅法。
在对控件的 Invoke ⽅法进⾏调⽤时或需要⼀个简单委托⼜不想⾃⼰定义时可以使⽤该委托。
*/
delegate{
/*匿名⽅法,C#2.0的新功能,这是⼀种允许程序员将⼀段完整代码区块当成参数传递的程序代码编写技术,通过此种⽅法可以直接使⽤委托来设计事件响应程序以下就是你要在主线程上实现的功能但是有⼀点要注意,这⾥不适宜处理过多的⽅法,this.tB_ReceiveDate.AppendText(SDateTemp.ToString());//输出到主窗⼝⽂本控件
this.tB_ReceiveDate.Text += " ";}
)
);
}
如何知道当前电脑有哪个串⼝
在窗体上添加⼀个comboBox控件。
然后使⽤comboBox1.Items.AddRange(System.IO.Ports.SerialPort.GetPortNames()); 或者
string[] portList = System.IO.Ports.SerialPort.GetPortNames();
for (int i = 0; i < portList.Length; ++i)
{
string name = portList;
comboBox1.Items.Add(name);
}
例⼦讲解与源码:
Serial Communication using C# and Whidbey
[转载]C#中串⼝通信编程:总结了串⼝类,
C#:
1) 添加引⽤
using System.IO.Ports;
2) 定义SerialPort类实例
private SerialPort SpCom2 = new SpCom ("COM2", 9600,Parity.None, 8, StopBits.One);
3) 设置通讯端⼝号及波特率、数据位、停⽌位和校验位。
SpCom.PortName = "COM1";
SpCom.BaudRate = 9600;
SpCom.Parity = IO.Ports.Parity.None;
SpCom.DataBits = 8;
SpCom.StopBits = IO.Ports.StopBits.One;
或是定义时直接初始化
private SerialPort SpCom2 = new SpCom ("COM2", 9600,Parity.None, 8, StopBits.One);
4) 发送数据
SpCom.Write(TextSendData.Text);
5) 添加接受事件
a) 在运⾏时将事件与事件处理程序相关联(通过委托实现)
SpCom.DataReceived += new SerialDataReceivedEventHandler(SpCom2_DataReceived);
说明:
SerialDataReceivedEventHandler 委托表⽰将处理 SerialPort 对象的 DataReceived 事件的⽅法
b) 添加事件处理程序(签名⼀定要⼀致)
private void SpCom_DataReceived(object sender, SerialDataReceivedEventArgs e)
6) 读取数据
string data = SpCom .ReadExisting();
c#中,确保数据接收完整的串⼝处理程序:
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
/*
int n = comm.BytesToRead;//先记录下来,避免某种原因,⼈为的原因,操作⼏次之间时间长,缓存不⼀致
byte[] buf = new byte[n];//声明⼀个临时数组存储当前来的串⼝数据
received_count += n;//增加接收计数
comm.Read(buf, 0, n);//读取缓冲数据
builder.Clear();//清除字符串构造器的内容
//因为要访问ui资源,所以需要使⽤invoke⽅式同步ui。
this.Invoke((EventHandler)(delegate
{
//判断是否是显⽰为16禁⽌
if (checkBoxHexView.Checked)
{
//依次的拼接出16进制字符串
foreach (byte b in buf)
{
builder.Append(b.ToString("X2") + " ");
}
}
else
{
//直接按ASCII规则转换成字符串
builder.Append(Encoding.ASCII.GetString(buf));
}
//追加的形式添加到⽂本框末端,并滚动到最后。
*
* //要解析字符串,根据长度定位,根据特殊字符定位,来解析数据。
(还是要确保⼀个完整的数据包接收完整,并处理完整) *
this.txGet.AppendText(builder.ToString());
//修改接收计数
labelGetCount.Text = "Get:" + received_count.ToString();
}));
*/
int n = serialPort1.BytesToRead;//待读字节个数
byte[] buf = new byte[n];//创建n个字节的缓存
serialPort1.Read(buf, 0, n);//读到在数据存储到buf
//1.缓存数据
buffer.AddRange(buf);//不断地将接收到的数据加⼊到buffer链表中
//2.完整性判断
while (buffer.Count >= 4) //⾄少包含帧头(2字节)、长度(1字节)、功能位(1字节);根据设计不同⽽不同
{
//2.1 查找数据头
if (buffer[0] == 0x0AA) //传输数据有帧头,⽤于判断. 找到帧头 AA AA 0A
{
int len = buffer[2];
//int len = 79;
if (buffer.Count < len + 4) //数据区尚未接收完整,
{
break;//跳出接收函数后之后继续接收数据
}
//得到完整的数据,复制到ReceiveBytes中进⾏校验
buffer.CopyTo(0, ReceiveBytes, 0, len + 4);//
byte jiaoyan; //开始校验
jiaoyan = 0x01;//jiaoyan = this.JY(ReceiveBytes);
if (jiaoyan != ReceiveBytes[3]) //验证功能位失败 if (jiaoyan != ReceiveBytes[len+3])
{
buffer.RemoveRange(0, len + 4);//从链表中移除接收到的校验失败的数据,
//MessageBox.Show("数据包不正确!");//显⽰数据包不正确,
continue;//继续执⾏while循环程序,
}
buffer.RemoveRange(0, len + 4);
//执⾏其他代码,对数据进⾏处理。
//解析5 6, 7 8字节的经纬度.
DataProgress();
}
else //帧头不正确时,记得清除
{
buffer.RemoveAt(0);//清除第⼀个字节,继续检测下⼀个。
}
}
}
对串⼝⽽⾔,不存在完整数据长度,都是以Byte为单位;⼀般来说,通常是透过时间跟固定数量来进⾏接收动作。
(可能要看各PC的OS或Driver的设置情况)通常在串⼝处理上,要确认接收数据完整,是在PC软件上进⾏接收、保存跟判断的动作,在完整收到後,才进⾏显⽰或处理。
我现在的处理⽅法是根据串⼝接收事件的实际效果来的:接收的数量到达了⼀个数量后,我才开始处理,这样⽐原来的简单的判断效果好多了。
private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
try
{
int byteNumber = SerialPort.BytesToRead;
Common.Delay(20);
//延时等待数据接收完毕。
while ((byteNumber < SerialPort.BytesToRead) && (SerialPort.BytesToRead < 4800))
{
byteNumber = SerialPort.BytesToRead;
Common.Delay(20);
}
int n = SerialPort.BytesToRead; //记录下缓冲区的字节个数
byte[] buf = new byte[n]; //声明⼀个临时数组存储当前来的串⼝数据
SerialPort.Read(buf, 0, n); //读取缓冲数据到buf中,同时将这串数据从缓冲区移除
//设置⽂字显⽰
Control.CheckForIllegalCrossThreadCalls = false;
StringBuilder sb = new StringBuilder();
for (int i = 0; i < n; i++)
{
string s;
if (buf[i] < 16)
s = "0" + Convert.ToString(buf[i], 16).ToUpper() + " ";
else
s = Convert.ToString(buf[i], 16).ToUpper() + " ";
sb.Append(s);
}
textBox1.Text = sb.ToString();
}
catch (Exception ee)
{
}
}。