串口调试程序的实现

由于需要用到串口读写程序,然后就简单的实现了个串口读写程序(基于MFC)。

首先是串口的读写,基本的函数就是CreateFile,ReadFile,WriteFile,SetCommState和GetCommState。

所以首先为了更好的调用这些函数我对这些函数进行了封装,在SerialPortIO.h里面:

#ifndef  ___SERIAL_IO_H_
#define  ___SERIAL_IO_H_
#include <Windows.h>
#define Interface  struct
Interface ISerialIO
{
	virtual bool openSerialPort(IN char*)=0;
	virtual bool closeSerialPort()=0;
	virtual bool getSerialPortStatus(OUT DCB& dcb)=0;
	virtual bool setSerialPortStatus(IN DCB& dcb)=0;
	virtual bool readSerialPort(OUT byte*,IN int,OUT int&)=0;
	virtual bool writeSerialPort(IN byte*,IN int,OUT int&)=0;
};
class CSerialIO:public ISerialIO
{
private:
	HANDLE hComm;
	char   cComm[6];
	DCB    dcbSerial;
	DWORD  dwInBuffer;
	DWORD  dwOutBuffer;
public:
	CSerialIO():hComm(NULL){};
	virtual bool openSerialPort(IN char*);
	virtual bool closeSerialPort();
	virtual bool getSerialPortStatus(OUT DCB& dcb);
	virtual bool setSerialPortStatus(IN DCB& dcb);
	virtual bool readSerialPort(OUT byte*,IN int,OUT int&);
	virtual bool writeSerialPort(IN byte*,IN int,OUT int&);
	~CSerialIO();
	bool   setBuffer(IN int,IN int);
};
#endif
下面是实现代码SerialPortIO.cpp

#include "stdafx.h"
#include "SerialIO.h"
bool CSerialIO::openSerialPort(char* szSerial)
{
	HANDLE hSerial=CreateFileA(szSerial,
		GENERIC_READ|GENERIC_WRITE,
		0,
		NULL,
		OPEN_EXISTING,
		FILE_ATTRIBUTE_NORMAL,
		NULL);
	if(INVALID_HANDLE_VALUE==hSerial)
		return false;
	this->hComm=hSerial;
	memcpy(cComm,szSerial,strlen(szSerial));
	cComm[strlen(szSerial)]='\0';
	return true;
}
bool CSerialIO::closeSerialPort()
{
	if(hComm!=0)
	{
		CloseHandle(hComm);
		hComm=0;
	}
	return true;
}
bool CSerialIO::getSerialPortStatus(DCB& dcb)
{
	if(hComm==0)
		return false;
	bool bHr=GetCommState(hComm,&dcb);
	if(false==bHr)
		return bHr;
	dcbSerial=dcb;
	return bHr;
}
bool CSerialIO::setSerialPortStatus(DCB& dcb)
{
	if(hComm==0)
		return false;
	bool bHr=SetCommState(hComm,&dcb);
	if(false==bHr)
		return bHr;
	dcbSerial=dcb;
	return bHr;
}
bool CSerialIO::readSerialPort(byte* pbBuffer,int iBuffer,int& iRead)
{
	if(0==hComm)
		return false;
	bool bReadFile=ReadFile(hComm,pbBuffer,iBuffer,(LPDWORD)&iRead,NULL);
	if(true==bReadFile)
		if(iRead>0)
			return true;
	return false;
}
bool CSerialIO::writeSerialPort(IN byte* pbBuffer,IN int iBuffer,OUT int& iWrite)
{
	if(0==hComm)
		return false;
	bool bWriteFile=WriteFile(hComm,pbBuffer,iBuffer,(LPDWORD)&iWrite,NULL);
	if(bWriteFile==true)
		if(iWrite==iBuffer)
			return true;
	return false;
}
bool CSerialIO::setBuffer(IN int iInput,IN int iOutput)
{
	if(0==hComm)
		return false;
	bool bSetBuffer=SetupComm(hComm,iInput,iOutput);
	if(bSetBuffer==true)
	{
		this->dwInBuffer=iInput;
		this->dwOutBuffer=iOutput;
	}
	return bSetBuffer;
}
CSerialIO::~CSerialIO()
{
	if(hComm)
		closeSerialPort();
}
上面基本上就是功能函数的核心了,后面只需要根据不同需要调用就可以了。

在MFC里面,首先添加一个按钮,用来打开和设置串口。在打开串口的同时创建一个新的线程进行读串口如下:

void CSerialPortAssistDlg::OnBnClickedButton2()
{
	static bool bThread=false;
	EnterCriticalSection(&cs);
	if(pSerialIO==NULL)
		pSerialIO=new CSerialIO();
	CString csSerialPort;
	CString csBoundRate;
	m_COMBOBOX_SerialPort.GetWindowText(csSerialPort);
	m_COMBOBOX_BoundRate.GetWindowText(csBoundRate);
	//把宽字符转换成ANSI
	char cSerialPort[6];
	char cBoundRate[10];
	unsigned int  iBoundRate;
	wcstombs(cSerialPort,csSerialPort,csSerialPort.GetLength());
	cSerialPort[csSerialPort.GetLength()]='\0';
	wcstombs(cBoundRate,csBoundRate,csBoundRate.GetLength());
	cBoundRate[csBoundRate.GetLength()]='\0';
	iBoundRate=atoi(cBoundRate);
	if(pSerialIO->openSerialPort(cSerialPort))
	{
		DCB dcb;
		if(pSerialIO->getSerialPortStatus(dcb))
		{
			dcb.BaudRate=iBoundRate;
			if(pSerialIO->setSerialPortStatus(dcb))
			{
				MessageBox(TEXT("设置串口成功"));
				if(bThread==false)
				{
					unsigned int  uiThreadID;
					_beginthreadex(NULL,0,ThreadFunc,(void*)&m_EDIT_ReadControl,0,&uiThreadID);
					bThread=true;
				}
				
			}
		}

	}
	// TODO: 在此添加控件通知处理程序代码
}
上面代码可以看到,首先是打开串口,然后是设置串口,如果成功就创建新的线程,注意这里为了防止不停的按打开串口按钮,这里用了一个static变量用来使线程只创建一个。
_beginthreadex(NULL,0,ThreadFunc,(void*)&m_EDIT_ReadControl,0,&uiThreadID);
这句代码就是用来创建读串口的线程,在ThreadFunc里面读串口。

下面来看ThreadFunc函数:

unsigned WINAPI ThreadFunc(void* pVar)
{ 
	while(1)
	{
		byte byteBuffer[300]={0};
		int iRead;
		if(pSerialIO==NULL)
		{
			Sleep(1000);
			continue;
		}

		if(pSerialIO->readSerialPort(byteBuffer,300,iRead))
		{
			if(iRead<=0)
				Sleep(1000);
			else
			{
				//EnterCriticalSection(&cs);
				for(int i=0;i!=iRead;++i)
					csBuffer.AppendFormat(TEXT("%02x "),byteBuffer[i]);
				//LeaveCriticalSection(&cs);
				SetWindowText(((CEdit*)pVar)->GetSafeHwnd(),csBuffer);
				((CEdit*)pVar)->LineScroll(((CEdit*)pVar)->GetLineCount(),0);
			}
			continue;
		}
		Sleep(1000);
	}
	return 0;
}
首先判断串口是否打开,如果没打开就Sleep(1000)。然后读串口,如果没有读到数据,也同样Sleep,否则就以16进制显示数据。

写串口主要在sendMsg这个函数里面实现:

void CSerialPortAssistDlg::sendMsg()
{
	if(pSerialIO==0)
		return ;
	/*byte byteBuffer[32]={0x7E, 0x7E, 0x7E,0x7E,
		0x71, 0x01, 0x08, 0x19,
		0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00,
		0x00, 0x00, 0x00, 0x00,
		0x00, 0x9F, 0xD6, 0xFC};*/
	byte byteBuffer[100];
	int iLength;
	if(bHex==false)
	{
		CString csSend;
		m_EDIT_WriteControl.GetWindowText(csSend);
		wcstombs((char*)byteBuffer,csSend,csSend.GetLength());
		iLength=csSend.GetLength();
	}
	else
		praseMessage(byteBuffer,100,iLength);
	int iWrite=0;
	if(pSerialIO->writeSerialPort(byteBuffer,iLength,iWrite))
	{
		if(iWrite==32)
			return ;
	}
	MessageBox(TEXT("write error"));
}

首先是判断串口是否打开,然后判断数据是否以16进制表示,如果不是以16进制表示,那么先转化成单字节发送,如果是以16进制表示那么首先对数据进行解析,然后发送,解析数据是通过 praseMessag来实现的,代码如下:

void CSerialPortAssistDlg::praseMessage(byte* pByte,int iLength,int& iSend)
{
	CString csSend;
	m_EDIT_WriteControl.GetWindowText(csSend);
	iSend=0;
	while(csSend.Find(TEXT(" "))!=-1)
	{
		int k=csSend.Find(TEXT(" "));
		CString csTemp=csSend.Left(k);
		csSend=csSend.Mid(k+1);
		unsigned num=_tcstoul(csTemp,0,16);
		pByte[iSend++]=(byte)num;
	}

}
上面是把CString数据转换成16进制
如: TEXT("7E 7E 7E 03 03 00 00"),就把每个字符串转换成16进制发送,中间空格略掉。

主要实现代码就是上面,其实后面花时间最多的就是praseMessage这个函数,以前很少用CString,所以不知道怎么去转化,后面查资料才搞定。

后面想实现 远程控制串口读写,然后远程显示。周末有时间实现下。




评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值