VC實現串口通訊常式 作者:阮幫秋

來源:互聯網
上載者:User
VC實現串口通訊常式 作者:阮幫秋 發布時間:2001/04/19
 
文章摘要:
  WIN95介面下的VC++串口通訊程式在WIN32下是不建議對連接埠進行操作的,在WIN32中所有的裝置都被看成是檔案,串列口也不例外也是作為檔案來進行處理的。
  關鍵詞 串列口,DWORD,緩衝區

       

本文:  


VC實現串口通訊常式 


  WIN95介面下的VC++串口通訊程式在WIN32下是不建議對連接埠進行操作的,在WIN32中所有的裝置都被看成是檔案,串列口也不例外也是作為檔案來進行處理的。這是我的一份關於串口編程的讀書筆記,對於使 用VC進行編程的同行應該有一定的協助。

1.開啟串口:

  在Window 95下串列口作為檔案處理,使用檔案操作對串列口進行處理。使用CreateFile()開啟串口,CreateFile()將返回串口的控制代碼。
  HANDLE CreateFile(
  LPCTSTR lpFileName, // pointer to name of the file
  DWORD dwDesiredAccess, // access (read-write) mode
  DWORD dwShareMode, // share mode
  LPSECURITY_ATTRIBUTES lpSecurityAttributes, // pointer to security attributes
  DWORD dwCreationDistribution, // how to create
  DWORD dwFlagsAndAttributes, // file attributes
  HANDLE hTemplateFile // handle to file with attributes to copy
  );
  lpFileName: 指明串口製備,例:COM1,COM2
  dwDesiredAccess: 指明串口存取方式,例:GENERIC_READ|GENERIC_WRITE
  dwShareMode: 指明串口共用方式
  lpSecurityAttributes: 指明串口的安全屬性結構,NULL為預設安全屬性
  dwCreateionDistribution: 必須為OPEN_EXISTIN
  dwFlagAndAttributes: 對串口唯一有意義的是FILE_FLAG_OVERLAPPED
  hTemplateFile: 必須為NULL

2.關閉串口:

  CloseHandle(hCommDev);

3.設定緩衝區長度:

  BOOL SetupComm(
  HANDLE hFile, // handle of communications device
  DWORD dwInQueue, // size of input buffer
  DWORD dwOutQueue // size of output buffer
  );

4.COMMPROP結構:

  可使用GetCommProperties()取得COMMPROP結構,COMMPROP結構中記載了系統支援的各項設定。
  typedef struct _COMMPROP { // cmmp
  WORD wPacketLength; // packet size, in bytes
  WORD wPacketVersion; // packet version
  DWORD dwServiceMask; // services implemented
  DWORD dwReserved1; // reserved
  DWORD dwMaxTxQueue; // max Tx bufsize, in bytes
  DWORD dwMaxRxQueue; // max Rx bufsize, in bytes
  DWORD dwMaxBaud; // max baud rate, in bps
  DWORD dwProvSubType; // specific provider type
  DWORD dwProvCapabilities; // capabilities supported
  DWORD dwSettableParams; // changeable parameters
  DWORD dwSettableBaud; // allowable baud rates
  WORD wSettableData; // allowable byte sizes
  WORD wSettableStopParity; // stop bits/parity allowed
  DWORD dwCurrentTxQueue; // Tx buffer size, in bytes
  DWORD dwCurrentRxQueue; // Rx buffer size, in bytes
  DWORD dwProvSpec1; // provider-specific data
  DWORD dwProvSpec2; // provider-specific data
  WCHAR wcProvChar[1]; // provider-specific data
  } COMMPROP;
  dwMaxBaud:
  BAUD_075 75 bps
  BAUD_110 110 bps
  BAUD_134_5 134.5 bps
  BAUD_150 150 bps
  BAUD_300 300 bps
  BAUD_600 600 bps
  BAUD_1200 1200 bps
  BAUD_1800 1800 bps
  BAUD_2400 2400 bps
  BAUD_4800 4800 bps
  BAUD_7200 7200 bps
  BAUD_9600 9600 bps
  BAUD_14400 14400 bps
  BAUD_19200 19200 bps
  BAUD_38400 38400 bps
  BAUD_56K 56K bps
  BAUD_57600 57600 bps
  BAUD_115200 115200 bps
  BAUD_128K 128K bps
  BAUD_USER Programmable baud rates available
  dwProvSubType:
  PST_FAX 傳真裝置
  PST_LAT LAT協議
  PST_MODEM 數據機裝置
  PST_NETWORK_BRIDGE 未指定的橋接器
  PST_PARALLELPORT 並口
  PST_RS232 RS-232口
  PST_RS422 RS-422口
  PST_RS423 RS-432口
  PST_RS449 RS-449口
  PST_SCANNER 掃描器裝置
  PST_TCPIP_TELNET TCP/IP Telnet協議
  PST_UNSPECIFIED 未指定
  PST_X25 X.25標準
  dwProvCapabilities
  PCF_16BITMODE 支援特殊的16位元模式
  PCF_DTRDSR 支援DTR(資料終端機就緒)/DSR(資料裝置就緒)
  PCF_INTTIMEOUTS 支援區間逾時
  PCF_PARITY_CHECK 支援同位
  PCF_RLSD 支援RLSD(接收線訊號檢測)
  PCF_RTSCTS 支援RTS(請求發送)/CTS(清除發送)
  PCF_SETXCHAR 支援可設定的XON/XOFF
  PCF_SPECIALCHARS 支援特殊字元
  PCF_TOTALTIMEOUTS 支援總(佔用時間)逾時
  PCF_XONXOFF 支援XON/XOFF流量控制
  標準RS-232和WINDOW支援除PCF_16BITMODE和PCF_SPECIALCHAR外的所有功能
  dwSettableParams
  SP_BAUD 可配置傳輸速率
  SP_DATABITS 可配置資料位元個數
  SP_HANDSHAKING 可配置握手(流量控制)
  SP_PARITY 可配置同位模式
  SP_PARITY_CHECK 可配置同位允許/禁止
  SP_RLSD 可配置RLSD(接收訊號檢測)
  SP_STOPBITS 可配置停止位個數
  標準RS-232和WINDOW支援以上所有功能
  wSettableData
  DATABITS_5 5個資料位元
  DATABITS_6 6個資料位元
  DATABITS_7 7個資料位元
  DATABITS_8 8個資料位元
  DATABITS_16 16個資料位元
  DATABITS_16X 通過串列硬體線路的特殊寬度路徑
  WINDOWS 95支援16的所有設定

5.DCB結構:

  typedef struct _DCB {// dcb
  DWORD DCBlength; // sizeof(DCB)
  DWORD BaudRate; // current baud rate
  指定當前的傳輸速率
  DWORD fBinary: 1; // binary mode, no EOF check
  指定是否允許二進位模式,
  WINDOWS 95中必須為TRUE
  DWORD fParity: 1; // enable parity checking
  指定同位是否允許
  DWORD fOutxCtsFlow:1; // CTS output flow control
  指定CTS是否用於檢測發送控制。
  當為TRUE是CTS為OFF,發送將被掛起。
  DWORD fOutxDsrFlow:1; // DSR output flow control
  指定CTS是否用於檢測發送控制。
  當為TRUE是CTS為OFF,發送將被掛起。
  DWORD fDtrControl:2; // DTR flow control type
  DTR_CONTROL_DISABLE值將DTR置為OFF, DTR_CONTROL_ENABLE值將DTR置為ON, DTR_CONTROL_HANDSHAKE允許DTR"握手",DWORD fDsrSensitivity:1; // DSR sensitivity 當該值為TRUE時DSR為OFF時接收的位元組被忽略
  DWORD fTXContinueOnXoff:1; // XOFF continues Tx
  指定當接收緩衝區已滿,並且驅動程式已經發
  送出XoffChar字元時發送是否停止。
  TRUE時,在接收緩衝區接收到緩衝區已滿的位元組XoffLim且驅動程式已經發送出XoffChar字元中止接收位元組之後,發送繼續進行。
  FALSE時,在接收緩衝區接收到代表緩衝區已空的位元組XonChar且驅動程式已經發送出恢複發送的XonChar之後,發送繼續進行。
  DWORD fOutX: 1; // XON/XOFF out flow control
  TRUE時,接收到XoffChar之後便停止發送
  接收到XonChar之後將重新開始
  DWORD fInX: 1; // XON/XOFF in flow control
  TRUE時,接收緩衝區接收到代表緩衝區滿的XoffLim之後,XoffChar發送出去
  接收緩衝區接收到代表緩衝區空的XonLim之後,XonChar發送出去
  DWORD fErrorChar: 1; // enable error replacement
  該值為TRUE且fParity為TRUE時,用ErrorChar 成員指定的字元代替同位錯誤的接收字元
  DWORD fNull: 1; // enable null stripping
  TRUE時,接收時去掉空(0值)位元組
  DWORD fRtsControl:2; // RTS flow control
  RTS_CONTROL_DISABLE時,RTS置為OFF
  RTS_CONTROL_ENABLE時, RTS置為ON
  RTS_CONTROL_HANDSHAKE時,
  當接收緩衝區小於半滿時RTS為ON
  當接收緩衝區超過四分之三滿時RTS為OFF
  RTS_CONTROL_TOGGLE時,
  當接收緩衝區仍有剩餘位元組時RTS為ON ,否則預設為OFF
  DWORD fAbortOnError:1; // abort reads/writes on error
  TRUE時,有錯誤發生時中止讀和寫操作
  DWORD fDummy2:17; // reserved
  未使用
  WORD wReserved; // not currently used
  未使用,必須為0
  WORD XonLim; // transmit XON threshold
  指定在XON字元發送這前接收緩衝區中可允許的最小位元組數
  WORD XoffLim; // transmit XOFF threshold
  指定在XOFF字元發送這前接收緩衝區中可允許的最小位元組數
  BYTE ByteSize; // number of bits/byte, 4-8
  指定連接埠當前使用的資料位元
  BYTE Parity; // 0-4=no,odd,even,mark,space
  指定連接埠當前使用的同位方法,可能為:
  EVENPARITY,MARKPARITY,NOPARITY,ODDPARITY
  BYTE StopBits; // 0,1,2 = 1, 1.5, 2
  指定連接埠當前使用的停止位元,可能為:
  ONESTOPBIT,ONE5STOPBITS,TWOSTOPBITS
  char XonChar; // Tx and Rx XON character
  指定用於發送和接收字元XON的值
  char XoffChar; // Tx and Rx XOFF character
  指定用於發送和接收字元XOFF值
  char ErrorChar; // error replacement character
  本字元用來代替接收到的同位發生錯誤時的值
  char EofChar; // end of input character
  當沒有使用二進位模式時,本字元可用來指示資料的結束
  char EvtChar; // received event character
  當接收到此字元時,會產生一個事件
  WORD wReserved1; // reserved; do not use 未使用
  } DCB;

6.改變連接埠設定

  使用如下的兩個方法
  BOOL GetCommState(hComm,&dcb);
  BOOL SetCommState(hComm,&dcb);

7.改變普通設定

  BuildCommDCB(szSettings,&DCB);
  szSettings的格式:baud parity data stop
  例: "baud=96 parity=n data=8 stop=1"
  簡寫:"96,N,8,1"
  szSettings 的有效值
  baud:
  11 or 110 = 110 bps
  15 or 150 = 150 bps
  30 or 300 = 300 bps
  60 or 600 = 600 bps
  12 or 1200 = 1200 bps
  24 or 2400 = 2400 bps
  48 or 4800 = 4800 bps
  96 or 9600 = 9600 bps
  19 or 19200= 19200bps
  parity:
  n=none
  e=even
  o=odd
  m=mark
  s=space
  data:
  5,6,7,8
  StopBit
  1,1.5,2

8.COMMCONFIG結構:

  typedef struct _COMM_CONFIG {
  DWORD dwSize;
  WORD wVersion;
  WORD wReserved;
  DCB dcb;
  DWORD dwProviderSubType;
  DWORD dwProviderOffset;
  DWORD dwProviderSize;
  WCHAR wcProviderData[1];
  } COMMCONFIG, *LPCOMMCONFIG;
  可方便的使用BOOL CommConfigDialog(
  LPTSTR lpszName,
  HWND hWnd,
  LPCOMMCONFIG lpCC);
  來設定串列口。

9.逾時設定:

  可通過COMMTIMEOUTS結構設定逾時,
  typedef struct _COMMTIMEOUTS {
  DWORD ReadIntervalTimeout;
  DWORD ReadTotalTimeoutMultiplier;
  DWORD ReadTotalTimeoutConstant;
  DWORD WriteTotalTimeoutMultiplier;
  DWORD WriteTotalTimeoutConstant;
  } COMMTIMEOUTS,*LPCOMMTIMEOUTS;
  區間逾時:(僅對從連接埠中讀取資料有用)它指定在讀取兩個字元之間要經曆的時間
  總逾時: 當讀或寫特定的位元組數需要的總時間超過某一閾值時,逾時觸發.
  逾時公式:
  ReadTotalTimeout = (ReadTotalTimeoutMultiplier * bytes_to_read)
  + ReadToTaltimeoutConstant
  WriteTotalTimeout = (WriteTotalTimeoutMuliplier * bytes_to_write)
  + WritetoTotalTimeoutConstant
  NOTE:在設定逾時時參數0為無限等待,既無逾時
  參數MAXDWORD為立即返回
  逾時設定:
  GetCommTimeouts(hComm,&timeouts);
  SetCommTimeouts(hComm,&timeouts);

10.查詢方式讀寫資料

  常式:
  COMMTIMEOUTS to;
  DWORD ReadThread(LPDWORD lpdwParam)
  {
  BYTE inbuff[100];
  DWORD nBytesRead;
  if(!(cp.dwProvCapabilities&PCF_INTTIMEOUTS))
  return 1L;
  memset(&to,0,sizeof(to));
  to.ReadIntervalTimeout = MAXDWORD;
  SetCommTimeouts(hComm,&to);
  while(bReading)
  {
  if(!ReadFile(hComm,inbuff,100,&nBytesRead,NULL))
  locProcessCommError(GetLastError());
  else
  if(nBytesRead)
  locProcessBytes(inbuff,nBytesRead);
  }
  PurgeComm(hComm,PURGE_RXCLEAR);
  return 0L;
  }
  NOTE:
  PurgeComm()是一個清除函數,它可以中止任何未決的後台讀或寫,並且可以衝掉I/O緩衝區.
  BOOL PurgeComm(HANDLE hFile,DWORD dwFlags);
  dwFlages的有效值:
  PURGE_TXABORT: 中止後台寫操作
  PRUGE_RXABORT: 中止後台讀操作
  PRUGE_TXCLEAR: 清除發送緩衝區
  PRUGE_RXCLEAR: 清除接收緩衝區
  技巧:
  可通過ClearCommError()來確定接收緩區中處於等待的位元組數。
  BOOL ClearCommError(
  HANDLE hFile, // handle to communications device
  LPDWORD lpErrors, // pointer to variable to receive error codes
  LPCOMSTAT lpStat // pointer to buffer for communications status
  );
  ClearCommError()將返回一個COMSTAT結構:
  typedef struct _COMSTAT { // cst
  DWORD fCtsHold : 1; // Tx waiting for CTS signal
  DWORD fDsrHold : 1; // Tx waiting for DSR signal
  DWORD fRlsdHold : 1; // Tx waiting for RLSD signal
  DWORD fXoffHold : 1; // Tx waiting, XOFF char rec`d
  DWORD fXoffSent : 1; // Tx waiting, XOFF char sent
  DWORD fEof : 1; // EOF character sent
  DWORD fTxim : 1; // character waiting for Tx
  DWORD fReserved : 25; // reserved
  DWORD cbInQue; // bytes in input buffer
  DWORD cbOutQue; // bytes in output buffer
  } COMSTAT, *LPCOMSTAT;
  其中的cbInQue和cbOutQue中即為緩衝區位元組。

11.同步I/O讀寫資料

  COMMTIOMOUTS to;
  DWORD ReadThread(LPDWORD lpdwParam)
  {
  BYTE inbuff[100];
  DWORD nByteRead,dwErrorMask,nToRead;
  COMSTAT comstat;
  if(!cp.dwProvCapabilities&PCF_TOTALTIMEOUTS)
  return 1L;
  memset(&to,0,sizeof(to));
  to.ReadTotalTimeoutMultiplier = 5;
  to.ReadTotalTimeoutConstant = 50;
  SetCommTimeouts(hComm,&to);
  while(bReading)
  {
  ClearCommError(hComm,&dwErrorMask,&comstat);
  if(dwErrorMask)
  locProcessCommError(dwErrorMask);
  if(comstat.cbInQue >100)
  nToRead = 100;
  else
  nToRead = comstat.cbInQue;
  if(nToRead == 0)
  continue;
  if(!ReadFile(hComm,inbuff,nToRead,&nBytesRead,NULL))
  locProcessCommError(GetLastError());
  else
  if(nBytesRead)
  locProcessBytes(inbuff,nBytesRead);
  }
  return 0L;
  }

12.非同步I/O讀寫資料

  當CreateFile()中的fdwAttrsAndFlags參數為FILE_FLAG_OVERLAPPEN時, 連接埠是為非同步I/O開啟的,此時可以在ReadFile的最後一個參數中指定一個OVERLAPPED結構,使資料的讀操作在後台進行。WINDOWS 95包括了非同步I/O的許多變種。
  typedef struct _OVERLAPPED {
  DWORD Internal;
  DWORD InternalHigh;
  DWORD Offset;
  DWORD OffsetHigh;
  HANDLE hEvent;
  } OVERLAPPED;
  對於串列口僅hEvent成員有效,其於成員必須為0。
  常式:
  COMMTIMEOUTS to;
  ...
  DWORD ReadThread((LPDWORD lpdwParam)
  {
  BYTE inbuff[100];
  DWORD nRytesRead,endtime,lrc;
  static OVERLAPPED o;
  if(!cp.dwProvCapabilities & PCF_TOTALTIMEOUTS)
  return 1L;
  memset(&to,0,sizeof(to));
  to.ReadTotalTimeoutMultiplier = 5;
  to.ReadTotalTimeoutConstant = 1000;
  SetCommTimeouts(hComm,&to);
  o.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
  while(bReading)
  {
  if(!ReadFile(hComm,inbuff,10,&nBytesRead,&o))
  {
  nBytesRead = 0;
  if(lrc=GetLastError() == ERROR_IO_PENDING)
  {
  endtime = GetTickCount() + 1000;
  while(!GetOverlappedResult(hComm,&o,&nBytesRead,FALSE))
  if(GetTickCount() > endtime) break;
  }
  if(nBytesRead) locProcessBytes(inbuff,nBytesRead);
  }
  else
  {
  if(nBytesRead) locProcessBytes(inbuff,nBytesRead);
  ResetEvent(o.hEvent);
  }
  }
  PurgeComm(hComm,PURGE_RXCLEAR);
  return 0L;
  }
  這一常式是對一開始讀緩衝區就讀到所需的位元組時的處理:
  while(bReading)
  {
  if(!ReadFile(hComm,inbuff,10,&nBytesRead,&o))
  {
  if((lrc=GetLastError()) ==ERROR_IO_PENDING)
  {
  if(GetOverlappedResult(hComm,&o,&nBytesRead,TRUE))
  {
  if(nBytesRead)
  locProcessBytesa(inbuff,nBytesRead);
  }
  else
  locProcessCommError(GetLastError());
  }
  else
  locProcessCommError(GetLastError));
  }
  else
  if(nBytesRead) locProcessBytes(inbuff,nBytesRead);
  ResetEvent(o.hEvent);
  }

13.事件驅I/O讀寫:

  GetCommMask(hComm,&dwMask)
  Windows 95報告給應用程式的事件由此方法返回。
  SetCommMasl(hComm,&dwMask)
  添加或修改Windows 95所報告的事件列表。
  事件掩碼如下:
  EV_BREAK 檢測到輸入為止
  EV_CTS CTS(清除發送)訊號改變狀態
  EV_DSR DSR(資料設定就緒)訊號改變狀態
  EV_ERR 發生了線路狀態錯誤.
  線路狀態錯誤為:
  CE_FRAME(幀錯誤)
  CE_OVERRUN(接收緩衝區超限)
  CE_RXPARITY(同位錯誤)
  EV_RING 檢測到響鈴
  EV_RLSD RLSD(接收線路訊號檢測)訊號改變狀態
  EV_EXCHAR 接收到一個字元,並放入輸入緩衝區
  EV_RXFLAG 接收到事件字元(DCB成員的EvtChar成員),度放入輸入緩衝區
  EV_TXEMPTY 輸出緩衝區中最後一個字元發送出去
  在用SetCommMask指定了有用的事件後,應用程式可調用WaitCommEvent()來等待事件發生.
  BOOL WaitCommEvent(
  HANDLE hFile, // handle of communications device
  LPDWORD lpEvtMask, // address of variable for event that occurred
  LPOVERLAPPED lpOverlapped, // address of overlapped structure
  );
  此方法可以以同步或非同步方式操作
  常式:
  COMMTIMEOUTS to;
  ...
  DWORD ReadTherad(LPDWORD lpdwParam)
  {
  BYTE binbuff[100];
  DWORD nBytesRead,dwEvent,dwError;
  COMSTAT cs;
  SetCommMask(hComm,EV_RXHAR);
  while(bReading)
  {
  if(WaitCommEvent(hComm,&dwEvent,NULL))
  {
  ClearCommError(hComm,&dwError,&cs);
  if((dwEvent&EV_RXCHAR)&&cs.cbInQue)
  {
  if(!ReadFile(hComm,inbuff,cs.cbInQue,&nBytesRead,NULL)
  locProcessCommError(GetLastError());
  }
  else
  {
  if(nByteRead)
  locProcessBytes(inbuff,nBytesRead);
  }
  else
  locProcessCommError(GetLastError());
  }
  PurgeComm(hComm,PURGE_RXCLEAR);
  return 0L;
  }
  NOTE: SetCommMask(hComm,0)可使WaitCommEvent()中止.
  可使用GetCommmodemStatus()方法,常式:
  if(cp.dwProvCapabilities&PCF_RTSCTS)
  {
  SetCommMask(hComm,EV_CTS);
  WaitCommEvent(hComm,&dwMask,NULL);
  if(dwMask&EV_CTS)
  {
  GetCommModemStatus(hComm,&dwStatus)
  if(dwStatus&MS_CTS_ON) /* CTS stransition OFF-ON */
  else /* CTS stransition ON-OFF */
  }
  }
  MS_CTS_ON CTS為ON
  MS_DSR_ON DSR為ON
  MS_RING_ON RING為ON
  MS_ELSD_ON RLSD為ON

14.錯誤

  當發生錯誤時應用方法ClearCommError(hComm,&dwErrorMask,&constat)得到錯誤掩碼。
  CE_BREAK 中止條件
  CE_FRAME 幀錯誤
  CW_IOE 一般I/O錯誤,常伴有更為詳細的錯誤標誌
  CE_MODE 不支援要求的模式
  CE_OVERRUN 緩衝區超限下一個字元將丟失
  CE_RXOVER 接收緩衝區超限
  CE_RXPARITY 同位錯誤
  CE_TXFULL 發送緩衝區滿
  CE_DNS 沒有選擇平行裝置
  CE_PTO 平行裝置發生逾時
  CE_OOP 平行裝置缺紙

15.控制命令

  EscapeCommFunction()可將硬體訊號置ON或OFF,類比XON或XOFF

  BOOL EscapeCommFunction(
  HANDLE hFile, // handle to communications device
  DWORD dwFunc // extended function to perform
  );
  dwFunc的有效值(可用'|'同時使用多個值)
  CLRDTR DTR置OFF
  CLRRTS RTS置OFF
  SETDTR STR置ON
  SETRTS TRS置ON
  SETXOFF 類比XOFF字元的接收
  SETXON 類比XON字元的接收
  SETBREAK 在發送中產生一個中止
  CLRBREAK 在發送中清除中止

作者會員名:ruan_bangqiu

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.