MFC使用MScomm32.ocx控件实现串口通信

⌚Time: 2023-09-16 20:58:17

👨‍💻Author: Jack Ge

首先电脑应该有MSCOMM32.OCX并注册,我在相关文章写了安装过程

建立项目

使用VS2005新建一个基于对话框的MFC项,在资源视图,右键窗体,插入ActiveX控件,选择Microsoft Communications Control

之后窗体就会出现一个电话图标,表示MSCOMM控件,这个图标在运行时并不会显示

添加MSCOMM控件变量

给MSCOMM控件添加一个变量,有两种办法,

==方法一==

直接对控件右键,添加变量

填写变量名字,系统会自动生成变量。并且建立一个CMscomm1类和它的头文件、源文件

==方法二==

在解决方案管理器,点击项目,添加类,选择ActiveX控件中的MFC类

在可用的ActiveX控件,选择Microsoft Communications Control,下面的接口使用>移动到右侧生成的类,点击完成,系统自动创建一个CMSComm类、它的头文件CMSComm.h和源文件CMSComm.cpp

在窗体类的头文件里包含


#include "CMSComm.h"

定义一个变量


CMSComm m_MSComm;

在窗体的DoDataExchange函数里建立与ocx控件IDC_MSCOMM1的数据关联


void CSerialPortQDlg::DoDataExchange(CDataExchange* pDX)

{

    CDialog::DoDataExchange(pDX);

    DDX_Control(pDX, IDC_MSCOMM1, m_MSComm);

}

变量就添加完成了

串口的打开和关闭

在窗体添加两个按钮,打开和关闭串口,实现功能

打开串口


void CSerialPortQDlg::OnBnClickedButton1()

{

    // TODO: 在此添加控件通知处理程序代码



    if(m_MSComm.get_PortOpen())//如果串口已打开则返回

    {

        return;

    }

    m_MSComm.put_CommPort(2);//选择COM2

    m_MSComm.put_InputLen(0);//设置当前接收区数据长度为0

    m_MSComm.put_InputMode(1);//1表示以二进制方式读写数据

    m_MSComm.put_RThreshold(1);//接收缓冲区有1个及1个以上字符时,将引发接收数据的OnComm事件

    m_MSComm.put_Settings(_T("9600,n,8,1"));//波特率9600 无检验位,8个数据位,1个停止位



    m_MSComm.put_PortOpen(TRUE);//打开串口

    m_MSComm.get_Input();//预读缓冲区以清除残留数据



    MessageBox(L"打开串口成功");

}

关闭串口


void CSerialPortQDlg::OnBnClickedButton2()

{

    // TODO: 在此添加控件通知处理程序代码



    if(m_MSComm.get_PortOpen())//如果串口已打开则关闭

    {

        m_MSComm.put_PortOpen(FALSE);

        MessageBox(L"关闭串口成功");

    }

}

串口发送和接收数据

窗体添加两个CEdit控件,一个显示接收数据,一个发送数据。

其中接收数据的控件,属性里面

Vertical Scroll设置ture

Multiline设置true

Read Only设置true

为了方便显示收发数据,在窗体类添加两个CString变量,并与两个CEdit建立关联


    CString m_strGet;//接收的数据

    CString m_strSend;//发送的数据

在DoDataExchange里面将变量与控件建立数据交换


void CSerialPortQDlg::DoDataExchange(CDataExchange* pDX)

{

    CDialog::DoDataExchange(pDX);

    DDX_Control(pDX, IDC_MSCOMM1, m_MSComm);

    DDX_Text( pDX, IDC_EDIT1, m_strGet);//接收的数据

    DDX_Text( pDX, IDC_EDIT2, m_strSend);//发送的数据

}

数据接收

对OCX控件右键,添加事件处理程序。选择OnComm消息,添加编辑


void CSerialPortQDlg::OnCommMscomm1()

{

    // TODO: 在此处添加消息处理程序代码

    VARIANT variant_inp;

    COleSafeArray safearray_inp;

    LONG len,k;

    BYTE rxdata[2048]; //设置BYTE数组 An 8-bit integer that is not signed.

    CString strtemp;



    if(m_MSComm.get_CommEvent()==2) //事件值为2表示接收缓冲区内有字符

    {

        variant_inp=m_MSComm.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(L"%c",bt); //将字符送入临时变量strtemp存放



            m_strGet += strtemp; //字符追加到接收编辑框对应的字符串变量

        }

    }

    m_strGet += L"\r\n";//加换行

    UpdateData(FALSE); //将数据更新到控件

}

数据发送


void CSerialPortQDlg::OnBnClickedButton3()

{

    // TODO: 在此添加控件通知处理程序代码

    UpdateData(TRUE);//控件数据更新到字符串变量



    m_MSComm.put_Output(COleVariant(m_strSend));//发送数据

    

}


16进制数据的收发

添加一个选择框,决定16进制发送,右键选择框,添加一个变量

转换函数

用到函数将CString转化为CByteArray


char ConvertHexChar(char ch) 

{

    if((ch>='0')&&(ch<='9'))

        return ch-0x30;

    else if((ch>='A')&&(ch<='F'))

        return ch-'A'+10;

    else if((ch>='a')&&(ch<='f'))

        return ch-'a'+10;

    else return (-1);

}

int String2Hex(CString str, CByteArray &senddata)

{

    int hexdata,lowhexdata;

    int hexdatalen=0;

    int len=str.GetLength();

    senddata.SetSize(len/2);

    for(int i=0;i<len;)

    {

        char lstr,hstr=str[i];

        if(hstr==' ')

        {

            i++;

            continue;

        }

        i++;

        if(i>=len){

            break;

        }

        lstr=str[i];

        hexdata=ConvertHexChar(hstr);

        lowhexdata=ConvertHexChar(lstr);

        if((hexdata==16)||(lowhexdata==16)){

            break;

        }else{

            hexdata=hexdata*16+lowhexdata;

        }

        i++;

        senddata[hexdatalen]=(char)hexdata;

        hexdatalen++;

    }

    senddata.SetSize(hexdatalen);

    return hexdatalen;

}

数据发送


void CSerialportDlg::OnBnClickedButton4()

{

    UpdateData(TRUE);//控件数据更新到字符串变量

    if(m_16Check.GetCheck()){

        CByteArray hexdata;

        int len=String2Hex(m_strSend,hexdata); //此处返回的len可以用于计算发送了多少个十六进制数

        m_MSComm.put_Output(COleVariant(hexdata)); //发送十六进制数据

    }else{

        m_MSComm.put_Output(COleVariant(m_strSend));//发送数据

    }

}

数据接收


void CSerialPortQDlg::OnCommMscomm1()

{

    // TODO: 在此处添加消息处理程序代码

    VARIANT variant_inp;

    COleSafeArray safearray_inp;

    LONG len,k;

    BYTE rxdata[2048]; //设置BYTE数组 An 8-bit integer that is not signed.

    CString strtemp;



    if(m_MSComm.get_CommEvent()==2) //事件值为2表示接收缓冲区内有字符

    {

        variant_inp=m_MSComm.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); //字符型

            if(m_16Check.GetCheck()){

                strtemp.Format(L"%02x ",bt); //将字符以十六进制方式送入临时变量strtemp存放

            }else{

                strtemp.Format(L"%c",bt); //将字符送入临时变量strtemp存放

            }

            m_strGet += strtemp; //字符追加到接收编辑框对应的字符串变量

        }

    }

    m_strGet += L"\r\n";//加换行

    UpdateData(FALSE); //将数据更新到控件