用户自定义协议之串口发送与接收

效果图:

image

开发过程:

一、数据发送端程序讲解

1、规定协议规范,利用虚拟串口工具VSPD来模拟两个串口com2与com3。

2、制作对话框界面,如上左图所示。并为控件添加相应的变量及函数。

3、在工程中插入MSComm控件,并为其绑定CMSComm类的变量m_Comm。

4、为对话框类添加一个bool型变量,用于标识串口是否打开,进而对某些按钮进行使能处理。这里需要添加函数:

   1:  void CSDataSenderProDlg::UpdateButton(void)
   2:  {
   3:      GetDlgItem(IDC_BUTTON_OPEN) ->EnableWindow(m_bIsPortOpen==FALSE);
   4:      GetDlgItem(IDC_BUTTON_CLOSE) ->EnableWindow(m_bIsPortOpen==TRUE);
   5:      GetDlgItem(IDC_BUTTON_SEND) ->EnableWindow(m_bIsPortOpen==TRUE);
   6:  }

5、为打开串口按钮添加函数。双击即可,其实就是串口的初始化函数。

   1:  void CSDataSenderProDlg::OnBnClickedButtonOpen()
   2:  {
   3:      // TODO: 在此添加控件通知处理程序代码
   4:      m_Comm.put_CommPort(2);
   5:      m_Comm.put_InputMode(1);
   6:      m_Comm.put_Settings(_T("9600,n,8,1"));
   7:      m_Comm.put_InBufferSize(1024);
   8:      m_Comm.put_OutBufferSize(512);
   9:      if(!m_Comm.get_PortOpen())
  10:      {
  11:          m_Comm.put_PortOpen(TRUE);
  12:      }
  13:      m_Comm.put_RThreshold(1);
  14:      m_Comm.put_InputLen(0);
  15:      m_Comm.get_Input();
  16:      m_bIsPortOpen = TRUE;//标识串口打开与否的状态
  17:      UpdateButton();//更新按钮状态
  18:   
  19:  }

6、为关闭串口按钮添加函数。

   1:  void CSDataSenderProDlg::OnBnClickedButtonClose()
   2:  {
   3:      // TODO: 在此添加控件通知处理程序代码
   4:      if(m_Comm.get_PortOpen()) //如果串口是打开的,手动关闭之
   5:      {
   6:          m_Comm.put_PortOpen(FALSE);
   7:      }
   8:      m_bIsPortOpen = FALSE;
   9:      UpdateButton();
  10:  }

7、为MSComm控件的OnComm事件添加处理代码,用来接收发送端回传回来的数据,与上面的进行验证,到底传的对不对。

    相当于一次握手。

   1:  void CSDataSenderProDlg::OnCommMscomm1()
   2:  {
   3:      // TODO: 在此处添加消息处理程序代码
   4:      VARIANT variant_inp;
   5:      COleSafeArray safearray_inp;
   6:      LONG len,k;
   7:      BYTE rxdata[2048];
   8:      CString strtemp;
   9:      if(m_Comm.get_CommEvent() == 2)
  10:      {
  11:          variant_inp = m_Comm.get_Input();
  12:          safearray_inp = variant_inp;
  13:          len = safearray_inp.GetOneDimSize();
  14:          for(k = 0; k < len; k++)
  15:          {
  16:              safearray_inp.GetElement(&k,rxdata+k);
  17:          }
  18:          for(k = 0; k < len; k++)
  19:          {
  20:              BYTE bt = *(char *)(rxdata + k);
  21:              strtemp.Format(_T("%c"),bt);
  22:              m_strRXData += strtemp;
  23:          }
  24:      }
  25:      CString temp = _T("
");
  26:      m_strRXData += temp;
  27:      UpdateData(FALSE);//把值传给控件并显示。
  28:  }

8、为发送数据按钮添加消息处理代码。这是本程序核心部分。在这个程序里面实现了函数的打包过程。

  

   1:  void CSDataSenderProDlg::OnBnClickedButtonSend()
   2:  {
   3:      // TODO: 在此添加控件通知处理程序代码
   4:      CString strSend = _T("$");
   5:      for(int i = 1; i <= 8; i++)
   6:      {
   7:          if(GetSwitchStatus(i))
   8:          {
   9:              strSend += _T("1");
  10:          }
  11:          else
  12:          {
  13:              strSend += _T("0");
  14:          }
  15:      }
  16:      strSend += _T("*");
  17:      m_Comm.put_Output(COleVariant(strSend)); //发送到此已经成功
  18:      m_strTXData.Format(_T("要发送的数据为:%s"),strSend);
  19:      UpdateData(FALSE); //这一步,主要是为了显示要发送的内容
  20:  }
  21:   
  22:   
  23:  bool CSDataSenderProDlg::GetSwitchStatus(UINT i)//辅助函数,用于判断复选框的状态,并返回TRUE或者FALSE;
  24:  {
  25:      bool bStatus = FALSE;
  26:      switch(i)
  27:      {
  28:                  case 1:
  29:            bStatus = ((CButton *)GetDlgItem(IDC_CHECK1)) -> GetCheck();break;
  30:                  case 2:
  31:            bStatus = ((CButton *)GetDlgItem(IDC_CHECK2)) -> GetCheck();break;
  32:                  case 3:
  33:            bStatus = ((CButton *)GetDlgItem(IDC_CHECK3)) -> GetCheck();break;
  34:                  case 4:
  35:            bStatus = ((CButton *)GetDlgItem(IDC_CHECK4)) -> GetCheck();break;
  36:                  case 5:
  37:            bStatus = ((CButton *)GetDlgItem(IDC_CHECK5)) -> GetCheck();break;
  38:                  case 6:
  39:            bStatus = ((CButton *)GetDlgItem(IDC_CHECK6)) -> GetCheck();break;
  40:                  case 7:
  41:            bStatus = ((CButton *)GetDlgItem(IDC_CHECK7)) -> GetCheck();break;
  42:                  case 8:
  43:            bStatus = ((CButton *)GetDlgItem(IDC_CHECK8)) -> GetCheck();break;
  44:                  default:
  45:                         break;
  46:      }
  47:      
  48:      return bStatus;
  49:  }

9、整个程序代码如下所示:

SDataSenderProDlg.h文件

   1:   
   2:  // SDataSenderProDlg.h : 头文件
   3:  //
   4:   
   5:  #pragma once
   6:  #include "mscomm1.h"
   7:   
   8:   
   9:  // CSDataSenderProDlg 对话框
  10:  class CSDataSenderProDlg : public CDialogEx
  11:  {
  12:  // 构造
  13:  public:
  14:      CSDataSenderProDlg(CWnd* pParent = NULL);    // 标准构造函数
  15:   
  16:  // 对话框数据
  17:      enum { IDD = IDD_SDATASENDERPRO_DIALOG };
  18:   
  19:      protected:
  20:      virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持
  21:   
  22:   
  23:  // 实现
  24:  protected:
  25:      HICON m_hIcon;
  26:   
  27:      // 生成的消息映射函数
  28:      virtual BOOL OnInitDialog();
  29:      afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
  30:      afx_msg void OnPaint();
  31:      afx_msg HCURSOR OnQueryDragIcon();
  32:      DECLARE_MESSAGE_MAP()
  33:  public:
  34:      CString m_strTXData;
  35:      CMscomm1 m_Comm;
  36:      DECLARE_EVENTSINK_MAP()
  37:      void OnCommMscomm1();
  38:      CString m_strRXData;
  39:      bool m_bIsPortOpen;
  40:      void UpdateButton(void);
  41:      afx_msg void OnBnClickedButtonOpen();
  42:      afx_msg void OnBnClickedButtonClose();
  43:      afx_msg void OnBnClickedButtonSend();
  44:      bool GetSwitchStatus(UINT i);
  45:  };

Resource.h文件:

   1:  //{{NO_DEPENDENCIES}}
   2:  // Microsoft Visual C++ generated include file.
   3:  // Used by SDataSenderPro.rc
   4:  //
   5:  #define IDM_ABOUTBOX                    0x0010
   6:  #define IDD_ABOUTBOX                    100
   7:  #define IDS_ABOUTBOX                    101
   8:  #define IDD_SDATASENDERPRO_DIALOG       102
   9:  #define IDR_MAINFRAME                   128
  10:  #define IDC_CHECK1                      1000
  11:  #define IDC_CHECK2                      1001
  12:  #define IDC_CHECK3                      1002
  13:  #define IDC_CHECK4                      1003
  14:  #define IDC_CHECK5                      1004
  15:  #define IDC_CHECK6                      1005
  16:  #define IDC_CHECK7                      1006
  17:  #define IDC_CHECK8                      1007
  18:  #define IDC_EDIT1                       1008
  19:  #define IDC_BUTTON_OPEN                 1009
  20:  #define IDC_BUTTON_CLOSE                1010
  21:  #define IDC_BUTTON_SEND                 1011
  22:  #define IDC_EDIT2                       1012
  23:  #define IDC_MSCOMM1                     1013
  24:   
  25:  // Next default values for new objects
  26:  // 
  27:  #ifdef APSTUDIO_INVOKED
  28:  #ifndef APSTUDIO_READONLY_SYMBOLS
  29:  #define _APS_NEXT_RESOURCE_VALUE        133
  30:  #define _APS_NEXT_COMMAND_VALUE         32771
  31:  #define _APS_NEXT_CONTROL_VALUE         1014
  32:  #define _APS_NEXT_SYMED_VALUE           101
  33:  #endif
  34:  #endif

SDataSenderProDlg.cpp文件:

   1:   
   2:  // SDataSenderProDlg.cpp : 实现文件
   3:  //
   4:   
   5:  #include "stdafx.h"
   6:  #include "SDataSenderPro.h"
   7:  #include "SDataSenderProDlg.h"
   8:  #include "afxdialogex.h"
   9:  #include "Resource.h"
  10:  #ifdef _DEBUG
  11:  #define new DEBUG_NEW
  12:  #endif
  13:   
  14:   
  15:  // 用于应用程序“关于”菜单项的 CAboutDlg 对话框
  16:   
  17:  class CAboutDlg : public CDialogEx
  18:  {
  19:  public:
  20:      CAboutDlg();
  21:   
  22:  // 对话框数据
  23:      enum { IDD = IDD_ABOUTBOX };
  24:   
  25:      protected:
  26:      virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持
  27:   
  28:  // 实现
  29:  protected:
  30:      DECLARE_MESSAGE_MAP()
  31:  };
  32:   
  33:  CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
  34:  {
  35:  }
  36:   
  37:  void CAboutDlg::DoDataExchange(CDataExchange* pDX)
  38:  {
  39:      CDialogEx::DoDataExchange(pDX);
  40:  }
  41:   
  42:  BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
  43:  END_MESSAGE_MAP()
  44:   
  45:   
  46:  // CSDataSenderProDlg 对话框
  47:   
  48:   
  49:   
  50:   
  51:  CSDataSenderProDlg::CSDataSenderProDlg(CWnd* pParent /*=NULL*/)
  52:      : CDialogEx(CSDataSenderProDlg::IDD, pParent)
  53:      , m_strTXData(_T(""))
  54:      , m_strRXData(_T(""))
  55:      , m_bIsPortOpen(false)
  56:  {
  57:      m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
  58:  }
  59:   
  60:  void CSDataSenderProDlg::DoDataExchange(CDataExchange* pDX)
  61:  {
  62:      CDialogEx::DoDataExchange(pDX);
  63:      DDX_Text(pDX, IDC_EDIT1, m_strTXData);
  64:      DDX_Control(pDX, IDC_MSCOMM1, m_Comm);
  65:      DDX_Text(pDX, IDC_EDIT2, m_strRXData);
  66:   
  67:  }
  68:   
  69:  BEGIN_MESSAGE_MAP(CSDataSenderProDlg, CDialogEx)
  70:      ON_WM_SYSCOMMAND()
  71:      ON_WM_PAINT()
  72:      ON_WM_QUERYDRAGICON()
  73:      ON_BN_CLICKED(IDC_BUTTON_OPEN, &CSDataSenderProDlg::OnBnClickedButtonOpen)
  74:      ON_BN_CLICKED(IDC_BUTTON_CLOSE, &CSDataSenderProDlg::OnBnClickedButtonClose)
  75:      ON_BN_CLICKED(IDC_BUTTON_SEND, &CSDataSenderProDlg::OnBnClickedButtonSend)
  76:  END_MESSAGE_MAP()
  77:   
  78:   
  79:  // CSDataSenderProDlg 消息处理程序
  80:   
  81:  BOOL CSDataSenderProDlg::OnInitDialog()
  82:  {
  83:      CDialogEx::OnInitDialog();
  84:   
  85:      // 将“关于...”菜单项添加到系统菜单中。
  86:   
  87:      // IDM_ABOUTBOX 必须在系统命令范围内。
  88:      ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
  89:      ASSERT(IDM_ABOUTBOX < 0xF000);
  90:   
  91:      CMenu* pSysMenu = GetSystemMenu(FALSE);
  92:      if (pSysMenu != NULL)
  93:      {
  94:          BOOL bNameValid;
  95:          CString strAboutMenu;
  96:          bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
  97:          ASSERT(bNameValid);
  98:          if (!strAboutMenu.IsEmpty())
  99:          {
 100:              pSysMenu->AppendMenu(MF_SEPARATOR);
 101:              pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
 102:          }
 103:      }
 104:   
 105:      // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
 106:      //  执行此操作
 107:      SetIcon(m_hIcon, TRUE);            // 设置大图标
 108:      SetIcon(m_hIcon, FALSE);        // 设置小图标
 109:   
 110:      // TODO: 在此添加额外的初始化代码
 111:   
 112:      return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
 113:  }
 114:   
 115:  void CSDataSenderProDlg::OnSysCommand(UINT nID, LPARAM lParam)
 116:  {
 117:      if ((nID & 0xFFF0) == IDM_ABOUTBOX)
 118:      {
 119:          CAboutDlg dlgAbout;
 120:          dlgAbout.DoModal();
 121:      }
 122:      else
 123:      {
 124:          CDialogEx::OnSysCommand(nID, lParam);
 125:      }
 126:  }
 127:   
 128:  // 如果向对话框添加最小化按钮,则需要下面的代码
 129:  //  来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,
 130:  //  这将由框架自动完成。
 131:   
 132:  void CSDataSenderProDlg::OnPaint()
 133:  {
 134:      if (IsIconic())
 135:      {
 136:          CPaintDC dc(this); // 用于绘制的设备上下文
 137:   
 138:          SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
 139:   
 140:          // 使图标在工作区矩形中居中
 141:          int cxIcon = GetSystemMetrics(SM_CXICON);
 142:          int cyIcon = GetSystemMetrics(SM_CYICON);
 143:          CRect rect;
 144:          GetClientRect(&rect);
 145:          int x = (rect.Width() - cxIcon + 1) / 2;
 146:          int y = (rect.Height() - cyIcon + 1) / 2;
 147:   
 148:          // 绘制图标
 149:          dc.DrawIcon(x, y, m_hIcon);
 150:      }
 151:      else
 152:      {
 153:          CDialogEx::OnPaint();
 154:      }
 155:  }
 156:   
 157:  //当用户拖动最小化窗口时系统调用此函数取得光标
 158:  //显示。
 159:  HCURSOR CSDataSenderProDlg::OnQueryDragIcon()
 160:  {
 161:      return static_cast<HCURSOR>(m_hIcon);
 162:  }
 163:   
 164:  BEGIN_EVENTSINK_MAP(CSDataSenderProDlg, CDialogEx)
 165:      ON_EVENT(CSDataSenderProDlg, IDC_MSCOMM1, 1, CSDataSenderProDlg::OnCommMscomm1, VTS_NONE)
 166:  END_EVENTSINK_MAP()
 167:   
 168:   
 169:  void CSDataSenderProDlg::OnCommMscomm1()
 170:  {
 171:      // TODO: 在此处添加消息处理程序代码
 172:      VARIANT variant_inp;
 173:      COleSafeArray safearray_inp;
 174:      LONG len,k;
 175:      BYTE rxdata[2048];
 176:      CString strtemp;
 177:      if(m_Comm.get_CommEvent() == 2)
 178:      {
 179:          variant_inp = m_Comm.get_Input();
 180:          safearray_inp = variant_inp;
 181:          len = safearray_inp.GetOneDimSize();
 182:          for(k = 0; k < len; k++)
 183:          {
 184:              safearray_inp.GetElement(&k,rxdata+k);
 185:          }
 186:          for(k = 0; k < len; k++)
 187:          {
 188:              BYTE bt = *(char *)(rxdata + k);
 189:              strtemp.Format(_T("%c"),bt);
 190:              m_strRXData += strtemp;
 191:          }
 192:      }
 193:      CString temp = _T("
");
 194:      m_strRXData += temp;
 195:      UpdateData(FALSE);//把值传给控件并显示。
 196:  }
 197:   
 198:   
 199:  void CSDataSenderProDlg::UpdateButton(void)
 200:  {
 201:      GetDlgItem(IDC_BUTTON_OPEN) ->EnableWindow(m_bIsPortOpen==FALSE);
 202:      GetDlgItem(IDC_BUTTON_CLOSE) ->EnableWindow(m_bIsPortOpen==TRUE);
 203:      GetDlgItem(IDC_BUTTON_SEND) ->EnableWindow(m_bIsPortOpen==TRUE);
 204:  }
 205:   
 206:   
 207:  void CSDataSenderProDlg::OnBnClickedButtonOpen()
 208:  {
 209:      // TODO: 在此添加控件通知处理程序代码
 210:      m_Comm.put_CommPort(2);
 211:      m_Comm.put_InputMode(1);
 212:      m_Comm.put_Settings(_T("9600,n,8,1"));
 213:      m_Comm.put_InBufferSize(1024);
 214:      m_Comm.put_OutBufferSize(512);
 215:      if(!m_Comm.get_PortOpen())
 216:      {
 217:          m_Comm.put_PortOpen(TRUE);
 218:      }
 219:      m_Comm.put_RThreshold(1);
 220:      m_Comm.put_InputLen(0);
 221:      m_Comm.get_Input();
 222:      m_bIsPortOpen = TRUE;//标识串口打开与否的状态
 223:      UpdateButton();//更新按钮状态
 224:   
 225:  }
 226:   
 227:   
 228:  void CSDataSenderProDlg::OnBnClickedButtonClose()
 229:  {
 230:      // TODO: 在此添加控件通知处理程序代码
 231:      if(m_Comm.get_PortOpen()) //如果串口是打开的,手动关闭之
 232:      {
 233:          m_Comm.put_PortOpen(FALSE);
 234:      }
 235:      m_bIsPortOpen = FALSE;
 236:      UpdateButton();
 237:  }
 238:   
 239:   
 240:  void CSDataSenderProDlg::OnBnClickedButtonSend()
 241:  {
 242:      // TODO: 在此添加控件通知处理程序代码
 243:      CString strSend = _T("$");
 244:      for(int i = 1; i <= 8; i++)
 245:      {
 246:          if(GetSwitchStatus(i))
 247:          {
 248:              strSend += _T("1");
 249:          }
 250:          else
 251:          {
 252:              strSend += _T("0");
 253:          }
 254:      }
 255:      strSend += _T("*");
 256:      m_Comm.put_Output(COleVariant(strSend)); //发送到此已经成功
 257:      m_strTXData.Format(_T("要发送的数据为:%s"),strSend);
 258:      UpdateData(FALSE); //这一步,主要是为了显示要发送的内容
 259:  }
 260:   
 261:   
 262:  bool CSDataSenderProDlg::GetSwitchStatus(UINT i)
 263:  {
 264:      bool bStatus = FALSE;
 265:      switch(i)
 266:      {
 267:                case 1:
 268:            bStatus = ((CButton *)GetDlgItem(IDC_CHECK1)) -> GetCheck();break;
 269:                  case 2:
 270:            bStatus = ((CButton *)GetDlgItem(IDC_CHECK2)) -> GetCheck();break;
 271:                  case 3:
 272:            bStatus = ((CButton *)GetDlgItem(IDC_CHECK3)) -> GetCheck();break;
 273:                  case 4:
 274:            bStatus = ((CButton *)GetDlgItem(IDC_CHECK4)) -> GetCheck();break;
 275:                  case 5:
 276:            bStatus = ((CButton *)GetDlgItem(IDC_CHECK5)) -> GetCheck();break;
 277:                  case 6:
 278:            bStatus = ((CButton *)GetDlgItem(IDC_CHECK6)) -> GetCheck();break;
 279:                  case 7:
 280:            bStatus = ((CButton *)GetDlgItem(IDC_CHECK7)) -> GetCheck();break;
 281:                  case 8:
 282:            bStatus = ((CButton *)GetDlgItem(IDC_CHECK8)) -> GetCheck();break;
 283:                  default:
 284:                         break;
 285:      }
 286:      
 287:      return bStatus;
 288:  }

二、数据接收端程序讲解

1、建立项目,并在对话框中加入需要的控件。

2、插入MSComm控件,并绑定变量m_Comm。

3、为对话框添加一个bool型变量,标识串口的打开与否,以此来使能某个按钮控件。

    函数如下:

   1:  void CSDataReceiverProDlg::UpdateButton(void)
   2:  {
   3:      GetDlgItem(IDC_BUTTON_OPEN) ->EnableWindow(m_bIsPortOpen == FALSE);
   4:      GetDlgItem(IDC_BUTTON_CLOSE) ->EnableWindow(m_bIsPortOpen == TRUE);
   5:  }

4、为打开串口按钮添加函数:

   1:  void CSDataReceiverProDlg::OnBnClickedButtonOpen()
   2:  {
   3:      // TODO: 在此添加控件通知处理程序代码
   4:      m_Comm.put_CommPort(3);
   5:      m_Comm.put_InputMode(1);
   6:      m_Comm.put_InBufferSize(1024);
   7:      m_Comm.put_OutBufferSize(512);
   8:      m_Comm.put_Settings(_T("9600,n,8,1"));
   9:      if(!m_Comm.get_PortOpen())
  10:      {
  11:          m_Comm.put_PortOpen(TRUE);
  12:      }
  13:      m_Comm.put_RThreshold(1); //收到一个字符
  14:      //m_Comm.put_SThreshold(1);
  15:      m_Comm.put_InputLen(0);
  16:      m_Comm.get_Input();
  17:      m_bIsPortOpen = TRUE;
  18:      UpdateButton();
  19:  }

5、为关闭串口按钮添加函数:

   1:  void CSDataReceiverProDlg::OnBnClickedButtonClose()
   2:  {
   3:      // TODO: 在此添加控件通知处理程序代码
   4:      if(m_Comm.get_PortOpen())
   5:      {
   6:          m_Comm.put_PortOpen(FALSE);
   7:      }
   8:      m_bIsPortOpen = FALSE;
   9:      UpdateButton();
  10:  }

6、为OnComm消息处理程序添加接收数据处理函数,其实就是一个拆包的过程。里面用到了CString里面的截取函数Mid等。并用自定义的函数,实现转变PICTURE控件的状态。

     另外对于回传的数据的显示汉字部分,个人建议通过串口传递非字符不可取,我们可以在另一方自己手动加上汉字显示部分。没必要将汉字也发过去,当然我们可以发送字母,这个没有问题,发送汉字在另一方会出现乱码,这个不可取。所以,个人建议假如要发送汉字,就不要发了。在另一方加上汉字,其实效果一样。

    函数如下:

   1:  void CSDataReceiverProDlg::OnCommMscomm1()
   2:  {
   3:      // TODO: 在此处添加消息处理程序代码
   4:      VARIANT variant_inp;
   5:      COleSafeArray safearray_inp;
   6:      BYTE rxdata[1024];
   7:      LONG len,k;
   8:      CString strtemp;
   9:      if(m_Comm.get_CommEvent()==2)
  10:      {
  11:          m_strRXData.Empty();//接收字符清空
  12:          variant_inp = m_Comm.get_Input();
  13:          safearray_inp = variant_inp;
  14:          len = safearray_inp.GetOneDimSize();
  15:          if(len != 10)   //协议要求数据长度为10
  16:          {
  17:              MessageBox(_T("不符合协议的数据格式"),_T("提示"));
  18:              return;
  19:          }
  20:          for(k = 0; k < len; k++)
  21:          {
  22:              safearray_inp.GetElement(&k,rxdata+k);
  23:          }
  24:          for(k = 0; k< len; k++)
  25:          {
  26:              BYTE bt = *(char *)(rxdata + k); //获得字符数组中每个字符的内容
  27:              strtemp.Format(_T("%c"),bt);
  28:              m_strRXData += strtemp;
  29:          }
  30:          //对接收到的数据进行处理
  31:          if(rxdata[0] == '$' && rxdata[len-1] == '*')//对数据包头与包尾进行判断
  32:          {
  33:              CString strSwitch,strBack;
  34:              strSwitch = m_strRXData.Mid(1,8);//mid函数截取字符串的特定字串
  35:              for(int i = 0; i < 8; i++)
  36:              {
  37:                  if(strSwitch.Mid(i,1) == '1')
  38:                      SetSwitchStatus(i+1,TRUE);//自定义函数,用于更新界面
  39:                  else
  40:                      SetSwitchStatus(i+1,FALSE);
  41:              }
  42:              strBack = _T("string back:"); //给发送端回传数据
  43:              strBack += strSwitch;
  44:              m_Comm.put_Output(COleVariant(strBack));
  45:          }
  46:          UpdateData(FALSE);//更新界面,显示控件数据。这句话就是将变量值交给控件去显示
  47:      }
  48:  }
  49:   
  50:   
  51:  void CSDataReceiverProDlg::SetSwitchStatus(UINT i, bool bStatus)
  52:  {
  53:      if (bStatus)
  54:      {
  55:          switch(i)
  56:          {
  57:          case 1:  //GetDlgItem的返回类型为CWnd,必须强制转换为CStatic类型然后才能调用后面的函数。
  58:              ((CStatic*)GetDlgItem(IDC_STATIC1))->SetIcon(AfxGetApp()->LoadIconW(IDI_OPEN));
  59:              break;
  60:          case 2:
  61:              ((CStatic*)GetDlgItem(IDC_STATIC2))->SetIcon(AfxGetApp()->LoadIconW(IDI_OPEN));
  62:              break;
  63:          case 3:
  64:              ((CStatic*)GetDlgItem(IDC_STATIC3))->SetIcon(AfxGetApp()->LoadIconW(IDI_OPEN));
  65:              break;
  66:          case 4:
  67:              ((CStatic*)GetDlgItem(IDC_STATIC4))->SetIcon(AfxGetApp()->LoadIconW(IDI_OPEN));
  68:              break;
  69:          case 5:
  70:              ((CStatic*)GetDlgItem(IDC_STATIC5))->SetIcon(AfxGetApp()->LoadIconW(IDI_OPEN));
  71:              break;
  72:          case 6:
  73:              ((CStatic*)GetDlgItem(IDC_STATIC6))->SetIcon(AfxGetApp()->LoadIconW(IDI_OPEN));
  74:              break;
  75:          case 7:
  76:              ((CStatic*)GetDlgItem(IDC_STATIC7))->SetIcon(AfxGetApp()->LoadIconW(IDI_OPEN));
  77:              break;
  78:          case 8:
  79:              ((CStatic*)GetDlgItem(IDC_STATIC8))->SetIcon(AfxGetApp()->LoadIconW(IDI_OPEN));
  80:              break;
  81:          default:
  82:              break;
  83:          }
  84:          
  85:   
  86:      } 
  87:      else
  88:      {
  89:          switch(i)
  90:          {
  91:          case 1:
  92:              ((CStatic*)GetDlgItem(IDC_STATIC1))->SetIcon(AfxGetApp()->LoadIconW(IDI_CLOSE));
  93:              break;
  94:          case 2:
  95:              ((CStatic*)GetDlgItem(IDC_STATIC2))->SetIcon(AfxGetApp()->LoadIconW(IDI_CLOSE));
  96:              break;
  97:          case 3:
  98:              ((CStatic*)GetDlgItem(IDC_STATIC3))->SetIcon(AfxGetApp()->LoadIconW(IDI_CLOSE));
  99:              break;
 100:          case 4:
 101:              ((CStatic*)GetDlgItem(IDC_STATIC4))->SetIcon(AfxGetApp()->LoadIconW(IDI_CLOSE));
 102:              break;
 103:          case 5:
 104:              ((CStatic*)GetDlgItem(IDC_STATIC5))->SetIcon(AfxGetApp()->LoadIconW(IDI_CLOSE));
 105:              break;
 106:          case 6:
 107:              ((CStatic*)GetDlgItem(IDC_STATIC6))->SetIcon(AfxGetApp()->LoadIconW(IDI_CLOSE));
 108:              break;
 109:          case 7:
 110:              ((CStatic*)GetDlgItem(IDC_STATIC7))->SetIcon(AfxGetApp()->LoadIconW(IDI_CLOSE));
 111:              break;
 112:          case 8:
 113:              ((CStatic*)GetDlgItem(IDC_STATIC8))->SetIcon(AfxGetApp()->LoadIconW(IDI_CLOSE));
 114:              break;
 115:          default:
 116:              break;
 117:          }
 118:          
 119:      }
 120:  }

     7、整个函数代码如下:

SDataReceiverProDlg.h  文件:

   1:   
   2:  // SDataReceiverProDlg.h : 头文件
   3:  //
   4:   
   5:  #pragma once
   6:  #include "mscomm1.h"
   7:   
   8:   
   9:  // CSDataReceiverProDlg 对话框
  10:  class CSDataReceiverProDlg : public CDialogEx
  11:  {
  12:  // 构造
  13:  public:
  14:      CSDataReceiverProDlg(CWnd* pParent = NULL);    // 标准构造函数
  15:   
  16:  // 对话框数据
  17:      enum { IDD = IDD_SDATARECEIVERPRO_DIALOG };
  18:   
  19:      protected:
  20:      virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持
  21:   
  22:   
  23:  // 实现
  24:  protected:
  25:      HICON m_hIcon;
  26:   
  27:      // 生成的消息映射函数
  28:      virtual BOOL OnInitDialog();
  29:      afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
  30:      afx_msg void OnPaint();
  31:      afx_msg HCURSOR OnQueryDragIcon();
  32:      DECLARE_MESSAGE_MAP()
  33:  public:
  34:      CString m_strRXData;
  35:      bool m_bIsPortOpen;
  36:      void UpdateButton(void);
  37:      afx_msg void OnBnClickedButtonOpen();
  38:      CMscomm1 m_Comm;
  39:      afx_msg void OnBnClickedButtonClose();
  40:      DECLARE_EVENTSINK_MAP()
  41:      void OnCommMscomm1();
  42:      void SetSwitchStatus(UINT i, bool bStatus);
  43:  };

Resource.h 文件:

   1:  //{{NO_DEPENDENCIES}}
   2:  // Microsoft Visual C++ generated include file.
   3:  // Used by SDataReceiverPro.rc
   4:  //
   5:  #define IDM_ABOUTBOX                    0x0010
   6:  #define IDD_ABOUTBOX                    100
   7:  #define IDS_ABOUTBOX                    101
   8:  #define IDD_SDATARECEIVERPRO_DIALOG     102
   9:  #define IDR_MAINFRAME                   128
  10:  #define IDI_OPEN                        131
  11:  #define IDI_CLOSE                       132
  12:  #define IDC_BUTTON_OPEN                 1000
  13:  #define IDC_BUTTON_CLOSE                1001
  14:  #define IDC_STATIC1                     1002
  15:  #define IDC_STATIC2                     1003
  16:  #define IDC_STATIC3                     1004
  17:  #define IDC_STATIC4                     1005
  18:  #define IDC_STATIC5                     1006
  19:  #define IDC_STATIC6                     1007
  20:  #define IDC_STATIC7                     1008
  21:  #define IDC_STATIC8                     1009
  22:  #define IDC_EDIT1                       1010
  23:  #define IDC_MSCOMM1                     1011
  24:   
  25:  // Next default values for new objects
  26:  // 
  27:  #ifdef APSTUDIO_INVOKED
  28:  #ifndef APSTUDIO_READONLY_SYMBOLS
  29:  #define _APS_NEXT_RESOURCE_VALUE        130
  30:  #define _APS_NEXT_COMMAND_VALUE         32771
  31:  #define _APS_NEXT_CONTROL_VALUE         1012
  32:  #define _APS_NEXT_SYMED_VALUE           101
  33:  #endif
  34:  #endif

SDataReceiverProDlg.cpp文件:

   1:   
   2:  // SDataReceiverProDlg.cpp : 实现文件
   3:  //
   4:   
   5:  #include "stdafx.h"
   6:  #include "SDataReceiverPro.h"
   7:  #include "SDataReceiverProDlg.h"
   8:  #include "afxdialogex.h"
   9:  #include "Resource.h"
  10:   
  11:  #ifdef _DEBUG
  12:  #define new DEBUG_NEW
  13:  #endif
  14:   
  15:   
  16:  // 用于应用程序“关于”菜单项的 CAboutDlg 对话框
  17:   
  18:  class CAboutDlg : public CDialogEx
  19:  {
  20:  public:
  21:      CAboutDlg();
  22:   
  23:  // 对话框数据
  24:      enum { IDD = IDD_ABOUTBOX };
  25:   
  26:      protected:
  27:      virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持
  28:   
  29:  // 实现
  30:  protected:
  31:      DECLARE_MESSAGE_MAP()
  32:  };
  33:   
  34:  CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
  35:  {
  36:  }
  37:   
  38:  void CAboutDlg::DoDataExchange(CDataExchange* pDX)
  39:  {
  40:      CDialogEx::DoDataExchange(pDX);
  41:  }
  42:   
  43:  BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
  44:  END_MESSAGE_MAP()
  45:   
  46:   
  47:  // CSDataReceiverProDlg 对话框
  48:   
  49:   
  50:   
  51:   
  52:  CSDataReceiverProDlg::CSDataReceiverProDlg(CWnd* pParent /*=NULL*/)
  53:      : CDialogEx(CSDataReceiverProDlg::IDD, pParent)
  54:      , m_strRXData(_T(""))
  55:      , m_bIsPortOpen(false)
  56:  {
  57:      m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
  58:  }
  59:   
  60:  void CSDataReceiverProDlg::DoDataExchange(CDataExchange* pDX)
  61:  {
  62:      CDialogEx::DoDataExchange(pDX);
  63:      DDX_Text(pDX, IDC_EDIT1, m_strRXData);
  64:      DDX_Control(pDX, IDC_MSCOMM1, m_Comm);
  65:  }
  66:   
  67:  BEGIN_MESSAGE_MAP(CSDataReceiverProDlg, CDialogEx)
  68:      ON_WM_SYSCOMMAND()
  69:      ON_WM_PAINT()
  70:      ON_WM_QUERYDRAGICON()
  71:      ON_BN_CLICKED(IDC_BUTTON_OPEN, &CSDataReceiverProDlg::OnBnClickedButtonOpen)
  72:      ON_BN_CLICKED(IDC_BUTTON_CLOSE, &CSDataReceiverProDlg::OnBnClickedButtonClose)
  73:  END_MESSAGE_MAP()
  74:   
  75:   
  76:  // CSDataReceiverProDlg 消息处理程序
  77:   
  78:  BOOL CSDataReceiverProDlg::OnInitDialog()
  79:  {
  80:      CDialogEx::OnInitDialog();
  81:   
  82:      // 将“关于...”菜单项添加到系统菜单中。
  83:   
  84:      // IDM_ABOUTBOX 必须在系统命令范围内。
  85:      ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
  86:      ASSERT(IDM_ABOUTBOX < 0xF000);
  87:   
  88:      CMenu* pSysMenu = GetSystemMenu(FALSE);
  89:      if (pSysMenu != NULL)
  90:      {
  91:          BOOL bNameValid;
  92:          CString strAboutMenu;
  93:          bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
  94:          ASSERT(bNameValid);
  95:          if (!strAboutMenu.IsEmpty())
  96:          {
  97:              pSysMenu->AppendMenu(MF_SEPARATOR);
  98:              pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
  99:          }
 100:      }
 101:   
 102:      // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
 103:      //  执行此操作
 104:      SetIcon(m_hIcon, TRUE);            // 设置大图标
 105:      SetIcon(m_hIcon, FALSE);        // 设置小图标
 106:   
 107:      // TODO: 在此添加额外的初始化代码
 108:   
 109:      return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
 110:  }
 111:   
 112:  void CSDataReceiverProDlg::OnSysCommand(UINT nID, LPARAM lParam)
 113:  {
 114:      if ((nID & 0xFFF0) == IDM_ABOUTBOX)
 115:      {
 116:          CAboutDlg dlgAbout;
 117:          dlgAbout.DoModal();
 118:      }
 119:      else
 120:      {
 121:          CDialogEx::OnSysCommand(nID, lParam);
 122:      }
 123:  }
 124:   
 125:  // 如果向对话框添加最小化按钮,则需要下面的代码
 126:  //  来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,
 127:  //  这将由框架自动完成。
 128:   
 129:  void CSDataReceiverProDlg::OnPaint()
 130:  {
 131:      if (IsIconic())
 132:      {
 133:          CPaintDC dc(this); // 用于绘制的设备上下文
 134:   
 135:          SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
 136:   
 137:          // 使图标在工作区矩形中居中
 138:          int cxIcon = GetSystemMetrics(SM_CXICON);
 139:          int cyIcon = GetSystemMetrics(SM_CYICON);
 140:          CRect rect;
 141:          GetClientRect(&rect);
 142:          int x = (rect.Width() - cxIcon + 1) / 2;
 143:          int y = (rect.Height() - cyIcon + 1) / 2;
 144:   
 145:          // 绘制图标
 146:          dc.DrawIcon(x, y, m_hIcon);
 147:      }
 148:      else
 149:      {
 150:          CDialogEx::OnPaint();
 151:      }
 152:  }
 153:   
 154:  //当用户拖动最小化窗口时系统调用此函数取得光标
 155:  //显示。
 156:  HCURSOR CSDataReceiverProDlg::OnQueryDragIcon()
 157:  {
 158:      return static_cast<HCURSOR>(m_hIcon);
 159:  }
 160:   
 161:   
 162:   
 163:  void CSDataReceiverProDlg::UpdateButton(void)
 164:  {
 165:      GetDlgItem(IDC_BUTTON_OPEN) ->EnableWindow(m_bIsPortOpen == FALSE);
 166:      GetDlgItem(IDC_BUTTON_CLOSE) ->EnableWindow(m_bIsPortOpen == TRUE);
 167:  }
 168:   
 169:   
 170:  void CSDataReceiverProDlg::OnBnClickedButtonOpen()
 171:  {
 172:      // TODO: 在此添加控件通知处理程序代码
 173:      m_Comm.put_CommPort(3);
 174:      m_Comm.put_InputMode(1);
 175:      m_Comm.put_InBufferSize(1024);
 176:      m_Comm.put_OutBufferSize(512);
 177:      m_Comm.put_Settings(_T("9600,n,8,1"));
 178:      if(!m_Comm.get_PortOpen())
 179:      {
 180:          m_Comm.put_PortOpen(TRUE);
 181:      }
 182:      m_Comm.put_RThreshold(1); //收到一个字符
 183:      //m_Comm.put_SThreshold(1);
 184:      m_Comm.put_InputLen(0);
 185:      m_Comm.get_Input();
 186:      m_bIsPortOpen = TRUE;
 187:      UpdateButton();
 188:  }
 189:   
 190:   
 191:  void CSDataReceiverProDlg::OnBnClickedButtonClose()
 192:  {
 193:      // TODO: 在此添加控件通知处理程序代码
 194:      if(m_Comm.get_PortOpen())
 195:      {
 196:          m_Comm.put_PortOpen(FALSE);
 197:      }
 198:      m_bIsPortOpen = FALSE;
 199:      UpdateButton();
 200:  }
 201:  BEGIN_EVENTSINK_MAP(CSDataReceiverProDlg, CDialogEx)
 202:      ON_EVENT(CSDataReceiverProDlg, IDC_MSCOMM1, 1, CSDataReceiverProDlg::OnCommMscomm1, VTS_NONE)
 203:  END_EVENTSINK_MAP()
 204:   
 205:   
 206:  void CSDataReceiverProDlg::OnCommMscomm1()
 207:  {
 208:      // TODO: 在此处添加消息处理程序代码
 209:      VARIANT variant_inp;
 210:      COleSafeArray safearray_inp;
 211:      BYTE rxdata[1024];
 212:      LONG len,k;
 213:      CString strtemp;
 214:      if(m_Comm.get_CommEvent()==2)
 215:      {
 216:          m_strRXData.Empty();//接收字符清空
 217:          variant_inp = m_Comm.get_Input();
 218:          safearray_inp = variant_inp;
 219:          len = safearray_inp.GetOneDimSize();
 220:          if(len != 10)   //协议要求数据长度为10
 221:          {
 222:              MessageBox(_T("不符合协议的数据格式"),_T("提示"));
 223:              return;
 224:          }
 225:          for(k = 0; k < len; k++)
 226:          {
 227:              safearray_inp.GetElement(&k,rxdata+k);
 228:          }
 229:          for(k = 0; k< len; k++)
 230:          {
 231:              BYTE bt = *(char *)(rxdata + k); //获得字符数组中每个字符的内容
 232:              strtemp.Format(_T("%c"),bt);
 233:              m_strRXData += strtemp;
 234:          }
 235:          //对接收到的数据进行处理
 236:          if(rxdata[0] == '$' && rxdata[len-1] == '*')//对数据包头与包尾进行判断
 237:          {
 238:              CString strSwitch,strBack;
 239:              strSwitch = m_strRXData.Mid(1,8);//mid函数截取字符串的特定字串
 240:              for(int i = 0; i < 8; i++)
 241:              {
 242:                  if(strSwitch.Mid(i,1) == '1')
 243:                      SetSwitchStatus(i+1,TRUE);//自定义函数,用于更新界面
 244:                  else
 245:                      SetSwitchStatus(i+1,FALSE);
 246:              }
 247:              strBack = _T("string back:"); //给发送端回传数据
 248:              strBack += strSwitch;
 249:              m_Comm.put_Output(COleVariant(strBack));
 250:          }
 251:          UpdateData(FALSE);//更新界面,显示控件数据。这句话就是将变量值交给控件去显示
 252:      }
 253:  }
 254:   
 255:   
 256:  void CSDataReceiverProDlg::SetSwitchStatus(UINT i, bool bStatus)
 257:  {
 258:      if (bStatus)
 259:      {
 260:          switch(i)
 261:          {
 262:          case 1:  //GetDlgItem的返回类型为CWnd,必须强制转换为CStatic类型然后才能调用后面的函数。
 263:              ((CStatic*)GetDlgItem(IDC_STATIC1))->SetIcon(AfxGetApp()->LoadIconW(IDI_OPEN));
 264:              break;
 265:          case 2:
 266:              ((CStatic*)GetDlgItem(IDC_STATIC2))->SetIcon(AfxGetApp()->LoadIconW(IDI_OPEN));
 267:              break;
 268:          case 3:
 269:              ((CStatic*)GetDlgItem(IDC_STATIC3))->SetIcon(AfxGetApp()->LoadIconW(IDI_OPEN));
 270:              break;
 271:          case 4:
 272:              ((CStatic*)GetDlgItem(IDC_STATIC4))->SetIcon(AfxGetApp()->LoadIconW(IDI_OPEN));
 273:              break;
 274:          case 5:
 275:              ((CStatic*)GetDlgItem(IDC_STATIC5))->SetIcon(AfxGetApp()->LoadIconW(IDI_OPEN));
 276:              break;
 277:          case 6:
 278:              ((CStatic*)GetDlgItem(IDC_STATIC6))->SetIcon(AfxGetApp()->LoadIconW(IDI_OPEN));
 279:              break;
 280:          case 7:
 281:              ((CStatic*)GetDlgItem(IDC_STATIC7))->SetIcon(AfxGetApp()->LoadIconW(IDI_OPEN));
 282:              break;
 283:          case 8:
 284:              ((CStatic*)GetDlgItem(IDC_STATIC8))->SetIcon(AfxGetApp()->LoadIconW(IDI_OPEN));
 285:              break;
 286:          default:
 287:              break;
 288:          }
 289:          
 290:   
 291:      } 
 292:      else
 293:      {
 294:          switch(i)
 295:          {
 296:          case 1:
 297:              ((CStatic*)GetDlgItem(IDC_STATIC1))->SetIcon(AfxGetApp()->LoadIconW(IDI_CLOSE));
 298:              break;
 299:          case 2:
 300:              ((CStatic*)GetDlgItem(IDC_STATIC2))->SetIcon(AfxGetApp()->LoadIconW(IDI_CLOSE));
 301:              break;
 302:          case 3:
 303:              ((CStatic*)GetDlgItem(IDC_STATIC3))->SetIcon(AfxGetApp()->LoadIconW(IDI_CLOSE));
 304:              break;
 305:          case 4:
 306:              ((CStatic*)GetDlgItem(IDC_STATIC4))->SetIcon(AfxGetApp()->LoadIconW(IDI_CLOSE));
 307:              break;
 308:          case 5:
 309:              ((CStatic*)GetDlgItem(IDC_STATIC5))->SetIcon(AfxGetApp()->LoadIconW(IDI_CLOSE));
 310:              break;
 311:          case 6:
 312:              ((CStatic*)GetDlgItem(IDC_STATIC6))->SetIcon(AfxGetApp()->LoadIconW(IDI_CLOSE));
 313:              break;
 314:          case 7:
 315:              ((CStatic*)GetDlgItem(IDC_STATIC7))->SetIcon(AfxGetApp()->LoadIconW(IDI_CLOSE));
 316:              break;
 317:          case 8:
 318:              ((CStatic*)GetDlgItem(IDC_STATIC8))->SetIcon(AfxGetApp()->LoadIconW(IDI_CLOSE));
 319:              break;
 320:          default:
 321:              break;
 322:          }
 323:          
 324:      }
 325:  }
原文地址:https://www.cnblogs.com/zhuxuekui/p/3552352.html