VC++串口通讯

在VC++中有两种方法可以进行串口通讯。一种是利用Microsoft公司提供的ActiveX控件 Microsoft Communications Control。另一种是直接用VC++访问串口。下面将简述这两种方法。

  一、Microsoft Communications Control
  Microsoft公司在WINDOWS中提供了一个串口通讯控件,用它,我们可以很简单的利用串口进行通讯。在使用它之前,应将控件加在应用程序的对话框上。然后再用ClassWizard 生成相应的对象。现在我们可以使用它了。

  该控件有很多自己的属性,你可以通过它的属性窗口来设置,也可以用程序设置。我推荐用程序设置,这样更灵活。

   SetCommPort:指定使用的串口。
   GetCommPort:得到当前使用的串口。
   SetSettings:指定串口的参数。一般设为默认参数"9600,N,8,1"。这样方便与其他串口进行通讯。
   GetSettings:取得串口参数。
   SetPortOpen:打开或关闭串口,当一个程序打开串口时,另外的程序将无法使用该串口。
   GetPortOpen:取得串口状态。
   GetInBufferCount:输入缓冲区中接受到的字符数。
   SetInPutLen:一次读取输入缓冲区的字符数。设置为0时,程序将读取缓冲区的全部字符。
   GetInPut:读取输入缓冲区。
   GetOutBufferCount:输出缓冲区中待发送的字符数。
   SetOutPut:写入输出缓冲区。

  一般而言,使用上述函数和属性就可以进行串口通讯了。以下是一个范例。

[cpp]  view plain copy
  1. #define MESSAGELENGTH 100  
  2. class CMyDialog : public CDialog  
  3. {  
  4. protected:   
  5. VARIANT InBuffer;  
  6. VARIANT OutBuffer;  
  7. CMSComm m_Com;  
  8. public:  
  9. ......  
  10. }  
  11.   
  12. BOOL CMyDiaLog::OnInitDialog()  
  13. {  
  14. CDialog::OnInitDialog();  
  15. m_Com.SetCommPort(1);  
  16. if (!m_Com.GetPortOpen()) {  
  17. m_Com.SetSettings("57600,N,8,1");  
  18. m_Com.SetPortOpen(true);  
  19. m_Com.SetInBufferCount(0);  
  20. SetTimer(1,10,NULL);  
  21. InBuffer.bstrVal=new unsigned short[MESSAGELENGTH];  
  22. OutBuffer.bstrVal=new unsigned short[MESSAGELENGTH];  
  23. OutBuffer.vt=VT_BSTR;  
  24. }  
  25. return true;  
  26. }  
  27.   
  28. void CMyDiaLog::OnTimer(UINT nIDEvent)   
  29. {  
  30. if (m_Com.GetInBufferCount()>=MESSAGELENGTH) {  
  31. InBuffer=m_Com.GetInput();  
  32. // handle the InBuffer.   
  33. // Fill the OutBuffer.   
  34. m_Com.SetOutput(OutBuffer);  
  35. }  
  36. CDialog::OnTimer(nIDEvent);  
  37. }  

二、直接用VC++访问串口。
  用该控件传输的数据是UNICODE格式。关于UNICODE和ANSI的关系和转换请参看MSDN。 
  关于该控件的其他详细资料请查看MSDN关于COMM CONTROL部分。

  在VC++中,串口和磁盘文件可以统一的方式来简单读写。这两者几乎没有什么不同,只是在WINDOWS 9X下磁盘文件只能做同步访问,而串口只能做异步访问。
  CreateFile:用指定的方式打开指定的串口。通常的方式为

  m_hCom = CreateFile( "COM1", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL );
  m_hCom为文件句柄。GENERIC_READ | GENERIC_WRITE指定可以对串口进行读写操作。第三个参数0表示串口为独占打开。OPEN_EXISTING表示当指定串口不存在时,程序将返回失败。 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED则表示文件属性。当打开串口时,必须指定 FILE_FLAG_OVERLAPPED,它表示文件或设备不会维护访问指针,则在读写时,必须使用OVERLAPPED 结构指定访问的文件偏移量。

   ReadFile:读取串口数据。
   WriteFile:向串口写数据。
   CloseHandle:关闭串口。
  COMMTIMEOUTS:COMMTIMEOUTS主要用于串口超时参数设置。COMMTIMEOUTS结构如下:

[cpp]  view plain copy
  1. typedef struct _COMMTIMEOUTS {   
  2. DWORD ReadIntervalTimeout;   
  3. DWORD ReadTotalTimeoutMultiplier;   
  4. DWORD ReadTotalTimeoutConstant;   
  5. DWORD WriteTotalTimeoutMultiplier;   
  6. DWORD WriteTotalTimeoutConstant;   
  7. } COMMTIMEOUTS,*LPCOMMTIMEOUTS;   

  ReadIntervalTimeout:两字符之间最大的延时,当读取串口数据时,一旦两个字符传输的时间差超过该时间,读取函数将返回现有的数据。设置为0表示该参数不起作用。 
  ReadTotalTimeoutMultiplier:读取每字符间的超时。
  ReadTotalTimeoutConstant:一次读取串口数据的固定超时。所以在一次读取串口的操作中,其超时为ReadTotalTimeoutMultiplier乘以读取的字节数再加上ReadTotalTimeoutConstant。将ReadIntervalTimeout设置为MAXDWORD,并将ReadTotalTimeoutMultiplier 和ReadTotalTimeoutConstant设置为0,表示读取操作将立即返回存放在输入缓冲区的字符。
  WriteTotalTimeoutMultiplier:写入每字符间的超时。
  WriteTotalTimeoutConstant:一次写入串口数据的固定超时。所以在一次写入串口的操作中,其超时为WriteTotalTimeoutMultiplier乘以写入的字节数再加上 WriteTotalTimeoutConstant。
  SetCommTimeouts函数可以设置某设备句柄的超时参数,要得到某设备句柄的超时参数可以用GetCommTimeouts函数。
  DCB:DCB结构主要用于串口参数设置。该结构太庞大,这里就不一一讲述了,有兴趣者可查看MSDN关于DCB的描述。其中下面两个是比较重要的属性。
  BaudRate:串口的通讯速度。一般设置为9600。
  ByteSize:字节位数。一般设置为8。

  DCB结构可以用SetCommState函数来设置,并可以用GetCommState来得到现有串口的属性。
  SetupComm:设置串口输入、输出缓冲区。
  OVERLAPPED:保存串口异步通讯的信息。具体结构如下:

[cpp]  view plain copy
  1. typedef struct _OVERLAPPED {   
  2. DWORD Internal;   
  3. DWORD InternalHigh;   
  4. DWORD Offset;   
  5. DWORD OffsetHigh;   
  6. HANDLE hEvent;   
  7. } OVERLAPPED;   

  Internal,InternalHigh是保留给系统使用的,用户不需要设置。
  Offset,OffsetHigh是读写串口的偏移量,一般设置OffsetHigh为NULL,可以支持2GB数据。
  hEvent读写事件,因为串口是异步通讯,操作可能被其他进程堵塞,程序可以通过检查该时间来得知是否读写完毕。事件将在读写完成后,自动设置为有效。

  通过以上这些函数和结构,我们就可以通过串口进行通讯了,现在我们具体看下面的实例:

[cpp]  view plain copy
  1. BOOL CSerial::Open( int nPort, int nBaud )  
  2. {  
  3. if( m_bOpened ) return( TRUE );  
  4.   
  5. char szPort[15];  
  6. DCB dcb;  
  7.   
  8. wsprintf( szPort, "COM%d", nPort );  
  9. m_hComDev = CreateFile( szPort, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL );  
  10. if( m_hComDev == NULL ) return( FALSE );  
  11.   
  12. memset( &m_OverlappedRead, 0, sizeof( OVERLAPPED ) );  
  13. memset( &m_OverlappedWrite, 0, sizeof( OVERLAPPED ) );  
  14.   
  15. COMMTIMEOUTS CommTimeOuts;  
  16. CommTimeOuts.ReadIntervalTimeout = 0xFFFFFFFF;  
  17. CommTimeOuts.ReadTotalTimeoutMultiplier = 0;  
  18. CommTimeOuts.ReadTotalTimeoutConstant = 0;  
  19. CommTimeOuts.WriteTotalTimeoutMultiplier = 0;  
  20. CommTimeOuts.WriteTotalTimeoutConstant = 5000;  
  21. SetCommTimeouts( m_hComDev, &CommTimeOuts );  
  22.   
  23. m_OverlappedRead.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );  
  24. m_OverlappedWrite.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );  
  25.   
  26. dcb.DCBlength = sizeof( DCB );  
  27. GetCommState( m_hComDev, &dcb );  
  28. dcb.BaudRate = nBaud;  
  29. dcb.ByteSize = 8;  
  30. if( !SetCommState( m_hComDev, &dcb ) ||!SetupComm( m_hComDev, 10000, 10000 ) ||  
  31. m_OverlappedRead.hEvent == NULL ||m_OverlappedWrite.hEvent == NULL ){  
  32. DWORD dwError = GetLastError();  
  33. if( m_OverlappedRead.hEvent != NULL ) CloseHandle( m_OverlappedRead.hEvent );  
  34. if( m_OverlappedWrite.hEvent != NULL ) CloseHandle( m_OverlappedWrite.hEvent );  
  35. CloseHandle( m_hComDev );  
  36. return FALSE;  
  37. }  
  38.   
  39. m_bOpened = TRUE;  
  40.   
  41. return m_bOpened;  
  42.   
  43. }  
  44.   
  45. int CSerial::InBufferCount( void )  
  46. {  
  47.   
  48. if( !m_bOpened || m_hComDev == NULL ) return( 0 );  
  49.   
  50. DWORD dwErrorFlags;  
  51. COMSTAT ComStat;  
  52.   
  53. ClearCommError( m_hIDComDev, &dwErrorFlags, &ComStat );  
  54.   
  55. return (int)ComStat.cbInQue;  
  56. }  
  57.   
  58. DWORD CSerial::ReadData( void *buffer, DWORD dwBytesRead)  
  59. {  
  60. if( !m_bOpened || m_hComDev == NULL ) return 0;  
  61.   
  62. BOOL bReadStatus;  
  63. DWORD dwErrorFlags;  
  64. COMSTAT ComStat;  
  65.   
  66. ClearCommError( m_hComDev, &dwErrorFlags, &ComStat );  
  67. if( !ComStat.cbInQue ) return 0;  
  68.   
  69. dwBytesRead = min(dwBytesRead,(DWORD) ComStat.cbInQue);  
  70.   
  71. bReadStatus = ReadFile( m_hComDev, buffer, dwBytesRead, &dwBytesRead, &m_OverlappedRead );  
  72. if( !bReadStatus ){  
  73. if( GetLastError() == ERROR_IO_PENDING ){  
  74. WaitForSingleObject( m_OverlappedRead.hEvent, 2000 );  
  75. return dwBytesRead;  
  76. }  
  77. return 0;  
  78. }  
  79.   
  80. return dwBytesRead;  
  81. }  
  82.   
  83. DWORD CSerial::SendData( const char *buffer, DWORD dwBytesWritten)  
  84. {  
  85. if( !m_bOpened || m_hComDev == NULL ) return( 0 );  
  86.   
  87. BOOL bWriteStat;  
  88.   
  89. bWriteStat = WriteFile( m_hComDev, buffer, dwBytesWritten, &dwBytesWritten, &m_OverlappedWrite );  
  90. if( !bWriteStat){  
  91. if ( GetLastError() == ERROR_IO_PENDING ) {  
  92. WaitForSingleObject( m_OverlappedWrite.hEvent, 1000 );  
  93. return dwBytesWritten;  
  94. }  
  95. return 0;  
  96. }  
  97. return dwBytesWritten;  




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值