1、VC串口通讯DLLVC串口通讯DLL 串口在工业应用是极为普遍的,我用API封装了同步和异步的串口类,以及一个具有监视线程的异步串口类;使用简单高效,具有工业强度,我在BC, BCB, VC, BCBX, GCC下编译通过,相信足够应付大多数情况,而且还可以继承扩展,下面简单介绍使用方法 库的层次结构: _base_com:虚基类,基本接口,可自行扩展自己的串口类 _sync_com:_base_com 的子类, 同步应用,适合简单应用 _asyn_com:_base_com 的子类, 异步应用(重叠I/O),适合较高效应用,NT平台 _thread_com:_asyn_com 的子类, 异步
2、应用,监视线程,适合较复杂应用,窗口通知消息和继承扩展的使用方式;几个问题: 结束线程 如何从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 = Crea
3、teFile( “COM10“, GENERIC_READ GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL FILE_FLAG_OVERLAPPED, /重叠I/O NULL );将提示错误, 这样就OK:_com_handle = CreateFile( “.COM10“,/对应的就是.COM10 GENERIC_READ GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL FILE_FLAG_OVERLAPPED, /重叠I/O NULL ); 线
4、程中循环的低效率问题 使用SetCommMask(pcom-_com_handle, EV_RXCHAR EV_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
5、 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) /_noti
6、fy_num 是设定得字符数 pcom-on_receive(); 类似于流的输出方式我编了一个简单的写串口的方式,可以类似于流将简单的数据类型输出template _asyn_com& operator (T x) strstream s; s x ; write(s.str(), s.pcount(); return *this;就可以这样使用_sync_com com1;com1.open(1, 9600);com1 “ then random() s return value is “ rand() “ .n“ ;com1.close();本串口类库的主要接口class _base_c
7、om bool open(int port); bool open(int port, int baud_rate); bool open(int port, char * set_str); / set_str : “9600, 8, n, 1“ bool set_state(int BaudRate, int ByteSize = 8, int Parity = NOPARITY, int StopBits = ONESTOPBIT) /设置内置结构串口参数:波特率,停止位 bool set_state(char *set_str) bool is_open(); HANDLE get_h
8、andle(); virtual bool open_port()=0; /继承用的重要函数 virtual close();class _sync_com :public _base_com /同步 int read(char *buf, int buf_size); /自动补上0,将用去一个字符的缓冲区 int write(char *buf, int len); int write(char *buf);class _asyn_com :public _base_com /异步 int read(char *buf, int buf_size); /自动补上0,将用去一个字符的缓冲区 i
9、nt write(char *buf, int len); int write(char *buf);class _thread_com :public _asyn_com /线程 virtual void on_receive() /供线程接受到字符时调用, 可继承替换之 if(_notify_hwnd) PostMessage(_notify_hwnd, ON_COM_RECEIVE, WPARAM(_port), LPARAM(0); else if(_func) _func(_port); void set_hwnd(HWND hwnd); /设置窗口句柄, 发送 ON_COM_REC
10、EIVE WM_USER + 618 void set_func(void (*f)(int); /设置调用函数 ,窗口句柄优先 void set_notify_num(int num); /设定发送通知, 接受字符最小值一些应用范例 当然首先 #include _com.h 一、打开串口1同步写 char str = com_class test; _sync_com com1; /同步 com1.open(1); / 相当于 com1.open(1, 9600); com1.open(1, 9600,8,n,1); for(int i=0; i100; i+) Sleep(500); co
11、m1.write(str); /也可以 com1.write(str, strlen(str); com1.close(); 二、打开串口2异步读 char str100; _asyn_com com2; /异步 com2.open(2); / 相当于 com2.open(2, 9600); com2.open(2, 9600,8,n,1); if(!com2.is_open() cout COM2 not open , error : GetLastError() endl; /* 也可以如下用法 if(!com2.open(2) cout COM2 not open , error : G
12、etLastError() endl; */ for(int i=0; i 0) /异步读,返回读取字符数 cout 0) /异步读,返回读取字符数 cout str; ; int main(int argc, char *argv) try char str100; _com_ex com2; /异步扩展 com2.open(2); Sleep(10000); com2.close(); catch(exception &e) cout e.what() m_hWnd); 处理消息 LRESULT ComDlg:On_Receive(WPARAM wp, LPARAM lp) char st
13、r100; com2.read(str, 100); char com_str10; strcpy(com_str, COM); ltoa(long)wp, com_str + 3, 10); / WPARAM 保存端口号 MessageBox(str, com_str, MB_OK); return 0; C+ Builder class TForm1 : public TForm _published: / IDE-managed Components void _fastcall FormClose(TObject *Sender, TCloseAction &Action); void
14、 _fastcall FormCreate(TObject *Sender); private: / User declarations public: / User declarations void On_Receive(TMessage& Message); _fastcall TForm1(TComponent* Owner); _thread_com com2; BEGIN_MESSAGE_MAP MESSAGE_HANDLER(ON_COM_RECEIVE, TMessage, On_Receive) END_MESSAGE_MAP(TForm) ; void _fastcall
15、TForm1:FormClose(TObject *Sender, TCloseAction &Action) com2.close(); /- void _fastcall TForm1:FormCreate(TObject *Sender) com2.open(2); com2.set_hwnd(Handle); /- void TForm1:On_Receive(TMessage& Message) char xx20; int port = Message.WParam; if(com2.read(xx, 20) 0) ShowMessage(xx); 错误和缺陷在所难免,欢迎来信批评
16、指正;wushaojian 附完整源代码 _com.h/*串口基础类库(WIN32) ver 0.1编译器 : BC+ 5; C+ BUILDER 4, 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
17、) 2004.8 llbird wushaojian*/*Example :*/#ifndef _COM_H_#define _COM_H_#pragma warning(disable: 4530)#pragma warning(disable: 4786)#pragma warning(disable: 4800)#include #include #include #include #include using namespace std;#include class _base_com /虚基类 基本串口接口protected: volatile int _port; /串口号 vol
18、atile HANDLE _com_handle;/串口句柄 char _com_str20; DCB _dcb; /波特率,停止位,等 COMMTIMEOUTS _co; / 超时时间 virtual bool open_port() = 0; void init() /初始化 memset(_com_str, 0, 20); memset(&_co, 0, sizeof(_co); memset(&_dcb, 0, sizeof(_dcb); _dcb.DCBlength = sizeof(_dcb); _com_handle = INVALID_HANDLE_VALUE; virtual
19、 bool setup_port() if(!is_open() return false; if(!SetupComm(_com_handle, 8192, 8192) return false; /设置推荐缓冲区 if(!GetCommTimeouts(_com_handle, &_co) return false; _co.ReadIntervalTimeout = 0xFFFFFFFF; _co.ReadTotalTimeoutMultiplier = 0; _co.ReadTotalTimeoutConstant = 0; _co.WriteTotalTimeoutMultiplie
20、r = 0; _co.WriteTotalTimeoutConstant = 2000; if(!SetCommTimeouts(_com_handle, &_co) return false; /设置超时时间 if(!PurgeComm(_com_handle, PURGE_TXABORT PURGE_RXABORT PURGE_TXCLEAR PURGE_RXCLEAR ) return false; /清空串口缓冲区 return true; inline void set_com_port(int port) char p12; _port = port; strcpy(_com_st
21、r, .COM); ltoa(_port, p, 10); strcat(_com_str, p); public: _base_com() init(); virtual _base_com() close(); /设置串口参数:波特率,停止位,等 支持设置字符串 9600, 8, n, 1 bool set_state(char *set_str) if(is_open() if(!GetCommState(_com_handle, &_dcb) return false; if(!BuildCommDCB(set_str, &_dcb) return false; return SetC
22、ommState(_com_handle, &_dcb) = TRUE; return false; /设置内置结构串口参数:波特率,停止位 bool set_state(int BaudRate, int ByteSize = 8, int Parity = NOPARITY, int StopBits = ONESTOPBIT) if(is_open() if(!GetCommState(_com_handle, &_dcb) return false; _dcb.BaudRate = BaudRate; _dcb.ByteSize = ByteSize; _dcb.Parity = Pa
23、rity; _dcb.StopBits = StopBits; return SetCommState(_com_handle, &_dcb) = TRUE; return false; /打开串口 缺省 9600, 8, n, 1 inline bool open(int port) return open(port, 9600); /打开串口 缺省 baud_rate, 8, n, 1 inline bool open(int port, int baud_rate) if(port 1024) return false; set_com_port(port); if(!open_port
24、() return false; if(!setup_port() return false; return set_state(baud_rate); /打开串口 inline bool open(int port, char *set_str) if(port 1024) return false; set_com_port(port); if(!open_port() return false; if(!setup_port() return false; return set_state(set_str); inline bool set_buf(int in, int out) re
25、turn is_open() ? SetupComm(_com_handle, in, out) : false; /关闭串口 inline virtual void close() if(is_open() CloseHandle(_com_handle); _com_handle = INVALID_HANDLE_VALUE; /判断串口是或打开 inline bool is_open() return _com_handle != INVALID_HANDLE_VALUE; /获得串口句炳 HANDLE get_handle() return _com_handle; operator
26、HANDLE() return _com_handle; ;class _sync_com : public _base_comprotected: /打开串口 virtual bool open_port() if(is_open() close(); _com_handle = CreateFile( _com_str, GENERIC_READ GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL , NULL ); assert(is_open(); return is_open();/检测串口是否成功打开 public: _sync_com() /同步读 int read(char *buf, int buf_len) if(!is_open() return 0; buf0 = 0; COMSTAT stat; DWORD error; if(ClearCommError(_com_handle,
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1