MFC实现串口助手

界面如图所示
打开串口

void CMXC1730Dlg::OnBnClickedButton1()//打开串口
{
	// TODO: 在此添加控件通知处理程序代码
	CString temp;
	m_OpenCloseCtrl.GetWindowText(temp);
	UpdateData(true);
	if (temp == _T("关闭串口"))
	{
		KillTimer(0);
		u2clas.ClosePort();
		m_OpenCloseCtrl.SetWindowText(_T("打开串口"));

		m_PortNum.EnableWindow(TRUE);
		m_Baud.EnableWindow(TRUE);
		m_DataBit.EnableWindow(TRUE);
		m_Parity.EnableWindow(TRUE);
		m_StopData.EnableWindow(TRUE);
		UpdateData(false);
	}
	else
	{
		if (m_PortNum.GetCount())//有端口号
		{
			int SelPortNO, SelBaudRate, SelDataBits, SelStopBits;
			char SelParity;

			temp = m_strPortNO;
			temp.Delete(0, 3);
			SelPortNO = _ttoi(temp);

			SelBaudRate = _ttoi(m_strBaudRate);
			SelDataBits = _ttoi(m_strDataBits);
			SelParity = m_strParity.GetAt(0);
			SelStopBits = _ttoi(m_strStopBits);
			if (SelStopBits == 1)
			{
				SelStopBits = SelStopBits - 1;
			}
			if (u2clas.InitPort(this->GetSafeHwnd(), SelPortNO, SelBaudRate, SelParity, SelDataBits, SelStopBits, EV_RXFLAG | EV_RXCHAR | EV_CTS | EV_DSR | EV_TXEMPTY, 512/*写缓冲区大小*/))
			{
				u2clas.StartMonitoring();
				m_OpenCloseCtrl.SetWindowText(_T("关闭串口"));
				m_PortNum.EnableWindow(FALSE);
				m_Baud.EnableWindow(FALSE);
				m_DataBit.EnableWindow(FALSE);
				m_Parity.EnableWindow(FALSE);
				m_StopData.EnableWindow(FALSE);
				UpdateData(false);
			}
			else
				AfxMessageBox(TEXT("该串口已经被其他应用程序所占用!\n请选择其它的串口"));
		}
	}
}

界面获取的字符串转十六进制发送

void CMXC1730Dlg::ChangeCharstr2Hexstr(CString Charstr)
{
	CString Hexstr = _T("");
	memset(Hexstr1, 0, sizeof(BYTE) * 7);
	Charstr.MakeUpper();//改为大写
	HexStringFilter(Charstr);//十六进制字符串过滤(即字母不能大于F)
	int Length = Charstr.GetLength();//得到字符串的长度:几个字节
	if (Length % 2)//奇数个字节的话就省去最后一个字节
	{
		Charstr.Delete(Length - 1);
	}
	Length = Charstr.GetLength();
	for (int i = 0; i < Length / 2; i++)
	{
		Hexstr1[i] = (unsigned char)CombineHexChar(Charstr.GetAt(i * 2), Charstr.GetAt(i * 2 + 1));
	}
}

void CMXC1730Dlg::HexStringFilter(CString & str)
{
	BOOL bOK;
	for (int i = 0; i < str.GetLength()/*得到字符串的长度:几个字节*/;)
	{
		bOK = ((str.GetAt(i) >= '0') && (str.GetAt(i) <= '9')) ||
			((str.GetAt(i) >= 'A') && (str.GetAt(i) <= 'F')) ||
			((str.GetAt(i) >= 'a') && (str.GetAt(i) <= 'f'));
		if (!bOK)
		{
			str.Delete(i);
		}
		else
		{
			i++;
		}
	}
}

char CMXC1730Dlg::CombineHexChar(char CharH, char CharL)
{
	char result;
	char temp;
	if (CharH >= '0'&&CharH <= '9')
		result = (CharH - '0');
	else if
		(CharH >= 'a'&&CharH <= 'f')		result = (CharH - 'a' + 10);
	else if
		(CharH >= 'A'&&CharH <= 'F')		result = (CharH - 'A' + 10);
	else
		result = 0;

	if (CharL >= '0'&&CharL <= '9')
		temp = (CharL - '0');
	else if (CharL >= 'a'&&CharL <= 'f')
		temp = (CharL - 'a' + 10);
	else if (CharL >= 'A'&&CharL <= 'F')
		temp = (CharL - 'A' + 10);
	else
		temp = 0;

	result = result * 16 + temp;
	return result;
}

发送事件

void CMXC1730Dlg::OnBnClickedButton2()//发送事件
{
	// TODO: 在此添加控件通知处理程序代码
	CString temp;
	m_OpenCloseCtrl.GetWindowText(temp);
	UpdateData(true);
	if (temp == _T("打开串口"))
	{
		MessageBoxW(TEXT("请打开串口"));
	}
	else
	{
		temp = m_strSend;//"发送"显示编辑框
		ChangeCharstr2Hexstr(temp);//十六进制发送
		if (sizeof(*Hexstr1))//发送编辑框有内容
		{
			u2clas.WriteToPort(Hexstr1, 7);
			UpdateData(false);
		}
	}
}

接收数据

//接收数据
/*接收数据时通过相应固定的消息来实现的,也就是只要有数据,串口类就会发生消息给窗口,窗口进行数据解析显示;
本例子接收32自己为的数,校验和不算字头;
第一包数据不足32字节或者没有找到字节时,这包数据不会丢弃,会和下一报数据拼接在一起,直到找到第一个字头位置;
*/
LRESULT CMXC1730Dlg::OnReceiveData(WPARAM wParam, LPARAM commInfo)
{
	CString strLog, strline;
	struct serialPortInfo
	{
		UINT portNr;//串口号
		DWORD bytesRead;//读取的字节数
	}*pCommInfo;
	pCommInfo = (serialPortInfo*)commInfo;

	nData = pCommInfo->bytesRead;//读取的字节数
	strline.Format(TEXT(" %d-:%d"), nData, __LINE__);
	strLog = strline + TEXT(" ");

	BYTE *pByte = (BYTE *)wParam;//接收到的数据

	CByteArray tempary;//保存完整的帧数据
	tempary.RemoveAll();

	CByteArray datary;//存放此次接收到的数据
	datary.RemoveAll();

	for (int i = 0; i < nData; i++)
	{
		datary.Add(pByte[i]);//将接受的原始数据转换成【字节型】保存到动态数组
	}

	int total_len = 0;
	if (m_ary.GetSize() > 0)//解析完数据后还有数据
	{
		//进入此条件表明【不是第一组数据】出现过不完整帧后,遗留数据
		total_len = m_ary.GetSize() + datary.GetSize();
		tempary.SetSize(total_len);
		memcpy(tempary.GetData(), m_ary.GetData(), m_ary.GetCount());
		memcpy(tempary.GetData() + m_ary.GetSize()/*数组大小*/, datary.GetData(), datary.GetSize());
		m_ary.RemoveAll();
	}
	else
	{
		//进入此条件表明【是第一组数据】
		tempary.Append(datary);
		datary.RemoveAll();
	}
	AnalysisData(tempary, m_ary/*NULL*/);
	return TRUE;
}

void CMXC1730Dlg::AnalysisData(CByteArray & im_pcks, CByteArray & om_pcks)
{
	int nCount = 0;
	rxLen = 0;//有效长度
	int nStart = 0;
	bool flag_rev = false;
	int pcklen = im_pcks.GetCount();//完整帧数据字节数
		for (int i = 0; i < pcklen; i++)
	{
		switch (nCount)
		{
		case 0:
			if (0xdd == im_pcks.GetAt(i))//返回指定下标处的数组元素的值 
			{
				nCount++;
				nStart = i;
			}
			else
			{
				nCount = 0;
			}
			break;
		default:
			nCount++;
			break;
		}
		if (nCount > 31)
		{
			//按位异或 两个二进制位相同,则结果为0,不同为1
			BYTE datasum = 0;
			for (int i = 0; i < 28; i++)//取校验和
			{
				datasum += im_pcks.GetAt(nStart + i + 3);
			}
			datasum = datasum & 0xff;
			if (datasum == im_pcks.GetAt(nStart + 31))//判断校验和
			{
				rxLen = nCount;
				nCount = 0;
				flag_rev = true;
				Uartpck(im_pcks, rxLen, nStart);//im_pcks接收到的数据,rxLen422数组元素个数,nStart是存0xAA这个值的下标
			}
			else
			{
				nCount = 0;
				flag_rev = false;
			}
		}
	}
	if (!flag_rev)
	{
		unsigned char *p = (unsigned char*)(im_pcks.GetData()/* + rxLen422 +1*/);
		om_pcks.SetSize(im_pcks.GetSize()/* - rxLen422 - 1*/);
		memcpy(om_pcks.GetData(), p, (im_pcks.GetSize()/* - rxLen422 - 1*/));
	}

	//Uartpck(im_pcks, pcklen, 0);
}

bool CMXC1730Dlg::Uartpck(CByteArray & szData, int ilen, int iStart)
{
	unsigned char *ptempdata = new unsigned char[ilen]();//存储十六进制发送的数据
	CString im_pckss = _T("");
	CString szTemp = _T("");

	for (int i = 0; i < ilen; i++)
	{
		ptempdata[i] = szData.GetAt(i + iStart);
		szTemp.Format(TEXT("%02x "), szData.GetAt(i + iStart));
		im_pckss = im_pckss + szTemp;
	}
	m_strReceive = im_pckss;//接收有效数据
	UpdateData(FALSE);
	return TRUE;
}

本例子在VS2010上编写,MFC静态库编译生成,用到了网上开源的SerialPort串口类,我在项目中都是这样用的,比较稳定。有问题请联系我:[email protected]

发布了4 篇原创文章 · 获赞 6 · 访问量 154

猜你喜欢

转载自blog.csdn.net/weixin_44533976/article/details/103995759