串口类

  从本系列文章连载三、四可以看出,与通过WIN32 API进行串口访问相比,通过MScomm这个Activex控件进行串口访问要来的方便许多,它基本上可以向用户屏蔽多线程的细节,以事件(发出OnComm消息)方式实现串口的异步访问。

  尽管如此,MScomm控件的使用仍有诸多不便,譬如其发送和接收数据都要进行VARIANT类型对象与字符串的转化等。因此,国内外许多优秀的程序员自己编写了一些串口类,使用这些类,我们将可以更方便的操作串口。在笔者的《深入浅出Win32多线程程序设计之综合实例》(网址:http://dev.yesky.com)一文中,曾向读者展示了由Remon Spekreijse编写的CSerialPort串口类,而本文将向您展示由程序员llbird编写的cnComm(中国串口?)串口类。

  llbird是一位优秀的程序员,他的代码风格简洁而紧凑,类的声明和实现都被定义在一个头文件中,使用这个类的朋友只需要在工程中包含这一头文件即可:

/*
Comm Base Library(WIN98/NT/2000) ver 1.1
Compile by: BC++ 5; C++ BUILDER 4, 5, 6, X; VC++ 5, 6; VC.NET; GCC;
copyright(c) 2004.5 - 2005.8 llbird wushaojian@21cn.com
*/
#ifndef _CN_COMM_H_
#define _CN_COMM_H_

#pragma warning(disable: 4530)
#pragma warning(disable: 4786)
#pragma warning(disable: 4800)

#include <assert.h>
#include <stdio.h>
#include <windows.h>

//送到窗口的消息 WPARAM 端口号
#define ON_COM_RECEIVE WM_USER + 618
#define ON_COM_CTS WM_USER + 619 //LPARAM 1 valid
#define ON_COM_DSR WM_USER + 621 //LPARAM 1 valid
#define ON_COM_RING WM_USER + 623
#define ON_COM_RLSD WM_USER + 624
#define ON_COM_BREAK WM_USER + 625
#define ON_COM_TXEMPTY WM_USER + 626
#define ON_COM_ERROR WM_USER + 627 //LPARAM save Error ID
#define DEFAULT_COM_MASK_EVENT EV_RXCHAR | EV_ERR | EV_CTS | EV_DSR | EV_BREAK | EV_TXEMPTY | EV_RING | EV_RLSD

class cnComm
{
 public:

 //------------------------------Construction-----------------------------------
 //第1个参数为是否在打开串口时启动监视线程, 第2个参数为IO方式 阻塞方式(0)/ 异步重叠方式(默认)
 cnComm(bool fAutoBeginThread = true, DWORD dwIOMode =
FILE_FLAG_OVERLAPPED): _dwIOMode(dwIOMode), _fAutoBeginThread(fAutoBeginThread)
 {
  Init();
 }

 virtual ~cnComm()
 {
  Close();
  UnInit();
 }

 //----------------------------------Attributes----------------------------------
 //判断串口是否打开
 inline bool IsOpen()
 {
  return _hCommHandle != INVALID_HANDLE_VALUE;
 }
 //判断串口是否打开
 operator bool()
 {
  return _hCommHandle != INVALID_HANDLE_VALUE;
 }
 //获得串口句炳
 inline HANDLE GetHandle()
 {
  return _hCommHandle;
 }
 //获得串口句炳
 operator HANDLE()
 {
  return _hCommHandle;
 }
 //获得串口参数 DCB
 DCB *GetState()
 {
  return IsOpen() && ::GetCommState(_hCommHandle, &_DCB) == TRUE ?
  &_DCB: NULL;
 }
 //设置串口参数 DCB
 bool SetState(DCB *pdcb = NULL)
 {
  return IsOpen() ? ::SetCommState(_hCommHandle, pdcb == NULL ? &_DCB:pdcb) == TRUE: false;
 }
 //设置串口参数:波特率,停止位,等 支持设置字符串 "9600, 8, n, 1"
 bool SetState(char *szSetStr)
 {
  if (IsOpen())
  {
   if (::GetCommState(_hCommHandle, &_DCB) != TRUE)
    return false;
   if (::BuildCommDCB(szSetStr, &_DCB) != TRUE)
    return false;
   return ::SetCommState(_hCommHandle, &_DCB) == TRUE;
  }
  return false;
 }
 //设置串口参数:波特率,停止位,等
 bool SetState(DWORD dwBaudRate, DWORD dwByteSize = 8, DWORD dwParity =
NOPARITY, DWORD dwStopBits = ONESTOPBIT)
 {
  if (IsOpen())
  {
   if (::GetCommState(_hCommHandle, &_DCB) != TRUE)
    return false;
   _DCB.BaudRate = dwBaudRate;
   _DCB.ByteSize = (unsigned char)dwByteSize;
   _DCB.Parity = (unsigned char)dwParity;
   _DCB.StopBits = (unsigned char)dwStopBits;
   return ::SetCommState(_hCommHandle, &_DCB) == TRUE;
  }
  return false;
 }
 //获得超时结构
 LPCOMMTIMEOUTS GetTimeouts(void)
 {
  return IsOpen() && ::GetCommTimeouts(_hCommHandle, &_CO) == TRUE ?
&_CO: NULL;
 }
 //设置超时
 bool SetTimeouts(LPCOMMTIMEOUTS lpCO)
 {
  return IsOpen() ? ::SetCommTimeouts(_hCommHandle, lpCO) == TRUE:false;
 }
 //设置串口的I/O缓冲区大小
 bool SetBufferSize(DWORD dwInputSize, DWORD dwOutputSize)
 {
  return IsOpen() ? ::SetupComm(_hCommHandle, dwInputSize, dwOutputSize)== TRUE: false;
 }
 //关联消息的窗口句柄
 inline void SetWnd(HWND hWnd)
 {
  assert(::IsWindow(hWnd));
  _hNotifyWnd = hWnd;
 }
 //设定发送通知, 接受字符最小值
 inline void SetNotifyNum(DWORD dwNum)
 {
  _dwNotifyNum = dwNum;
 }
 //线程是否运行
 inline bool IsThreadRunning()
 {
  return _hThreadHandle != NULL;
 }
 //获得线程句柄
 inline HANDLE GetThread()
 {
  return _hThreadHandle;
 }
 //设置要监视的事件, 打开前设置有效
 void SetMaskEvent(DWORD dwEvent = DEFAULT_COM_MASK_EVENT)
 {
  _dwMaskEvent = dwEvent;
 }
 //获得读缓冲区的字符数
 int GetInputSize()
 {
  COMSTAT Stat;
  DWORD dwError;

  return ::ClearCommError(_hCommHandle, &dwError, &Stat) == TRUE ? Stat.cbInQue : (DWORD) - 1L;
 }

 //----------------------------------Operations----------------------------------
 //打开串口 缺省 9600, 8, n, 1
 bool Open(DWORD dwPort)
 {
  return Open(dwPort, 9600);
 }
 //打开串口 缺省 baud_rate, 8, n, 1
 bool Open(DWORD dwPort, DWORD dwBaudRate)
 {
  if (dwPort < 1 || dwPort > 1024)
   return false;
  BindCommPort(dwPort);

  if (!OpenCommPort())
   return false;

  if (!SetupPort())
   return false;

  return SetState(dwBaudRate);
 }
 //打开串口, 使用类似"9600, 8, n, 1"的设置字符串设置串口
 bool Open(DWORD dwPort, char *szSetStr)
 {
  if (dwPort < 1 || dwPort > 1024)
   return false;

  BindCommPort(dwPort);

  if (!OpenCommPort())
   return false;

  if (!SetupPort())
   return false;

  return SetState(szSetStr);
 }
 //读取串口 dwBufferLength个字符到 Buffer 返回实际读到的字符数 可读任意数据
 DWORD Read(LPVOID Buffer, DWORD dwBufferLength, DWORD dwWaitTime = 10)
 {
  if (!IsOpen())
   return 0;

  COMSTAT Stat;
  DWORD dwError;

  if (::ClearCommError(_hCommHandle, &dwError, &Stat) && dwError > 0)
  {
   ::PurgeComm(_hCommHandle,PURGE_RXABORT | PURGE_RXCLEAR);
   return 0;
  } 
  if (!Stat.cbInQue)
   // 缓冲区无数据
   return 0;

  unsigned long uReadLength = 0;

  dwBufferLength = dwBufferLength > Stat.cbInQue ? Stat.cbInQue :dwBufferLength;

  if (!::ReadFile(_hCommHandle, Buffer, dwBufferLength, &uReadLength,&_ReadOverlapped))
  {
   if (::GetLastError() == ERROR_IO_PENDING)
   {
    WaitForSingleObject(_ReadOverlapped.hEvent, dwWaitTime);
    // 结束异步I/O
    if (!::GetOverlappedResult(_hCommHandle, &_ReadOverlapped,&uReadLength, false))
    {
     if (::GetLastError() != ERROR_IO_INCOMPLETE)
      uReadLength = 0;
    }
   }
   else
    uReadLength = 0;
  }

  return uReadLength;
 }
 //读取串口 dwBufferLength - 1 个字符到 szBuffer 返回ANSI C 模式字符串指针 适合一般字符通讯

 char *ReadString(char *szBuffer, DWORD dwBufferLength, DWORD dwWaitTime =20)
 {
  unsigned long uReadLength = Read(szBuffer, dwBufferLength - 1,dwWaitTime);
  szBuffer[uReadLength] = '/0';
  return szBuffer;
 }
 //写串口 可写任意数据 "abcd" or "/x0/x1/x2"
 DWORD Write(LPVOID Buffer, DWORD dwBufferLength)
 {
  if (!IsOpen())
   return 0;

  DWORD dwError;

  if (::ClearCommError(_hCommHandle, &dwError, NULL) && dwError > 0)
   ::PurgeComm(_hCommHandle, PURGE_TXABORT | PURGE_TXCLEAR);

  unsigned long uWriteLength = 0;

  if (!::WriteFile(_hCommHandle, Buffer, dwBufferLength, &uWriteLength,&_WriteOverlapped))
   if (::GetLastError() != ERROR_IO_PENDING)
    uWriteLength = 0;

   return uWriteLength;
  }
  //写串口 写ANSI C 模式字符串指针
  DWORD Write(const char *szBuffer)
  {
   assert(szBuffer);

   return Write((void*)szBuffer, strlen(szBuffer));
  }
  //读串口 同步应用
  DWORD ReadSync(LPVOID Buffer, DWORD dwBufferLength)
  {
   if (!IsOpen())
    return 0;

   DWORD dwError;
   if (::ClearCommError(_hCommHandle, &dwError, NULL) && dwError > 0)
   {
    ::PurgeComm(_hCommHandle,PURGE_RXABORT | PURGE_RXCLEAR);
    return 0;
   }

   DWORD uReadLength = 0;
   ::ReadFile(_hCommHandle, Buffer, dwBufferLength, &uReadLength, NULL);
   return uReadLength;
  }
  //写串口 同步应用
  DWORD WriteSync(LPVOID Buffer, DWORD dwBufferLength)
  {
   if (!IsOpen())
    return 0;

   DWORD dwError;
   if (::ClearCommError(_hCommHandle, &dwError, NULL) && dwError > 0)
    ::PurgeComm(_hCommHandle, PURGE_TXABORT | PURGE_TXCLEAR);

   unsigned long uWriteLength = 0;
   ::WriteFile(_hCommHandle, Buffer, dwBufferLength, &uWriteLength, NULL);
   return uWriteLength;
  }
  //写串口 szBuffer 可以输出格式字符串 包含缓冲区长度
  DWORD Write(char *szBuffer, DWORD dwBufferLength, char *szFormat, ...)
  {
   if (!IsOpen())
    return 0;

   va_list va;
   va_start(va, szFormat);
   _vsnprintf(szBuffer, dwBufferLength, szFormat, va);
   va_end(va);

   return Write(szBuffer);
  }
  //写串口 szBuffer 可以输出格式字符串 不检查缓冲区长度 小心溢出
  DWORD Write(char *szBuffer, char *szFormat, ...)
  {
   if (!IsOpen())
    return 0;

   va_list va;
   va_start(va, szFormat);
   vsprintf(szBuffer, szFormat, va);
   va_end(va);

   return Write(szBuffer);
  }
  //关闭串口 同时也关闭关联线程
  virtual void Close()
  {
   if (IsOpen())
   {
    PurgeComm(_hCommHandle, PURGE_TXABORT | PURGE_TXCLEAR);

    EndThread();
    ::CloseHandle(_hCommHandle);

    _hCommHandle = INVALID_HANDLE_VALUE;
   }
  }
  //DTR 电平控制
  bool SetDTR(bool OnOrOff)
  {
   return IsOpen() ? EscapeCommFunction(_hCommHandle, OnOrOff ? SETDTR :CLRDTR): false;
  }
  //RTS 电平控制
  bool SetRTS(bool OnOrOff)
  {
   return IsOpen() ? EscapeCommFunction(_hCommHandle, OnOrOff ? SETRTS :CLRRTS): false;
  }
  //
  bool SetBreak(bool OnOrOff)
  {
   return IsOpen() ? EscapeCommFunction(_hCommHandle, OnOrOff ? SETBREAK: CLRBREAK): false;
  }
  //辅助线程控制 建监视线程
  bool BeginThread()
  {
   if (!IsThreadRunning())
   {
    _fRunFlag = true;
    _hThreadHandle = NULL;

    DWORD id;

    _hThreadHandle = ::CreateThread(NULL, 0, CommThreadProc, this, 0,&id);

    return (_hThreadHandle != NULL);
   }
   return false;
  }
  //暂停监视线程
  inline bool SuspendThread()
  {
   return IsThreadRunning() ? ::SuspendThread(_hThreadHandle) !=0xFFFFFFFF: false;
  }
  //恢复监视线程
  inline bool ResumeThread()
  {
   return IsThreadRunning() ? ::ResumeThread(_hThreadHandle) !=0xFFFFFFFF: false;
  }
  //终止线程
  bool EndThread(DWORD dwWaitTime = 100)
  {
   if (IsThreadRunning())
   {
    _fRunFlag = false;
    ::SetCommMask(_hCommHandle, 0);
    ::SetEvent(_WaitOverlapped.hEvent);
    if (::WaitForSingleObject(_hThreadHandle, dwWaitTime) !=WAIT_OBJECT_0)
     if (!::TerminateThread(_hThreadHandle, 0))
      return false;

     ::CloseHandle(_hThreadHandle);
     ::ResetEvent(_WaitOverlapped.hEvent);

     _hThreadHandle = NULL;

     return true;
   }
   return false;
  }

 protected:
  volatile DWORD _dwPort; //串口号
  volatile HANDLE _hCommHandle; //串口句柄
  char _szCommStr[20]; //保存COM1类似的字符串

  DCB _DCB; //波特率,停止位,等
  COMMTIMEOUTS _CO; //超时结构

  DWORD _dwIOMode; // 0 同步 默认 FILE_FLAG_OVERLAPPED重叠I/O异步
  OVERLAPPED _ReadOverlapped, _WriteOverlapped; // 重叠I/O

  volatile HANDLE _hThreadHandle; //辅助线程
  volatile HWND _hNotifyWnd; // 通知窗口
  volatile DWORD _dwNotifyNum; //接受多少字节(>=_dwNotifyNum)发送通知消息
  volatile DWORD _dwMaskEvent; //监视的事件
  volatile bool _fRunFlag; //线程运行循环标志
  bool _fAutoBeginThread; //Open() 自动 BeginThread();
  OVERLAPPED _WaitOverlapped; //WaitCommEvent use

  //初始化
  void Init()
  {
   memset(_szCommStr, 0, 20);
   memset(&_DCB, 0, sizeof(_DCB));
   _DCB.DCBlength = sizeof(_DCB);
   _hCommHandle = INVALID_HANDLE_VALUE;

   memset(&_ReadOverlapped, 0, sizeof(_ReadOverlapped));
   memset(&_WriteOverlapped, 0, sizeof(_WriteOverlapped));

   _ReadOverlapped.hEvent = ::CreateEvent(NULL, true, false, NULL);
   assert(_ReadOverlapped.hEvent != INVALID_HANDLE_VALUE);

   _WriteOverlapped.hEvent = ::CreateEvent(NULL, true, false, NULL);
   assert(_WriteOverlapped.hEvent != INVALID_HANDLE_VALUE);

   _hNotifyWnd = NULL;
   _dwNotifyNum = 0;
   _dwMaskEvent = DEFAULT_COM_MASK_EVENT;
   _hThreadHandle = NULL;

   memset(&_WaitOverlapped, 0, sizeof(_WaitOverlapped));
   _WaitOverlapped.hEvent = ::CreateEvent(NULL, true, false, NULL);
   assert(_WaitOverlapped.hEvent != INVALID_HANDLE_VALUE);
  }
  //析构
  void UnInit()
  {
   if (_ReadOverlapped.hEvent != INVALID_HANDLE_VALUE)
    CloseHandle(_ReadOverlapped.hEvent);

   if (_WriteOverlapped.hEvent != INVALID_HANDLE_VALUE)
    CloseHandle(_WriteOverlapped.hEvent);

   if (_WaitOverlapped.hEvent != INVALID_HANDLE_VALUE)
    CloseHandle(_WaitOverlapped.hEvent);
  }
  //绑定串口
  void BindCommPort(DWORD dwPort)
  {
   assert(dwPort >= 1 && dwPort <= 1024);

   char p[5];

   _dwPort = dwPort;
   strcpy(_szCommStr, ".//COM");
   ltoa(_dwPort, p, 10);
   strcat(_szCommStr, p);
  }
  //打开串口
  virtual bool OpenCommPort()
  {
   if (IsOpen())
    Close();

   _hCommHandle = ::CreateFile(_szCommStr, GENERIC_READ | GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | _dwIOMode,NULL);

   if (_fAutoBeginThread)
   {
    if (IsOpen() && BeginThread())
     return true;
    else
    {
     Close(); //创建线程失败
     return false;
    }
   }
   return IsOpen();
  }
  //设置串口
  virtual bool SetupPort()
  {
   if (!IsOpen())
    return false;

   if (!::SetupComm(_hCommHandle, 4096, 4096))
    return false;

   if (!::GetCommTimeouts(_hCommHandle, &_CO))
    return false;
   _CO.ReadIntervalTimeout = 0;
   _CO.ReadTotalTimeoutMultiplier = 1;
   _CO.ReadTotalTimeoutConstant = 1000;
   _CO.WriteTotalTimeoutMultiplier = 1;
   _CO.WriteTotalTimeoutConstant = 1000;
   if (!::SetCommTimeouts(_hCommHandle, &_CO))
    return false;

   if (!::PurgeComm(_hCommHandle, PURGE_TXABORT | PURGE_RXABORT |PURGE_TXCLEAR | PURGE_RXCLEAR))
    return false;
   return true;
  }

  //---------------------------------------threads callback-----------------------------------
  //线程收到消息自动调用, 如窗口句柄有效, 送出消息, 包含串口编号, 均为虚函数可以在基层类中扩展
  virtual void OnReceive() //EV_RXCHAR
  {
   if (::IsWindow(_hNotifyWnd))
    ::PostMessage(_hNotifyWnd, ON_COM_RECEIVE, WPARAM(_dwPort), LPARAM (0));
  }

  virtual void OnDSR()
  {
   if (::IsWindow(_hNotifyWnd))
   {
    DWORD Status;
    if (GetCommModemStatus(_hCommHandle, &Status))
     ::PostMessage(_hNotifyWnd, ON_COM_DSR, WPARAM(_dwPort),LPARAM((Status &MS_DSR_ON) ? 1 : 0));
   }
  }

  virtual void OnCTS()
  {
   if (::IsWindow(_hNotifyWnd))
   {
    DWORD Status;
    if (GetCommModemStatus(_hCommHandle, &Status))
     ::PostMessage(_hNotifyWnd, ON_COM_CTS, WPARAM(_dwPort), LPARAM( (Status &MS_CTS_ON) ? 1 : 0));
   }
  }

  virtual void OnBreak()
  {
   if (::IsWindow(_hNotifyWnd))
   {
    ::PostMessage(_hNotifyWnd, ON_COM_BREAK, WPARAM(_dwPort), LPARAM(0));
   }
  }

  virtual void OnTXEmpty()
  {
   if (::IsWindow(_hNotifyWnd))
    ::PostMessage(_hNotifyWnd, ON_COM_TXEMPTY, WPARAM(_dwPort), LPARAM (0));
  }

  virtual void OnError()
  {
   DWORD dwError;
   ::ClearCommError(_hCommHandle, &dwError, NULL);
   if (::IsWindow(_hNotifyWnd))
    ::PostMessage(_hNotifyWnd, ON_COM_ERROR, WPARAM(_dwPort), LPARAM (dwError));
  }

  virtual void OnRing()
  {
   if (::IsWindow(_hNotifyWnd))
    ::PostMessage(_hNotifyWnd, ON_COM_RING, WPARAM(_dwPort), LPARAM(0));
  }

  virtual void OnRLSD()
  {
   if (::IsWindow(_hNotifyWnd))
    ::PostMessage(_hNotifyWnd, ON_COM_RLSD, WPARAM(_dwPort), LPARAM(0));
  }

  virtual DWORD ThreadFunc()
  {
   if (!::SetCommMask(_hCommHandle, _dwMaskEvent))
   {
    char szBuffer[256];
    _snprintf(szBuffer, 255,
"%s(%d) : COM%d Call WINAPI SetCommMask(%x, %x) Fail, thread work invalid! GetLastError() = %d;", __FILE__, __LINE__, _dwPort, _hCommHandle, _dwMaskEvent, GetLastError());
    MessageBox(NULL, szBuffer, "Class cnComm", MB_OK);
    return 1;
   }

   COMSTAT Stat;
   DWORD dwError;

   for (DWORD dwLength, dwMask = 0; _fRunFlag && IsOpen(); dwMask = 0)
   {
    if (!::WaitCommEvent(_hCommHandle, &dwMask, &_WaitOverlapped))
    {
     if (::GetLastError() == ERROR_IO_PENDING)
      // asynchronous
      ::GetOverlappedResult(_hCommHandle, &_WaitOverlapped,&dwLength, TRUE);
     else
      continue;
    }

    if (dwMask == 0)
     continue;

    switch (dwMask)
    {
     case EV_RXCHAR:
      ::ClearCommError(_hCommHandle, &dwError, &Stat);
      if (Stat.cbInQue >= _dwNotifyNum)
       OnReceive();
      break;

     case EV_TXEMPTY:
      OnTXEmpty();
      break;
 
     case EV_CTS:
      OnCTS();
      break;

     case EV_DSR:
      OnDSR();
      break;

     case EV_RING:
      OnRing();
      break;

     case EV_RLSD:
      OnRLSD();
      break;

     case EV_BREAK:
      OnBreak();
      break;

     case EV_ERR:
      OnError();
      break;
    } //case
   } //for
   return 0;
  }

 private:
  //the function protected

  cnComm(const cnComm &);
  cnComm &operator = (const cnComm &);

  //base function for thread
  static DWORD WINAPI CommThreadProc(LPVOID lpPara)
  {
   return ((cnComm*)lpPara)->ThreadFunc();
  }
 };
#endif //_CN_COMM_H_

2.实例

  程序的功能和界面(如下图)都与本文连载三、四中《基于WIN32 API的串口编程》和《基于控件的串口编程》相同,不同的只是本节的串口通信要以llbird定义的cnComm类来实现。

  我们需要为串口的接收事件定义一个用户消息ON_COM_RECEIVE,因此对话框的消息映射为:

BEGIN_MESSAGE_MAP(CSerialPortClassDlg, CDialog)
//{{AFX_MSG_MAP(CSerialPortClassDlg)
 ON_WM_SYSCOMMAND()
 ON_WM_PAINT()
 ON_WM_QUERYDRAGICON()
 ON_BN_CLICKED(IDC_CLEAR_BUTTON, OnClearButton)
 ON_BN_CLICKED(IDC_SEND_BUTTON, OnSendButton)
 ON_MESSAGE(ON_COM_RECEIVE,OnCommRecv)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

  同时,我们需要在对话框类的头文件中定义cnComm类的成员变量com和接收数据消息处理函数OnCommRecv:

cnComm com;
afx_msg void OnCommRecv(WPARAM wParam, LPARAM lParam);

  在对话框初始化时调用打开串口:

BOOL CSerialPortClassDlg::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

 com.Open(1); //打开串口1并使用默认设置
 com.SetWnd(AfxGetMainWnd()->m_hWnd); //设置消息处理窗口

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

  发送字符串的过程很简单,只需要调用cnComm类的Write函数:

//"发送"按钮函数(完成数据的发送功能)
void CSerialPortClassDlg::OnSendButton()
{
 // TODO: Add your control notification handler code here
 UpdateData(true);

 com.Write(m_send); //发送字符串
}

  接收字符串的过程也很简单,只需要调用cnComm类的ReadString函数:

void CSerialPortClassDlg::OnCommRecv(WPARAM wParam, LPARAM lParam)
{
 UpdateData(true);

 //读取串口上的字符
 char str[100];
 com.ReadString(str, 100);
 m_recv += str;

 UpdateData(false);
}

  读者朋友们这时一定会发出感慨:使用cnComm类后,进行串口数据收发的程序是多么简单啊!的确,串口的初始化、读写几乎都是用1~2条语句搞定的!

  这就是我们要特别用一次连载来讲述使用第三方类来进行串口通信的原因。实际上,笔者在进行网络通信程序编程时,也不认为MS提供的CSocket类是最方便的选择,照样习惯使用第三方的网络通信类。它们的确有非常简洁明快的接口,这一点也是值得MS哥哥们学习的。

深入浅出VC++串口编程--第三方类相关推荐

  1. 深入浅出VC++串口编程--基于控件

    深入浅出VC++串口编程之基于控件源代码下载 MSComm控件 Visual C++为我们提供了一种好用的ActiveX控件Microsoft Communications Control(即MSCo ...

  2. 深入浅出VC++串口编程--基本概念

    引言 在PC机的主板上,有一种类型的接口可能为我们所忽视,那就是RS-232C串行接口,在微软的Windows系统中称其为COM.我们可以通过设备管理器来查看COM的硬件参数设置,如图1. 图1 在W ...

  3. 深入浅出VC++串口编程--短信应用开发

    前面数次连载我们以较长的篇幅讲解了串口通信的硬件原理.DOS平台控制以及基于WIN32 API.控件和第三方类的串口编程.作为本系列文章的最后一次连载,本章将给出一个典型的应用实例:西门子短信服务模块 ...

  4. 深入浅出VC++串口编程之短信应用开发

    前面数次连载我们以较长的篇幅讲解了串口通信的硬件原理.DOS平台控制以及基于WIN32 API.控件和第三方类的串口编程.作为本系列文章的最后一次连载,本章将给出一个典型的应用实例:西门子短信服务模块 ...

  5. 深入浅出VC++串口编程--基于Win32 API

    1.API描述 在WIN32 API中,串口使用文件方式进行访问,其操作的API基本上与文件操作的API一致. 打开串口 Win32 中用于打开串口的API 函数为CreateFile,其原型为: H ...

  6. 深入浅出VC++串口编程之基于Win32 API

    1.API描述 在WIN32 API中,串口使用文件方式进行访问,其操作的API基本上与文件操作的API一致. 打开串口 Win32 中用于打开串口的API 函数为CreateFile,其原型为: H ...

  7. 深入浅出Visual C++串口编程--深入浅出VC++串口编程之DOS的串口编程

    在DOS平台下,操作串口主要有下列方式:通过BIOS调用.通过串口的硬件中断或通过对串口硬件进行轮询,本章将对以上三种方式进行具体的介绍并给出例子. 1.BIOS中断 在DOS操作系统下,IBM PC ...

  8. MFC 串口编程实例

    MFC 串口编程实例 VC串口编程从实现方法上一般分为两种,一种使用MSCOMM控件,这种方法比较简单,软件的移植性较低,在这里介绍一种串口封装类的使用方法. 代码 先看代码 CommUtils.cp ...

  9. 一个由印度人编写的VC串口类

    软件介绍 一个由印度人编写的VC串口类(也是一种VC串口控件),他还配合这个类写了VC 串口通信方面的一些基础知识,如怎么用VC打开串口,如何对串口进行配置,读串口.写串口等. 这个类有点特别,它没有 ...

最新文章

  1. 16.6 创建测试数据
  2. SharePoint安全 - SharePoint网站常用页面URL索引
  3. 数据源管理 | OLAP查询引擎,ClickHouse集群化管理
  4. 自己配置的WAMP环境,扩展oracle函数库(oci)
  5. python汉语读音_【学习】python 汉语转拼音
  6. MTK:屏幕模板机制
  7. 33. 数据类型转换
  8. LncRNADisease:IncRNA相关疾病数据库简介
  9. 微软智能云Azure在华新增数据中心区域正式启用
  10. 常见的直流稳压电源电容有哪些?及其详细介绍
  11. [组图]国外专家谈游戏制作
  12. Matlab中num2str函数的用法
  13. java 绘制动态的图形
  14. ZK-SNARKS | 创建第一个零知识snark电路
  15. rstudio运行python_RStudio网状Python
  16. Reloading current route in Angular 5 / Angular 6 / Angular 7
  17. 正则表达式\\s+ - 匹配任意空白字符
  18. matlab谐波含量,基于谐波检测中的数字低通滤波器的MATLAB设计
  19. java set 排序的_Set集合排序
  20. python封装继承多态_Python:封装、继承、多态、私有成员

热门文章

  1. 第十二单元       打包,压缩,主机传送文件
  2. Windows下Nginx的启动、停止等基本命令
  3. OEA 中 WPF 树型表格虚拟化设计方案
  4. 我的城市,我的汽车:Autoblog 摄影大赛
  5. Royal TS 一款非常好用的SSH客户端,XShell的完美代替品
  6. Tomcat 比 nio 、aio性能更好的apr介绍
  7. 3、MapReduce详解与源码分析
  8. docker安装redis并将配置文件和数据文件映射到外部
  9. 给你的网站添加运行时间
  10. C#LeetCode刷题-拒绝采样