多线程多接收模式串口类LsComm.docx
- 文档编号:4683599
- 上传时间:2022-12-07
- 格式:DOCX
- 页数:13
- 大小:48.34KB
多线程多接收模式串口类LsComm.docx
《多线程多接收模式串口类LsComm.docx》由会员分享,可在线阅读,更多相关《多线程多接收模式串口类LsComm.docx(13页珍藏版)》请在冰豆网上搜索。
多线程多接收模式串口类LsComm
多线程,多接收模式串口类LsComm
作者:
Liu_sir
下载示例源代码
描述:
一个串口通讯类
应用平台:
Windows
版本:
v1.0
主要功能:
设计了一个简洁易用的多线程串行通讯接口,可以切换查询和自动接收模式,进行对串口数据收发的类
接触VC,很不习惯mscomm等Active控件老让人去注册的方式,所以参照Delphi中的SpComm设计了一个类CComPort,对PJNaughter的CSerialPort(
下面我从如何使用和类的设计两个方面说明一下:
一如何使用:
考虑到使用过程尽可能简洁,实用,为了满足不同的使用要求设计4种接收模式,前两种为手动接收方式,后两种为自动类回调方式,下面是使用代码
1.ManualReceiveByQuery手动查询接收
#include"ComPort.h"
LsComm:
:
CComPortm_ComPort;//LsCommisnamespaceinc++
m_ComPort.Open(2,LsComm:
:
CComPort:
:
AutoReceiveByquery);
//ReCeiveComData:
接收语句
DWORDInBufferCount;
bytepbuffer[2048];
InBufferCount=m_ComPort.GetInBufferCount();
if(InBufferCount>0)
{
m_ComPort.GetInput(pbuffer,InBufferCount);
}
//WriteComData:
写串口数据
chara[10]="abcdefg";
this->m_ComPort.Output(a,sizeof(a));
2.ManualReceiveByConst(异步模式)手动定常数接收模式
#include"ComPort.h"
LsComm:
:
CComPortm_ComPort;//LsCommisnamespaceinc++
m_ComPort.Open(2,LsComm:
:
CComPort:
:
AutoReceiveByConst);
//ReCeiveComData:
//接收数据
DWORDInBufferCount=0;
bytepbuffer[2048];
InBufferCount=this->m_ComPort.GetInput(pbuffer,10,1000);
//上面我要在1000毫秒内接收10字节的数据,IbufferCount返回实际得到的数据
if(InBufferCount==0)
return;
CStringc;
chara[4];
for(inti=0;i<(int)InBufferCount;i++)
{
:
:
sprintf(a,"%2.2X",pbuffer[i]);
c+=a;
c+="";
}
c="接收(Receive):
"+c;
写串口数据的过程同上
注意:
第3,4种模式为自动接收模式,在用以前你必须先定义回调函数,然后,设置类的接收函数
/*回调函数定义*/
voidOnReceiveData(LPVOIDpSender,void*pBuf,DWORDInBufferCount)
{
CStringc;
bytea[100];
charb[4]="";
memcpy(a,pBuf,InBufferCount);
CLsCommDemoDlg*pDlg=(CLsCommDemoDlg*)pSender;
CListBox*pList=(CListBox*)pDlg->GetDlgItem(IDC_LIST1);
for(inti=0;i<(int)InBufferCount;i++)
{
:
:
sprintf(b,"%2.2X",a[i]);
c+="";
c+=b;
}
c="接收(Receive):
"+c;
pList->AddString(c);
}
3.AutoReceiveBySignal自动信号接收模式
#include"ComPort.h"
LsComm:
:
CComPortm_ComPort;//LsCommisnamespaceinc++
m_ComPort.Open(2,LsComm:
:
CComPort:
:
AutoReceiveBySignal);
m_ComPort.SetReceiveFunc((FOnReceiveData)OnReceiveData,this);
m_ComPort.SetBreakHandleFunc(OnComBreak);
//ReCeiveComData:
接收数据函数
inOnReceiveData(LPVOIDpSender,void*pBuf,DWORDInBufferCount)//above
//writedata
thesameasthefirstmode;
4.AutoReceiveByBreak中断接收模式
#include"ComPort.h"
LsComm:
:
CComPortm_ComPort;//LsCommisnamespaceinc++
m_ComPort.Open(2,LsComm:
:
CComPort:
:
AutoReceiveByBreak);
m_ComPort.SetReceiveFunc((FOnReceiveData)OnReceiveData,this);
//ReCeiveComData:
接收数据函数
inOnReceiveData(LPVOIDpSender,void*pBuf,DWORDInBufferCount)//above
//writedata
thesameasthefirstmode;
另外说明2点:
(1)如果你需要处理中断事件,你可以在每种模式中设置中断接收事件:
如下
//定义中断事件接收函数
voidOnComBreak(LPVOIDpSender,DWORDdwMask,COMSTATstat)
{
//dealwiththebreakofcomhere
}
m_ComPort.SetBreakHandleFunc(OnComBreak);//设置中断事件
(2)如何处理如,改变波特率,以及其它参数呢?
m_ComPort.GetSerialPort()可以获得一个CSerialPort类的指针,如何就可以操作各种com属性了.
DCBdcb;
this->m_ComPort.GetSerialPort()->GetState(dcb);
二.类的设计与编程
1.类结构
为了说明一个大概的类构成,我用Rose画了一下类图:
如下
CComPort内部聚合了一个CSerialPort的串口类,并与一个CReadComThread线程关联,让其去读取串口数据.
LsComm:
:
CComPortm_ComPort;//LsCommisnamespaceinc++
m_ComPort.Open(2,LsComm:
:
CComPort:
:
AutoReceiveBySignal);
m_ComPort.SetReceiveFunc(OnReceiveData,this);
m_ComPort.SetBreakHandleFunc(OnComBreak);
这些语句是怎么实现串口数据的发送和读取的呢?
2.打开过程CComPort:
:
Open()
voidCComPort:
:
Open(intnPort,ReceiveModemode,DWORDdwBaud,Parityparity,BYTEDataBits,
StopBitsstopbits,FlowControlfc)
{
//1.新建串口
this->m_pPort=newCSerialPort();
//2.判断收发模式
if(mode==ReceiveMode:
:
ManualReceiveByQuery)
{
this->m_IsOverlapped=false;
}
else
{
this->m_IsOverlapped=true;
}
this->m_RecvMode=mode;
//3.转换参数,打开串口
intindex;
index=parity-CComPort:
:
EvenParity;
CSerialPort:
:
ParityspParity=(CSerialPort:
:
Parity)(CSerialPort:
:
EvenParity+index);
…略去
this->m_pPort->Open(nPort,dwBaud,spParity,DataBits,spStopbits,spFC,m_IsOverlapped);
this->m_pPort->Setup(4096,4096);
this->m_pPort->Purge(PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);
//itisimportant!
!
COMMTIMEOUTStimeouts;
this->m_pPort->GetTimeouts(timeouts);
timeouts.ReadIntervalTimeout=100;
this->m_pPort->SetTimeouts(timeouts);
this->m_CurPortNum=nPort;
//创建关闭事件
this->m_hCloseEvent=CreateEvent(NULL,true,false,NULL);
ASSERT(this->m_hCloseEvent);
//4.创建线程类
this->m_pReadThread=newCReadComThread();
this->m_pReadThread->BandSerialPort(this);
this->m_pReadThread->Create();
this->m_pReadThread->Resume();
if(this->IsOverlapped())
{
this->m_hWriteEvent=:
:
CreateEvent(NULL,false,false,NULL);
}
}
主要做的工作是:
新建串口this->m_pPort=newCSerialPort();
打开串口this->m_pPort->Open
创建读取线程this->m_pReadThread=newCReadComThread();
设立线程类与CComPort的关联关系this->m_pReadThread->BandSerialPort(this);
voidCReadComThread:
:
BandSerialPort(CComPort*pPort)
{
ASSERT(pPort);
this->m_pPort=pPort;
//创建异步读取事件
if(this->m_pPort->IsOverlapped())
{
this->m_ReadOverlapped.hEvent=:
:
CreateEvent(NULL,false,false,NULL);
ASSERT(this->m_ReadOverlapped.hEvent);
this->m_BreakOverlapped.hEvent=:
:
CreateEvent(NULL,false,false,NULL);
ASSERT(this->m_BreakOverlapped.hEvent);
}
}
模式主要在线程执行的过程中发挥作用
3.串口的发送数据过程
DWORDCComPort:
:
Output(void*pBuf,DWORDCount)
{
DWORDdwWriteBytes=0;
if(this->IsOverlapped())//异步模式
{
this->m_pPort->Write(pBuf,Count,this->m_WriteOverlapped);
if(WaitForSingleObject(this->m_WriteOverlapped.hEvent,INFINITE)==WAIT_OBJECT_0)
{
this->m_pPort->GetOverlappedResult(this->m_WriteOverlapped,dwWriteBytes,false);
}
}
else
dwWriteBytes=this->m_pPort->Write(pBuf,Count);
returndwWriteBytes;
}
再看this->m_pPort->Write(pBuf,Count);
实际上是:
调用
DWORDCSerialPort:
:
Write(constvoid*lpBuf,DWORDdwCount)
{
ASSERT(IsOpen());
ASSERT(!
m_bOverlapped);
DWORDdwBytesWritten=0;
if(!
WriteFile(m_hComm,lpBuf,dwCount,&dwBytesWritten,NULL))
{
TRACE(_T("FailedincalltoWriteFile\n"));
AfxThrowSerialException();
}
returndwBytesWritten;
}
或者是BOOLCSerialPort:
:
Write(constvoid*lpBuf,DWORDdwCount,OVERLAPPED&overlapped,DWORD*pBytesWritten)异步写串口的过程
4.串口的读取过程
分两种:
查询读取和线程自动读取
(1)查询读取
DWORDCComPort:
:
GetInput(void*pBuf,DWORDCount,DWORDdwMilliseconds)
{
//不能在自动模式下getinput
if(this->GetReceiveMode()==CComPort:
:
AutoReceiveByBreak||
this->GetReceiveMode()==CComPort:
:
AutoReceiveBySignal)
{
:
:
AfxMessageBox("Can''tuseGetInputmethordinthismode!
");
return0;
}
if(this->IsOverlapped())
{
ASSERT(this->m_pReadThread);
DWORDdwBytes=this->m_pReadThread->ReadInput(pBuf,Count,dwMilliseconds);
this->m_pPort->TerminateOutstandingReads();
returndwBytes;
}
else
returnthis->m_pPort->Read(pBuf,Count);
}
主要是调用m_pPort->Read(pBuf,Count);然后调用API函数ReadFile
(2)线程等待处理
主要过程:
在线程CreadComThread的Execute中
voidCReadComThread:
:
Execute()
{
if(this->m_pPort->GetReceiveMode()==CComPort:
:
ManualReceiveByQuery)
{
this->ExecuteByManualQueryRecvMode();
}
elseif(this->m_pPort->GetReceiveMode()==CComPort:
:
ManualReceiveByConst)
{
this->ExecuteByManualConstRecvMode();
}
elseif(this->m_pPort->GetReceiveMode()==CComPort:
:
AutoReceiveBySignal)
{
this->ExecuteByAutoSignalRecvMode();
}
else//中断模式
{
this->ExecuteByAutoBreakRecvMode();
}
}
主要是选择模式然后执行:
下面看看this->ExecuteByAutoSignalRecvMode();
voidCReadComThread:
:
ExecuteByAutoSignalRecvMode()
{
DWORDdwMask=0;
HANDLEWaitHandles[3];//监听事件数组
DWORDdwSignaledHandle;
WaitHandles[0]=this->m_pPort->GetCloseHandle();
WaitHandles[1]=this->m_ReadOverlapped.hEvent;
WaitHandles[2]=this->m_BreakOverlapped.hEvent;
this->m_pPort->GetSerialPort()->SetMask(EV_ERR|EV_RLSD|EV_RING);
if(!
SetBreakEvent(dwMask))
gotoEndThread;
//设置读事件
if(!
SetReadEvent(this->m_ReadOverlapped))
gotoEndThread;
//设置comEvent
for(;;)
{
dwSignaledHandle=:
:
WaitForMultipleObjects(3,WaitHandles,false,INFINITE);
switch(dwSignaledHandle)
{
caseWAIT_OBJECT_0:
gotoEndThread;
break;
caseWAIT_OBJECT_0+1:
if(!
this->HandleReadEvent(this->m_ReadOverlapped))
gotoEndThread;
if(!
this->SetReadEvent(this->m_ReadOverlapped))
gotoEndThread;
break;
caseWAIT_OBJECT_0+2:
if(!
this->HandleBreakEvent(dwMask))
gotoEndThread;
if(!
this->SetBreakEvent(dwMask))
gotoEndThread;
break;
default:
//gotoEndThread;
break;
}
}
EndThread:
this->m_pPort->GetSerialPort()->Purge(PURGE_RXABORT|PURGE_RXCLEAR);
:
:
CloseHandle(this->m_ReadOverlapped.hEvent);
:
:
CloseHandle(this->m_BreakOverlapped.hEvent);
return;
}
主要是一个等待事件发送然后调用,响应的过程,如果读取事件发生则调用this->HandleReadEvent(this->m_ReadOverlapped);
boolCReadComThread:
:
HandleReadEvent(OVERLAPPED&overlapped)
{
if(this->m_pPort->GetSerialPort()->GetOverlappedResult(overlapped,this->m_InBufferCount,false))
{
returnthis->HandleData();
}
DWORDdwError=:
:
GetLastError();
if(dwError==ERROR_INVALID_HANDLE)
returnfalse;
else
returntrue;
}
如果查询有数据,则this->HandleData();
boolCReadComThread:
:
HandleData()//处理读取数据
{
if(this->m_InBufferCount>0)
{
this->m_pBuffer=newbyte[this->m_InBufferCount];
for(inti=0;i<(int)this->m_InBufferCount;i++)
{
this->m_pBuffer[i]=this->m_InputBuffer[i];
}
this->m_pPort->ReceiveData(this->m_pBuffer,this->m_InBufferCount);
delete[]this->m_pBuffer;
}
returntrue;
}
在这调用了this->m_pPort->ReceiveData(this->m_pBuffer,this->m_InBufferCount);即调用了你传入的函数.整个读取过程就这样了.如果还有不明白,请看我写的CComPort的类的代码.
当然,由于串行通讯各种情况综合在一起比较复杂,另外本人水平有限,所以一时很难考虑全面,这个版本暂时定为1.0,希望大家如果在使用过程中发现什么问题,请及时的告诉偶(E-Mail:
Milo2002@),有时间我做个升级什么的,当然,希望大家多多提出批评意见.
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 多线程 接收 模式 串口 LsComm