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

📄 serial.cpp

📁 程序实现了PDA对手持型GPS的导航设计。用一个串口类控制串口通讯
💻 CPP
字号:
// Serial.cpp: implementation of the CSerial class.

//

//////////////////////////////////////////////////////////////////////

 

#include "stdafx.h"
#include "Serial.h"
#include "GpsNavDoc.h" 
#include "MainFrm.h"


#include <windows.h>



#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif


 
TCHAR* GetUnicodeString(const char *s);

//////////////////////////////////////////////////////////////////////

// Construction/Destruction

//////////////////////////////////////////////////////////////////////
 

CSerial::CSerial()
{
	m_strReceived="";
	m_index=0;
} 

CSerial::~CSerial()
{
       if(hPort != INVALID_HANDLE_VALUE)
              ClosePort(hPort);
} 

BOOL CSerial::OpenPort(CWnd* pPortOwner,UINT  portnr,UINT  baud,char  parity,UINT  databits,UINT  stopbits,DWORD dwCommEvents,UINT  buffersize)
{
	   if(!(portnr > 0 && portnr < 5&&pPortOwner != NULL))
		   return FALSE;
       DWORD dwError,dwThreadID;
	   CString str="";
	   TCHAR *szPort = new TCHAR[50];
       if(hPort!= NULL)
       {
			CloseHandle(hPort);
			hPort = NULL;
       }
	   str.Format( _T("COM%d:"), portnr);
	   lstrcpy(szPort,(LPCTSTR)str);

       //打开串口
       hPort = CreateFile (szPort, 
						GENERIC_READ | GENERIC_WRITE,
						0, 
						NULL, 
						OPEN_EXISTING,
						0, 
						NULL);
       //如果打开端口出错, 返回FALSE
       if ( hPort == INVALID_HANDLE_VALUE )
       {
              //不能打开端口
              CString strError;
              strError.Format(_T("Unable to open com%d, Error No.=%d"),portnr, GetLastError());
              MessageBox (NULL, strError,      TEXT("Error!"), MB_OK);
			  delete [] szPort;
			  //delete [] szBaud;
              return FALSE;
       }
       //指定端口监测的事件集
       SetCommMask (hPort, dwCommEvents);
       //分配设备缓冲区
       SetupComm(hPort,buffersize,buffersize);
       //初始化缓冲区中的信息
       PurgeComm(hPort,PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT); 

       //配置串行端口
       if(!InitDCB(baud))
              return FALSE; 

       //设置端口超时值
       if(!InitCommTimeouts())
              return FALSE;
 
       //设置端口上指定信号的状态
       // SETDTR: 发送DTR (data-terminal-ready)信号
       // SETRTS: 发送RTS (request-to-send)信号

       EscapeCommFunction (hPort, SETDTR);
       EscapeCommFunction (hPort, SETRTS);

        //创建一个从串口读取数据的线程
       if (hReadThread = CreateThread (NULL, 0, ReadPortThread, this, 0,&dwThreadID))
       {

       }
       else
       {
              //不能创建线程
              MessageBox (NULL, TEXT("Unable to create the read thread"),TEXT("Error!"), MB_OK);
              dwError = GetLastError ();
              return FALSE;
       }
       m_bConnected=TRUE;
	   m_pOwner=pPortOwner;
       return TRUE;
}

 

DWORD CSerial::WritePort(TCHAR *buf,DWORD dwCharToWrite)
{
       BOOL fWriteState;
       DWORD dwBytesWritten; 
       //写入数据
       fWriteState=WriteFile(hPort,buf,dwCharToWrite*sizeof(TCHAR),&dwBytesWritten,NULL);
       if(!fWriteState)
       {
              //不能写数据
              MessageBox(NULL,TEXT("Can't Write String to Comm"),TEXT("Error!"),MB_OK);
              dwBytesWritten=0;
       }
       return dwBytesWritten;
} 

BOOL CSerial::ClosePort(HANDLE hCommPort)
{
       if (hCommPort != INVALID_HANDLE_VALUE)
       {
              //设置连接属性为FALSE
              m_bConnected=FALSE;
              //结束线程中WaitCommEvent的等待
              SetCommMask(hPort,0);
              //阻塞至线程停止

              if(hReadThread)
              {
                     TerminateThread(hReadThread,0);
                     CloseHandle(hReadThread);
              }

              //清除端口上指定信号的状态
              EscapeCommFunction(hPort,CLRDTR);
              EscapeCommFunction(hPort,CLRRTS);
              //清除驱动程序内部的发送和接收队列

              PurgeComm(hPort,PURGE_TXCLEAR|PURGE_RXCLEAR);
              //关闭串口
              CloseHandle (hCommPort);
              hCommPort = INVALID_HANDLE_VALUE;
              return TRUE;
       }
       else
       {
              return TRUE;
       }
} 

BOOL CSerial::InitDCB(UINT  baud)
{
       DCB PortDCB;
       DWORD dwError; 

       PortDCB.DCBlength = sizeof (DCB); 

       //得到端口的默认设置信息
       GetCommState (hPort, &PortDCB); 

       //改变DCB结构设置
       PortDCB.BaudRate = baud;               //波特率
       PortDCB.fBinary = TRUE;                //Win32不支持非二进制串行传输模式,必须为TRUE
       PortDCB.fParity = TRUE;                 //启用奇偶校验
       PortDCB.fOutxCtsFlow = TRUE;            //串行端口的输出由CTS线控制
       PortDCB.fOutxDsrFlow = FALSE;           //关闭串行端口的DSR流控制
       PortDCB.fDtrControl = DTR_CONTROL_ENABLE;   //启用DTR线
       PortDCB.fDsrSensitivity = FALSE;        //如果设为TRUE将忽略任何输入的字节,除非DSR线被启用
       //PortDCB.fTXContinueOnXoff = TRUE;       //当为TRUE时,如果接收缓冲区已满且驱动程序已传送XOFF字符,将使驱动程序停止传输字符

       PortDCB.fTXContinueOnXoff = FALSE;
       PortDCB.fOutX = FALSE;                  //设为TRUE指定XON/XOFF控制被用于控制串行输出 
       PortDCB.fInX = FALSE;                   //设为TRUE指定XON/XOFF控制被用于控制串行输入 
       PortDCB.fErrorChar = FALSE;             //WINCE串行驱动程序的默认执行将忽略这个字段 
       PortDCB.fNull = FALSE;                  //设为TRUE将使串行驱动程序忽略收到的空字节 
       PortDCB.fRtsControl = RTS_CONTROL_ENABLE;   //启用RTS线 
       PortDCB.fAbortOnError = FALSE;          //WINCE串行驱动程序的默认执行将忽略这个字段
       PortDCB.ByteSize = 8;                   //每字节的位数 
       PortDCB.Parity = NOPARITY;              //无奇偶校验 
       PortDCB.StopBits = ONESTOPBIT;          //每字节一位停止位  

       //根据DCB结构配置端口 
       if (!SetCommState (hPort, &PortDCB))
       {
              //不能配置串行端口
              MessageBox (NULL, TEXT("Unable to configure the serial port"),TEXT("Error!"), MB_OK);
              dwError = GetLastError ();
              return FALSE;
       }
       return TRUE;
}
 

BOOL CSerial::InitCommTimeouts()
{
       COMMTIMEOUTS CommTimeouts;
       DWORD dwError;
 
       //得到超时参数
       GetCommTimeouts (hPort, &CommTimeouts); 

       //改变COMMTIMEOUTS结构设置
       CommTimeouts.ReadIntervalTimeout =MAXDWORD;//1000;
       CommTimeouts.ReadTotalTimeoutMultiplier = 0;//1000;
       CommTimeouts.ReadTotalTimeoutConstant = 0;//1000;
       CommTimeouts.WriteTotalTimeoutMultiplier = 0;
       CommTimeouts.WriteTotalTimeoutConstant = 5000;//5000;
 

       //设置端口超时值 
       if (!SetCommTimeouts (hPort, &CommTimeouts))
       {
              //不能设置超时值
              MessageBox (NULL, TEXT("Unable to set the time-out parameters"), TEXT("Error"), MB_OK);
              dwError = GetLastError ();
              return FALSE;
       }
       return TRUE;
}

DWORD WINAPI ReadPortThread(LPVOID pParam)
{
							 
	POSITION po=AfxGetApp()->GetFirstDocTemplatePosition();
	CDocTemplate *pDocTem=AfxGetApp()->GetNextDocTemplate(po);
	po=pDocTem->GetFirstDocPosition();
	CGpsNavDoc *pDoc=(CGpsNavDoc *)pDocTem->GetNextDoc(po);

	CSerial *port = (CSerial*)pParam;

    BOOL fReadState;
    DWORD dwCommModemStatus;

    DWORD dwLength,dwreadedLength;
	dwreadedLength=0;
    COMSTAT ComStat;
    DWORD dwErrorFlags;
	unsigned char RXBuff;
    /*char* buf=new char[256];*/
	int nTemp=0;
	BOOL bResult;
	int i=0;
	unsigned long r_len = 0;
	OVERLAPPED _ro; // 重叠I/O
	
	_ro.Offset = 0;
	_ro.OffsetHigh = 0;

	// create events
	DWORD CommEvent = 0;
	_ro.hEvent = NULL;
	if (_ro.hEvent != NULL)
		ResetEvent(_ro.hEvent);
	_ro.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

	CMainFrame *pMain =(CMainFrame *)AfxGetMainWnd();
	PurgeComm(port->hPort, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);
    while (port->hPort != INVALID_HANDLE_VALUE) 
    {
           //等待串口的事件发生
			//PurgeComm(port->hPort,PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT); 

			//PurgeComm(port->hPort,PURGE_RXCLEAR);
			// 指定监视的端口事件
			//SetCommMask (port->hPort, EV_RXCHAR | EV_CTS /*| EV_DSR | EV_RLSD | EV_RING */);

           bResult =WaitCommEvent (port->hPort, &dwCommModemStatus, &_ro);//(NULL);
		   if(!bResult)
			   continue;

		   ClearCommError(port->hPort,&dwErrorFlags,&ComStat);
		   if (ComStat.cbInQue == 0)
			   continue;			
		   
			//SetCommMask (port->hPort, EV_RXCHAR | EV_CTS /*| EV_DSR | EV_RING */);////
			if ((dwCommModemStatus & EV_RXCHAR) == EV_RXCHAR) 
			{//有数据信号
				pDoc->UpdateAllViews(NULL);

                  ClearCommError(port->hPort,&dwErrorFlags,&ComStat);
                  //cbInQue返回在串行驱动程序输入队列中的字符数
                  dwLength=ComStat.cbInQue;
                  if(dwLength>0)
				  {	
					  //从串口读取数据
                      fReadState=ReadFile(port->hPort,
											/*buf,*/&RXBuff,
											/*dwLength,*/1,
											&dwreadedLength,
											&_ro);
											//NULL);
                      if(!fReadState)
                      {
                             //不能从串口读取数据
                             MessageBox(NULL,TEXT("Error in read from serial port"),TEXT("Read Error"),MB_OK);
                      }
                      else
                      {
							char ch=(char)RXBuff;

							if (ch == 10 && port->m_strReceived[port->m_index-1] == 13)
							{
 								port->m_strReceived+=ch;
								port->m_index++;
								i=port->m_strReceived.Find(_T("$GPGGA"));
								if(i==-1)
								{
									return 0;
								}
								port->m_strReceived=port->m_strReceived.Mid(i);	
								pMain->m_strReceived=port->m_strReceived;
								::SendMessage((port->m_pOwner)->m_hWnd, WM_COMM_RXCHAR, (WPARAM)0, (LPARAM) port->m_nPortNr);
								port->m_index=0;
								port->m_strReceived="";
							}
							else if (port->m_index<1000)
							{
								port->m_strReceived+= ch;
								port->m_index++;
							}
							else
							{
								port->m_index=0;
							}
                      }
                      //delete[] buf;
                  }
           }
           GetCommModemStatus (port->hPort, &dwCommModemStatus);
		   nTemp=1;/////////
    }
	CloseHandle(_ro.hEvent);
	pMain->m_wndStatusBar.SetPaneText(0,_T("Thread End...."),TRUE);
    return 0;
}


// Restart the comm thread
//
BOOL CSerial::RestartMonitoring()
{
	ResumeThread(hPort);
	return TRUE;
}
//
// Suspend the comm thread
//
BOOL CSerial::StopMonitoring()
{
	SuspendThread(hPort); 
	return TRUE;	
}















⌨️ 快捷键说明

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