基于MSCOMM控件串口通讯(MFC)

注:本人博文整理至CSDN以方便查阅,源博文位于EDN


虽然网上很多关于这个的资料了,但还是自己总结下

获取当前可用的串口可以通过读取注册表获取相应的值。当前可用的COM口在注册表中的位置:


HKEY_LOCAL_MACHINE\\HARDWARE\\DEVICEMAP\\SERIALCOMM


通过枚举来获取所有的COM口。实现如下:

调用举例:

enum_reg_key_value(HKEY_LOCAL_MACHINE, ”HARDWARE\\DEVICEMAP\\SERIALCOMM”);


bool CValueDlg::enum_reg_key_value(HKEY hKey, LPCTSTR lpSubKey)

{

    #define MAX_VALUE_NAME 100


    HKEY    hOpenKey;

    long    lResult = 0;

    CHAR    achClass[MAX_PATH];

    DWORD   cchClassNameLen;

    DWORD   cMaxClassLen;

    DWORD   cSubKeysNum;

    DWORD   cbMaxSubKeyLen;

    DWORD   cbValuesNum;

    DWORD   cbMaxValueNameLen;

    DWORD   cbMaxValueLen;

    DWORD   cbSecurityDescriptor;

    FILETIME ftLastWriteTime;

    CHAR  achValue[MAX_VALUE_NAME];

    DWORD cbValue = MAX_VALUE_NAME;

    DWORD DataType;

    BYTE  Data[255];

    DWORD DataLen;

    CString StrData = L"";


    lResult = RegOpenKeyEx(hKey, lpSubKey, 0, KEY_READ, &hOpenKey);


    if(ERROR_SUCCESS != lResult)

    {

        return FALSE;

    }


    RegQueryInfoKey(hOpenKey, //已打开的键的句柄

                                       achClass, //类型名称

                                       &cchClassNameLen, //类型名称的长度

                                       NULL, //保留

                                       &cSubKeysNum, // 返回子键的数目

                                       &cbMaxSubKeyLen, // 返回最长的子键长度

                                       &cMaxClassLen, // 返回最长的类长度

                                       &cbValuesNum, // 返回值的数目

                                       &cbMaxValueNameLen, // 返回最长的值项,名称的长度

                                       &cbMaxValueLen, // 返回最长的值的长度

                                       &cbSecurityDescriptor, //返回安全描述

                                       &ftLastWriteTime); // 返回键最后被写入的时间


   for (DWORD j = 0, retValue = ERROR_SUCCESS; j < cbValuesNum; j++)

   {

        cbValue = MAX_VALUE_NAME;


        memset(achValue, 0, sizeof(achValue));

        memset(Data, 0, sizeof(Data));

        StrData = L"";

 

        retValue = RegEnumValue(hOpenKey,

                                                           j,

                                                          achValue,

                                                          &cbValue,

                                                          NULL,

                                                          &DataType,

                                                          Data,

                                                          &DataLen);


         if (retValue == (DWORD) ERROR_SUCCESS )

         { 

             StrData.Format("%s", Data);

             m_ComboComSelect.AddString(StrData);  

         }

    }


    RegCloseKey(hOpenKey);

    return true;


#undef MAX_VALUE_NAME

}


打开串口

m_CMSComm.SetCommPort(4);

m_CMSComm. SetInBufferSize(1024);

m_CMSComm. SetOutBufferSize(512);


if(!m_CMSComm.GetPortOpen())

{

       try

       {

              m_CMSComm.SetPortOpen(TRUE); //打开串口

       }

       catch(COleDispatchException *e)//如果所要打开的串口已经被其他程序使用,会报异常

       {    

              AfxMessageBox("Error:The COM has been occupied or isn't Exist");

              e = NULL;

              return;

       }


       m_CMSComm.SetInputMode(0); //设置输入方式为Text

       m_CMSComm.SetSettings(m_Uart_Struct.settings);

       m_CMSComm.SetRThreshold(1); //为1表示接收到一个字符便出发接收事件

       m_CMSComm.SetInputLen(0);// 设置当前接收区数据长度为0,表示全部读取

}

else

{

       AfxMessageBox("Error:The COM has been occupied or isn't Exist");

}


串口数据发送

关于串口数据的发送网上很多的写法都是利用以下的方法

CByteArray array;

DWORD len = 0;

char TxData [1024 + 1];

CString StrData = L"";

len = StrData.GetLength();

memset(TxData, 0, sizeof(TxData));

strcpy(TxData, StrData);

array.RemoveAll();

array.SetSize(len);


for(DWORD i=0; i<len; i++)

{

       array.SetAt(i, TxData[i]);

}


m_CMSComm.SetOutput(COleVariant(array)); …………………………①


其实所有的关键都在于①这条语句,传入的数据类型强制转换为任意数据类型COleVariant,于是将所要发送的字符串直接强制转换也是可以的。以上代码便以下面一条语句即可实现发送数据的操作。


m_CMSComm.SetOutput(COleVariant(StrData));


数据接收


事件2表示接收事件,其他事件所对应的值可以网上查下,很多有介绍了。如

http://blog.ednchina.com/bobi2005/175488/message.aspx


其实这里的关键就在于接收到的数据存在数据类型VARIANT中,关于它的使用也自己查吧。以下是接收的一种写法。


void CValueDlg::OnComm ()

{

       VARIANT          vResponse;

       int                        rec_data_len;


       if(m_CMSComm.GetCommEvent() == 2)

       {

              rec_data_len = m_CMSComm.GetInBufferCount();


              if(rec_data_len > 0)

              {

                     vResponse = m_CMSComm.GetInput();


                     if(VT_BSTR == vResponse.vt)

                     {

                            save_rec_data(CString(vResponse.bstrVal));

                     }

              } 

       }


       return;

}


以下介绍另外两种接收数据写法,注意,这两种写法需要将open函数中的模式设为二进制模式即

m_CMSComm.SetInputMode(1);


方法 一、


void CValueDlg::OnComm ()

{

       VARIANT variant_inp;

       int rec_data_len;

       CString strtemp;

       char chData[1024 + 1];


       if(m_CMSComm.GetCommEvent() == 2)

       {

              variant_inp = m_CMSComm.GetInput();

              rec_data_len = variant_inp.parray->rgsabound->cElements;


              if (rec_data_len > 0)

              {

                     memset(chData, 0, sizeof(chData));

                     memcpy(chData, (char *)variant_inp.parray->pvData, rec_data_len);

                     strtemp.Format("%s", chData);

                     save_rec_data(strtemp);

              }

       }


       return;

}


方法 二、

这种方法是网上很多人转帖的写法,也可以实现接收的功能。如下


void CValueDlg::OnComm ()

{

    VARIANT      variant_tmp;

    COleSafeArray  safe_array_tmp;

    long length, i;

    BYTE data[1024];

    CString str ="";

    CString strTemp;

 

    if(m_CMSComm.GetCommEvent() == 2)

   {

       variant_tmp  =  m_CMSComm.GetInput();

       safe_array_tmp  =  variant_tmp;………………②

       length = safe_array_tmp.GetOneDimSize();

           

       for(i=0; i<length; i++)

      {

              safe_array_tmp.GetElement(&i, data+i); //将数据转换为BYTE型

     }

           

      for(i=0; i<length; i++) //将数组转换为Cstring型变量

      {

           BYTE bt = *(char*)(data+i);

           strTemp.Format("%c",bt);

           m_strReceiveMsg += strTemp;

            ……

      }

  }

}


       我最开始看到的也是这种方法,但是和许多的网友一样在执行到②语句的时候,就弹出一个警告框,忽略后还是可以继续运行。还以为是这种写法有错呢,硬着头皮看了VARIANT和COleSafeArray这两个类确定没错,回头仔细检查打开串口的设置发现设置输入模式的地方错了,如果你要用以上这种方法需要将输入模式设置成二进制模式,这样②这条语句便可以正确执行了,不知道其他人是否也很我一样的这样解决的,提出来分享下。

以上三法希望你可以找到合适的。


关闭串口


if(m_CMSComm.GetPortOpen())

{

       m_CMSComm.SetPortOpen(FALSE);

}


        用控件虽然大大简化,但是如果有台上位机没装VC++程序,那么Release出来的程序也是不能运行的,这里下了个批处理文件,来注册控件,见附件。这样串口通信就OK了。


MSCOMM到我的资源中下载。http://download.csdn.net/detail/jerome_home/4913971


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值