程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> VC++ >> VC學習:Windows CE下的串口通訊類

VC學習:Windows CE下的串口通訊類

編輯:VC++

  串行通訊是目前計算機、通信和控制領域最基本的通信方式。在CSDN的“嵌入式開發/WINCE”社區中,經常有人提問該到哪找串口通訊類,其實這個問題我自己也問過。:)而一般的回答是給你提供一個Pocket PC 2002的SDK例子程序。但到底SDK的程序和MFC的結構有很大的不同,對於想用MFC編寫通信程序的人來說也不是很便利。
  
  另一方面,由於Windows CE是一個基於Unicode的操作系統,並且Windows CE不支持Windows下常用的串行通信重疊I/O方式(OVERLAPPED),因此編寫Windows CE下的串口通訊類有一些與桌面Windows不同的地方。
  
  以下是我從SDK程序改寫而來的MFC類,希望能和致力於WINCE開發的朋友多多交流,由於本人才疏學淺,程序中有許多不完善的地方,請大家指正。我的程序是基於“主動發送請求,被動接收響應”的假設,因此我只設置了一個接收數據的線程。如果有朋友能提供有獨立發送數據和接收數據線程的類,我將十分感激。我的E_mail:[email protected]
  
  感謝“嵌入式開發/WINCE”社區為我提供SDK例子的朋友,感謝CSDN上所有熱心的朋友,祝願中國的軟硬件水平能早日擠身世界一流。
  
  頭文件Serial.h
  
  // Serial.h: interface for the CSerial class.
  
  //
  
  /////////////////////////////
  
  #if !defined(AFX_SERIAL_H__59575586_AAA9_4FEF_B2A7_E089553698EF__INCLUDED_)
  
  #define AFX_SERIAL_H__59575586_AAA9_4FEF_B2A7_E089553698EF__INCLUDED_
  
  #if _MSC_VER > 1000
  
  #pragma once
  
  #endif // _MSC_VER > 1000
  
  DWORD WINAPI ReadPortThread(LPVOID lpvoid); //讀數據線程
  
  class CSerial
  
  {
  
  public:
  
  BOOL InitCommTimeouts(); //設置超時參數
  
  BOOL InitDCB(); //配置串口

  BOOL m_bConnected;
  
  BOOL ClosePort(HANDLE hCommPort); //關閉串口
  
  DWORD WritePort(TCHAR *buf,DWORD dwBytesToWrite); //寫數據
  
  BOOL OpenPort(LPTSTR lpszPortName); //打開串口
  
  CSerial();
  
  HANDLE hReadThread;
  
  virtual ~CSerial();
  
  };
  
  #endif // !defined(AFX_SERIAL_H__59575586_AAA9_4FEF_B2A7_E089553698EF__INCLUDED_)
  
  源文件:Serial.cpp
  
  // Serial.cpp: implementation of the CSerial class.
  
  //
  
  /////////////////
  
  #include "stdafx.h"
  
  #include "Serial.h"
  
  #ifdef _DEBUG
  
  #undef THIS_FILE
  
  static char THIS_FILE[]=__FILE__;
  
  #define new DEBUG_NEW
  
  #endif
  
  HANDLE hPort;
  
  CString strInChar;
  
  //////////////////////////////////////////
  
  // Construction/Destruction
  
  /////////////////////////////////////////

  CSerial::CSerial()
  
  {
  
  }
  
  CSerial::~CSerial()
  
  {
  
  if(hPort != INVALID_HANDLE_VALUE)
  
  ClosePort(hPort);
  
  }
  
  BOOL CSerial::OpenPort(LPTSTR lpszPortName)
  
  {
  
  DWORD dwError,
  
  dwThreadID;

  if(hPort)
  
  {
  
  return FALSE;
  
  }
  
  //打開串口
  
  hPort = CreateFile (lpszPortName, GENERIC_READ | GENERIC_WRITE,
  
  0, NULL, OPEN_EXISTING,0, NULL);
  
  //如果打開端口出錯, 返回FALSE
  
  if ( hPort == INVALID_HANDLE_VALUE )
  
  {
  
  //不能打開端口
  
  CString strError;
  
  strError.Format(_T("Unable to open %s, Error No.=%d"),
  
  lpszPortName, GetLastError());
  
  MessageBox (NULL, strError,TEXT("Error"), MB_OK);
  
  return FALSE;
  
  }
  
  //指定端口監測的事件集

  SetCommMask (hPort, EV_RXCHAR);
  
  //分配設備緩沖區
    
  SetupComm(hPort,512,512);
  
  //初始化緩沖區中的信息
  
  PurgeComm(hPort,PURGE_TXCLEAR|PURGE_RXCLEAR);
  
  //配置串行端口
  
  if(!InitDCB())
  
  return FALSE;
  
  //設置端口超時值
  
  if(!InitCommTimeouts())
  
  return FALSE;
  
  //設置端口上指定信號的狀態
  
  // SETDTR: 發送DTR (data-terminal-ready)信號
  
  // SETRTS: 發送RTS (request-to-send)信號
  
  EscapeCommFunction (hPort, SETDTR);
  
  EscapeCommFunction (hPort, SETRTS);
  
  //創建一個從串口讀取數據的線程
  
  if (hReadThread = CreateThread (NULL, 0, ReadPortThread, 0, 0,
  
  &dwThreadID))
  
  {
  
  }
  
  else
  
  {
  
  //不能創建線程
  
  MessageBox (NULL, TEXT("Unable to create the read thread"),
  
  TEXT("Error"), MB_OK);
  
  dwError = GetLastError ();
  
  return FALSE;
  
  }

  m_bConnected=TRUE;
  
  return TRUE;
  
  }
  
  DWORD CSerial::WritePort(TCHAR *buf,DWORD dwCharToWrite)
  
  {
  
  BOOL fWriteState;
  
  DWORD dwBytesWritten;
  
  //寫入數據
  
  fWriteState=WriteFile(hPort,buf,dwCharToWrite*sizeof  (TCHAR),&dwBytesWritten,NULL);
  
  if(!fWriteState)
  
  {
  
  //不能寫數據
  
  MessageBox(NULL,TEXT("Can't Write String to Comm"),TEXT("Error"),MB_OK);
  
  dwBytesWritten=0;
  
  }

  return dwBytesWritten;
  
  }
  
  DWORD WINAPI ReadPortThread(LPVOID lpvoid)
  
  {
  
  BOOL fReadState;
  
  DWORD dwCommModemStatus;
  
  DWORD dwLength;
  
  COMSTAT ComStat;
  
  DWORD dwErrorFlags;
  
  while (hPort != INVALID_HANDLE_VALUE)
  
  {
  
  //等待串口的事件發生
  
  WaitCommEvent (hPort, &dwCommModemStatus, 0);
  
  if (dwCommModemStatus & EV_RXCHAR)
  
  {

  ClearCommError(hPort,&dwErrorFlags,&ComStat);

  //cbInQue返回在串行驅動程序輸入隊列中的字符數
  
  dwLength=ComStat.cbInQue;
  
  if(dwLength>0)
  
  {
  
  //從串口讀取數據
  
  TCHAR* buf=new TCHAR[256];
  
  fReadState=ReadFile(hPort,buf,dwLength,&dwLength,NULL);
  
  if(!fReadState)
  
  {
  
  //不能從串口讀取數據
  
  MessageBox(NULL,TEXT("Error in read from serial port"),TEXT("Read Error"),MB_OK);
  
  }
  
  else
  
  {
  
  //把數據賦值給全局變量
  
  strInChar=buf;
  
  }
  
  delete[] buf;
  
  }
  
  }
  
  GetCommModemStatus (hPort, &dwCommModemStatus);
  
  }
  
  return 0;
  
  }
  
  BOOL CSerial::ClosePort(HANDLE hCommPort)
  
  {
  
  if (hCommPort != INVALID_HANDLE_VALUE)
  
  {
  
  //設置連接屬性為FALSE

  m_bConnected=FALSE;
  
  //結束線程中WaitCommEvent的等待
  
  SetCommMask(hPort,0);
  
  //阻塞至線程停止
  
  if(hReadThread)
  
  {
  
  TerminateThread(hReadThread,0);
  
  CloseHandle(hReadThread);

  }
  
  //清除端口上指定信號的狀態
  
  EscapeCommFunction(hPort,CLRDTR);
  
  EscapeCommFunction(hPort,CLRRTS);
  
  //清除驅動程序內部的發送和接收隊列
  
  PurgeComm(hPort,PURGE_TXCLEAR|PURGE_RXCLEAR);
  
  //關閉串口
  
  CloseHandle (hCommPort);
  
  hCommPort = INVALID_HANDLE_VALUE;
  
  return TRUE;
  
  }
  
  else

  {
  
  return TRUE;
  
  }
  
  }
  
  BOOL CSerial::InitDCB()
  
  {

  DCB PortDCB;
  
  DWORD dwError;
  
  PortDCB.DCBlength = sizeof (DCB);
  
  //得到端口的默認設置信息
  
  GetCommState (hPort, &PortDCB);

  //改變DCB結構設置
  
  PortDCB.BaudRate = 19200; //波特率
  
  PortDCB.fBinary = TRUE; //Win32不支持非二進制串行傳輸模式,必須為TRUE

  PortDCB.fParity = TRUE; //啟用奇偶校驗
  
  PortDCB.fOutxCtsFlow = TRUE; //串行端口的輸出由CTS線控制
  
  PortDCB.fOutxDsrFlow = FALSE;//關閉串行端口的DSR流控制

  PortDCB.fDtrControl = DTR_CONTROL_ENABLE; //啟用DTR線
  
  PortDCB.fDsrSensitivity = FALSE; //如果設為TRUE將忽略任何輸入的字節,除非DSR線被啟用
  
  //PortDCB.fTXContinueOnXoff = TRUE;//當為TRUE時,如果接收緩沖區已滿且驅動程序已傳送XOFF字符,將使驅動程序停止傳輸字符
  
  PortDCB.fTXContinueOnXoff = FALSE;
  
  PortDCB.fOutX = FALSE;//設為TRUE指定XON/XOFF控制被用於控制串行輸出
  
  PortDCB.fInX = FALSE; //設為TRUE指定XON/XOFF控制被用於控制串行輸入
  
  PortDCB.fErrorChar = FALSE;//WINCE串行驅動程序的默認執行將忽略這個字段
  
  PortDCB.fNull = FALSE;//設為TRUE將使串行驅動程序忽略收到的空字節
  
  PortDCB.fRtsControl = RTS_CONTROL_ENABLE; //啟用RTS線
  
  PortDCB.fAbortOnError = FALSE; //WINCE串行驅動程序的默認執行將忽略這個字段
  
  PortDCB.ByteSize = 8; //每字節的位數
  
  PortDCB.Parity = NOPARITY;//無奇偶校驗
  
  PortDCB.StopBits = ONESTOPBIT; //每字節一位停止位
    
  //根據DCB結構配置端口

  if (!SetCommState (hPort, &PortDCB))
    
  {
    
  //不能配置串行端口

  MessageBox (NULL, TEXT("Unable to configure the serial port"),
  
  TEXT("Error"), MB_OK);
  
  dwError = GetLastError ();
  
  return FALSE;
  
  }
  
  return TRUE;
  
  }
  
  BOOL CSerial::InitCommTimeouts()
    
  {
  
  COMMTIMEOUTS CommTimeouts;
  
  DWORD dwError;
  
  //得到超時參數
  
  GetCommTimeouts (hPort, &CommTimeouts);
  
  //改變COMMTIMEOUTS結構設置

  CommTimeouts.ReadIntervalTimeout = MAXDWORD;
  
  CommTimeouts.ReadTotalTimeoutMultiplier = 0;
  
  CommTimeouts.ReadTotalTimeoutConstant = 0;
  
  CommTimeouts.WriteTotalTimeoutMultiplier = 10;
  
  CommTimeouts.WriteTotalTimeoutConstant = 1000;
  
  //設置端口超時值
  
  if (!SetCommTimeouts (hPort, &CommTimeouts))
  
  {
  
  //不能設置超時值
  
  MessageBox (NULL, TEXT("Unable to set the time-out parameters"),

  TEXT("Error"), MB_OK);
  
  dwError = GetLastError ();
  
  return FALSE;
  
  }
  
  return TRUE;
  
  }
  
  以上類代碼在eMbedded Visual C++4.0和基於ARM9的三星S3C2410開發板(運行Windows CE.NET 4.1)上測試通過。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved