[MFC]使用强大的第三方串口类 CSerialPort

原创文章,欢迎转载。转载请注明:转载自 祥的博客

原文链接:http://blog.csdn.net/humanking7/article/details/48110543


最近要写一个串口程序,用MFC自带COM组件的效果很差(一次接收一个缓冲区的数据,没办法像写嵌入式程序那样单字节就能触发中断接收那样),所以进行了一些研究,发现了一个 第三方串口类 很强大,效果非常好。

资源下载

第三方串口类资源下载:http://download.csdn.net/detail/humanking7/9064717

步骤详解

编程环境:VS2008

Step1 构建界面

建立一个基于对话框的MFC应用程序,我在这里是 SerialPortTest ,画的界面如下:

k1)

Step2 添加第三方类

SerialPort.hSerialPort.cpp 两个文件复制到工程所在的文件夹中,而且添加到工程里,并在MFC生成的对话框类的头文件中包含 #include "SerialPort.h"

k2

Step3 添加串口响应函数

在我的对话框类中( class CSerialPortTestDlg : public CDialogSerialPortTest.h 头文件中) 添加串口字符接收消息 WM_COMM_RXCHAR(串口接收缓冲区内有一个字符)的响应函数声明:

    public:
    //******************************************
    afx_msg LONG OnCommunication(WPARAM ch, LPARAM port);//串口接收处理函数
    //******************************************

然后再在 SerialPortTest.cpp 中进行 WM_COMM_RXCHAR 消息映射:

    BEGIN_MESSAGE_MAP(CSerialPortTestDlg, CDialog)
        ·········
        //******************************************
        ON_MESSAGE(WM_COMM_RXCHAR, OnCommunication)//串口接收处理函数
        //******************************************
        ·········
    END_MESSAGE_MAP()

最后在 SerialPortTest.cpp 对串口接收响应函数进行实现:

    LONG CSerialPortTestDlg::OnCommunication(WPARAM ch, LPARAM port)
    {//串口接收  处理函数

        ······

        return 0;
    }

Step4 初始化串口

其实就是打开串口和关闭串口
首先 class CSerialPortTestDlg : public CDialog 类加入一个 Public 的成员变量 m_Com :

CSerialPort m_Com;//串口类

在对对话框的 “打开串口”CButton 控件添加 单击消息处理函数 在里面实现打开和关闭串口的功能

    void CSerialPortTestDlg::OnBnClickedBtnOpen()
    {//打开&关闭 串口

        m_PortName = m_Combox.GetCurSel()+1;                       //获取串口号
        m_Baud     = m_Baud_Group[ m_Combox_Baud.GetCurSel() ];    //获取波特率
        m_Parity   = m_Parity_Group[ m_Combox_Parity.GetCurSel() ];//获取校验位
        m_DataBit  = m_DataBit_Group[ m_Combox_Data.GetCurSel() ]; //获取数据位
        m_StopBit  = m_StopBit_Group[ m_Combox_Stop.GetCurSel() ]; //获取停止位
        if (m_IsOpenCom)//串口已经打开
        {
            //关闭串口
            m_Com.ClosePort();
            m_IsOpenCom = FALSE;
            m_Btn_Open.SetWindowText("打开串口");//说明已经关闭了串口

            //修改状态
            GetDlgItem(IDC_COMBO_PORT)->EnableWindow(TRUE);  //允许改
            GetDlgItem(IDC_COMBO_BAUD)->EnableWindow(TRUE);  //允许改
            GetDlgItem(IDC_COMBO_PARITY)->EnableWindow(TRUE);//允许改
            GetDlgItem(IDC_COMBO_DATA)->EnableWindow(TRUE);  //允许改
            GetDlgItem(IDC_COMBO_STOP)->EnableWindow(TRUE);  //允许改

        } 
        else//串口已经关闭
        {
            //if (m_Com.InitPort(this, m_PortName, 9600 ,'N',8, 0))
            if (m_Com.InitPort(this, m_PortName, m_Baud ,m_Parity,m_DataBit, m_StopBit))
            {                           //串口号,波特率,校验位,数据位,停止位为1(在此输入0,代表停止位为1)
                //打开串口成功
                m_Com.StartMonitoring();
                m_IsOpenCom = TRUE;
                m_Btn_Open.SetWindowText("关闭串口");//说明已经打开了串口


                //修改状态          
                GetDlgItem(IDC_COMBO_PORT)->EnableWindow(FALSE);  //不许改
                GetDlgItem(IDC_COMBO_BAUD)->EnableWindow(FALSE);  //不许改
                GetDlgItem(IDC_COMBO_PARITY)->EnableWindow(FALSE);//不许改
                GetDlgItem(IDC_COMBO_DATA)->EnableWindow(FALSE);  //不许改
                GetDlgItem(IDC_COMBO_STOP)->EnableWindow(FALSE);  //不许改

            }
            else
            {//串口打开失败           
                MessageBox("没有发现此串口或被占用","串口打开失败",MB_ICONWARNING);
            }   
        }   
    }

Step4 串口发送

至于串口的发送可以调用 CSerialPort类 中的类成员函数:

    void        WriteToPort(char* string);
    void        WriteToPort(char* string,int n); // add by mrlong 2007-12-25
    void        WriteToPort(LPCTSTR string);     // add by mrlong 2007-12-25
    void        WriteToPort(BYTE* Buffer, int n);// add by mrlong

具体我是这样用的:

      //m_String_Send_ASCII 是我CEdit控件绑定的CString的一个成员变量,用于获取发送数据
      char* SendBuf;
      int length = m_String_Send_ASCII.GetLength();
      SendBuf = m_String_Send_ASCII.GetBuffer(length);

      m_Com.WriteToPort( SendBuf ); //发送数据

      m_String_Send_ASCII.ReleaseBuffer();

出现的错误及其解决

使用这个串口类会遇到这个问题

    Run-Time Check Failure #3 - The variable 'comstat' is being used without being initialized

下面是我搜集到的解决方法,屡试不爽(基本用 方案1)

方案1: 改变项目配置属性

一种解决方案是改变基本运行时检查(changing the runtime checks in project settings):在菜单Project->Project properties-> C/C++ -> Code generation-> Basic Runtime checks –> change to ‘Default’,在中文版中是:项目-〉属性-〉配置属性-〉C/C++代码生成-〉基本运行时检查-〉设置为默认,当将基本运行时检查改为默认之后,编译自然顺利通过了,向串口调试助手发送消息正常了,再从串口调试助手向SerialPortTest发送消息时,也正常了。

方案2:改变comstat变量属性

另一种解决方案是将CSerialPort.CPP中的COMSTAT comstat;改为static COMSTAT comstat;这样改了之后,debug顺利通过,然后调试,与串口调试助手相互发消息都OK了。为什么这样就能解决呢?其实当你使用debug解决方案时,它的基本运行时检查初始设置为:两者(/RTC1,等同于 /RTCsu),这个两者是指:堆栈帧(/RTCs),未初始化的变量(/RTCu)。由于它要检查未初始化的变量,所以将SerialPort.cpp中的COMSTAT comstat;改为static COMSTAT comstat;就可以正常使用CSerialPort类了。
以上是在debug下的解决方案,当在Release编译状态时,你会发现并不需要将COMSTAT comstat;改为static COMSTAT comstat;就能编译成功并且发送接收消息正常。其实,在Release下,它的基本运行时检查初始设置已为默认。这应该也算是第一种解决方案之内。
而当你将它设置为两者(/RTC1,等同于 /RTCsu)时,不论是否将COMSTAT comstat;改为static COMSTAT comstat;,编译都不能通过,报错““cl.exe”返回的结果有误。”,这个应该是属于Release的问题了,另当别论了。

方案3:

添加代码:memset(&comstat, 0, sizeof(COMSTAT)); //VC6不用这句也可以用,2008就要加


donate

  • 38
    点赞
  • 156
    收藏
    觉得还不错? 一键收藏
  • 17
    评论
CSerialPort First Version by Remon Spekreijse on 2000-02-08 http://www.codeguru.com/cpp/i-n/network/serialcommunications/article.php/c2483/A-communication-class-for-serial-port.htm Second Version by mrlong on 2007-12-25 https://code.google.com/p/mycom/ 增加 ClosePort 增加 WriteToPort 两个方法 增加 SendData 与 RecvData 方法 by liquanhai on 2011-11-04 http://blog.csdn.net/liquanhai/article/details/4955253 增加 ClosePort 中交出控制权,防止死锁问题 by liquanhai on 2011-11-06 http://blog.csdn.net/liquanhai/article/details/6941574 增加 ReceiveChar 中防止线程死锁 by viruscamp on 2013-12-04 https://github.com/viruscamp/CSerialPort 增加 IsOpen 判断是否打开 修正 InitPort 中 parity Odd Even 参数取值错误 修改 InitPortportnr 取值范围,portnr>9 时特殊处理 取消对 MFC 的依赖,使用 HWND 替代 CWnd,使用 win32 thread 函数而不是 MFC 的 增加用户消息编号自定义,方法来自 CnComm by itas109 on 2014-01-10 http://blog.csdn.net/itas109/article/details/18358297 解决COM10以上端口无法显示的问题 扩展可选择端口,最大值MaxSerialPortNum可以自定义 添加QueryKey()和Hkey2ComboBox两个方法,用于自动查询当前有效的串口号。 by liquanhai on 2014-12-18 增加一些处理措施,主要是对减少CPU占用率 by itas109 on 2016-05-07 http://blog.csdn.net/itas109 修复每次打开串口发送一次,当串口无应答时,需要关闭再打开或者接收完数据才能发送的问题。 解决办法:在m_hEventArray中调整m_hWriteEvent的优先级高于读的优先级。CommThread(LPVOID pParam)函数中读写的位置也调换。 参考:http://zhidao.baidu.com/link?url=RSrbPcfTZRULFFd2ziHZPBwnoXv1iCSu_Nmycb_yEw1mklT8gkoNZAkWpl3UDhk8L35DtRPo5VV5kEGpOx-Gea 修复停止位在头文件中定义成1导致SetCommState报错的问题,应为1对应的停止位是1.5。UINT stopsbits = ONESTOPBIT switch(stopbits)和switch(parity)增加默认情况,增强程序健壮性 by itas109 on 2016-06-22 http://blog.csdn.net/itas109 增加ReceiveStr方法,用于接收字符串(接收缓冲区有多少字符就接收多少字符)。 解决ReceiveChar只能接收单个字符的问题。 by itas109 on 2016-06-29 http://blog.csdn.net/itas109 解决RestartMonitoring方法和StopMonitoring方法命令不准确引起的歧义,根据实际作用。 将RestartMonitoring更改为ResumeMonitoring,将StopMonitoring更改为SuspendMonitoring。 增加IsThreadSuspend方法,用于判断线程是否挂起。 改进ClosePort方法,增加线程挂起判断,解决由于线程挂起导致串口关闭死锁的问题。 增加IsReceiveString宏定义,用于接收时采用单字节接收还是多字节接收 by itas109 on 2016-08-02 http://blog.csdn.net/itas109 https://github.com/itas109 改进IsOpen方法,m_hComm增加INVALID_HANDLE_VALUE的情况,因为CreateFile

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值