⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 comport.cpp

📁 EVC(嵌入式VC++)发的用于串口通信的程序
💻 CPP
📖 第 1 页 / 共 2 页
字号:
    wsprintf(sPort, L"COM%d:", 4);//L("COM4:")或者_T("COM4")
	HANDLE hCom;
	DCB dcb;
	COMMTIMEOUTS to;
    m_comport.LoadIniFiles();
	hCom = CreateFile(sPort, GENERIC_READ | GENERIC_WRITE,
			0, // exclusive access, until the handle is closed
			NULL, // no security
			OPEN_EXISTING,
			0, // no overlapped I/O
			NULL); // null template
	m_pConn->hCommDev=hCom;
	m_pConn->bConnected=false;
   if (hCom== INVALID_HANDLE_VALUE )//判断串口句柄
	{
   	return false;
    }
	// set timeout parameter
	// 把间隔超时设为最大,把总超时设为0将导致ReadFile立即返回并完成操作
	to.ReadIntervalTimeout = 0;
	to.ReadTotalTimeoutMultiplier = 0;
	to.ReadTotalTimeoutConstant = 0;
	to.WriteTotalTimeoutMultiplier = 0;
	to.WriteTotalTimeoutConstant = 0;
	if (!SetCommTimeouts(hCom,&to))
	{
		CloseHandle(hCom);
		m_pConn->hCommDev=INVALID_HANDLE_VALUE;
		return false;
	}
	// set serial setting
	GetCommState(hCom, &dcb);
	dcb.BaudRate = m_dcb.dwBaudRate;
	dcb.ByteSize = m_dcb.byByteSize;
	dcb.StopBits = m_dcb.byStopBits;
	dcb.Parity = m_dcb.byParity;
	dcb.fOutxCtsFlow=false;
    dcb.fOutxDsrFlow=false;
    dcb.fDtrControl=false;
    dcb.fRtsControl=false;
	//dcb.fRtsControl = RTS_CONTROL_DISABLE;//RTS_CONTROL_HANDSHAKE;
	dcb.fOutxCtsFlow = FALSE;
	dcb.fInX = dcb.fOutX= false;//屏蔽开关
	dcb.XonChar = 0x00;
	dcb.XoffChar = 0x00;
	dcb.XonLim = 100;
	dcb.XoffLim = 100;
    // other various settings
    dcb.fBinary = TRUE;
    dcb.fParity = false;
	SetCommState(hCom, &dcb);
	PurgeComm(hCom,PURGE_TXCLEAR|PURGE_RXCLEAR); //初始化缓冲区中的信息
    m_hReadCloseEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
	m_hWriteCloseEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
	m_hDataDisposeCloseEvent = CreateEvent(NULL,TRUE,FALSE,NULL);//人工重置,初始化为非信号状态
	//m_hCom=hCom;
    //创建写串口线程
	m_hWriteThread = CreateThread(NULL,0,comWriteThread,this,0,&m_dwWriteThreadID);
	m_pConn->bConnected=true;

	return true;
}

void CComPort::DataDispose()
{
	unsigned char *p; //控制数组m_byRec[]下标移动的指针
   /* LPCHANNEL_DATA m_chandata;
    if(!m_chandata)
         {
            m_chandata = (LPCHANNEL_DATA)GlobalLock(m_chandata);
         }*/
	int nCRC=0; //校验的数据长度
	float  getValue[8]={ 0.0 }; 
	int nValue=0;
    int m=0,n=0,l=0;//m:数组下标起始值,n:组下标结束值,l:控制浮动型数组fValue[]下标
	WORD dwCRC=0;
	p=m_comport.m_byRec;
	BOOL  bCRC=true;  //CRC校验是否正确
	int nFunction=0;  //功能码
	nFunction=m_comport.m_byRec[1];
  for(int i=0;i<counts;i++)
  { if(m_comport.m_byRec[0] == INIDATA[i].address)  //在存储了ini文件中卡件配置信息的结构体数组中查找
  //MEMDATA[128]
	//检查从站地址,看是不是发送给本机的数据
//	if((m_comport.m_byRec[0] == 0x02) || (m_comport.m_byRec[0] == 0x03))  
	{
	   switch(nFunction)//switch
		{
		
			case 3: 
				m_csSync.Lock();//同步处理
				dwCRC=m_comport.CRC16(m_comport.m_byRec,37); //17*2+3,17为MEMDATA[i].RegNumber
				if(dwCRC/256==m_comport.m_byRec[37] && dwCRC%256==m_comport.m_byRec[38])
				{ 	if(m_byType ==1)
					{

					p=p+3;						    
					memcpy(m_comport.m_Reg4,p,34); //要解析的数据保存到m_Reg4[]中,17*2
                    for(m=0,n=3,l=0;m<=28,n<=31,l<8;m+=4,n+=4,l++)
                        {
	                       ChangeData(m_comport.m_Reg4,m,n);
                           //if(m_byType==1)
                             {
                           memcpy(&getValue[l],m_comport.m_Reg4+m,sizeof(float)); //这样默认只取前面四个字节赋值给fValue 
                          // memcpy(&m_chandata->fValue[l],&getValue[l],sizeof(float));
                          //搜索DLL中存取数据到数据库(相应数据结构)中,测试在主函数中显示CHANNEL_DATA.fValue[l]
                           memcpy(&MEMDATA[i].fValue,&getValue[l],sizeof(float));
							 }
						}
                          ////测试显示////
                        for(int k=0;k<8;k++)
                         {
                            printf("DLL:%f\n",getValue[k]);
                         }
						}	
                   ////m_Reg4[34]数组中第34字节即存放报警状态的字节的8位,预留/////
                   //byte bit_0 = (byte)(m_Reg4[33] >> 7);//获取从左往右的第一位
                   //byte bit_7 = (byte)((byte)(b << 7) >> 7);//获取从右往左的第一位
                   //byte bit_6 = (byte)((byte)(b << 6) >> 7);//获取从右往左的第一位
				 bCRC=true;	
				}
				else
				{
					bCRC=false;//校验错
				}
				m_csSync.Unlock();
				break;
			case 4:
			case 5:
			case 6:
				break;
			default:
				break;
		}//switch
	}
	else
	{
		bCRC=false;	//从站号错误,校验码错误
	}
  }
/////////////处理CRC校验错误的情况//////////////
	if(!bCRC)
	{
     m_comport.m_nRec=0;//直接抛弃掉
    //m_comport.m_byRec[]={0};
     //continue;
	}
	SetEvent(m_hDataDisposeCloseEvent); //设置数据解析完成事件,设置事件对象为有信号状态	

}


bool CComPort::WriteComm(BYTE *buf, DWORD dwLength)//写串口函数
{
	DWORD length=dwLength;   //要写入串口的数据长度
//	BYTE buf[MAX_DATA_LEN+1]; //写入串口的字节  不需要重新定义,否则收数据出问题,因为这样外面的*buf的值就传不进来,而这里默认定义的是,所以发送的是0而没有返回值了
	COMSTAT ComStat;
	DWORD dwErrorFlags;
	ClearCommError(m_pConn->hCommDev,&dwErrorFlags,&ComStat); //清除串口可能有的错误
	if (!WriteFile(m_pConn->hCommDev, buf, length, &dwBytesWritten, NULL))//length改成8
	{	
		return false;
	}

	return true;
}

DWORD CComPort::comWriteThread(LPVOID param)//调用创建写线程函数,调用写串口函数,选择卡件
{
   	CComPort *comport = (CComPort*)param;
	BYTE buf[8];
	BYTE buf1[8];
    unsigned char zxaddr;
    unsigned char zxnum;
	WORD dwCRC; //获取CRC16校验值
	int nFunction=3;  //功能码选择
/////////卡件1:AI-8 mA////////
    zxaddr=0x02;//读取地址为02的巡检表数据设备
    zxnum=0x11;//读取三个通道的数据
   /* buf[0]=zxaddr;
    buf[1]=0x03;
    buf[2]=0x00; 
    buf[3]=0x00;
    buf[4]=0x00;
    buf[5]=zxnum;
	dwCRC=m_comport.CRC16(buf,6);
	buf[6]=dwCRC/256;
	buf[7]=dwCRC%256;*/
/////////卡件2:AI-8 mA////////
    buf1[0]=0x03;
    buf1[1]=0x03;
    buf1[2]=0x00;
    buf1[3]=0x00;
    buf1[4]=0x00;
    buf1[5]=0x11;
	dwCRC=m_comport.CRC16(buf1,6);
	buf1[6]=dwCRC/256;
	buf1[7]=dwCRC%256;	
	//wcscpy(buf,(unsigned char)CRC(buf,6));

   // if(m_comport.m_pConn->bConnected) 
	while(m_comport.m_pConn->bConnected)
	  { /* switch(nFunction)//switch
          {
			case 3:*/
           for(int i=0;i<m_comport.counts;i++)//根据配置的卡件个数进行循环发送
		   { 
		   buf[0]=INIDATA[i].address;
		   buf[1]=0x03;
		   buf[2]=0x00; 
		   buf[3]=0x00;
		   buf[4]=0x00;
		   buf[5]=INIDATA[i].RegNumber;
		   dwCRC=m_comport.CRC16(buf,6);
		   buf[6]=dwCRC/256;
		   buf[7]=dwCRC%256;

           ResetEvent(comport->m_hDataDisposeCloseEvent);//数据处理前重置事件对象为非信号状态
			 if (!m_comport.WriteComm(buf,8))
			 {
			  return false;		
			 }
  //发送完后等待数据处理函数处理完后SetEvent置事件对象为信号状态,从而才能继续运行该线程
	       WaitForSingleObject(comport->m_hDataDisposeCloseEvent,INFINITE);//同步处理,等待DataDispose处理完成后再循环发送第二条指令
           //break; 因为没有类似于while的循环,所以不能用
		  /*	if (!m_comport.WriteComm(buf1,8)) //改为一个buf if(!m_comport.WriteComm(buf,8))
			{
			  return false;		
			}*/	
           Sleep(500);
		   }
         /*  break;
           default:
			break; //扩展其他功能码	
	     }//switch*/
	 }   

   
	return 0;
}

//设置回调函数  读线程创建了并启动后就开始执行了,monitor函数是传递回调函数的指针同时建立读线程
bool CComPort::Monitor(LPMONITORPROC lpMonitorProc, LPARAM lParam)
{
   bool bMonitor = false;
   // create monitoring thread
   if(m_pConn && m_pConn->bConnected)
   {
      if(lpMonitorProc)
      {
         if(!m_hMPP)
         {
            m_hMPP = GlobalAlloc(GMEM_MOVEABLE, sizeof(MONITORPROCPARAMS));
            m_pMPP = (LPMONITORPROCPARAMS)GlobalLock(m_hMPP);
         }
         m_pMPP->lpConn = m_pConn;
         m_pMPP->lpCallback = lpMonitorProc; //传递回调函数的指针 
         m_pMPP->lpCallbackParam = lParam;
         // create a secondary thread to watch for an event
         DWORD dwThreadID;
         if(m_hThread=CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)comReadThread,
                           (LPVOID)m_pMPP, 0, &dwThreadID))
         {
            EscapeCommFunction(m_pMPP->lpConn->hCommDev, SETDTR);
            bMonitor = true;
         }         
      }
      else
      {
        // ASSERT(FALSE);  // not currently implemented
      }
   }
   return bMonitor;
}


DWORD CComPort::comReadThread(LPVOID param)//读线程函数 通过回调函数触发
{
   HGLOBAL hParams = (HGLOBAL)param;
   LPMONITORPROCPARAMS pParams = (LPMONITORPROCPARAMS)GlobalLock(hParams);
   if(!pParams)
      return 0;
	HANDLE hCom = (HANDLE)pParams->lpConn->hCommDev ;
	DWORD rtn; //实际读取的字节数
	unsigned char buffer[MAX_DATA_LEN+1]; //和m_byRec[]一样也是存放卡件返回到串缓冲区的数据
	int i=0;
    if (hCom== INVALID_HANDLE_VALUE )
	{
   	return false;
    }
   //PurgeComm(hCom,PURGE_RXCLEAR | PURGE_TXCLEAR);//清空串口
   // SetCommMask(hCom,EV_RXCHAR | EV_CTS| EV_DSR); //设置串口事件集
	while(pParams->lpConn->bConnected) //如果串口状态为已连接上
	{
		COMSTAT ComStat;
		DWORD dwErrorFlags;
		ClearCommError(hCom,&dwErrorFlags,&ComStat); //清除串口可能有的错误
	    DWORD dwLength = ComStat.cbInQue; //读取串口接收处的字节数
		if (dwLength<0)
         { continue; }
		if(dwLength==0)
		  	dwLength=16;
		i++;
        if (ReadFile(hCom, buffer, dwLength, &rtn, NULL)==0 ||rtn==0)//检测到串口没有数据
		{
			CloseHandle(hCom);
			return 0;
		}
	//	if (rtn >0) //如果实际读取的数据大于0,如果=0则有可能死循环,因为不能调用回调函数退出执行
		else //检测到串口有数据		
		{
			if(pParams->lpCallback) //lpCallback为指向回调函数的指针,触发调用回调函数
				pParams->lpCallback(buffer, rtn, pParams->lpCallbackParam);//将接收的数据送回调函数处理
        }
		/*
		DWORD nowTime=0;
		nowTime=::GetTickCount();
		buffer[rtn] = ' \0';
		printf("Data = %d: %s\n",nowTime,buffer);
		Sleep(10);
		*/

	}
	CloseHandle(hCom);
	return 0;
}


//回调函数,接收串口收到的数据
int CALLBACK CComPort::MonitorCallbackGprs(unsigned char *pBuf, int nLen, LPARAM lParam)
{
    int nHeadLen=0;
  // try{
		 if(pBuf && nLen>0)
		 {
			//接收数据
			memcpy(m_comport.m_byRec+m_comport.m_nRec,pBuf,nLen);//类似于定义了数组a[],则a+i=a[i];
			m_comport.m_nRec+=nLen;
			//判断
				if(m_comport.m_nRec>=37)
						{   //m_comport.m_csSync.Lock();
							//处理接收的数据
							m_comport.DataDispose();
							m_comport.m_nRec-=39; //处理完成后已接受的字符数据长度清0
							//m_comport.m_csSync.Unlock();
						
						}
		  }
//	}
   //catch(...)
  //  {
//		m_comport.m_nRec=0;	
//	}
    return 0;
}

bool CComPort::OpenCommPort()
{
	if(!m_comport.OpenComm())
    {
		return false;
	}
	if(!m_comport.Monitor((LPMONITORPROC)&m_comport.MonitorCallbackGprs, (LPARAM)this)) //回调函数将自己函数的地址作为参数传给调用者,通过回调函数通知外部处理
	{
  	   m_comport.CloseComm();
	   return false;
	}
	return true;
}



⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -