C#串口收发数据,子线程更新textbox控件内容,一段时间后,界面卡死,请教问题原因所在

jcyhcs 2014-07-06 03:44:02
1、现象描述:
我自己用C#做了一个模拟流量计软件,下位机大概每100ms会发送一些数据(8字节),我的软件接收后,响应一个9字节的数据。数据的接收和发送都在richtextbox中显示出来。我开了一个子线程,这个线程每100ms去更新textbox控件内容,(就是先读取textbox的内容,在此基础上递增一个常量,再显示在textbox中),程序能够正常运行一段时间,然后就出现了界面卡死的现象,串口能够正常收发,richtextbox中的日志数据能够正常打印,但就是主界面死掉了,点什么都没反应,请教问题出现在什么地方。

为了方便大牛查看问题,现在将我的源程序贴在下面,请指点,谢谢!

关键程序如下:


public void JQHandler()
{
#if true
while (true)
{
//当前气量增加,流速/10
if (chkJQStart.Checked)
{
if (txtCurVol.InvokeRequired)
{
txtCurVol.BeginInvoke(new MethodInvoker(delegate()
{
fCurVol = float.Parse(txtCurVol.Text) + float.Parse(txtFlowRate.Text) / 10.0f;
txtCurVol.Text = fCurVol.ToString("#0.0000");
}));
}
//Thread.Sleep(100);
Thread.CurrentThread.Join(100);
}
}
#endif
}

private void frmFlowMeter_Load(object sender, EventArgs e)
{
//创建一个新的线程
threadTimer = new Thread(JQHandler);
threadTimer.IsBackground = true;
threadTimer.Start();
comport.DataReceived += new SerialDataReceivedEventHandler(ComDataRecv);//串口接到数据会激发这个事件
}

public void ComDataRecv(object sender, SerialDataReceivedEventArgs e)
{

int bytes = comport.BytesToRead;
byte[] buf = new byte[bytes];
comport.Read(buf, 0, bytes);
//1.缓存数据
buffer.AddRange(buf);
//2.完整性判断
while (buffer.Count >= 8)
{
if (buffer[0] > 2) { buffer.RemoveRange(0, buffer.Count); break; } //枪号不对,清除缓冲,重新开始
if (buffer[1] != 3 && buffer[1] != 5) { buffer.RemoveRange(0, buffer.Count); break; } //命令字不是3和5,清除缓冲,重新开始
byte[] ReceiveBytes = new byte[8];
//得到完整的数据,复制到ReceiveBytes中进行校验
buffer.CopyTo(0, ReceiveBytes, 0, 8);
Log(LogMsgType.Incoming, ByteArrayToHexString(ReceiveBytes) + "\n");
cp_ModBusDeed(ReceiveBytes);
buffer.RemoveRange(0, buffer.Count);

}
}
public void cp_ModBusDeed(byte[] RecvBuf)
{
//判断CRC是否正确
ushort usCRC16;
byte CRC16H, CRC16L;
byte[] SendBuf = new byte[9];

usCRC16 = CRC16(0xff, 0xff, RecvBuf, 6);
CRC16H = (byte)(usCRC16 >> 8); CRC16L = (byte)(usCRC16 & 0xff);
if ((RecvBuf[6] != CRC16L) || RecvBuf[7] != CRC16H) return;
if(RecvBuf[1] == 0x03) //读寄存器
{
String strAddr = BitConverter.ToString(RecvBuf,2,2);
strAddr = strAddr.Replace("-", "");
switch(strAddr)
{
case "00F4":
cp_SendComm(SendBuf, "0.0000", true);
break;
case "00F6": //读流速
cp_SendComm(SendBuf, txtFlowRate.Text,true);
break;
case "0102":
cp_SendComm(SendBuf, txtCurVol.Text, true);
break;


}

}
else if (RecvBuf[1] == 0x05) //写寄存器
{
String strAddr = BitConverter.ToString(RecvBuf, 2, 2);
strAddr = strAddr.Replace("-", "");
switch (strAddr)
{
case "0037": //清本次加气量
txtCurVol.BeginInvoke(new EventHandler(delegate { txtCurVol.Text = "0.0000"; }));
//Thread.Sleep(30);
cp_SendComm(RecvBuf,"",false);
break;

}
}



}
public void cp_SendComm(byte[] SendBuf, String strData, bool CountCRCF)
{
float TemSingle;
ushort usCRC16;
if (CountCRCF)
{
SendBuf[0] = 1;
SendBuf[1] = 3;
SendBuf[2] = 4;
TemSingle = float.Parse(strData);
unsafe
{
byte* p = (byte*)&TemSingle;
for (int i = 0; i < 4; i++) SendBuf[i + 3] = p[3 - i];
}
//填写CRC
usCRC16 = CRC16(0xff, 0xff, SendBuf, 7);
SendBuf[7] = (byte)(usCRC16 & 0xff);
SendBuf[8] = (byte)(usCRC16 >> 8);
}
//Thread.Sleep(50);
if(comport.IsOpen)
{
comport.Write(SendBuf, 0, SendBuf.Length);
Log(LogMsgType.Outgoing, ByteArrayToHexString(SendBuf) + "\n");
}


}
private void Log(LogMsgType msgtype, string msg)
{
rtfTerminal.BeginInvoke(new EventHandler(delegate
{
rtfTerminal.SelectedText = string.Empty;//表示空字符串。此字段为只读
rtfTerminal.SelectionFont = new Font(rtfTerminal.SelectionFont, FontStyle.Regular);
rtfTerminal.SelectionColor = LogMsgTypeColor[(int)msgtype];
if (msgtype == LogMsgType.Incoming)
rtfTerminal.AppendText("Recv:[" + DateTime.Now.ToLongTimeString() + ":" + DateTime.Now.Millisecond + "] ");
else if (msgtype == LogMsgType.Outgoing)
rtfTerminal.AppendText("Send:[" + DateTime.Now.ToLongTimeString() + ":" + DateTime.Now.Millisecond + "] ");
else
rtfTerminal.AppendText("[" + DateTime.Now.ToLongTimeString() + ":" + DateTime.Now.Millisecond + "] ");
rtfTerminal.AppendText(msg);
rtfTerminal.ScrollToCaret();
}));
}



...全文
895 8 打赏 收藏 转发到动态 举报
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
lccleo 2015-12-25
  • 打赏
  • 举报
回复
引用 7 楼 woainicaicai 的回复:
但是那个 comport.DataReceived += new SerialDataReceivedEventHandler(ComDataRecv);//串口接到数据会激发这个事件 不是会自动创建一个线程吗?这个相当于我没有在主线程里面进行通信啊?不是很明白,请指点
我也遇到同样问题了,一开始自己在UI没有新建进程,用DataReceived 事件加invoke回调 在串口速度很快的时候,例如大于100Hz的时候,用上述方法的效果非常不好,因为Invoke使本在辅助线程执行的指令发送到主线程的消息队列中执行,容易引起主线程消息阻塞,界面响应不好。 楼主说的对 DataReceived 自己开了辅助线程 然后我在UI自己开了线程被卡死了
jcyhcs 2014-07-06
  • 打赏
  • 举报
回复
但是那个 comport.DataReceived += new SerialDataReceivedEventHandler(ComDataRecv);//串口接到数据会激发这个事件 不是会自动创建一个线程吗?这个相当于我没有在主线程里面进行通信啊?不是很明白,请指点
於黾 2014-07-06
  • 打赏
  • 举报
回复
comport.DataReceived += new SerialDataReceivedEventHandler(ComDataRecv);//串口接到数据会激发这个事件 还有,你把串口通信的代码写在主线程里了。 涉及通信的,最好都另开线程。反而是UI应该在主线程。 你弄反了。 通信放主线程,更新UI放新线程里再委托,这是闹哪样
於黾 2014-07-06
  • 打赏
  • 举报
回复
textbox中的内容不能太多,否则刷新时间比100ms还长的话,那么就变成所有时间都在忙着刷新你那个textbox。
jcyhcs 2014-07-06
  • 打赏
  • 举报
回复
但是我在子线程里面已经用了匿名委托来更新控件了啊,如下: public void JQHandler() { #if true while (true) { //当前气量增加,流速/10 if (chkJQStart.Checked) { if (txtCurVol.InvokeRequired) { txtCurVol.BeginInvoke(new MethodInvoker(delegate() { fCurVol = float.Parse(txtCurVol.Text) + float.Parse(txtFlowRate.Text) / 10.0f; txtCurVol.Text = fCurVol.ToString("#0.0000"); })); } //Thread.Sleep(100); Thread.CurrentThread.Join(100); } } #endif }
tanta 2014-07-06
  • 打赏
  • 举报
回复
多线程更新界面一定要用代理
Anymore 2014-07-06
  • 打赏
  • 举报
回复
委托试试 http://blog.sina.com.cn/s/blog_a3d2fd2d0101dcwy.html
jcyhcs 2014-07-06
  • 打赏
  • 举报
回复
请问如何添加附件啊,程序不能全部贴上来,不知道能不能把关键点给大家显示出来了

110,534

社区成员

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

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

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