VC串口通讯DLL.docx
《VC串口通讯DLL.docx》由会员分享,可在线阅读,更多相关《VC串口通讯DLL.docx(25页珍藏版)》请在冰豆网上搜索。
VC串口通讯DLL
VC串口通讯DLL
串口在工业应用是极为普遍的,我用API封装了同步和异步的串口类,以及一个具有监视线程的异步串口类;使用简单高效,具有工业强度,我在BC,BCB,VC,BCBX,GCC下编译通过,相信足够应付大多数情况,而且还可以继承扩展,下面简单介绍使用方法
库的层次结构:
_base_com:
虚基类,基本接口,可自行扩展自己的串口类
_sync_com:
_base_com的子类,同步应用,适合简单应用
_asyn_com:
_base_com的子类,异步应用(重叠I/O),适合较高效应用,NT平台
_thread_com:
_asyn_com的子类,异步应用,监视线程,适合较复杂应用,窗口通知消息和继承扩展的使用方式;几个问题:
结束线程
如何从WaitCommEvent(pcom->_com_handle,&mask,&pcom->_wait_o)这个API退出以便顺利结束线程:
方案1:
SetCommMask(_com_handle,0);这个方法在MSDN有载,当在一些情况下并不完全有效,原因未知;
方案2:
SetEvent(_wait_o.hEvent);直接激活重叠IO结构中的事件句柄,绝对有效;这份代码我两种都用;
打开10以上的COM端口
在NT/2000下打开编号10以上端口用
_com_handle=CreateFile(
“COM10“,
GENERIC_READGENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMALFILE_FLAG_OVERLAPPED,//重叠I/O
NULL
);
将提示错误,这样就OK:
_com_handle=CreateFile(
“\\\\.\\COM10“,//对应的就是\\.\COM10
GENERIC_READGENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMALFILE_FLAG_OVERLAPPED,//重叠I/O
NULL
);
线程中循环的低效率问题
使用SetCommMask(pcom->_com_handle,EV_RXCHAREV_ERR)监视接受字符和错误消息;一旦有个字符来就会激活WaitCommEvent通常作以下接受操作:
if(!
WaitCommEvent(pcom->_com_handle,&mask,&pcom->_wait_o))
{
if(GetLastError()==ERROR_IO_PENDING)
{
GetOverlappedResult(pcom->_com_handle,&pcom->_wait_o,&length,true);
}
}
if(mask&EV_ERR)//==EV_ERR
ClearCommError(pcom->_com_handle,&error,&stat);
if(mask&EV_RXCHAR)//==EV_RXCHAR
{
pcom->on_receive();//接收到字符
//或发送到窗口消息
}
这样频繁的函数调用或接受发送消息,效率低下,我添加扫描缓冲区的代码,当字符数超过设定的字符数才作接受字符的操作;
if(mask&EV_RXCHAR)//==EV_RXCHAR
{
ClearCommError(pcom->_com_handle,&error,&stat);
if(stat.cbInQue>pcom->_notify_num)//_notify_num是设定得字符数
pcom->on_receive();
}
类似于流的输出方式
我编了一个简单的写串口的方式,可以类似于流将简单的数据类型输出
template
_asyn_com&operator<<(Tx)
{
strstreams;
s<write(s.str(),s.pcount());
return*this;
}
就可以这样使用
_sync_comcom1;
com1.open(1,9600);
com1<<“thenrandom()'sreturnvalueis“<com1.close();
本串口类库的主要接口
class_base_com
{
boolopen(intport);
boolopen(intport,intbaud_rate);
boolopen(intport,char*set_str);//set_str:
“9600,8,n,1“
boolset_state(intBaudRate,intByteSize=8,intParity=NOPARITY,intStopBits=ONESTOPBIT)
//设置内置结构串口参数:
波特率,停止位
boolset_state(char*set_str)
boolis_open();
HANDLEget_handle();
virtualboolopen_port()=0;//继承用的重要函数
virtualclose();
}
class_sync_com:
public_base_com//同步
{
intread(char*buf,intbuf_size);//自动补上'\0',将用去一个字符的缓冲区
intwrite(char*buf,intlen);
intwrite(char*buf);
}
class_asyn_com:
public_base_com//异步
{
intread(char*buf,intbuf_size);//自动补上'\0',将用去一个字符的缓冲区
intwrite(char*buf,intlen);
intwrite(char*buf);
}
class_thread_com:
public_asyn_com//线程
{
virtualvoidon_receive()//供线程接受到字符时调用,可继承替换之
{
if(_notify_hwnd)
PostMessage(_notify_hwnd,ON_COM_RECEIVE,WPARAM(_port),LPARAM(0));
else
{
if(_func)
_func(_port);
}
}
voidset_hwnd(HWNDhwnd);//设置窗口句柄,发送ON_COM_RECEIVEWM_USER+618
voidset_func(void(*f)(int));//设置调用函数,窗口句柄优先
voidset_notify_num(intnum);//设定发送通知,接受字符最小值
}
一些应用范例
当然首先#include"_com.h"
一、打开串口1同步写
charstr[]="com_classtest";
_sync_comcom1;//同步
com1.open
(1);//相当于com1.open(1,9600);com1.open(1,"9600,8,n,1");
for(inti=0;i<100;i++)
{
Sleep(500);
com1.write(str);//也可以com1.write(str,strlen(str));
}
com1.close();
二、打开串口2异步读
charstr[100];
_asyn_comcom2;//异步
com2.open
(2);//相当于com2.open(2,9600);com2.open(2,"9600,8,n,1");
if(!
com2.is_open())
cout<<"COM2notopen,error:
"</*
也可以如下用法
if(!
com2.open
(2))
cout<<"COM2notopen,error:
"<*/
for(inti=0;i<100;i++)
{
Sleep(500);
if(com2.read(str,100)>0)//异步读,返回读取字符数
cout<}
com2.close();
三、扩展应用具有监视线程的串口类
class_com_ex:
publicthread_com
{
public:
virtualon_receive()
{
charstr[100];
if(read(str,100)>0)//异步读,返回读取字符数
cout<}
};
intmain(intargc,char*argv[])
{
try
{
charstr[100];
_com_excom2;//异步扩展
com2.open
(2);
Sleep(10000);
com2.close();
}
catch(exception&e)
{
cout<}
return0;
}
四、桌面应用可发送消息到指定窗口(在C++Builder和VC++测试通过)
VC++
接受消息
BEGIN_MESSAGE_MAP(ComDlg,CDialog)
//{{AFX_MSG_MAP(ComDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_WM_DESTROY()
//}}AFX_MSG_MAP
ON_MESSAGE(ON_COM_RECEIVE,On_Receive)
END_MESSAGE_MAP()
打开串口,传递窗口句柄
_thread_comcom2;
com2.open
(2);
com2.set_hwnd(ComDlg->m_hWnd);
处理消息
LRESULTComDlg:
:
On_Receive(WPARAMwp,LPARAMlp)
{
charstr[100];
com2.read(str,100);
charcom_str[10];
strcpy(com_str,"COM");
ltoa((long)wp,com_str+3,10);//WPARAM保存端口号
MessageBox(str,com_str,MB_OK);
return0;
}
C++Builder
classTForm1:
publicTForm
{
__published:
//IDE-managedComponents
void__fastcallFormClose(TObject*Sender,TCloseAction&Action);
void__fastcallFormCreate(TObject*Sender);
private:
//Userdeclarations
public:
//Userdeclarations
voidOn_Receive(TMessage&Message);
__fastcallTForm1(TComponent*Owner);
_thread_comcom2;
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(ON_COM_RECEIVE,TMessage,On_Receive)
END_MESSAGE_MAP(TForm)
};
void__fastcallTForm1:
:
FormClose(TObject*Sender,TCloseAction&Action)
{
com2.close();
}
//---------------------------------------------------------------------------
void__fastcallTForm1:
:
FormCreate(TObject*Sender)
{
com2.open
(2);
com2.set_hwnd(Handle);
}
//---------------------------------------------------------------------------
voidTForm1:
:
On_Receive(TMessage&Message)
{
charxx[20];
intport=Message.WParam;
if(com2.read(xx,20)>0)
ShowMessage(xx);
}
错误和缺陷在所难免,欢迎来信批评指正;wushaojian@
附完整源代码_com.h
/*
串口基础类库(WIN32)ver0.1
编译器:
BC++5;C++BUILDER4,5,6,X;VC++5,6;VC.NET;GCC;
class_base_com:
虚基类基本串口接口;
class_sync_com:
同步I/O串口类;
class_asyn_com:
异步I/O串口类;
class_thread_com:
异步I/O辅助读监视线程可转发窗口消息串口类(可继承虚函数on_receive用于读操作);
class_com:
_thread_com同名
copyright(c)2004.8llbirdwushaojian@
*/
/*
Example:
*/
#ifndef_COM_H_
#define_COM_H_
#pragmawarning(disable:
4530)
#pragmawarning(disable:
4786)
#pragmawarning(disable:
4800)
#include
#include
#include
#include
#include
usingnamespacestd;
#include
class_base_com//虚基类基本串口接口
{
protected:
volatileint_port;//串口号
volatileHANDLE_com_handle;//串口句柄
char_com_str[20];
DCB_dcb;//波特率,停止位,等
COMMTIMEOUTS_co;//超时时间
virtualboolopen_port()=0;
voidinit()//初始化
{
memset(_com_str,0,20);
memset(&_co,0,sizeof(_co));
memset(&_dcb,0,sizeof(_dcb));
_dcb.DCBlength=sizeof(_dcb);
_com_handle=INVALID_HANDLE_VALUE;
}
virtualboolsetup_port()
{
if(!
is_open())
returnfalse;
if(!
SetupComm(_com_handle,8192,8192))
returnfalse;//设置推荐缓冲区
if(!
GetCommTimeouts(_com_handle,&_co))
returnfalse;
_co.ReadIntervalTimeout=0xFFFFFFFF;
_co.ReadTotalTimeoutMultiplier=0;
_co.ReadTotalTimeoutConstant=0;
_co.WriteTotalTimeoutMultiplier=0;
_co.WriteTotalTimeoutConstant=2000;
if(!
SetCommTimeouts(_com_handle,&_co))
returnfalse;//设置超时时间
if(!
PurgeComm(_com_handle,PURGE_TXABORTPURGE_RXABORTPURGE_TXCLEARPURGE_RXCLEAR))
returnfalse;//清空串口缓冲区
returntrue;
}
inlinevoidset_com_port(intport)
{
charp[12];
_port=port;
strcpy(_com_str,"\\\\.\\COM");
ltoa(_port,p,10);
strcat(_com_str,p);
}
public:
_base_com()
{
init();
}
virtual~_base_com()
{
close();
}
//设置串口参数:
波特率,停止位,等支持设置字符串"9600,8,n,1"
boolset_state(char*set_str)
{
if(is_open())
{
if(!
GetCommState(_com_handle,&_dcb))
returnfalse;
if(!
BuildCommDCB(set_str,&_dcb))
returnfalse;
returnSetCommState(_com_handle,&_dcb)==TRUE;
}
returnfalse;
}
//设置内置结构串口参数:
波特率,停止位
boolset_state(intBaudRate,intByteSize=8,intParity=NOPARITY,intStopBits=ONESTOPBIT)
{
if(is_open())
{
if(!
GetCommState(_com_handle,&_dcb))
returnfalse;
_dcb.BaudRate=BaudRate;
_dcb.ByteSize=ByteSize;
_dcb.Parity=Parity;
_dcb.StopBits=StopBits;
returnSetCommState(_com_handle,&_dcb)==TRUE;
}
returnfalse;
}
//打开串口缺省9600,8,n,1
inlineboolopen(intport)
{
returnopen(port,9600);
}
//打开串口缺省baud_rate,8,n,1
inlineboolopen(intport,intbaud_rate)
{
if(port<1port>1024)
returnfalse;
set_com_port(port);
if(!
open_port())
returnfalse;
if(!
setup_port())
returnfalse;
returnset_state(baud_rate);
}
//打开串口
inlineboolopen(intport,char*set_str)
{
if(port<1port>1024)
returnfalse;
set_com_port(port);
if(!
open_port())
returnfalse;
if(!
setup_port())
returnfalse;
returnset_state(set_str);
}
inlineboolset_buf(intin,intout)
{
returnis_open()?
SetupComm(_com_handle,in,out):
false;
}
//关闭串口
inlinevirtualvoidclose()
{
if(is_open())
{
CloseHandle(_com_handle);
_com_handle=INVALID_HANDLE_VALUE;
}
}
//判断串口是或打开
inlineboolis_open()
{
return_com_handle!
=INVALID_HANDLE_VALUE;
}
//获得串口句炳
HANDLEget_handle()
{
return_com_handle;
}
operatorHANDLE()
{
return_com_handle;
}
};
class_sync_com:
public_base_com
{
protected:
//打开串口
virtualboolopen_port()
{
if(is_open())
close();
_com_handle=CreateFile(
_com_str,
GENERIC_READGENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
assert(is_open());
returnis_open();//检测串口是否成功打开
}
public:
_sync_com()
{
}
//同步读
intread(char*buf,intbuf_len)
{
if(!
is_open())
return0;
buf[0]='\0';
COMSTATstat;
DWORDerror;
if(ClearCommError(_com_handle,