MFC串口助手实现

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_36305492/article/details/78318571

学习了MFC测试看着别人的例程写了一个串口调试助手,

分享一下我的学习过程,我调用了一个定时器,一个MSCOMM控件,

 我实现了自动搜索可打开串口,串口波特率,奇偶校验,各种配置串口功能的实现,没有编辑16位发送,感觉很鸡肋就没有写,

程序很简单基本上就是在配置MSCOMM控件上花了很多时间。

这是我的可视化界面,首先加入这个串口控件

为MSCOMM建立一个事件:参照这个程序

我为了显示16进制数据在这个函数上进行了修改

VARIANT variant_inp;
	COleSafeArray safearray_inp;
	LONG len,k; 
	BYTE rxdata[2048];
    CString strtemp,buffer;

	if(m_ctrlComm.get_CommEvent()==2)//等于二表明接收到数据
	{

		if(BST_UNCHECKED==((CButton*)GetDlgItem(IDC_CHECK16RECEIVE))->GetCheck())
		{
			   ////////以下是正常显示效果处理代码 
			variant_inp=m_ctrlComm.get_Input(); //读缓冲区  
			safearray_inp=variant_inp; //VARIANT型变量转换为ColeSafeArray型变量
			len=safearray_inp.GetOneDimSize(); //得到有效数据长度        
			for(k=0;k<len;k++)             
			safearray_inp.GetElement(&k,rxdata+k);//转换为BYTE型数组         
			for(k=0;k<len;k++)                    //将数组转换为Cstring型变量    
			{           
			  BYTE bt=*(char*)(rxdata+k);//字符型      
			  strtemp.Format(_T("%c"),bt); //将字符送入临时变量strtemp存放   
			  if(strtemp=='\n'||strtemp=='\r')
			  {
				  strtemp="\r\n";
			  }
	////此处编译有错误,可在项目属性->配置属性->常规里将“字符集”改为使用多字节字符集即可
			  m_strRXDATA+=strtemp; //加入接收编辑框对应字符串      
			}
            
             //UpdateData(FALSE); //更新编辑框内容
			SetDlgItemText(IDC_RECEIVE_EDIT1,m_strRXDATA);
			/*IDC_RECEIVE_EDIT1->ReplaceSel(m_strRXDATA, FALSE);*/
			 m_recvshw.LineScroll(m_recvshw.GetLineCount());
		 }     
		
	 

	else
	   {

		variant_inp=m_ctrlComm.get_Input(); //读缓冲区  
		safearray_inp=variant_inp; //VARIA NT型变量转换为ColeSafeArray型变量
		len=safearray_inp.GetOneDimSize(); //得到有效数据长度        
		for(k=0;k<len;k++)             
		{
			safearray_inp.GetElement(&k,rxdata+k);//转换为BYTE型数组 
	/*		strtemp.Format(_T("%02X"), *(rxdata + k)); 
			buffer += strtemp;*/
		}
		//buffer.TrimLeft();
		//buffer.TrimRight();
		//CByteArray receivedata;
		//int receivedatalen;
		//receivedatalen = Str2Hex(buffer, receivedata);
		for(k=0;k<len;k++)
		{
			switch(rxdata[k]/16)
			{
	          case 0:  m_strRXDATA+='0';break;
			  case 1:  m_strRXDATA+='1';break;
              case 2:  m_strRXDATA+='2';break;
			  case 3:  m_strRXDATA+='3';break;
	          case 4:  m_strRXDATA+='4';break;
			  case 5:  m_strRXDATA+='5';break;
              case 6:  m_strRXDATA+='6';break;
			  case 7:  m_strRXDATA+='7';break;
	          case 8:  m_strRXDATA+='8';break;
			  case 9:  m_strRXDATA+='9';break;
              case 10:  m_strRXDATA+='A';break;
			  case 11:  m_strRXDATA+='B';break;
	          case 12:  m_strRXDATA+='C';break;
			  case 13:  m_strRXDATA+='D';break;
              case 14:  m_strRXDATA+='E';break;
			  case 15:  m_strRXDATA+='F';break;
			
			}
			switch(rxdata[k]%16)
			{
	          case 0:  m_strRXDATA+='0';break;
			  case 1:  m_strRXDATA+='1';break;
              case 2:  m_strRXDATA+='2';break;
			  case 3:  m_strRXDATA+='3';break;
	          case 4:  m_strRXDATA+='4';break;
			  case 5:  m_strRXDATA+='5';break;
              case 6:  m_strRXDATA+='6';break;
			  case 7:  m_strRXDATA+='7';break;
	          case 8:  m_strRXDATA+='8';break;
			  case 9:  m_strRXDATA+='9';break;
              case 10:  m_strRXDATA+='A';break;
			  case 11:  m_strRXDATA+='B';break;
	          case 12:  m_strRXDATA+='C';break;
			  case 13:  m_strRXDATA+='D';break;
              case 14:  m_strRXDATA+='E';break;
			  case 15:  m_strRXDATA+='F';break;
			}
        m_strRXDATA+=' ';
		}
		
		 UpdateData(FALSE); //更新编辑框内容
		 m_recvshw.LineScroll(m_recvshw.GetLineCount());
	   }
	//}

	//else{;}

	}
}
这个函数会获取check就是打对号那种控件的值判断是执行那一句操作

这里注意我是把接受控件的Multiline选为TRUL才能自自动换行,还要把Auto HScroll配置为flase ,Auto VScroll为真,还可以把READ only打开这样就不会再输入数据

我是在类中建立了一个全局变量
 bool Uart_Init;//串口初始化完成标志位

一旦我检测到配置变化就把串口关闭

DATASET_BOX dataset={0,1,3,0,1};
  CStringArray budecode;
  CStringArray datecode;
  CStringArray stopcode;
  CStringArray testcode;;/*={"n,","o,","e,"};*/

建立了四个动态数组注意检测位的无奇校验,偶校验是用 n, o, e控制的

我得打开串口配置函数如下


	if(Uart_Init!=true)
	{

    dataset.sm_comboCOM = m_comboCOM.GetCurSel();//获取组合框控件的列表框中选中项的索引  
	dataset.sm_comboSTOP=m_comboSTOP.GetCurSel();
	dataset.sm_comboTEST=m_comboTEST.GetCurSel();
	dataset.sm_comboDATA=m_comboDATA.GetCurSel();
	dataset.sm_comboBUTE = m_comboBUTE.GetCurSel();
    //CString comtemp;
    //comtemp.Format(_T("COM%d"),comstruct.commom[fori]);
    //m_comboCOM.AddString(comtemp);
	m_ctrlComm.put_CommPort( comstruct.commom[dataset.sm_comboCOM+1]);//设置com1



	////    char buff[15];
	////strcpy(buff,budecode[dataset.sm_comboBUTE]);
	////strcat(buff,testcode[dataset.sm_comboTEST]);
	////strcat(buff,datecode[dataset.sm_comboDATA]);
	////strcat(buff,stopcode[dataset.sm_comboSTOP]);
	////CString cstr(buff);
 ////   LPCTSTR pStr = LPCTSTR(cstr);
	////m_ctrlComm.put_Settings(pStr);//设置串口参数,波特率,无奇偶校验,位停止位,位数据位 

	////m_ctrlComm.put_Settings(_T("9600,n,8,1"));

	//m_ctrlComm.put_RThreshold(1);
	//m_ctrlComm.put_InBufferSize(2048);
	//m_ctrlComm.put_OutBufferSize(1024);

    m_ctrlComm.put_PortOpen(TRUE);//打开串口  
    m_ctrlComm.put_RThreshold(2);//收到两个字节引发OnComm事件   
    m_ctrlComm.put_InputMode(1);//输入模式选为二进制   


	CString str=budecode.GetAt(dataset.sm_comboBUTE);
    str+=testcode.GetAt(dataset.sm_comboTEST);
	str+=datecode.GetAt(dataset.sm_comboDATA);
	str+=stopcode.GetAt(dataset.sm_comboSTOP);
	LPCTSTR pStr = LPCTSTR(str);
    m_ctrlComm.put_Settings(pStr);//设置串口参数,波特率,无奇偶校验,位停止位,位数据位  

    m_ctrlComm.put_InputMode(1);  // 以二进制方式检取数据   
    m_ctrlComm.put_RThreshold(1); //参数1表示每当串口接收缓冲区中有多于或等于1个字符时将引发一个接收数据的OnComm事件   
    m_ctrlComm.put_InputLen(0); //设置当前接收区数据长度为0   
    m_ctrlComm.get_Input();//先预读缓冲区以清除残留数据   
    m_ctrlComm.put_OutBufferCount(0);
	GetDlgItem(IDC_OPENUART)->SetWindowText(_T("关闭串口"));

    Uart_Init=1;

		if(!m_ctrlComm.get_PortOpen())
		{
		Uart_Init=1;
		GetDlgItem(IDC_OPENUART)->SetWindowText(_T("打开串口"));
		//
		}
	}
	else 
	{
		GetDlgItem(IDC_OPENUART)->SetWindowText(_T("打开串口"));
		Uart_Init=0;
		m_ctrlComm.put_PortOpen(FALSE);
	}
}
在网上找了很多都没有我这种配置形式,这样可以随意配置自己的波特率,等等参数只要在参数里就好了

最后就是发送函数

void CUARTDlg::OnBnClickedSend()
{
	// TODO: 在此添加控件通知处理程序代码

  if (Uart_Init == true)    //判断是否打开并初始化串口  
   {  
	   if(BST_UNCHECKED==((CButton*)GetDlgItem(IDC_CHECK16SEND))->GetCheck())
	   {
	     if(BST_UNCHECKED==((CButton*)GetDlgItem(IDC_CHECKNEWLINE))->GetCheck())
	     {
			UpdateData(TRUE);  //读取编辑框内容  
			m_ctrlComm.put_Output(COleVariant(m_strTXDATA)); //发送数据  
		 }
		 else
		 {
             UpdateData(TRUE);  //读取编辑框内容 
			 m_strTXDATA+="\r\n";
			m_ctrlComm.put_Output(COleVariant(m_strTXDATA)); //发送数据  

		 }
	   }
  }

  else  
	{  
			MessageBox(_T("请先打开串口")); 
			return;
	} 


}
基本就是这样,还有我是用定时器扫描串口来时时检测串口数量和值的

建立定时器的这个文章很好讲的也很透彻我就把可视化配置图片 给大家看一下

在这里添加类向导




双击加入这个On Timer,我们就会再cXXXDLG.C的函数中找到一下函数


oid CUARTDlg::OnTimer(UINT_PTR nIDEvent)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值

	CDialogEx::OnTimer(nIDEvent) ;
	switch(nIDEvent)
	{
	case 1:{
				    QueryKey();
					if(comstruct.commax>=1)
				{
					for(int fori=1;fori<=comstruct.commax;fori++)
					{
						CString comtemp;
						comtemp.Format(_T("COM%d"),comstruct.commom[fori]);
						m_comboCOM.AddString(comtemp);
						m_comboCOM.SetCurSel(0);
					}
				}
		   }break;

	default:break;

  }
}
 QueryKey();
这个函数是我自己写的扫描系统串口函数

void CUARTDlg::QueryKey(void)   
{   


 HANDLE hCom;
 int i,num;
 CString str;
 BOOL flag;
 
 ((CComboBox *)GetDlgItem(IDC_COMCOM))->ResetContent();
 flag = FALSE;
 num = 0;

 comstruct.commax=0;

 for (i = 1;i <= 16;i++)
 {//此程序支持16个串口
    str.Format("\\\\.\\COM%d",i);
    hCom = CreateFile(str, 0, 0, 0,  OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
    if(INVALID_HANDLE_VALUE != hCom )
    {
	 	//能打开该串口,则添加该串口
		CloseHandle(hCom);
		str = str.Mid(4);
		//((CComboBox *)GetDlgItem(IDC_COMCOM))->AddString(str);
        comstruct.commax++;
		comstruct.commom[comstruct.commax]=i;
				
		if (flag == FALSE)
		{
		flag = TRUE;
		num = i;
		}
      }
    }
    /* i = ((CComboBox *)GetDlgItem(IDC_COMCOM))->GetCount();*/
	if (num == 0)
		{//若找不到可用串口则禁用“打开串口”功能
		((CComboBox *)GetDlgItem(IDC_COMCOM))->EnableWindow(FALSE);
         }
		 else
		 {
		 //k = ((CComboBox *)GetDlgItem((IDC_COMCOM)))->GetCount();
		 //((CComboBox *)GetDlgItem(IDC_COMCOM))->SetCurSel(k - 1);
		 //mCom.BindCommPort(num);
		 }
   } 
这个就是扫描函数我在函数中建立一个结构体

 struct commmmm
{
   int commax;
   int commom[20];
} comstruct={0,0};

commax是为了记录一共扫描到几个串口对应的common函数是对应串口号

我在扫描显示时能够体现出来。大概程序就是这个思路我的程序上传了上来,点击打开链接

如果有疑惑,可以留言相互交流,相互学习。如有错误,请各位大佬支出啊




猜你喜欢

转载自blog.csdn.net/qq_36305492/article/details/78318571