zoukankan      html  css  js  c++  java
  • vc 串口精灵软件分析

    前几天找这个源码,没有找到,今天找到了,有打开串口参数设置对话框,梳理一下关键实现代码:

    主界面如下:

          

    打开软件,设置初始的变量,串口参数:

    // CCommWizardDlg dialog
    
    CCommWizardDlg::CCommWizardDlg(CWnd* pParent /*=NULL*/)
        : CDialog(CCommWizardDlg::IDD, pParent)
    {
        bSend = FALSE;//自动发送标志
        bReceive = FALSE;//自动接收标志
    
        m_nPort = 1;//端口号
        m_strSettings = _T("9600,n,8,1");//串口参数
        m_strSendString = _T("");//发送的字符串
        m_nTime = 1000;//时间间隔1s
    
        m_nInputMode = 1;//输入模式设置为1
    
        //{{AFX_DATA_INIT(CCommWizardDlg)
        m_strReceive = _T("");//文本框内容清除
        //}}AFX_DATA_INIT
        // Note that LoadIcon does not require a subsequent DestroyIcon in Win32
        m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
    }

    初始化函数中:初始化输入模式选择,

        // TODO: Add extra initialization here
        m_ctrlDataType.AddString(_T("按ASCII码"));
        m_ctrlDataType.AddString(_T("按2进制"));//
        m_ctrlDataType.AddString(_T("按16进制"));
        m_ctrlDataType.SetCurSel(m_nInputMode);//初始化时是1,即按2进制

    改变组合框的输入模式代码:

    void CCommWizardDlg::OnSelchangeType() 
    {
        // TODO: Add your control notification handler code here
        m_nInputMode = m_ctrlDataType.GetCurSel();
    }

    
    
    清除接收文本框内容:

    void
    CCommWizardDlg::OnClear() { // TODO: Add your control notification handler code here m_strReceive = _T("");//清除接收文本框内容 }

    主对话框中定义声明的:

    // CCommWizardDlg dialog
    
    class CCommWizardDlg : public CDialog
    {
    // Construction
    public:
        char CCommWizardDlg::ConvertHexChar(char ch);
        int  String2Hex(CString str, CByteArray &senddata);//字符串到十六进制转换
        void OpenPort();//打开串口
        CCommWizardDlg(CWnd* pParent = NULL);    // standard constructor
    
        BOOL bSend;//发送
        BOOL bReceive;//接收
    
        int m_nInputMode;//输入模式
    
        int        m_nPort;//端口号
        CString    m_strSettings;//参数
        CString    m_strSendString;//发送的字符串
        int        m_nTime;//间隔时间
    // Dialog Data
        //{{AFX_DATA(CCommWizardDlg)
        enum { IDD = IDD_COMMWIZARD_DIALOG };
        CButton    m_ctrlReceive;//接收按钮控件
        CButton    m_ctrlSend;//发送按钮控件
        CComboBox    m_ctrlDataType;//控制数据类型  输入模式 组合框控件变量
        CString    m_strReceive;//接收到的字符串
        CMSComm    m_Com;//串口控件
        //}}AFX_DATA

    点击设置参数后,代码如下:

    void CCommWizardDlg::OnSettings() 
    {
        // TODO: Add your control notification handler code here
        CSettingDlg setDlg;//声明类对象
        
        setDlg.nPort = m_nPort;//上次设置的端口号值
        setDlg.nTime = m_nTime;//上次设置的间隔时间值
        setDlg.strSettings = m_strSettings;//上次设置的串口参数值
        setDlg.strSendString = m_strSendString;//上次设置的发送字符串值
    
        if(setDlg.DoModal() == IDOK)//弹出对话框,点确定按钮后返回值设置。
        {
            m_nPort = setDlg.nPort;//从setDlg(参数设置类)中获取端口号
            m_nTime = setDlg.nTime;//间隔时间值
            m_strSettings = setDlg.strSettings;//串口参数值
            m_strSendString = setDlg.strSendString;//发送字符串值
        }
        OpenPort();//打开串口
    }

    设置参数如下,设置串口相关参数。

    点确定之后,选择的串口就被打开了,代码如下:

    void CCommWizardDlg::OnSettings() 
    {
        // TODO: Add your control notification handler code here
        CSettingDlg setDlg;//声明类对象
        
        setDlg.nPort = m_nPort;//上次设置的端口号值
        setDlg.nTime = m_nTime;//上次设置的间隔时间值
        setDlg.strSettings = m_strSettings;//上次设置的串口参数值
        setDlg.strSendString = m_strSendString;//上次设置的发送字符串值
    
        if(setDlg.DoModal() == IDOK)//弹出对话框,点确定按钮后返回值设置。
        {
            m_nPort = setDlg.nPort;//从setDlg(参数设置类)中获取端口号
            m_nTime = setDlg.nTime;//间隔时间值
            m_strSettings = setDlg.strSettings;//串口参数值
            m_strSendString = setDlg.strSendString;//发送字符串值
        }
        OpenPort();//打开串口
    }

    打开串口函数:

    //打开串口
    void CCommWizardDlg::OpenPort()
    {
        if(m_Com.GetPortOpen())
            m_Com.SetPortOpen(FALSE);//关闭串口
    
        m_Com.SetCommPort(m_nPort); //选择串口号
        if( !m_Com.GetPortOpen())
            m_Com.SetPortOpen(TRUE);//打开串口
        else
            AfxMessageBox("cannot open serial port");
    
        m_Com.SetSettings(m_strSettings); //波特率9600,无校验,8个数据位,1个停止位
        m_Com.SetRThreshold(1); 
        //参数1表示每当串口接收缓冲区中有多于或等于1个字符时将引发一个接收数据的OnComm事件
        m_Com.SetInputMode(1);
        m_Com.SetInputLen(0);  //设置当前接收区数据长度为0
        m_Com.GetInput();//先预读缓冲区以清除残留数据    
    }

    程序中的变量的声明定义:

    // CSettingDlg dialog
    
    class CSettingDlg : public CDialog
    {
    // Construction
    public:
        CSettingDlg(CWnd* pParent = NULL);   // standard constructor
        int nPort, nTime;
        CString strSettings, strSendString;
    // Dialog Data
        //{{AFX_DATA(CSettingDlg)
        enum { IDD = IDD_DIALOG1 };
        int        m_nPort;
        CString    m_strSettings;
        CString    m_strSendString;
        int        m_nTime;
        //}}AFX_DATA

    点确定后将数据保存在当前参数设置窗口类中。

    自动发送:

    自动发送代码:

    void CCommWizardDlg::OnSend() 
    {
        // TODO: Add your control notification handler code here
        bSend = !bSend;//取反。
        if(bSend)//发送。
        {
            m_ctrlSend.SetWindowText(_T("停止发送"));
            SetTimer(1,m_nTime,NULL);//发送时间为1000毫秒,启动发送。
        }
        else//停止发送。
        {
            m_ctrlSend.SetWindowText(_T("自动发送"));
            KillTimer(1);  //取消发送定时。
        }    
    }

    自动发送时启动定时器:

    void CCommWizardDlg::OnTimer(UINT nIDEvent) 
    {
        // TODO: Add your message handler code here and/or call default
        OnManualsend();//手动发送函数
        CDialog::OnTimer(nIDEvent);
    }

    调用手动发送函数:

    void CCommWizardDlg::OnManualsend() 
    {
        // TODO: Add your control notification handler code here
        CString strSend;//发送字符串
    
        if(m_nInputMode > 1)//输入模式大于1(字节数组,十六进制)
        {
            CByteArray hexdata;//字节数据,
            int len=String2Hex(m_strSendString ,hexdata);//字符串转十六进制字节数组
            m_Com.SetOutput(COleVariant(hexdata));//发送字节数组
        }
        else
            m_Com.SetOutput(COleVariant(m_strSendString));//发送数据,发送字符串
    }
    //字符串转十六进制字节数组
    int CCommWizardDlg::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 CCommWizardDlg::OnSelchangeType() 
    {
        // TODO: Add your control notification handler code here
        m_nInputMode = m_ctrlDataType.GetCurSel();
    }

    接收数据:

    //自动接收按钮
    void CCommWizardDlg::OnReceive() 
    {
        // TODO: Add your control notification handler code here
        m_Com.GetInput();//先预读缓冲区以清除残留数据
        bReceive = !bReceive;//自动接收标志取反,,,定时器里有检测该变量
        if(bReceive)//自动接收
            m_ctrlReceive.SetWindowText(_T("停止接收"));//按钮控件文本设置
        else//不自动接收
            m_ctrlReceive.SetWindowText(_T("开始接收"));
    }
    //这是一个将字符转换为相应的十六进制值的函数
    //功能:若是在0-F之间的字符,则转换为相应的十六进制字符,否则返回-1
    char CCommWizardDlg::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);
    }

    串口控件:

    BEGIN_EVENTSINK_MAP(CCommWizardDlg, CDialog)
        //{{AFX_EVENTSINK_MAP(CCommWizardDlg)
        ON_EVENT(CCommWizardDlg, IDC_COMMCTRL, 1 /* OnComm */, OnOnCommCommctrl, VTS_NONE)
        //}}AFX_EVENTSINK_MAP
    END_EVENTSINK_MAP()

    接收函数:

    void CCommWizardDlg::OnOnCommCommctrl() 
    {
        // TODO: Add your control notification handler code here
        VARIANT variant_inp;
        COleSafeArray safearray_inp;
        LONG len,k;
        BYTE rxdata[2048]; //设置BYTE数组 An 8-bit integerthat is not signed.
        CString strtemp;
        if(bReceive)
        {
            if(m_Com.GetCommEvent()==2)     //事件值为2表示接收缓冲区内有字符
            {
                variant_inp = m_Com.GetInput();   //读缓冲区
                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_nInputMode == 2)
                        strtemp.Format("%02X ",bt); //将字符以十六进制方式送入临时变量strtemp存放,注意这里加入一个空隔
                    else 
                        strtemp.Format("%c",bt); //将字符送入临时变量strtemp存放
    
                    m_strReceive = m_strReceive + strtemp;    //加入接收编辑框对应字符串    
                }
                m_strReceive += "
    ";
            }
        }
        UpdateData(FALSE);           //更新编辑框内容
    }

    在主对话框中加入串口控件后,引入 头文件#include "mscomm.h"

    串口h文件中有这几行代码:

    // CMSComm wrapper class
    
    class CMSComm : public CWnd
    {
    protected:
        DECLARE_DYNCREATE(CMSComm)
    public:
        CLSID const& GetClsid()
        {
            static CLSID const clsid
                = { 0x648a5600, 0x2c6e, 0x101b, { 0x82, 0xb6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x14 } };
            return clsid;
        }
    发现自己的不足,善于利用找到的方法去扬长避短。行动起来。
  • 相关阅读:
    代理匹配浅谈spring——自动创建代理(八)
    进程算法操作系统常见算法
    DTCoreText备忘
    内核用户态用户态和内核态的区别
    注释光标vim中如何快速去除注释# 或者 //字符
    方法执行[置顶] onPause()和onStop()的使用方法及注意事项
    录音函数网络对讲机C#服务器 Android客户端(二) C#服务器代码分析 附加
    匹配行linux中grep命令的使用
    最大整数NYOJ 44 字串和 370 巧克力 (最大连续字串和问题)
    行列方阵顺时针旋转
  • 原文地址:https://www.cnblogs.com/rechen/p/5085253.html
Copyright © 2011-2022 走看看