用户操作
[即时聊天] [发私信] [加为好友]
朱俊ID:foxmail
136458次访问,排名638,好友0人,关注者1人。
foxmail的文章
原创 100 篇
翻译 0 篇
转载 10 篇
评论 235 篇
最近评论
vvukqr:WoW Gold
ym:好文才,对我就像醍醐灌顶
阿豪:你的墙纸设置方法有问题,无法设置jpg和gif,只能设置bmp。如果设置图片为jpg和gif墙纸没有任何变化。如果你感兴趣,我可以把代码发给你看看,看看到底是你的方法有问题还是我做得不对。
nqh@exchange.ricsson.com
xiaopianzi:看到你对svm有研究,所以请问svmlight多分类预测时,我连网页上提供的exampel效果都不好,怎么回事?参数的选定有没有窍门?还有libsvm我用它作多分类预测,总是报错!怎么回事?请指教!!!
egxsun:要是加flash,怎么改这段:if (filmURL != null) {
filmstring = '<object classid=""clsid:6BF52A52-394A-11D3-B153-00C04F79FAA6"" id=""WindowsMediaPlayer1"">'; ……
文章分类
收藏
相册
Funny
文章用图
朱俊
我的主页
MSN Space
中国人工智能网
恋雪
步天软件
留言
连连看
存档
软件项目交易
订阅我的博客
XML聚合  FeedSky
订阅到鲜果
订阅到Google
订阅到抓虾
订阅到BlogLines
订阅到Yahoo
订阅到GouGou
订阅到飞鸽
订阅到Rojo
订阅到newsgator
订阅到netvibes

原创 VC++ 的串口通讯收藏

新一篇: 如何在程序中动态设置墙纸 | 旧一篇: 增加注册OCX和DLL的菜单

                                              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:写入输出缓冲区。

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

#define MESSAGELENGTH 100

class CMyDialog : public CDialog
{
protected:
VARIANT InBuffer;
VARIANT OutBuffer;
CMSComm m_Com;
public:
......
}

BOOL CMyDiaLog::OnInitDialog()
{
CDialog::OnInitDialog();
m_Com.SetCommPort(1);
if (!m_Com.GetPortOpen()) {
m_Com.SetSettings("57600,N,8,1");
m_Com.SetPortOpen(true);
m_Com.SetInBufferCount(0);
SetTimer(1,10,NULL);
InBuffer.bstrVal=new unsigned short[MESSAGELENGTH];
OutBuffer.bstrVal=new unsigned short[MESSAGELENGTH];
OutBuffer.vt=VT_BSTR;
}
return true;
}

void CMyDiaLog::OnTimer(UINT nIDEvent)
{
if (m_Com.GetInBufferCount()>=MESSAGELENGTH) {
InBuffer=m_Com.GetInput();
// handle the InBuffer.
// Fill the OutBuffer.
m_Com.SetOutput(OutBuffer);
}
CDialog::OnTimer(nIDEvent);
}

 

  用该控件传输的数据是UNICODE格式。关于UNICODE和ANSI的关系和转换请参

看MSDN。

  关于该控件的其他详细资料请查看MSDN关于COMM CONTROL部分。

 


  二、直接用VC++访问串口。

  在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结构如下:

typedef struct _COMMTIMEOUTS {
DWORD ReadIntervalTimeout;
DWORD ReadTotalTimeoutMultiplier;
DWORD ReadTotalTimeoutConstant;
DWORD WriteTotalTimeoutMultiplier;
DWORD WriteTotalTimeoutConstant;
} 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:保存串口异步通讯的信息。具体结构如下:

typedef struct _OVERLAPPED {
DWORD Internal;
DWORD InternalHigh;
DWORD Offset;
DWORD OffsetHigh;
HANDLE hEvent;
} OVERLAPPED;
 

  Internal,InternalHigh是保留给系统使用的,用户不需要设置。

  Offset,OffsetHigh是读写串口的偏移量,一般设置OffsetHigh为NULL,可以支持

2GB数据。

  hEvent读写事件,因为串口是异步通讯,操作可能被其他进程堵塞,程序可以通

过检查该时间来得知是否读写完毕。事件将在读写完成后,自动设置为有效。

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

面的实例:

BOOL CSerial::Open( int nPort, int nBaud )
{
if( m_bOpened ) return( TRUE );

char szPort[15];
DCB dcb;

wsprintf( szPort, "COM%d", nPort );
m_hComDev = CreateFile( szPort, GENERIC_READ | GENERIC_WRITE, 0, NULL,

OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL );
if( m_hComDev == NULL ) return( FALSE );

memset( &m_OverlappedRead, 0, sizeof( OVERLAPPED ) );
memset( &m_OverlappedWrite, 0, sizeof( OVERLAPPED ) );

COMMTIMEOUTS CommTimeOuts;
CommTimeOuts.ReadIntervalTimeout = 0xFFFFFFFF;
CommTimeOuts.ReadTotalTimeoutMultiplier = 0;
CommTimeOuts.ReadTotalTimeoutConstant = 0;
CommTimeOuts.WriteTotalTimeoutMultiplier = 0;
CommTimeOuts.WriteTotalTimeoutConstant = 5000;
SetCommTimeouts( m_hComDev, &CommTimeOuts );

m_OverlappedRead.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
m_OverlappedWrite.hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );

dcb.DCBlength = sizeof( DCB );
GetCommState( m_hComDev, &dcb );
dcb.BaudRate = nBaud;
dcb.ByteSize = 8;
if( !SetCommState( m_hComDev, &dcb ) ||
!SetupComm( m_hComDev, 10000, 10000 ) ||
m_OverlappedRead.hEvent == NULL ||
m_OverlappedWrite.hEvent == NULL ){
DWORD dwError = GetLastError();
if( m_OverlappedRead.hEvent != NULL ) CloseHandle( m_OverlappedRead.hEvent );
if( m_OverlappedWrite.hEvent != NULL ) CloseHandle( m_OverlappedWrite.hEvent );
CloseHandle( m_hComDev );
return FALSE;
}

m_bOpened = TRUE;

return m_bOpened;

}

int CSerial::InBufferCount( void )
{

if( !m_bOpened || m_hComDev == NULL ) return( 0 );

DWORD dwErrorFlags;
COMSTAT ComStat;

ClearCommError( m_hIDComDev, &dwErrorFlags, &ComStat );

return (int)ComStat.cbInQue;

}

DWORD CSerial::ReadData( void *buffer, DWORD dwBytesRead)
{

if( !m_bOpened || m_hComDev == NULL ) return 0;

BOOL bReadStatus;
DWORD dwErrorFlags;
COMSTAT ComStat;

ClearCommError( m_hComDev, &dwErrorFlags, &ComStat );
if( !ComStat.cbInQue ) return 0;

dwBytesRead = min(dwBytesRead,(DWORD) ComStat.cbInQue);

bReadStatus = ReadFile( m_hComDev, buffer, dwBytesRead, &dwBytesRead,

&m_OverlappedRead );
if( !bReadStatus ){
if( GetLastError() == ERROR_IO_PENDING ){
WaitForSingleObject( m_OverlappedRead.hEvent, 2000 );
return dwBytesRead;
}
return 0;
}

return dwBytesRead;

}

DWORD CSerial::SendData( const char *buffer, DWORD dwBytesWritten)
{

if( !m_bOpened || m_hComDev == NULL ) return( 0 );

BOOL bWriteStat;

bWriteStat = WriteFile( m_hComDev, buffer, dwBytesWritten, &dwBytesWritten,

&m_OverlappedWrite );
if( !bWriteStat){
if ( GetLastError() == ERROR_IO_PENDING ) {
WaitForSingleObject( m_OverlappedWrite.hEvent, 1000 );
return dwBytesWritten;
}
return 0;
}
return dwBytesWritten;

}

 

  上述函数基本实现串口的打开,读写操作。本文章略去该串口类的说明和关闭函

数。读者应该能将这些内容写完。接下来,你就可以在你的程序中调用该串口类了。

关于本文有任何疑问,请与作者联系。

  本文参考文献:MSDN 1999, Microsoft Corp

发表于 @ 2004年06月25日 16:49:00|评论(loading...)|编辑

新一篇: 如何在程序中动态设置墙纸 | 旧一篇: 增加注册OCX和DLL的菜单

评论:没有评论。

发表评论  


当前用户设置只有注册用户才能发表评论。如果你没有登录,请点击登录
Csdn Blog version 3.1a
Copyright © Foxmail