主题:串口通讯线程问题 共有38975人关注过本帖 |
---|
bingdongcha |
1楼 信息 | 搜索 | 邮箱 |
加好友 发短信 |
串口通讯线程问题 Post By:2013-5-21 22:30:00 [只看该作者]
DWORD WINAPI CCESerial::ReceiveThreadFunc(LPVOID lparam) {
CCESerial *lpSerial = (CCESerial*)lparam;
DWORD dwEvtMask, dwReadError;
COMSTAT
cmStat;
ULONG nWillLen;
SetCommMask( lpSerial->m_hSer, EV_RXCHAR|EV_ERR );
for( ; ; )
{
printf( "WRITE WRITE WRITE WRITE CHAR \r\n"); /************************************************************************************************ //
if( WaitCommEvent( lpSerial->m_hSer, &dwEvtMask, NULL ) ) //
{ //
SetCommMask( lpSerial->m_hSer, EV_RXCHAR|EV_ERR ); //
// get how many data available in receive buffer //
if( dwEvtMask & EV_RXCHAR ) //
{ //
ClearCommError( lpSerial->m_hSer, &dwReadError, &cmStat );
//取接收数据长度信息 //
nWillLen = cmStat.cbInQue; //
if( nWillLen <=0 ) //
continue; // //
lpSerial->m_lDatLen = 0; //
ReadFile( lpSerial->m_hSer, lpSerial->DatBuf, nWillLen, &lpSerial->m_lDatLen, 0 ); //
//
if( lpSerial->m_lDatLen>0 ) //
{ //
// 调用回调函数处理接收到的数据 //
lpSerial->OnReceive( ); //
} //
} //
else if( dwEvtMask & EV_ERR ) //
{ //
// 清错误标志 //
ClearCommError( lpSerial->m_hSer, &dwReadError, &cmStat ); //
lpSerial->OnError( ); //
} // //
} // //
if( WaitForSingleObject( lpSerial->m_hKillRxThreadEvent, 0 ) == WAIT_OBJECT_0) //
{ //
SetEvent( lpSerial->m_hReceiveCloseEvent ); //
break; //
} *************************************************************************************************/
}
return 0; } 上边这个线程 可以循环打印,但是把注释的部分打开,只能运行一次打印。好像是线程只运行了一次。 在if( WaitCommEvent( lpSerial->m_hSer, &dwEvtMask, NULL ) )设置断点,暂停后也不能单步运行。按单步也直接就启动了。 是和WaitCommEvent( lpSerial->m_hSer, &dwEvtMask, NULL ) 这个函数有关系么?? 串口打开时是异步通信方式-非阻塞方式打开的。 m_hComm = CreateFile( szPort, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
// 异步通信方式-非阻塞方式 或者有跟好的方法实现在线程内实现收发数据。主要想做循环式通讯规约。 [此贴子已经被作者于2013-5-21 22:39:56编辑过]
|
单帖管理 | 引用 | 回复 |
lqk |
2楼 信息 | 搜索 | 邮箱 |
加好友 发短信 |
Post By:2013-5-22 9:41:00 [只看该作者]
WINCE不支持重叠I/O模式,所以不能使用FILE_FLAG_VOERLAPPED参数。
WaitCommEvent总是阻塞等待数据接收。 通讯规约一般有固定的格式,需要根据通讯规约将接收数据在本地缓存处理,然后根据接收数据的内核,做相应的应答。
|
单帖管理 | 引用 | 回复 |
bingdongcha |
3楼 信息 | 搜索 | 邮箱 |
加好友 发短信 |
Post By:2013-5-24 11:27:00 [只看该作者]
现在是这样实现的,把代码贴出来,童鞋们可以借鉴,老鸟们批判下。我继续改正。 电力规约循环发送CDT报文,串口没有用重叠I/O模式,线程启动前先发送一个字节,触发EV_TXEMPTY事件。以后就可以循环发送了,串口有数据来时,也可以接受处理。 最后的一句Sleep();加上它,报文会有卡顿。不加Sleep();这个线程一直在运行,不知道长时间运行对其他线程是否会有影响。暂时测试没有影响,所以把Sleep();封掉了。 DWORD WINAPI CDTSend(PVOID lparam) {
PVOID lpflag;
lpflag = lparam;
DWORD
dwEvtMask, dwReadError;
COMSTAT
cmStat;
ULONG
nWillLen;
unsigned char buf = 0xff;
BOOL
bReadStatus;
cdt_tx0.OpenPort(CDTA_Port,CDTA_Bate,CDTA_Pn,8,1);
SetCommMask(cdt_tx0.m_hComm, EV_RXCHAR|EV_ERR|EV_TXEMPTY);
cdt_tx0.WritePort(&buf,1);
while(TRUE)
{
// 阻塞串口时间 一直等待事件发生。
if(WaitCommEvent(cdt_tx0.m_hComm, &dwEvtMask, NULL))
{
SetCommMask(cdt_tx0.m_hComm, EV_RXCHAR|EV_ERR|EV_TXEMPTY);
if( dwEvtMask & EV_RXCHAR )
{
printf( "CDT_TX0 RECV RECV SUCCESS \r\n");
ClearCommError( cdt_tx0.m_hComm, &dwReadError, &cmStat );
//取接收数据长度信息
nWillLen = cmStat.cbInQue;
// cbInQue:表示接收缓冲区中存储的待ReadFile读取的字节数。
// cbOutQue:表示发送缓冲区中存储的待发送的字节数。
if( nWillLen <=0 )
continue;
cdt_tx0.RecvLen = 0;
bReadStatus = ReadFile(cdt_tx0.m_hComm, cdt_tx0.AcceBuf, nWillLen, &cdt_tx0.RecvLen, NULL);
if(cdt_tx0.RecvLen > 0)
cdt_tx0.Acces(cdt_tx0.AcceBuf,cdt_tx0.RecvLen);
}
if(dwEvtMask & EV_TXEMPTY)
{
cdt_tx0.WritePort(cdt_tx0.SendBuf,cdt_tx0.SendLen);
}
else if(dwEvtMask & EV_ERR)
{
// 清错误标志
ClearCommError(cdt_tx0.m_hComm, &dwReadError, &cmStat);
}
} //
Sleep(99);
// 线程挂起时间99MS 调度时间1MS 线程重新运行时间100MS
}
return 0; }
|
单帖管理 | 引用 | 回复 |
lqk |
4楼 信息 | 搜索 | 邮箱 |
加好友 发短信 |
Post By:2013-5-24 13:12:00 [只看该作者]
数据的接收和发送完全可以由两个线程来分别完成,在我们网站上有一篇基于RS485的电力系统DL645协议规约的实现方法http://www.emtronix.com/article/article2009326.html,可以做为一个例子参考。
如果需要源码,请留下邮箱。
|
单帖管理 | 引用 | 回复 |
bingdongcha |
5楼 信息 | 搜索 | 邮箱 |
加好友 发短信 |
Post By:2013-5-24 15:35:00 [只看该作者]
我们也做645规约。
gyangchina@163.com这是我的邮箱,感谢共享源码。 万分感谢!!
|
单帖管理 | 引用 | 回复 |
lqk |
6楼 信息 | 搜索 | 邮箱 |
加好友 发短信 |
Post By:2013-5-24 17:16:00 [只看该作者]
例程已发到你邮箱,请查收。
|
单帖管理 | 引用 | 回复 |