欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

两种串口通信端口编程

程序员文章站 2022-06-18 11:09:34
...

一.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;
}

两种串口通信端口编程


相关标签: 串口通信