1. 程式人生 > >深入淺出VC++串列埠程式設計之基於控制元件

深入淺出VC++串列埠程式設計之基於控制元件

1.MSComm控制元件

  Visual C++為我們提供了一種好用的ActiveX控制元件Microsoft Communications Control(即MSComm)來支援應用程式對串列埠的訪問,在應用程式中插入MSComm控制元件後就可以較為方便地實現對通過計算機串列埠收發資料。

  要使用ActiveX控制元件MSComm,程式設計師必須將其新增入工程,其方法是:

  (1)單擊主選單project的子選單Add To project的Components and Controls選項;

  (2)在彈出的"Components and Controls Gallery"對話方塊中選擇Registered ActiveX Controls資料夾中的"Microsoft Communications Control,version 6.0"選項,如下圖:


  單擊其中的"Insert"按鈕,MSComm控制元件就被增加到工程中了。與此同時,類CMSComm的相關檔案mscomm.h和mscomm.cpp也一併被加入Project的Header Files和Source Files中。當然,程式設計師可以自己修改檔名,如下圖:


  直接分析mscomm.h標頭檔案就可以完備地獲取這個控制元件的使用方法(主要是public型別的介面函式),下面我們摘取了標頭檔案的主要程式碼並對其關鍵部分給出了註釋:

#if !defined(AFX_MSCOMM_H__)
#define AFX_MSCOMM_H__
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// Machine generated IDispatch wrapper class(es) created by Microsoft Visual C++

// NOTE: Do not modify the contents of this file. If this class is regenerated by
// Microsoft Visual C++, your modifications will be overwritten.

/////////////////////////////////////////////////////////////////////////////
// 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;
 }
 virtual BOOL Create(LPCTSTR lpszClassName,
   LPCTSTR lpszWindowName, DWORD dwStyle,
   const RECT& rect,
   CWnd* pParentWnd, UINT nID,
   CCreateContext* pContext = NULL)
 { return CreateControl(GetClsid(), lpszWindowName, dwStyle, rect, pParentWnd, nID); }

 BOOL Create(LPCTSTR lpszWindowName, DWORD dwStyle,
   const RECT& rect, CWnd* pParentWnd, UINT nID,
   CFile* pPersist = NULL, BOOL bStorage = FALSE,
   BSTR bstrLicKey = NULL)
 { return CreateControl(GetClsid(), lpszWindowName, dwStyle, rect, pParentWnd, nID,
  pPersist, bStorage, bstrLicKey); }

  // Attributes
 public:

  // Operations
 public:
  void SetCDHolding(BOOL bNewValue);
  BOOL GetCDHolding();
  void SetCommID(long nNewValue);
  long GetCommID();
  void SetCommPort(short nNewValue);
  //設定埠號,如nNewValue =1表示COM1
  short GetCommPort();
  void SetCTSHolding(BOOL bNewValue);
  BOOL GetCTSHolding();
  void SetDSRHolding(BOOL bNewValue);
  BOOL GetDSRHolding();
  void SetDTREnable(BOOL bNewValue);
  BOOL GetDTREnable();
  void SetHandshaking(long nNewValue);
  long GetHandshaking();
  void SetInBufferSize(short nNewValue);
  short GetInBufferSize();
  void SetInBufferCount(short nNewValue);
  short GetInBufferCount();
  void SetBreak(BOOL bNewValue);
  BOOL GetBreak();
  void SetInputLen(short nNewValue);
  short GetInputLen();
  void SetNullDiscard(BOOL bNewValue);
  BOOL GetNullDiscard();
  void SetOutBufferSize(short nNewValue);
  short GetOutBufferSize();
  void SetOutBufferCount(short nNewValue);
  short GetOutBufferCount();
  void SetParityReplace(LPCTSTR lpszNewValue);
  CString GetParityReplace();
  void SetPortOpen(BOOL bNewValue);
  //開啟或關閉串列埠,TRUE:開啟,FALSE:關閉
  BOOL GetPortOpen();
  //串列埠是否已開啟,TRUE:開啟,FALSE:關閉
  void SetRThreshold(short nNewValue);
  //如果設定為1,表示一接收到字元就傳送2號事件
  short GetRThreshold();
  void SetRTSEnable(BOOL bNewValue);
  //硬體握手使能?
  BOOL GetRTSEnable();
  void SetSettings(LPCTSTR lpszNewValue);
  //Settings由4部分組成,其格式為:"BBBB,P,D,S",即"波特率,是否奇偶校驗,資料位 //個數,停止位",如設定為:"9600,n,8,1"
  CString GetSettings();
  void SetSThreshold(short nNewValue);
  //如果保持預設值0不變,則表示傳送資料的過程中串列埠上不發生事件
  short GetSThreshold();
  void SetOutput(const VARIANT& newValue);
  //一個非常重要的函式,用於寫串列埠,注意其接收的輸入引數為VARIANT型別物件,
  //我們需要將字串轉化為VARIANT型別物件
  VARIANT GetOutput();
  void SetInput(const VARIANT& newValue);
  VARIANT GetInput();
  //一個非常重要的函式,用於讀串列埠,注意其返回的是VARIANT型別物件,我們需要
  //將其轉化為字串
  void SetCommEvent(short nNewValue);
  short GetCommEvent();
  //一個非常重要的函式,獲得串列埠上剛發生的事件("事件"可以理解為軟體意義上的
  //"訊息"或硬體意義上的"中斷"),事件的傳送會導致OnComm訊息的誕生!
  void SetEOFEnable(BOOL bNewValue);
  BOOL GetEOFEnable();
  void SetInputMode(long nNewValue);
  long GetInputMode();
 };

 //{{AFX_INSERT_LOCATION}}
 // Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif


  分析上述原始碼可知,基本上,MSComm的諸多介面可以分為如下幾類:

  (1)開啟與設定串列埠介面函式;

  (2)獲得串列埠設定和串列埠狀態介面函式;

  (3)設定串列埠傳送資料方式、緩衝區介面及傳送資料介面函式;

  (4)設定串列埠接收資料方式、緩衝區介面及接收資料介面函式;

  (5)設定與獲取串列埠上發生的事件介面函式。

2.例程

  程式的功能和介面(如下圖)都與本文連載三中《基於WIN32 API的串列埠程式設計》相同,不同的只是連載三的串列埠通訊以API實現,而本節的串列埠通訊則以MSComm控制元件實現。


  使用第1節的方法將控制元件新增入工程並新增mscomm.h和mscomm.cpp檔案後,為了使用控制元件,我們將控制元件拖入對話方塊內任意一個位置(執行時"電話"圖示會隱藏),其操作如下圖:


  有趣而極富人性化的是我們可以直接右鍵單擊這個"電話",來設定串列埠的屬性,如下圖:


  接著,我們需要為控制元件新增一個對應的成員變數m_mscom,其對應的變數型別為CMSComm,如下圖:


  這樣就建立了m_mscom和IDC_MSCOMM1控制元件的相互對映:

void CSerialPortActivexDlg::DoDataExchange(CDataExchange* pDX)
{
 CDialog::DoDataExchange(pDX);
 //{{AFX_DATA_MAP(CSerialPortActivexDlg)
  DDX_Text(pDX, IDC_RECV_EDIT, m_recv);
  DDX_Text(pDX, IDC_SEND_EDIT, m_send);
  DDX_Control(pDX, IDC_MSCOMM1, m_mscom);
 //}}AFX_DATA_MAP
}

  同時,在對話方塊的標頭檔案也會由"MFC類嚮導"自動定義CSerialPortActivexDlg類的CMSComm型成員變數m_mscom:

CMSComm m_mscom;

  在對話方塊初始化時(即在CSerialPortActivexDlg::OnInitDialog函式中)開啟串列埠1:

BOOL CSerialPortActivexDlg::OnInitDialog()
{
 CDialog::OnInitDialog();

 // Add "About..." menu item to system menu.

 // IDM_ABOUTBOX must be in the system command range.
 ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
 ASSERT(IDM_ABOUTBOX < 0xF000);

 CMenu* pSysMenu = GetSystemMenu(FALSE);
 if (pSysMenu != NULL)
 {
  CString strAboutMenu;
  strAboutMenu.LoadString(IDS_ABOUTBOX);
  if (!strAboutMenu.IsEmpty())
  {
   pSysMenu->AppendMenu(MF_SEPARATOR);
   pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX,
   strAboutMenu);
  }
 }

 // Set the icon for this dialog. The framework does this automatically
 // when the application's main window is not a dialog
 SetIcon(m_hIcon, TRUE); // Set big icon
 SetIcon(m_hIcon, FALSE); // Set small icon

 // TODO: Add extra initialization here
 m_mscom.SetCommPort(1); //串列埠1
 m_mscom.SetInBufferSize(1024); //設定輸入緩衝區的大小,Bytes
 m_mscom.SetOutBufferSize(512); //設定輸入緩衝區的大小,Bytes
 if(!m_mscom.GetPortOpen()) //開啟串列埠
 {
  m_mscom.SetPortOpen(true);
 }
 m_mscom.SetInputMode(1); //設定輸入方式為二進位制方式
 m_mscom.SetSettings("9600,n,8,1"); //設定波特率等引數
 m_mscom.SetRThreshold(1); //為1表示有一個字元即引發事件
 m_mscom.SetInputLen(0);

 return TRUE; // return TRUE unless you set the focus to a control
}

  最核心的傳送串列埠資料函式("傳送"按鈕單擊事件)如下:

void CSerialPortActivexDlg::OnSendButton()
{
 // TODO: Add your control notification handler code here
 UpdateData(true);

 CByteArray sendArr;
 WORD wLength;

 wLength = m_send.GetLength();
 sendArr.SetSize(wLength);
 for(int i =0; i<wLength; i++)
 {
  sendArr.SetAt(i, m_send.GetAt(i));
 }
 m_mscom.SetOutput(COleVariant(sendArr));
}

3. 為了處理接收事件,我們需要為MScomm控制元件新增對應的訊息處理函式。如下圖,我們通過"MFC類嚮導"添加了CSerialPortActivexDlg 類的成員函式OnCommMscomm1():

  這樣,在對話方塊的標頭檔案中就會自動增加下面兩句:

afx_msg void OnCommMscomm1();//函式宣告
DECLARE_EVENTSINK_MAP()

  來自AFX_MSG部分:

// Generated message map functions
//{{AFX_MSG(CSerialPortActivexDlg)
 virtual BOOL OnInitDialog();
 afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
 afx_msg void OnPaint();
 afx_msg HCURSOR OnQueryDragIcon();
 afx_msg void OnClearButton();
 afx_msg void OnSendButton();
 afx_msg void OnCommMscomm1();
 DECLARE_EVENTSINK_MAP()
//}}AFX_MSG

  同時在對話方塊的.cpp檔案中會增加下列程式碼實現串列埠訊息對映:

BEGIN_EVENTSINK_MAP(CSerialPortActivexDlg, CDialog)
//{{AFX_EVENTSINK_MAP(CSerialPortActivexDlg)
 ON_EVENT(CSerialPortActivexDlg, IDC_MSCOMM1, 1 /* OnComm */,
 OnCommMscomm1, VTS_NONE)
//}}AFX_EVENTSINK_MAP
END_EVENTSINK_MAP()

  我們定義CSerialPortActivexDlg::OnCommMscomm1()函式主要處理資料的接收,其原始碼為:

void CSerialPortActivexDlg::OnCommMscomm1()
{
 // TODO: Add your control notification handler code here
 UpdateData(true);

 VARIANT variant_inp;
 COleSafeArray safearray_inp;

 long i = 0;
 int len;
 char rxdata[1000];
 CString tmp;
 switch (m_mscom.GetCommEvent())
 {
  case 2:
  //表示接收緩衝區內有字元
  {
   variant_inp = m_mscom.GetInput();
   safearray_inp = variant_inp;
   len = safearray_inp.GetOneDimSize();
   for (i = 0; i < len; i++)
   {
    safearray_inp.GetElement(&i, &rxdata[i]);
   }
   rxdata[i] = '/0';
  }
  m_recv += rxdata;
  UpdateData(false);
  break;
  default:
   break;
}
}

  最後,與連載三類似,再次藉助"串列埠除錯助手"以例項驗證了本程式的正確性,如下圖:


  最後,需要特別提示的是:如果要在基於"文件/檢視"的框架結構程式而非對話方塊程式中使用串列埠控制元件,我們不能輕鬆地使用"MFC類嚮導",這時候必須手動地新增相關程式碼。

  在MainFrm.h標頭檔案中加入:

afx_msg void OnCommMscomm();
DECLARE_EVENTSINK_MAP()

  並定義CMSComm成員變數:

CMSComm m_ComPort;

  在MainFrm.cpp檔案中新增

BEGIN_EVENTSINK_MAP(CMainFrame, CFrameWnd)
ON_EVENT(CMainFrame,ID_COMMCTRL,1,OnCommMscomm,VTS_NONE)
//對映ACTIVEX控制元件的事件
END_EVENTSINK_MAP()

  在MainFrm.cpp檔案的OnCreate(LPCREATESTRUCT lpCreateStruct)函式中新增:

ComPort.Create(NULL, WS_VISIBLE | WS_CHILD, CRect(0,0,0,0),this, ID_COMMCTRL);

  以建立CMSComm控制元件。

  此後,我們就可以在CMainFrame類的函式中使用串列埠控制元件對應的ComPort控制元件成員變數。

相關推薦

深入淺出VC++串列程式設計基於控制元件

1.MSComm控制元件  Visual C++為我們提供了一種好用的ActiveX控制元件Microsoft Communications Control(即MSComm)來支援應用程式對串列埠的訪問,在應用程式中插入MSComm控制元件後就可以較為方便地實現對通

深入淺出VC++串列程式設計基本概念

  除錯工具  在MS-DOS下使用的程式設計環境是TC 2.0;  在Windows 2000下的程式設計環境是VC++ 6.0;  藉助工具:串列埠除錯助手2.1(圖8)。 圖8 串列埠除錯助手   串列埠除錯助手是由《Visual C++/Turbo C串列埠通訊程式設計實踐》一書作者龔建偉編寫的

深入淺出VC++串列程式設計DOS的串列程式設計

/* Name : Sample Comm's Program - 1024 Byte Buffer - buff1024.c *//* Written By : Craig Peacock <[email protected]> */#include <dos.h>#inc

深入淺出VC++串列程式設計簡訊應用開發

前面數次連載我們以較長的篇幅講解了串列埠通訊的硬體原理、DOS平臺控制以及基於WIN32 API、控制元件和第三方類的串列埠程式設計。作為本系列文章的最後一次連載,本章將給出一個典型的應用例項:西門子簡訊服務模組TC35

深入淺出VC++串列程式設計--簡訊應用開發

前面數次連載我們以較長的篇幅講解了串列埠通訊的硬體原理、DOS平臺控制以及基於WIN32 API、控制元件和第三方類的串列埠程式設計。作為本系列文章的最後一次連載,本章將給出一個典型的應用例項:西門子簡訊服務模組TC35的串列埠控制。  1.簡訊控制終端  作為簡訊 (Sho

Vc 串列程式設計 Win32 控制元件

  在工業控制中,工控機(一般都基於Windows平臺)經常需要與智慧儀表通過串列埠進行通訊。串列埠通訊方便易行,應用廣泛。 一般情況下,工控機和各智慧儀表通過RS485匯流排進行通訊。RS485的通訊方式是半雙工的,只能由作為主節點的工控PC機依次輪詢網路上的各智慧控

串列程式設計串列初始化

Linux串列埠程式設計 常見資料通訊方式:並行通訊,序列通訊 UART的主要操作: 資料傳送及接受 產生中斷 產生波特率 Loopback模式 紅外模式 自動流控模式 串列埠引數的配置主要包括:波特率、資料位

VC串列程式設計的例項1

  本例程採用同步串列埠操作,我們只介紹軟體部分,RS485介面接線方法不作介紹,感興趣的讀者可以查閱相關資料。   開啟VC++6.0,新建基於對話方塊的工程RS485Comm,在主對話方塊視窗IDD_RS485COMM_DIALOG上新增兩個按鈕,ID分別

VC串列程式設計的例項2

  本例程採用非同步串列埠操作,我們只介紹軟體部分,RS485介面接線方法不作介紹,感興趣的讀者可以查閱相關資料。   開啟VC++6.0,新建基於對話方塊的工程RS485Comm,在主對話方塊視窗IDD_RS485COMM_DIALOG上新增兩個按鈕,ID分

[轉]js串列通訊 呼叫MSCOMM32控制元件 連結電子秤

本文轉自:https://www.cnblogs.com/x-j-p/p/7819724.html 硬體環境:RS232轉USB串列埠線*1      電子秤*1(本人採用G&G E600Y-C型號稱重儀)      電子秤原裝RS232資料線*1      計算機*1 軟體環境:RS232

基於VC++的串列程式設計

序列通訊介面標準有多個版本,但是基本上都是在RS-232標準的基礎上發展而來。RS-232C標準時美國EIA和BELL等公司一起開發並於1969年公佈的通訊協議。1997年TIA發不了最新的一個版本,命名為TIA/EIA-232-F。ITU和CCITT釋出了一個類似的標準-V

Android串列程式設計

閱讀時長:10分鐘 原文地址:juejin.im/post/5bd96c… 原文作者:YKamh 技術預備:Java基礎 如今我們生活中充滿了各種智慧裝置,方便了我們的生活,這正是物聯網時代。如果我們要開發智慧裝置,那麼Android串列埠程式設計是我們應該必備的技能。 在投身到An

菜鳥江濤帶你學最小物聯網系統模組篇(02)——STM32通過串列傳送AT指令控制ESP模組連線伺服器

接著上一篇繼續,這篇部落格我將帶大家使用STM32的串列埠來發送AT指令給ESP模組連線伺服器。當然目前測試使用的是區域網,自己的電腦當伺服器使用。使用TCP連線伺服器,STM32通過ESP12F模組透傳上傳溫溼度資料到伺服器。看下效果圖片 好了,看下主要的實現程式

linux串列程式設計控制流與終端)

流控制 資料在兩個串列埠之間傳輸時,常常會出現丟失資料的現象,或者兩臺計算機的處理速度不同,如桌上型電腦與微控制器之間的通訊,接收端資料緩衝區已滿,則此時繼續傳送來的資料就會丟失。流控制能解決這個問題,當接收端資料處理不過來時,就發出“不再接收”的訊號,傳送端就停止傳送,直到收到“可以繼續傳送”

Android基於藍芽串列程式設計實現HC-05通訊

Android基於藍芽串列埠程式設計實現HC-05通訊 最近接了個工程自動化的專案,需求是實時接收從微控制器傳過來的資料,並進行資料分析處理再進行顯示,在查閱大量的相關部落格和自己踩了不少的坑後,想說把自己的一些經驗分享出來給後來人做個參考www 先介紹下藍芽串列埠的定義

Android USB Host 串列程式設計

1.OTG:  A.手機作為Host,裝置作為Device,手機給裝置充電,需要通過OTG線實現(microUSB);(裝置可以為鍵盤/滑鼠/主機等等) B.手機作為Host,另一手機作為Device,通過OTG可以通訊; 2.PC連線Android:(不需要OTG) A.

vc串列原始碼除錯-控制元件初學者必看!

<pre name="code" class="cpp">// pj20Dlg.cpp : 實現檔案 // #include "stdafx.h" #include "pj20.h" #include "pj20Dlg.h" #ifdef _DEBUG #d

Unity串列通訊(基於三姿態感測器)

/*******************************/ using UnityEngine; using System.Collections; //Other libraries using System; using System.Threading; using System.Collect

UART0串列程式設計系列 串列(UART0)UC/OS(一)

一.在UC/OS中設計串列埠程式所要考慮的問題 1.     串列埠通訊資料以幀為單位進行處理,如果需要接收大量資料,則幀緩衝區規模必然很大;如果需要傳送大量資料,則可將原始資料快看作緩衝區,不需要另外再建立幀緩衝區。 2.     幀緩衝區是全域性資料結構,通常為共

20160426 VC++(VS2013)串列程式設計圖文教程(MSComm的使用)

1、新建MFC對話方塊工程如下 2、給編輯框控制元件新增變數,其中Edit Box新增Value變數,Button新增Control變數,ID和變數分別為: IDC_BTNOPEN()