首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > VC/MFC >

1000分求共享串口源代码,该怎么解决

2012-02-14 
1000分求共享串口源代码本人现急需共享串口的c++源代码,有的朋友可以和我联系:youth198011@tom.com.分数不

1000分求共享串口源代码
本人现急需共享串口的c++源代码,有的朋友可以和我联系:youth198011@tom.com.
分数不够可以再加

[解决办法]
cnComm
在网上搜索源代码,是一个不错的类
[解决办法]
//******************************************************************************/
//
//*一个较完整的串口类(WINAPI/C++/源码),解决10以上端口,合理结束线程等问题 */
//
//******************************************************************************/


串口在工业应用是极为普遍的,我用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_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
);

线程中循环的低效率问题

使用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
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 <typename T>
_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_com
{
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_handle();
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 ',将用去一个字符的缓冲区
int 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_RECEIVE 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; i <100; i++)
{
Sleep(500);
com1.write(str); //也可以 com1.write(str, strlen(str));
}
com1.close();

二、打开串口2异步读

char str[100];
_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 : " < < GetLastError() < < endl;
*/
for(int i=0; i <100; i++)
{
Sleep(500);
if(com2.read(str, 100) > 0) //异步读,返回读取字符数
cout < < str;
}
com2.close();

三、扩展应用具有监视线程的串口类

class _com_ex : public thread_com
{
public:
virtual on_receive()
{
char str[100];
if(read(str, 100) > 0) //异步读,返回读取字符数
cout < < str;
}
};

int main(int argc, char *argv[])
{
try
{
char str[100];
_com_ex com2; //异步扩展
com2.open(2);
Sleep(10000);
com2.close();
}
catch(exception &e)
{
cout < < e.what() < < endl;
}
return 0;
}

四、桌面应用可发送消息到指定窗口(在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_com com2;
com2.open(2);
com2.set_hwnd(ComDlg-> m_hWnd);

处理消息

LRESULT ComDlg::On_Receive(WPARAM wp, LPARAM lp)
{
char str[100];
com2.read(str, 100);

char com_str[10];
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 __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 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 xx[20];
int port = Message.WParam;
if(com2.read(xx, 20) > 0)
ShowMessage(xx);
}

错误和缺陷在所难免,欢迎来信批评指正;wushaojian@21cn.com

附完整源代码 _com.h



[解决办法]
//当接受到数据送到窗口的消息
#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; //线程运行循环标志
void (*_func)(int port);

OVERLAPPED _wait_o; //WaitCommEvent use

//线程收到消息自动调用, 如窗口句柄有效, 送出消息, 包含窗口编号
virtual void on_receive()
{
if(_notify_hwnd)
PostMessage(_notify_hwnd, ON_COM_RECEIVE, WPARAM(_port), LPARAM(0));
else
{
if(_func)
_func(_port);
}
}
//打开串口,同时打开监视线程
virtual bool open_port()
{
if(_asyn_com:pen_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;
_func = 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);
}
//设定发送通知, 接受字符最小值
void set_notify_num(int num)
{
_notify_num = num;
}
int get_notify_num()
{
return _notify_num;
}
//送消息的窗口句柄
inline void set_hwnd(HWND hWnd)
{
_notify_hwnd = hWnd;
}
inline HWND get_hwnd()
{
return _notify_hwnd;
}
inline void set_func(void (*f)(int))
{
_func = f;
}
//关闭线程及串口
virtual void close()
{
if(is_open())
{
_run_flag = false;
SetCommMask(_com_handle, 0);
SetEvent(_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;
ResetEvent(_wait_o.hEvent);
}
}
/*辅助线程控制*/
//获得线程句柄
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;


}
//重建监视线程
bool restart()
{
if(_thread_handle) /*只有已有存在线程时*/
{
_run_flag = false;
SetCommMask(_com_handle, 0);
SetEvent(_wait_o.hEvent);

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

CloseHandle(_thread_handle);

_run_flag = true;
_thread_handle = NULL;

DWORD id;
_thread_handle = CreateThread(NULL, 0, com_thread, this, 0, &id);
return (_thread_handle != NULL); //辅助线程
}
return 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;
}

};

typedef _thread_com _com; //名称简化

#endif //_COM_H_
[解决办法]

共享,那是驱动级的吧?
[解决办法]
注入并拦截CreateFile/ReadFile/WriteFile

热点排行