MFC实现的串口通信助手

需要用到VC串口调试程序,于是写了一个串口调试助手作参考,源码地址:http://download.csdn.net/detail/hc260164797/4360519,欢迎大家拍砖~~

程序界面是



串口设置是,9600波特率,8数据位,1位停止位,无校验位

该程序实现两个线程,一个线程串口读数据,并更新界面,一个座位主界面和串口发送数据。

主要实现函数:

1.枚举所有可用串口:

//枚举串口
void EnumerateSerialPorts(CUIntArray& ports)
{
  //Make sure we clear out any elements which may already be in the array
  ports.RemoveAll();

  //Determine what OS we are running on
  OSVERSIONINFO osvi;
  osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  BOOL bGetVer = GetVersionEx(&osvi);

  //On NT use the QueryDosDevice API
  if (bGetVer && (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT))
  {
    //Use QueryDosDevice to look for all devices of the form COMx. This is a better
    //solution as it means that no ports have to be opened at all.
    TCHAR szDevices[65535];
    DWORD dwChars = QueryDosDevice(NULL, szDevices, 65535);
    if (dwChars)
    {
      int i=0;
      for (;;)
      {
        //Get the current device name
        TCHAR* pszCurrentDevice = &szDevices[i];
        //If it looks like "COMX" then
        //add it to the array which will be returned
        int nLen = _tcslen(pszCurrentDevice);
        if (nLen > 3 && _tcsnicmp(pszCurrentDevice, _T("COM"), 3) == 0)
        {
          //Work out the port number
          int nPort = _ttoi(&pszCurrentDevice[3]);
          ports.Add(nPort);
        }
        // Go to next NULL character
        while(szDevices[i] != _T('\0'))
          i++;
        // Bump pointer to the next string
        i++;
        // The list is double-NULL terminated, so if the character is
        // now NULL, we're at the end
        if (szDevices[i] == _T('\0'))
          break;
      }
    }
    else
      TRACE(_T("Failed in call to QueryDosDevice, GetLastError:%d\n"), GetLastError());
  }
  else
  {
    //On 95/98 open up each port to determine their existence
    //Up to 255 COM ports are supported so we iterate through all of them seeing
    //if we can open them or if we fail to open them, get an access denied or general error error.
    //Both of these cases indicate that there is a COM port at that number. 
    for (UINT i=1; i<256; i++)
    {
      //Form the Raw device name
      CString sPort;
      sPort.Format(_T("\\\\.\\COM%d"), i);

      //Try to open the port
      BOOL bSuccess = FALSE;
      HANDLE hPort = ::CreateFile(sPort, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
      if (hPort == INVALID_HANDLE_VALUE)
      {
        DWORD dwError = GetLastError();
        //Check to see if the error was because some other app had the port open or a general failure
        if (dwError == ERROR_ACCESS_DENIED || dwError == ERROR_GEN_FAILURE)
          bSuccess = TRUE;
      }
      else
      {
        //The port was opened successfully
        bSuccess = TRUE;
        //Don't forget to close the port, since we are going to do nothing with it anyway
        CloseHandle(hPort);
      }
      //Add the port number to the array which will be returned
      if (bSuccess)
        ports.Add(i);
    }
  }
}
2.初始化串口:

void CSerial1AppDlg::OnBnClickedOpencomBtn()
{
	// TODO: 在此添加控件通知处理程序代码
	/*串口的初始化*/
	CString str_com=L"";
	com_combobox.GetWindowTextW(str_com);
	hCom=CreateFile(str_com,GENERIC_READ|GENERIC_WRITE,
		0,NULL,OPEN_EXISTING,0,NULL);   //打开串口
	if(hCom==(HANDLE)-1)
	{
		MessageBox(L"打开COM失败!");
	}
	else{
		open_btn.EnableWindow(FALSE);
		close_btn.EnableWindow(TRUE);
		send_btn.EnableWindow(TRUE);
		com_combobox.EnableWindow(FALSE);
		SetupComm(hCom,100,100); //输入缓冲区和输出缓冲区的大小都是100
		COMMTIMEOUTS TimeOuts;
		//设定读超时
		TimeOuts.ReadIntervalTimeout=MAXDWORD;
		TimeOuts.ReadTotalTimeoutMultiplier=0;
		TimeOuts.ReadTotalTimeoutConstant=0;
		//在读一次输入缓冲区的内容后读操作就立即返回,
		//而不管是否读入了要求的字符。


		//设定写超时
		TimeOuts.WriteTotalTimeoutMultiplier=100;
		TimeOuts.WriteTotalTimeoutConstant=500;
		SetCommTimeouts(hCom,&TimeOuts); //设置超时
		DCB dcb;
		GetCommState(hCom,&dcb);
		dcb.BaudRate=9600; //波特率为9600
		dcb.ByteSize=8; //每个字节有8位
		dcb.Parity=NOPARITY; //无奇偶校验位
		dcb.StopBits=ONESTOPBIT ; //停止位
		SetCommState(hCom,&dcb);
		PurgeComm(hCom,PURGE_TXCLEAR|PURGE_RXCLEAR);

		//创建新线程读取串口数据
		hThread_receiver=CreateThread(NULL,  0,  (LPTHREAD_START_ROUTINE)UpdateUIThread,  this,  0,  (unsigned long *)&ThreadID); 
	}
}

3.串口发送:

HCURSOR CSerial1AppDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}

void CSerial1AppDlg::OnBnClickedSendBtn()
{
	// TODO: 在此添加控件通知处理程序代码
	//UpdateData(true);
	CString str_senddata=L"";
	send_edit.GetWindowTextW(str_senddata);//需要发送到数据
	CStringA str_senddataA="";
	str_senddataA=CStrW2CStrA(str_senddata);
	int len=str_senddata.GetLength();
	DWORD dwBytesWrite=len;
	COMSTAT ComStat;
	DWORD dwErrorFlags;
	BOOL bWriteStat;
	ClearCommError(hCom,&dwErrorFlags,&ComStat);
	bWriteStat=WriteFile(hCom,str_senddataA,dwBytesWrite,& 
		dwBytesWrite,NULL);
	if(!bWriteStat)
	{
		MessageBox(L"写串口失败!");
	}
}

4.读串口,并更新界面:

//读数据
CString readdata(){
	char str[100];
	memset(str,'\0',100);
	DWORD wCount=100;//读取的字节数
	BOOL bReadStat;
	
	bReadStat=ReadFile(hCom,str,wCount,&wCount,NULL);
	if(!bReadStat){
		AfxMessageBox(L"读串口失败!,点击确定关闭程序");
		exit(0);
	}
	PurgeComm(hCom, PURGE_TXABORT|
	PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);
	return (CString)str;
}

//更新线程函数
void UpdateUIThread(CSerial1AppDlg *p){
	CString str=L"";
	CString str_previous=L"";
	while(1){
		str_previous=str;
		str.Append(readdata());
		if(str_previous!=str){
			p->receive_edit.SetWindowTextW(str);
		}
		//p->SendMessage(WM_MYUPDATEDATA,FALSE);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值