我的软件是与PDA通过串口通讯。
我用的是C#语言,串口通讯用的.NET的SerialPort类。
我的SerialPort打开了,为什么有时候我的软件接收不到PDA发送的数据呢?
用串口调试助手与PDA连接成功后,我的软件就能接受到PDA发送的数据了。但是有时候我的软件也能正常的接受PDA发送的数据。
配置参数如下:
BaudRate = 19200;
DataBits = 8;
DisCardNull = False;
DtrEnable = False;
Handshake = None;
Parity = None;
ParityReplace = 63;
PortName = COM1;
ReadBufferSize = 4096;
ReadTimeout = 1000;
ReceiveBytesThreshold = 1;
RtsEnable = False;
StopBits = One;
WriteBufferSize = 2048;
WriteTimeout = 1000;
技术要点:
(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;
}
}
/// <summary>
/// 打开串口
/// </summary>
/// <param name="strCom">串口名“COM1” </param>
/// <param name="nBot">波特率 </param>
/// <param name="nThreshold">引发消息事件的字节数 </param>
public void OpenPort(string strCom, int nBot)
{
try
{
//串口设置与打开
//_com.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(DataReceivedAddress);
_com.PortName = strCom;
_com.BaudRate = nBot;
_com.DataBits = 8;
_com.StopBits = StopBits.One;
_com.Parity = Parity.Even;
_com.Open();
}
catch (Exception ex)
{
//Application.Exit();//退出应用程序
//System.Diagnostics.Process.Start("JT.exe");//启动程序
MessageBox.Show("“" + ex.Message + "”设置硬件功能将不可用,如要使用该功能,请到主窗体的系统设置中选择正确的串口信息,并重新打开该模块!", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning); } }
OpenPort(com1, 9600);
_com.DataReceived += new System.IO.Ports.SerialDataReceivedEventHandler(DataReceivedAddress);
public void DataReceivedAddress(object sender, SerialDataReceivedEventArgs e)
{
byte[] data = new byte[_com.BytesToRead];
_com.Read(data, 0, data.Length);
if (data.Length != 0)
{ DisposeRecvDataAddress(data); }
}
public void DisposeRecvDataAddress(byte[] data)
{
string strReceive = "";
//MessageBox.Show("进来了");
try
{
for (int i = 0; i < data.Length; i++)
{
strReceive += TenToHex(data[i].ToString());
//strReceive += data[i].ToString();
}
然后把接收到的数据按照协议来处理
}
{
if (hComm!=INVALID_HANDLE_VALUE) CloseHandle(hComm);
exit(EXIT_SUCCESS);}
//---------------------------------------------------------------------------void __fastcall TForm1::Button1Click(TObject *Sender)
{
char *ComNo;
DCB dcb;
String Temp;
//取得要打开的通讯端口。
Temp = "COM"+IntToStr(1);
//转换至指针类型Char。
ComNo = Temp.c_str();
hComm = CreateFile(ComNo,GENERIC_READ | GENERIC_WRITE,
0, NULL, OPEN_EXISTING, 0, 0);
if (hComm == INVALID_HANDLE_VALUE) // 如果通讯端口未打开
{
MessageBox(0, "打开通讯端口错误!!","Comm Error",MB_OK);
return;
}
//
GetCommState(hComm,&dcb); // 获得当前通讯端口状态。
dcb.BaudRate = CBR_9600; // 设置速率为9600
dcb.ByteSize = 8; // 字节为8 bit
dcb.Parity = NOPARITY; // Parity 为 None
dcb.StopBits = ONESTOPBIT; // 1 个 Stop bit
//端口设置。
if (!SetCommState(hComm, &dcb)) { // 设置通讯端口状态
MessageBox (0, "通讯端口错误!!!","Set Error",MB_OK);
CloseHandle(hComm);
return;
}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button3Click(TObject *Sender)
{
String Temp;
char *SendData;
int ln;
unsigned long lrc,BS;
if (hComm==0) return; //检查Handle值
Temp = mSend->Text;//取得要发送的字符串
SendData = Temp.c_str(); //字符串转换
//取得要发送的字符串数。
BS = Temp.Length();
//BS = StrLen(SendData); //也可以用此方法取得要发送的字符串长度。
//实际的发送动作。
WriteFile(hComm,SendData,BS, &lrc,NULL); // 发送数据。
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button4Click(TObject *Sender)
{
String Temp;
char inbuff[1024];
DWORD nBytesRead, dwEvent, dwError;
COMSTAT cs;
//取得状态
ClearCommError(hComm,&dwError,&cs);
// 数据是否大于我们准备的缓冲区
if (cs.cbInQue > sizeof(inbuff))
{
PurgeComm(hComm, PURGE_RXCLEAR); // 清除通讯端口数据。
return;
}
ReadFile(hComm, inbuff,cs.cbInQue,&nBytesRead,NULL); //接收通讯端口的数据。
//数组中的字符串接尾处接上\0.
inbuff[cs.cbInQue]= '\0';
//将数组显示在MEMO1上。
mReceive->Text = inbuff;
}
//---------------------------------------------------------------------------
我这里有一个其他编程语言的API,不过API的编程几乎都一样,你参考一下!!
偶尔有错位的情况,自己处理下就行了
是不是硬件有问题啊,发指令没有响应
2. 接收事件里加上适当的延时,可以提高数据填满缓冲区的几率。 可提高通信质量
假设10次丢5次的话(数据未接收完全),适当延时几乎可以保证10次都收到,这是我实际的测试结果。(环境为长距离串口通信)
2、再用串口助手测试你的程序可以正确的发送数据。
3、程序与PDA互发数据。看是否通畅。
我原来做这个也遇到过类似问题,基本这样解决的。主要原因是PDA的串口通信不稳定。所以你有时候儿会认为你的程序有问题,当然也可能是真得有问题。
代码整两盘上来看看?
而用我的程序发送响应命令,PDA上也会显示连接成功,但有时候会接受不到PDA发送的数据。
是不是PDA的问题?
用串口调试助手,PDA的串口时流畅的,能够正常发送和接受数据。
用我的程序,也能与PDA进行正常的通讯。一直都能正常发送数据。因为我的程序发送命令后,PDA会显示连接成功,但有时候即使发送成功,连接成功,但还是接收不到数据。