两种串口通信端口编程

一.MS Comm串行通信控件

VC6.0安装时自动添加注册这个组件,VS平台需要自己来注册
1.准备MSCOMM32.DEP,MSCOMM32.oca,mscomm32.ocx复制到%windir%\system32\
2.regsvr32 /s %windir%\system32\mscomm32.ocx



1.添加MS comm组件

插入ActiveX控件->选择Microsoft Communications Controls


2.对话框类中添加打开代码ON_BN_CLICKED(IDC_BUTTON_OPEN, OnButtonOpen)

// 打开串口
void CMSCOMMSampleDlg::OnButtonOpen() 
{
    if(m_Comm.GetPortOpen()) //如果串口是打开的,则关闭串口 
        m_Comm.SetPortOpen(FALSE); 


    m_Comm.SetCommPort(1); //选择COM1 
    m_Comm.SetInBufferSize(1024); //接收缓冲区 
    m_Comm.SetOutBufferSize(1024);//发送缓冲区 
    m_Comm.SetInputLen(0);//设置当前接收区数据长度为0,表示全部读取 
    m_Comm.SetInputMode(0);//以文本方式读写数据 
    m_Comm.SetRThreshold(1);//接收缓冲区有1个及1个以上字符时,触发OnComm事件 
    m_Comm.SetSettings("9600,n,8,1");//波特率9600无检验位,8个数据位,1个停止位 


    if(!m_Comm.GetPortOpen())//如果串口没有打开则打开 
        m_Comm.SetPortOpen(TRUE);//打开串口 
    else m_Comm.SetOutBufferCount(0); 
    WriteLog("打开串口成功");
}


3.串口处理函数 ON_EVENT(CMSCOMMSampleDlg, IDC_MSCOMM1, 1 /* OnComm */, OnOnCommMscomm1, VTS_NONE)

//事件处理函数
void CMSCOMMSampleDlg::OnOnCommMscomm1() 
{
    VARIANT vInput; 
    COleSafeArray arrInput; 
    LONG len,k; 
    BYTE rxdata[2048]; //设置BYTE数组
    CString strtemp; 
    switch(m_Comm.GetCommEvent()) 
    { 
    case EV_CTS:		//发送数据 
        WriteLog("发送数据");
        break; 
    case EV_RXCHAR:		//读取数据 
        vInput=m_Comm.GetInput(); //读缓冲区 
        arrInput=vInput; 
        len=arrInput.GetOneDimSize(); //得到有效数据长度 
        // 读取数据 
        for(k=0; k < len; k++)
        { 
            arrInput.GetElement(&k,rxdata+k); //转换为BYTE型数组 
            BYTE bt=*(char*)(rxdata+k); //字符型 
            strtemp.Format("%c",bt); //将字符送入临时变量strtemp存放 
            m_editReceive+=strtemp; 
        } 
        WriteLog("接收数据");
        break; 
    default:	// 出错 
        m_Comm.SetOutBufferCount(0); 
        break; 
    } 
    UpdateData(FALSE); //更新图象内容 
    return ; 
}



4.发送按钮代码ON_BN_CLICKED(IDC_BUTTON_SEND, OnButtonSend)

void CMSCOMMSampleDlg::OnButtonSend() 
{
    UpdateData(TRUE);
    unsigned char  uiSum=0; 
    int iLen = m_editSend.GetLength();
    CByteArray  array; 


    for(int i=0; i<iLen-1; i++) 
        uiSum+=m_editSend[i];  //计算校验和 
    //TxData[uiCount-1]=uiSum; //存储校验和 
    array.RemoveAll();  //清空数组 
    array.SetSize(iLen+1);  //设置数组大小为帧长度 
    for(int i=0; i<iLen; i++)  //把待发送数据存入数组 
        array.SetAt(i,m_editSend[i]); 
    array.Add(uiSum);


    if (!m_Comm.GetPortOpen())
        m_Comm.SetPortOpen(TRUE); 


    m_Comm.SetOutput(COleVariant(array));    
}



二、win32 API函数进行通信端口的编程

1.串口线程初始化

IMPLEMENT_DYNCREATE(CThreadCom, CWinThread)


    CThreadCom::CThreadCom(HANDLE hCom)
{
    m_hCom=hCom;
    m_bInit=FALSE;
    m_sCom="";
    m_sError="No Error!";
    m_hThread=NULL;	
    m_dwSendMsgToParent=0;	
    m_dwRecvMsgToParent=0;	
    m_pWndParent=NULL;
    memset((unsigned char*)&m_overRead,0,sizeof(OVERLAPPED));
    memset((unsigned char*)&m_overWrite,0,sizeof(OVERLAPPED));
    m_overRead.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
    m_overWrite.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
}


CThreadCom::~CThreadCom()
{
	CloseHandle(m_overRead.hEvent);
	CloseHandle(m_overWrite.hEvent);
}


因为串口线程类是继承自CWinThread类,所以需要重载CWinThread的几个函数
//初始化实例函数
BOOL CThreadCom::InitInstance()
{


	m_bAutoDelete=FALSE;
	m_bDone=FALSE;
	return TRUE;
}
//退出实例函数
int CThreadCom::ExitInstance()
{
	
	BOOL bFlag=CloseCom();
	return CWinThread::ExitInstance();
}


2.串口接收函数

WaitCommEvent函数监控串口事件,接收来自串口的数据,并发送消息给主对话框
nt CThreadCom::Run() 
{
	// TODO: Add your specialized code here and/or call the base class
	/*if (m_hCom==INVALID_HANDLE_VALUE)
		return 0;*/
	
	DWORD CommMask;
	CommMask=0
			|	EV_BREAK	//A break was detected on input.
			|	EV_CTS		//The CTS(clear-to-send) signal changed state.
			|	EV_DSR		//The DSR(data-set-ready) signal changed state.
			|	EV_ERR		//A line-status error occurred.Line_status errors are CE_FRAME,CE_OVERRUN,and CE_RXPARITY.
			|	EV_EVENT1	//An event of the first provider-specific type occured
			|	EV_EVENT2	//An event of the second provider-specific type occured.
			|	EV_PERR		//A printer error occured.
			|	EV_RING		//A ring indicator was detected
			|	EV_RLSD		//The RLSD(receive-line-signal-detect) signal changed state.
			|	EV_RX80FULL	//The receive buffer is 80 percent full.
			|	EV_RXCHAR	//A character was received and placed in the input buffer.
			|	EV_RXFLAG	//The event character was received and placed in the input buffer.The event character is specified in the device's DCB structure,which is applied to a serial port by using the SetCommState function.
			|	EV_TXEMPTY;	//The last character in the output buffer was sent.
	::SetCommMask(m_hCom,CommMask);


	::GetCommTimeouts(m_hCom,&m_Commtimeout);
	m_Commtimeout.ReadTotalTimeoutMultiplier=5;
	m_Commtimeout.ReadTotalTimeoutConstant=100;


	DWORD dwError,dwReadNum,dwByteRead,dwEvent;
	COMSTAT ComStat;
	BYTE rBuf[MAXCOMINBUF];
	
	while (!m_bDone)
	{		
		while (m_hCom!=INVALID_HANDLE_VALUE)
		{			
			if(::WaitCommEvent(m_hCom,&dwEvent,NULL))
			{
				dwByteRead=0;
				if((dwEvent & EV_RXCHAR))
				{
					ClearCommError(m_hCom,&dwError,&ComStat);
					if(ComStat.cbInQue!=0)
					{
						dwReadNum=ComStat.cbInQue;
						dwByteRead=0;
						if(dwReadNum>200) dwReadNum=200;
						memset(rBuf,0,sizeof(rBuf));
						DWORD i=::ReadFile(m_hCom,rBuf,dwReadNum,&dwByteRead,&m_overRead);
						for(i=dwByteRead;i<1024;i++) rBuf[i]=0;
					}
				}				
				if(dwByteRead) if(m_pWndParent)
					m_pWndParent->SendMessage(m_dwRecvMsgToParent,(DWORD)rBuf,dwByteRead);			
			}	
		}
		Sleep(1000);
	}
	
	return CWinThread::Run();
}



3.打开和关闭串口

CloseCom()函数调用CloseHandle()函数关闭串口句柄。OpenCom()函数调用CreateFile()函数打开串口,调用SetupComm()函数设置串口输入输出缓冲区的大小,调用SetCommState()函数设置串口资源的状态,最重要的是调用SetCommMask函数设置监控
的事件。打开串口后,就可以向串口发送数据。
打开
BOOL CThreadCom::OpenCom(CString strCom, CWnd *pWndParent, 
							DWORD dwSendMsgToParent, DWORD dwRecvMsgToParent)
{
	CloseCom();
	CString strLog;
	m_hCom=::CreateFile(strCom,	GENERIC_READ|GENERIC_WRITE,	0, NULL,
		OPEN_EXISTING,FILE_FLAG_OVERLAPPED,	NULL);
	if (m_hCom==INVALID_HANDLE_VALUE)
	{		
		strLog.Format("Open %s Error",strCom);
		AfxMessageBox(strLog);
		return FALSE;
	}
	
	::SetupComm(m_hCom,MAXCOMINBUF,MAXCOMOUTBUF);		
	DCB dcb;
	if (!GetCommState(m_hCom,&dcb))
	{
		AfxMessageBox("获取串口状态错误!");
		CloseHandle(m_hCom);
		m_hCom=INVALID_HANDLE_VALUE;
		return FALSE;
	}


	/*dcb.BaudRate	=	9600;
	dcb.ByteSize	=	1;
	//dcb.Parity = NOPARITY;
	dcb.StopBits=ONESTOPBIT;*/
	
	if (!SetCommState(m_hCom,&dcb))
	{
		CloseHandle(m_hCom);
		m_hCom=INVALID_HANDLE_VALUE;		
		strLog.Format("Set %s CommState Error!",strCom);
		DWORD nError=GetLastError();
		AfxMessageBox(strLog);
		return FALSE;
	}
	
	m_sError="No Error";	
	m_pWndParent	=	pWndParent;
	m_dwSendMsgToParent	= dwSendMsgToParent;
	m_dwRecvMsgToParent	= dwRecvMsgToParent;
	
	DWORD CommMask;
	CommMask=0
			|	EV_BREAK	//A break was detected on input.
			|	EV_CTS		//The CTS(clear-to-send) signal changed state.
			|	EV_DSR		//The DSR(data-set-ready) signal changed state.
			|	EV_ERR		//A line-status error occurred.Line_status errors are CE_FRAME,CE_OVERRUN,and CE_RXPARITY.
			|	EV_EVENT1	//An event of the first provider-specific type occured
			|	EV_EVENT2	//An event of the second provider-specific type occured.
			|	EV_PERR		//A printer error occured.
			|	EV_RING		//A ring indicator was detected
			|	EV_RLSD		//The RLSD(receive-line-signal-detect) signal changed state.
			|	EV_RX80FULL	//The receive buffer is 80 percent full.
			|	EV_RXCHAR	//A character was received and placed in the input buffer.
			|	EV_RXFLAG	//The event character was received and placed in the input buffer.The event character is specified in the device's DCB structure,which is applied to a serial port by using the SetCommState function.
			|	EV_TXEMPTY;	//The last character in the output buffer was sent.
	::SetCommMask(m_hCom,CommMask);


	::GetCommTimeouts(m_hCom,&m_Commtimeout);
	m_Commtimeout.ReadTotalTimeoutMultiplier=5;
	m_Commtimeout.ReadTotalTimeoutConstant=100;


	m_bInit=TRUE;
	return TRUE;
}


 关闭
BOOL CThreadCom::CloseCom()
{
	if (m_hCom!=INVALID_HANDLE_VALUE)
	{
		PurgeComm(m_hCom,PURGE_RXCLEAR);//clear input buffer
		CloseHandle(m_hCom);
		m_hCom=INVALID_HANDLE_VALUE;
	}	
	m_bInit=FALSE;
	return TRUE;
}
4.向串口发送数据
SetCommTimeouts()函数设置写操作的超时时间,并调用writeFile()函数向串口发送数据。
BOOL CThreadCom::SendData(BYTE *s, DWORD dwLen)
{
	if (!dwLen) return TRUE;
	::GetCommTimeouts(m_hCom,&m_Commtimeout);
	m_Commtimeout.WriteTotalTimeoutMultiplier=0;
	m_Commtimeout.WriteTotalTimeoutConstant=2*dwLen;
	::SetCommTimeouts(m_hCom,&m_Commtimeout);


	if (m_hCom!=INVALID_HANDLE_VALUE)
	{
		DWORD dwSend;
		m_pWndParent->SendMessage(m_dwSendMsgToParent,(DWORD)s,dwLen);			
		if (!WriteFile(m_hCom,s,dwLen,&dwSend,&m_overWrite))
		{
			DWORD len=GetLastError();
			m_sError="串口发送数据错误";			
			return FALSE;
		}		
		return TRUE;
	}
	else
	{
		m_sError="串口句柄无效";
		return FALSE;
	}	
}


5.界面处理



// 打开串口ON_BN_CLICKED(IDC_BUTTON_OPEN, OnButtonOpen)
void CCommSampleDlg::OnButtonOpen() 
{
    if (pThreadCom != NULL)  return;
    CString str;
    CString com = "COM4";


    pThreadCom = (CThreadCom*)AfxBeginThread(RUNTIME_CLASS(CThreadCom));				
    pThreadCom->SetComStr(com);


    /*	try
    {
    pThreadCom = (CThreadCom*)AfxBeginThread(RUNTIME_CLASS(CThreadCom));				
    pThreadCom->SetComStr(com);
    }
    catch(CException e)
    {
    e.ReportError();
    pThreadCom->m_bDone=TRUE;
    StopWinThread((CWinThread*)pThreadCom,INFINITE);
    pThreadCom=NULL;		
    str.Format("创建串口%s线程错误!", com);
    WriteLog(str);	
    }   */




    if (pThreadCom->OpenCom(com, (CWnd*)this->GetSafeOwner(), 
        WM_USER_COMSENDMESSAGE, WM_USER_COMRECVMESSAGE))
    {		
        str.Format("打开串口%s成功", pThreadCom->GetComStr());
        WriteLog(str);
    }
    else
    {
        str.Format(pThreadCom->m_sError+",请重新配置串口!");
        WriteLog(str);
        pThreadCom->m_bInit=FALSE;		
        return ;		
    }
    m_bCom=TRUE;	
    return ;	
}


// 发送串口数据ON_BN_CLICKED(IDC_BUTTON_SEND, OnButtonSend)
void CCommSampleDlg::OnButtonSend() 
{
	UpdateData(TRUE);
	int iLen = m_editSend.GetLength();
	BYTE* s= new BYTE[iLen];
	memset(s, 0x00, iLen);
	memcpy(s, (LPCTSTR)m_editSend, iLen);
	pThreadCom->SendData((unsigned char*)s, iLen);
}





#define WM_USER_COMSENDMESSAGE WM_USER+200
#define WM_USER_COMRECVMESSAGE WM_USER+201


//发送数据通知ON_MESSAGE(WM_USER_COMSENDMESSAGE, OnSendMsg)
LRESULT CCommSampleDlg::OnSendMsg(WPARAM dwEvent,LPARAM dwLen)
{
	if(!dwLen)	return 0;
	BYTE* temp = new BYTE[dwLen+1];
	memset(temp, 0x00, dwLen+1);
	memcpy(temp, (const void*)dwEvent, dwLen);
	CString log;
	log.Format("\r\n发送数据=%s", (LPCTSTR)temp);
	
	if (m_editLog)
	{	
		CEdit* editLog=(CEdit*)FromHandle(m_editLog);
		if (editLog->GetWindowTextLength()>50000)		
		{
			editLog->SetSel(0,-1);
			editLog->Clear();
			editLog->SetSel(0,0);
			editLog->ReplaceSel(log);
		}
		else
		{
			editLog->SetSel(editLog->GetWindowTextLength(),editLog->GetWindowTextLength());
			editLog->ReplaceSel(log );
		}
	}	
	return 0;
}



// 接收消息通知 ON_MESSAGE(WM_USER_COMRECVMESSAGE, OnRecvMsg)
LRESULT CCommSampleDlg::OnRecvMsg(WPARAM dwEvent,LPARAM dwLen)
{
	if(!dwLen)	return 0;
	BYTE* temp = new BYTE[dwLen+1];
	memset(temp, 0x00, dwLen+1);
	memcpy(temp, (const void*)dwEvent, dwLen);
	CString log;
	log.Format("\r\n接收数据=%s", (LPCTSTR)temp);


	if (m_editRecv.GetLength() > 50000)	m_editRecv = "";
	m_editRecv += log;	
	UpdateData(FALSE);
	return 0;
}


展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客
应支付0元
点击重新获取
扫码支付

支付成功即可阅读