i++>
m_bWriteBuffer[i]=bWriteBuffer[i]。
//seteventforwrite
SetEvent(m_hWriteEvent>。
}
......
由于我们改串口接入了20台温度设备,在进行通讯地时候是通过发送某个地址地设备命令进行读取数据.我们首先对硬件设置相应地地址,这里我们设置0到19号地址.采集地时候采用循环地方式从0号地址向19号地址进行读取数据.当收到相应地数据包地时候我们进行相应地地址地数据解包处理.然后发送下一个地址地要数据命令.当地址为最后一台设备地时候我们将地址清0处理就可以了.但是如果我们这个20台设备中间某一个或者多个设备由于故障或者电源没开地话,上述通讯就会出现问题,我们发送没有运行地地址设备就会收不到相应地报文,我们就不会发送下一个地址地要数据命令,这是程序就会不走下去了.解决方法可以是我们从外部去判断是否对当前地址地发送要数据命令和收到数据命令是否超时.如果超时就进行跳过然后发送下一个地址要数据命令.当出现规定几个循环地时候进行该设备地采集参数清0等工作这个就可以随自己定义考虑了.具体实现如下:
jLBHrnAILg
定义SERIALPORT类对象,创建线程进行通讯.
CSerialPortm_Ports。
intnColtAddr,//这个用来存放当前采集设备地址.
nColts。
//这个用来存放当前缓冲区收到地字节数目
HANDLEm_pThread。
//外部控制线程
BYTEm_RecBuff[1000]。
//接收缓冲区
floatfVal[20]。
//处理解包内容,这里可以根据实际情况进行定义.
启动串口监视线程和外部控制线程
nColtAddr=0。
nColts=0。
if(m_Ports.InitPort(this,1,4800,'N',8,1,EV_RXCHAR|EV_RXFLAG,1024>>xHAQX74J0X
{
this->m_Ports.StartMonitoring(>。
启动监视线程
SetCommVal(>。
发送第一台设备数据命令
}
下面是启动外部控制线程
unsignedintnDummy。
m_pThread=(HANDLE>_beginthreadex(NULL,0,CommThread,this,CREATE_SUSPENDED,&nDummy>。
//开辟外部控制线程LDAYtRyKfE
ResumeThread(m_pThread>。
运行线程
外部控制线程控制当前设备发送要数据命令和收到数据报文是否超时
UINTC××××View:
:
CommThread(LPVOIDpParam>
{
C××××View*pView=(C××××View*>pParam。
while(1>
{
CTimecNowTime=CTime:
:
GetCurrentTime(>。
tNow=cNowTime.GetTime(>。
struct_timebtimebuffer。
_ftime(&timebuffer>。
intnNowMillSecond=timebuffer.millitm。
///
tLast=cLastColtTime[0].GetTime(>。
if((tNow-tLast>*1000+(nNowMillSecond-nMillSecond[0]>>800>Zzz6ZB2Ltk
pView->SetCommVal(>。
发送下一台设备要数据命令或者进行其他地相关处理
Sleep(100>。
}
}
发送串口数据命令,这里要根据外部设备地制定地通讯协议来进行.这次温度表采用地是ASCII地形式通讯.
voidC××××View:
:
SetCommVal(>
{
intHAddr,LAddr,m_Xnh。
intnHAdd,nLAdd。
nHAdd=ExchangeAscII((nColtAddr>>4>&0x0f>。
nLAdd=ExchangeAscII(nColtAddr&0x0f>。
m_Xnh=nHAdd^nLAdd^0x52^0x44。
HAddr=ExchangeAscII((m_Xnh>>4>&0x0f>。
LAddr=ExchangeAscII(m_Xnh&0x0f>。
BYTEOutBuff[8]={0x40,nHAdd,nLAdd,0x52,0x44,HAddr,LAddr,0x0d}。
dvzfvkwMI1
m_Ports.WriteToPort(OutBuff,8>。
cLastColtTime=CTime:
:
GetCurrentTime(>。
nColtAddr++。
if(nColtAddr>19>//19definemaxaddrnumbers
nColtAddr=0。
}
ASCII码地一些简单变换,我们进行一下简单地封装,方便调用:
BYTEC××××View:
:
ExchangeAscII(BYTEbInput>
{
BYTEbRef=0。
if(bInput>9>
bRef=bInput+0x37。
else
bRef=bInput+0x30。
returnbRef。
}
BYTEC××××View:
:
ExchangeAscIItoNormal(BYTEbInput>
{
BYTEbRef=0。
if(bInput>0x39>
bRef=bInput-0x37。
else
bRef=bInput-0x30。
returnbRef。
}
LONGC×××View:
:
OnCommunication(WPARAMch,LPARAMport>进行数据处理,WPARAM,LPARAM类型是多态性数据(polymorphicdatatype>,在WIN32中为32位,支持多种数据类型,根据需要自动适应,这样程序就有很强地适应性.再次我们这里理解成为BYTE类型<与外围设备通讯协议保持一致,方便解包).每当串口接收缓冲区内有一个字符地时候,就会产生一个WM_COMM_RXCHAR消息,触发OnCommunication函数,下面我们可以根据我们地需要进行解包处理了;rqyn14ZNXI
LONGCMy11View:
:
OnCommunication(WPARAMch,LPARAMport>EmxvxOtOco
{
if(port==1>
{
m_RecBuff[nColts]+=(BYTE>(char*>(ch>。
nColts++。
if(nColts==24>//这里根据通讯协议规定地发送定制要数据命令就会上传24个字节地数据报文内容.这里可以根据不同外部设备进行不同地设置SixE2yXPq5
{
DataProcessTemp(m_RecBuff>。
//处理解包
nColts=0。
//缓冲区指针清0,准备接收下一台设备数据
ResetBuffVal(>。
//清空缓冲区内容
SetCommVal(>。
//发送下一台设备内容
}
}
return0。
}
数据解包处理,这里就必须根据外部设备定义地通讯协议来处理了.
voidCMy11View:
:
DataProcessTemp(BYTEm_Inbuff[]>
{
intnTempAddr=nColtAddr-1。
if(nTempAddr<0>
nTempAddr=19。
intnHAdd,nLAdd。
nHAdd=ExchangeAscII((nTempAddr>>4>&0x0f>。
nLAdd=ExchangeAscII(nTempAddr&0x0f>。
if(m_Inbuff[0]==0x40>
{
if(m_Inbuff[1]==nHAdd&&m_Inbuff[2]==nLAdd>
{
if(m_Inbuff[3]==0x52&&m_Inbuff[4]==0x44>
{
intnzTemp[5]。
floatfTemp。
nzTemp[0]=m_Inbuff[7]。
nzTemp[1]=m_Inbuff[8]。
nzTemp[2]=m_Inbuff[9]。
nzTemp[3]=m_Inbuff[10]。
for(inti=0。
i<4。
i++>
{
if(nzTemp[i]>0x39>
nzTemp[i]-=0x37。
else
nzTemp[i]-=0x30。
}
fTemp=float(nzTemp[1]+(nzTemp[0]<<4>+(nzTemp[3]<<8>+(nzTemp[2]<<12>>/10。
6ewMyirQFL
fVal[nTempAddr]=fTemp。
RedrawWindow(>。
}
}
}
}
voidCMy11View:
:
ResetBuffVal(>
{
for(inti=0。
i<1000。
i++>
m_RecBuff[i]=0。
}
至此,基本地通讯外围程序基本完成,如果我们要扩充多个串口多线程地话,我们可以做如下修改:
CSerialPortm_Ports[20]。
BYTEm_RecBuff[20][1000]。
BYTEm_SendBuff[5][1000]。
intnColts[20]。
intnZBKType[24]。
intnWrongCount[20][20]。
intnColtAddr[20]。
HANDLEm_pThread。
//ProtectDevice
if(this->m_Ports[0].InitPort(this,2,9600,'N',8,1,EV_RXCHAR|EV_RXFLAG,1024>>kavU42VRUs
{
this->m_Ports[0].StartMonitoring(>。
SetComBufferVal(0>。
}
//DianduDevice
if(this->m_Ports[1].InitPort(this,4,1200,'E',8,1,EV_RXCHAR|EV_RXFLAG,1024>>y6v3ALoS89
{
this->m_Ports[1].StartMonitoring(>。
SetComBufferVal(1>。
}
我们对各种发送命令函数进行载入形参地方法来解决.