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

📄 gpsrecvdlg.cpp

📁 该程序用MFC实现串口通信
💻 CPP
字号:
// GpsRecvDlg.cpp : implementation file
//

#include "stdafx.h"
#include "GpsRecv.h"
#include "GpsRecvDlg.h"
#include "PortSetting.h"

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

/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About

UINT lpCommThreadProc(LPVOID lpParam);

class CAboutDlg : public CDialog
{
public:
	CAboutDlg();

// Dialog Data
	//{{AFX_DATA(CAboutDlg)
	enum { IDD = IDD_ABOUTBOX };
	//}}AFX_DATA

	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CAboutDlg)
	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
	//}}AFX_VIRTUAL

// Implementation
protected:
	//{{AFX_MSG(CAboutDlg)
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
	//{{AFX_DATA_INIT(CAboutDlg)
	//}}AFX_DATA_INIT
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CAboutDlg)
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
	//{{AFX_MSG_MAP(CAboutDlg)
		// No message handlers
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CGpsRecvDlg dialog

CGpsRecvDlg::CGpsRecvDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CGpsRecvDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CGpsRecvDlg)
		// NOTE: the ClassWizard will add member initialization here
	//}}AFX_DATA_INIT
	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
	m_hPort = NULL;
	m_pCommThread = NULL;
	m_bExitThread = FALSE;

	m_nPort = 1;
	m_nBaud = 9600;
	m_nParity = 0;
	m_nStopBits = 0;
	m_nDataBits = 8;

	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CGpsRecvDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CGpsRecvDlg)
	DDX_Control(pDX, IDC_GPS_DATA, m_Edit);
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CGpsRecvDlg, CDialog)
	//{{AFX_MSG_MAP(CGpsRecvDlg)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_PORT_SETTING, OnPortSetting)
	ON_BN_CLICKED(IDC_OPEN_PORT, OnOpenPort)
	ON_BN_CLICKED(IDC_CLOSE_PORT, OnClosePort)
	ON_MESSAGE(WM_RECVGPSDATA, OnRecvGpsData)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CGpsRecvDlg message handlers

BOOL CGpsRecvDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Add "About..." menu item to system menu.

	// IDM_ABOUTBOX must be in the system command range.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		CString strAboutMenu;
		strAboutMenu.LoadString(IDS_ABOUTBOX);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon
	
	// TODO: Add extra initialization here
	
	return TRUE;  // return TRUE  unless you set the focus to a control
}

void CGpsRecvDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialog::OnSysCommand(nID, lParam);
	}
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CGpsRecvDlg::OnPaint() 
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

// The system calls this to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CGpsRecvDlg::OnQueryDragIcon()
{
	return (HCURSOR) m_hIcon;
}

void CGpsRecvDlg::OnPortSetting() 
{
	CPortSetting PortSetting;
	PortSetting.m_nPort = m_nPort;
	PortSetting.m_nBaud = m_nBaud;
	PortSetting.m_nDataBits = m_nDataBits;
	PortSetting.m_nStopBits = m_nStopBits;
	PortSetting.m_nParity = m_nParity;

	if(PortSetting.DoModal() == IDOK)
	{
		m_nPort = PortSetting.m_nPort;
		m_nBaud = PortSetting.m_nBaud;
		m_nDataBits = PortSetting.m_nDataBits;
		m_nStopBits = PortSetting.m_nStopBits;
		m_nParity = PortSetting.m_nParity;

		//如果串口处于打开状态,则先关闭串口,再根据新参数打开串口
		if(m_hPort)
		{
			OnClosePort();
			OnOpenPort();
		}
	}
}

void CGpsRecvDlg::OnOpenPort() 
{
	if(m_hPort)
	{
		MessageBox(_T("串口已经打开!"));
		return;
	}

	//打开串口
	CString sPort;
	sPort.Format(_T("\\\\.\\COM%d"), m_nPort);
	m_hPort = CreateFile(sPort, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 
						 FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, NULL);
	if(m_hPort == INVALID_HANDLE_VALUE)
	{
		MessageBox("打开串口失败!");
		m_hPort = NULL;
		return;
	}

	//设置缓冲区
	SetupComm(m_hPort, 1024, 1024);

	//配置串口
	DCB ComDCB;
	ComDCB.DCBlength = sizeof(DCB);
	GetCommState(m_hPort, &ComDCB);

	//改变缺省配置
	ComDCB.BaudRate = m_nBaud;
	ComDCB.ByteSize = m_nDataBits;
	ComDCB.Parity = m_nParity;
	ComDCB.StopBits = m_nStopBits;

	SetCommState(m_hPort, &ComDCB);

	//设置超时值
	COMMTIMEOUTS ot;
	memset(&ot, 0, sizeof(ot));
	ot.ReadIntervalTimeout = MAXDWORD;
	SetCommTimeouts(m_hPort, &ot);		

	//启动接收线程
	m_bExitThread = FALSE;
	m_pCommThread = AfxBeginThread(lpCommThreadProc, this, THREAD_PRIORITY_NORMAL);
	if(m_pCommThread)
		m_pCommThread->m_bAutoDelete = TRUE;
	else 
	{
		MessageBox("启动接收线程失败!");
		CloseHandle(m_hPort);
		m_hPort = NULL;
		return;
	}
}

void CGpsRecvDlg::OnClosePort() 
{
	if(m_hPort == NULL)
	{
		MessageBox(_T("串口已经关闭!"));
		return;
	}

	//设置结束接收线程标志
	m_bExitThread = TRUE;

	//使串口接收线程中的WaitCommEvent()函数返回
	SetCommMask(m_hPort, 0);

	//等待接收线程结束
	WaitForSingleObject(m_pCommThread->m_hThread, INFINITE);
	m_pCommThread = NULL;

	//关闭串口
	CloseHandle(m_hPort);
	m_hPort = NULL;
}

void CGpsRecvDlg::OnOK() 
{
	if(m_hPort)
	{
		//设置结束接收线程标志
		m_bExitThread = TRUE;

		//使串口接收线程中的WaitCommEvent()函数返回
		SetCommMask(m_hPort, 0);

		//等待接收线程结束
		WaitForSingleObject(m_pCommThread->m_hThread, INFINITE);
		m_pCommThread = NULL;

		//关闭串口
		CloseHandle(m_hPort);
	}
	
	CDialog::OnOK();
}

UINT lpCommThreadProc(LPVOID lpParam)
{
	CGpsRecvDlg *pWnd = (CGpsRecvDlg *)lpParam;
	if(!pWnd || !pWnd->m_hPort) return 0;
		
	BYTE RecvBuf[1024];
	DWORD  dwSpace, dwReadCount = 0, dwReturnCount;
	DWORD dwError, dwEvtMask = 0;
	COMSTAT cs;

	OVERLAPPED overlapped;
	memset(&overlapped, 0, sizeof(overlapped));
	//创建一个人工复位事件对象
	overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

	//设置串口事件
	SetCommMask(pWnd->m_hPort, EV_RXCHAR);

	while(!pWnd->m_bExitThread)
	{
		//等待串口事件
		WaitCommEvent(pWnd->m_hPort, &dwEvtMask, NULL);
		if(dwEvtMask & EV_RXCHAR)
		{
			//获取串口状态
			ClearCommError(pWnd->m_hPort, &dwError, &cs);
			dwReadCount = cs.cbInQue;
			if(dwReadCount <= 0) continue;
			
			//获取GPS数据缓冲区的剩余空间
			dwSpace = (DWORD)pWnd->m_GpsBuf.GetDataBufSpace();
			if(dwReadCount > dwSpace) dwReadCount = dwSpace;

			//异步读取数据
			BOOL bReadStat = ReadFile(pWnd->m_hPort, RecvBuf, dwReadCount, 
									  &dwReturnCount, &overlapped); 
			if(!bReadStat)
			{
				if(GetLastError() == ERROR_IO_PENDING)
				{
					while(!GetOverlappedResult(pWnd->m_hPort, &overlapped, 
						   &dwReturnCount, FALSE))
					{
						dwError = GetLastError();
						if(dwError == ERROR_IO_INCOMPLETE) continue;
					}
				}
			}

			//把读取的数据放入GPS数据缓冲区
			pWnd->m_GpsBuf.Write(RecvBuf, dwReturnCount);
			//向主窗口发送消息
			pWnd->PostMessage(WM_RECVGPSDATA, 0, 0);
		}
	}

	CloseHandle(overlapped.hEvent);
	PurgeComm(pWnd->m_hPort, PURGE_TXABORT|PURGE_RXABORT|PURGE_RXCLEAR|PURGE_TXCLEAR);

	return 0;
}

void CGpsRecvDlg::OnRecvGpsData(WPARAM wp, LPARAM lp)
{
	BYTE buf[1024];
	int len;
	CString strEditText, strTemp;
	//从GPS数据缓冲区中读取一条完整的数据
	if(m_GpsBuf.Read(buf, len) == 1)
	{
		//将读取地GPS原始数据显示在编辑框中
		strEditText.Format(_T("%s"), (char *)buf);
		AddDataString(strEditText);

		//当数据有效时,将解释后地数据显示在编辑框中
		if(DealGpsData(buf, len) == 1)
		{
			strEditText.Format(_T("时间:%d-%d-%d %d:%d%d\r\n"), data.time.wYear, 
						data.time.wMonth, data.time.wDay, data.time.wHour, 
						data.time.wMinute, data.time.wSecond);
			strTemp.Format(_T("经度:%.5f 纬度:%.5f\r\n"), data.longitude, data.latitude);
			strEditText += strTemp;
			strTemp.Format(_T("速度:%.2f 方位:%.2f\r\n"), data.speed, data.course);
			strEditText += strTemp;
			AddDataString(strEditText);
		}
	}
}

//解释GPS数据
int CGpsRecvDlg::DealGpsData(BYTE *buf, DWORD len)
{
	int index;
	CString sData;
	sData.Format(_T("%s"), buf);

	index = sData.Find(_T(','));
	if(index == -1) return 0;
	sData = sData.Right(sData.GetLength() - index - 1);

	//get UTC time
	CString sLeft = sData.Left(2);
	data.time.wHour = atoi(sLeft);

	sData = sData.Right(sData.GetLength() - 2);

	sLeft = sData.Left(2);
	data.time.wMinute = atoi(sLeft);

	sData = sData.Right(sData.GetLength() - 2);

	sLeft = sData.Left(2);
	data.time.wSecond = atoi(sLeft);

	sData = sData.Right(sData.GetLength() - 3);

	//get status
	sLeft = sData.Left(1);
	data.status = sLeft[0];

	sData = sData.Right(sData.GetLength() - 2);

	//get latitude
	index = sData.Find(_T(','));
	if(index == -1) return 0;
	sLeft = sData.Left(index);
	sData = sData.Right(sData.GetLength() - index - 1);
	double lat = atof(sLeft);
	data.latitude = long(lat/100) + (lat - long(lat/100)*100)/60;

	//get latitude hemisphere
	sLeft = sData.Left(1);
	data.lat_hemi = sLeft[0];;

	sData = sData.Right(sData.GetLength() - 2);

	//get longitude
	index = sData.Find(_T(','));
	if(index == -1) return 0;
	sLeft = sData.Left(index);
	sData = sData.Right(sData.GetLength() - index - 1);
	double lon = atof(sLeft);
	data.longitude = long(lon/100) + (lon - long(lon/100)*100)/60;

	//get longitude hemisphere
	sLeft = sData.Left(1);
	data.lon_hemi = sLeft[0];;

	sData = sData.Right(sData.GetLength() - 2);

	//get speed
	index = sData.Find(_T(','));
	if(index == -1) return 0;
	sLeft = sData.Left(index);
	sData = sData.Right(sData.GetLength() - index - 1);
	data.speed = atof(sLeft);

	//get course
	index = sData.Find(_T(','));
	if(index == -1) return 0;
	sLeft = sData.Left(index);
	sData = sData.Right(sData.GetLength() - index - 1);
	data.course = atof(sLeft);

	//get UTC data
	sLeft = sData.Left(2);
	data.time.wDay = atoi(sLeft);

	sData = sData.Right(sData.GetLength() - 2);

	sLeft = sData.Left(2);
	data.time.wMonth = atoi(sLeft);

	sData = sData.Right(sData.GetLength() - 2);

	sLeft = sData.Left(2);
	data.time.wYear = atoi(sLeft);

	sData = sData.Right(sData.GetLength() - 3);

	data.time.wDayOfWeek = 0;
	data.time.wMilliseconds = 0;

	//get magnetic degree
	index = sData.Find(_T(','));
	if(index == -1) return 0;
	sLeft = sData.Left(index);
	sData = sData.Right(sData.GetLength() - index - 1);
	data.mag_degree = atof(sLeft);

	//get direction
	sLeft = sData.Left(1);
	data.direction = sLeft[0];;

	if(data.status != 'A')
	{
		return 0;
	}

	return 1;
}

void CGpsRecvDlg::AddDataString(LPCTSTR string)
{
	int nTextLen = m_Edit.GetWindowTextLength();

	//当编辑框中地字符长度大于2000时,将编辑框清空
	if(nTextLen > 2000)
	{
		m_Edit.SetWindowText(_T(""));
		nTextLen = 0;
	}
	m_Edit.SetSel(nTextLen, nTextLen);
	m_Edit.ReplaceSel(string);
}

⌨️ 快捷键说明

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