⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 com_class.h

📁 一个很好用的串口类
💻 H
字号:
/*
串口基础类库(WIN32)	ver 0.1

编译器 : BC++ 5; C++ BUILDER 4, 5, 6, X; VC++ 5, 6; VC.NET;  GCC;

class   _base_com : 虚基类 基本串口接口;
class   _aync_com : 同步I/O 串口类;
class   _sync_com : 异步I/O 串口类;
class _thread_com :	异步I/O 辅助读监视线程 可转发窗口消息 串口类(可继承虚函数on_receive用于读操作);

copyright(c) 2004.8 llbird wushaojian@21cn.com
*/

#ifndef	_COM_CLASS_H_
#define _COM_CLASS_H_

#pragma warning(disable: 4530)
#pragma warning(disable: 4786)
#pragma warning(disable: 4800)

#include <cassert>
#include <strstream>
#include <algorithm>
#include <exception>
#include <iomanip>
using namespace std;

#include <windows.h>

class _base_com	  //虚基类 基本串口接口
{
protected:

	volatile int _port;	 //串口号
	volatile HANDLE _com_handle;//串口句柄
	DCB _dcb;			  //波特率,停止位,等
	int _in_buf, _out_buf; // 缓冲区
	COMMTIMEOUTS _co;	 //	超时时间
	//虚函数,用于不同方式的串口打开
	virtual bool open_port() = 0;

	void init()	//初始化
	{
		memset(&_dcb, 0, sizeof(_dcb));
		_dcb.DCBlength = sizeof(_dcb);

		_com_handle = INVALID_HANDLE_VALUE;

		_in_buf = _out_buf = 8192;

		memset(&_co, 0, sizeof(_co));
		_co.ReadIntervalTimeout = 0xFFFFFFFF;
		_co.ReadTotalTimeoutMultiplier = 0;
		_co.ReadTotalTimeoutConstant = 0;
		_co.WriteTotalTimeoutMultiplier = 0;
		_co.WriteTotalTimeoutConstant = 5000;
	}

public:
	_base_com()
	{
		init();	
	}
	virtual ~_base_com()
	{
		close();				  
	}
	/*基本参数设置*/
	//设置串口参数:波特率,停止位,等
	inline bool set_para() 
	{
		return is_open() ? SetCommState(_com_handle, &_dcb) : false;
	}
	//打开设置对话框
	bool config_dialog()  
	{
		if(is_open())
		{
			COMMCONFIG cf;
			memset(&cf, 0, sizeof(cf));
			cf.dwSize = sizeof(cf);
			cf.wVersion = 1;

			char com_str[10];
			strcpy(com_str, "COM");
			ltoa(_port, com_str + 3, 10);

			if(CommConfigDialog(com_str, NULL, &cf))
			{
				 memcpy(&_dcb, &cf.dcb, sizeof(DCB));
				 return SetCommState(_com_handle, &_dcb);
			}
		}
		return false;
	}
	//支持设置字符串 "9600, 8, n, 1"
	bool set_dcb(char *set_str)	
	{
		return bool(BuildCommDCB(set_str, &_dcb));
	}
	//设置内置结构串口参数:波特率,停止位
	bool set_dcb(int BaudRate, int ByteSize = 8, int Parity = NOPARITY, int StopBits = ONESTOPBIT)
	{
		_dcb.BaudRate = BaudRate;
	    _dcb.ByteSize = ByteSize;
	    _dcb.Parity   = Parity;
	    _dcb.StopBits = StopBits;
		return true;
	}
	//设置缓冲区大小
	inline bool set_buf(int in_buf, int out_buf)
	{
		return is_open() ? SetupComm(_com_handle, in_buf, out_buf) : false;
	}
	//打开串口 缺省 9600, 8, n, 1
	inline bool open(int port)
	{
		if(port < 1 || port > 1024)
			return false;

		set_dcb(9600);
		_port = port;

		return open_port();
	}
	//打开串口 缺省 baud_rate, 8, n, 1
	inline bool open(int port, int baud_rate)
	{
		if(port < 1 || port > 1024)
			return false;

		set_dcb(baud_rate);
		_port = port;

		return open_port();
	}
	//打开串口
	inline bool open(int port, char *set_str)
	{
		if(port < 1 || port > 1024)
			return false;

		if(!BuildCommDCB(set_str, &_dcb))
			return false;

		_port = port;

		return open_port();
	}
	//关闭串口
	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;
	}
};

class _sync_com	: public _base_com
{
protected:
	//打开串口
	virtual bool open_port()
	{
		if(is_open())
			close();

		char com_str[10];
		
		strcpy(com_str, "COM");
		ltoa(_port, com_str + 3, 10);
		_com_handle = CreateFile(
			com_str,
			GENERIC_READ | GENERIC_WRITE,
			0,
			NULL,
			OPEN_EXISTING,
			FILE_ATTRIBUTE_NORMAL ,	
			NULL
			);
		assert(is_open());
		if(!is_open())//检测串口是否成功打开
			return false;
		
		BOOL ret; 
		ret = SetupComm(_com_handle, _in_buf, _out_buf);	//设置推荐缓冲区
		assert(ret);
		ret &= SetCommState(_com_handle, &_dcb);	//设置串口参数:波特率,停止位,等
		assert(ret);
		ret &= SetCommTimeouts(_com_handle, &_co);	//设置超时时间
		assert(ret);
		ret &= PurgeComm(_com_handle, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR );	//清空串口缓冲区
		assert(ret);
		if(!ret)
		{
			close();
			return false;
		}

		return true;
	}

public:

	_sync_com()
	{
		_co.ReadTotalTimeoutConstant = 5000;
	}
	//同步读
	int read(char *buf, int buf_len)
	{
		if(!is_open())
			return 0;

		buf[0] = '\0';
		
		COMSTAT  stat;
		DWORD error;

		if(ClearCommError(_com_handle, &error, &stat) && error > 0)	//清除错误
		{
			PurgeComm(_com_handle, PURGE_RXABORT | PURGE_RXCLEAR); /*清除输入缓冲区*/
			return 0;
		}
		 
		unsigned long r_len = 0;

		buf_len = min(buf_len - 1, (int)stat.cbInQue);
		if(!ReadFile(_com_handle, buf, buf_len, &r_len, NULL))
				r_len = 0;
		buf[r_len] = '\0';

		return r_len;
	}
	//同步写
	int write(char *buf, int buf_len)
	{
		if(!is_open() || !buf)
			return 0;
		
		DWORD    error;
		if(ClearCommError(_com_handle, &error, NULL) && error > 0)	//清除错误
			PurgeComm(_com_handle, PURGE_TXABORT | PURGE_TXCLEAR);

		unsigned long w_len = 0;
		if(!WriteFile(_com_handle, buf, buf_len, &w_len, NULL))
			w_len = 0;

		return w_len;
	}
	//同步写
	inline int write(char *buf)
	{
		assert(buf);
		return write(buf, strlen(buf));
	}
	//同步写, 支持部分类型的流输出
	template<typename T>
	_sync_com& operator << (T x)
	{
		strstream s;

		s << x;
		write(s.str(), s.pcount());

		return *this;
	}
};

class _asyn_com	: public _base_com
{
protected:

	OVERLAPPED _ro, _wo; //	重叠I/O

	virtual bool open_port()
	{
		if(is_open())
			close();

		char com_str[10];

		strcpy(com_str, "COM");
		ltoa(_port, com_str + 3, 10);
		_com_handle = CreateFile(
			com_str,
			GENERIC_READ | GENERIC_WRITE,
			0,
			NULL,
			OPEN_EXISTING,
			FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,	//重叠I/O
			NULL
			);
		assert(is_open());
		if(!is_open())//检测串口是否成功打开
			return false;
		
		BOOL ret; 
		ret = SetupComm(_com_handle, _in_buf, _out_buf);	//设置推荐缓冲区
		assert(ret);
		ret = SetCommState(_com_handle, &_dcb);	//设置串口参数:波特率,停止位,等
		assert(ret);
		ret = SetCommTimeouts(_com_handle, &_co);	//设置超时时间
		assert(ret);
		ret = PurgeComm(_com_handle, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR );	//清空串口缓冲区
		assert(ret);

		return true;
	}

public:

	_asyn_com()
	{
		memset(&_ro, 0, sizeof(_ro));
		memset(&_wo, 0, sizeof(_wo));

		_ro.hEvent = CreateEvent(NULL, true, false, NULL);
		assert(_ro.hEvent != INVALID_HANDLE_VALUE); 
		
		_wo.hEvent = CreateEvent(NULL, true, false, NULL);
		assert(_wo.hEvent != INVALID_HANDLE_VALUE);	
	}
	virtual ~_asyn_com()
	{
		close();

		if(_ro.hEvent != INVALID_HANDLE_VALUE)
			CloseHandle(_ro.hEvent);

		if(_wo.hEvent != INVALID_HANDLE_VALUE)
			CloseHandle(_wo.hEvent);
	}
	//异步读
	int read(char *buf, int buf_len)
	{
		if(!is_open())
			return 0;

		buf[0] = '\0';

		COMSTAT  stat;
		DWORD error;

		if(ClearCommError(_com_handle, &error, &stat) && error > 0)	//清除错误
		{
			PurgeComm(_com_handle, PURGE_RXABORT | PURGE_RXCLEAR); /*清除输入缓冲区*/
			return 0;
		}

		if(!stat.cbInQue)// 缓冲区无数据
			return 0;

		unsigned long r_len = 0;

		buf_len = min((int)(buf_len - 1), (int)stat.cbInQue);

		if(!ReadFile(_com_handle, buf, buf_len, &r_len, &_ro)) //2000 下 ReadFile 始终返回 True
		{
			if(GetLastError() == ERROR_IO_PENDING) // 结束异步I/O
			{
				if(!GetOverlappedResult(_com_handle, &_ro, &r_len, false))
				{
					if(GetLastError() != ERROR_IO_INCOMPLETE)//其他错误
							r_len = 0;
				}
			}
			else
				r_len = 0;
		}
			
		buf[r_len] = '\0';
		return r_len;
	}
	//异步写
	int write(char *buf, int buf_len)
	{
		if(!is_open())
			return 0;

		assert(buf);

		DWORD    error;
		if(ClearCommError(_com_handle, &error, NULL) && error > 0)	//清除错误
			PurgeComm(_com_handle, PURGE_TXABORT | PURGE_TXCLEAR);	

		unsigned long w_len = 0, o_len = 0;
		if(!WriteFile(_com_handle, buf, buf_len, &w_len, &_wo))
			if(GetLastError() != ERROR_IO_PENDING)
				w_len = 0;

		return w_len;
	}
	//异步写
	inline int write(char *buf)
	{
		assert(buf);
		return write(buf, strlen(buf));
	}
	//异步写, 支持部分类型的流输出
	template<typename T>
	_asyn_com& operator << (T x)
	{
		strstream s;

		s << x ;
		write(s.str(), s.pcount());

		return *this;
	}
};

//当接受到数据送到窗口的消息
#define ON_COM_RECEIVE WM_USER + 618	 //	 WPARAM 端口号

class _thread_com : public _asyn_com
{
protected:
	volatile HANDLE _thread_handle;	//辅助线程
	volatile HWND _notify_hwnd; // 通知窗口
	volatile long _notify_num;//接受多少字节(>_notify_num)发送通知消息
	volatile bool _run_flag; //线程运行循环标志

	OVERLAPPED _wait_o; //WaitCommEvent use

	//线程收到消息自动调用, 如窗口句柄有效, 送出消息, 包含窗口编号
	virtual void on_receive()
	{
		if(_notify_hwnd)
			PostMessage(_notify_hwnd, ON_COM_RECEIVE, WPARAM(_port), LPARAM(0));
	}
	//打开串口,同时打开监视线程
	virtual bool open_port()
	{
		if(_asyn_com::open_port())
		{
			_run_flag = true; 
			DWORD id;
			_thread_handle = CreateThread(NULL, 0, com_thread, this, 0, &id); //辅助线程
			assert(_thread_handle);
			if(!_thread_handle)
			{
				CloseHandle(_com_handle);
				_com_handle = INVALID_HANDLE_VALUE;
			}
			else
				return true;
		}
		return false;
	}

public:
	_thread_com()
	{
		_notify_num = 0;
		_notify_hwnd = NULL;
		_thread_handle = NULL;

		memset(&_wait_o, 0, sizeof(_wait_o));
		_wait_o.hEvent = CreateEvent(NULL, true, false, NULL);
		assert(_wait_o.hEvent != INVALID_HANDLE_VALUE);	
	}
	~_thread_com()
	{
		close();

		if(_wait_o.hEvent != INVALID_HANDLE_VALUE)
			CloseHandle(_wait_o.hEvent);
	}
	//设定发送通知, 接受字符最小值	 默认 0
	void set_notify_num(int num)
	{
		_notify_num = num;
	}
	//送消息的窗口句柄
	inline void set_hwnd(HWND hWnd)
	{
		_notify_hwnd = hWnd;
	}
	//关闭线程及串口
	virtual void close()
	{
		if(is_open())		
		{
			_run_flag = false;
			SetCommMask(_com_handle, 0);
			ResetEvent(_wait_o.hEvent);

			if(WaitForSingleObject(_thread_handle, 100) != WAIT_OBJECT_0)
				TerminateThread(_thread_handle, 0);

			CloseHandle(_com_handle);
			CloseHandle(_thread_handle);

			_thread_handle = NULL;
			_com_handle = INVALID_HANDLE_VALUE;
		}
	}
	/*辅助线程控制*/
	//获得线程句柄
	HANDLE get_thread()
	{
		return _thread_handle;
	}
	//暂停监视线程
	bool suspend()
	{
		return _thread_handle != NULL ? SuspendThread(_thread_handle) != 0xFFFFFFFF : false;
	}
	//恢复监视线程
	bool resume()
	{
		return _thread_handle != NULL ? ResumeThread(_thread_handle) != 0xFFFFFFFF : false;
	}

private:
	//监视线程
	static DWORD WINAPI com_thread(LPVOID para)
	{
		_thread_com *pcom = (_thread_com *)para;	
		

        if(!SetCommMask(pcom->_com_handle, EV_RXCHAR | EV_ERR))
			return 0;

		COMSTAT  stat;
		DWORD error;

		for(DWORD length, mask = 0; pcom->_run_flag && pcom->is_open(); mask = 0)
		{
			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
			{
				ClearCommError(pcom->_com_handle, &error, &stat);
				if(stat.cbInQue > pcom->_notify_num)
					pcom->on_receive();
			}
        }

		return 0;
	}
	
};

#endif _COM_CLASS_H_

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -