分享
 
 
 

工控系统串口通讯设计

王朝vc·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

工控系统通常由工控仪器和计算机终端组成,工控仪器和计算机终端之间通过符合RS-232协议的串口通讯,计算终端可以通过双方既定的数据协议,向工控仪器查询状态信号和发送控制信号。

一、硬件协议:定义了RS-232串口的电气规范。

1)DTE/DCE:

一般把工控仪器称为DCE,计算机终端称为DTE,设备之间通过RS-232电缆连接,DCE端采用母连接器(有槽),DTE端采用公连接器(有针)。但如果工控仪器和计算机终端都采用公连接器,则两者都是DTE设备,它们之间的连接应采用零调制解调器方式。

2)RS-232信号:

标准的RS-232管脚通常有D-25PIN和D-9PIN两种类型,常用的信号如下:

信号分类 D-9PIN D-25PIN 信号名称 信号缩写 信号方向

数据信号 3 2 数据传输 TD DTE->DCE

2 3 接收数据 RD DTE<-DCE

控制信号 7 4 请求发送 RTS DTE<-DCE

8 5 清除发送 CTS DTE<-DCE

6 6 数据发送就绪 DSR DTE<-DCE

1 8 载波检测 CD DTE<-DCE

4 20 数据终端就绪 DTR DTE->DCE

9 22 振铃指示 RI DTE<-DCE

接地信号 5 7 接地信号 GND

3)零调制解调连接(ZERO MODEM):

ZERO MODEM处理DTE和DTE设备的对称连接,其连接原理为,一方的传送数据信号为另一方的接收数据信号,一方的控制请求信号为另一方的控制应答信号,接地信号互连。连接示意如下:

信号分类 DTE DTE

数据信号 TD-- RD

RD-- TD

控制信号 RTS-- CTS

CTS-- RTS

(DSR-DCD-RI)-- DTR

DTR-- (DSR-DCD-RI )

接地信号 GND-- GND

二、软件协议:定义了DTE的串口配置,DTE和DCE之间连接协议和数据传输协议。

1)串口参数配置:

波特率(BaudRate):在CBR_110到CBR_256000之间指定,参照仪器指定

数据位(ByteSize):每个字节的位数,一般用7或8,默认为8

停止位(StopBits):停止位的位数,一般有:ONESTOPBIT、TOWSTOPBITS、ONE5STOPBITS,默认为ONESTOPBIT

奇偶校验(Parity): 定义了奇偶校验的模式,一般有:NO_PARITY、EVEN_PARITY、ODD_PARITY,默认NO_PARITY

流量控制(FlowCtrl):定义了流量控制方式,一般有:无控制、硬件方式、XON/XOFF方式,详见握手协议。

2)握手协议:常见有硬件方式RTS/CTS和DTR/DSR方式,软件方式有XON/XOFF和自定义的方式。

RTS/CTS:对于DTE来说,设置OutCtsFlow则CTS低水平位时停止输出,直至高水平位时恢复输出。设置RtsControl为HANDSHAKE则当输入缓冲区数据小于1/4时,DTE将RTS置为高水平位,通知DCE可以传输数据,当输入缓冲区数据大于3/4时,DTE将RTS置为低水平位,通知DCE停止传输数据。DTE(计算机)的缓冲区较大,通常都将RtsControl设置位ENABLE,即保持高水平位。

DTR/DSR:对于DTE来说,设置OutDsrFlow则DSR低水平位时停止输出,直至高水平位时恢复输出。设置DtrControl为HANDSHAKE则当DTR设置为高水平位时容许数据输入,当DTR为低水平位时阻止数据输入。DTE(计算机)的缓冲区较大,通常都将DtrControl设置位ENABLE,即保持高水平位。

XON/XOFF:对于DTE来说,设置OutX时,输出流在DTE收到XoffChar时停止,在收到XonChar时恢复。设置InX时,输入流在缓冲区空闲不足XoffLim时DTE发送XoffChar,通知DCE中止传输数据。当输入流达到缓冲区空闲超过XonLim时,DTE发送XonChar,通知DCE恢复传输数据。

三、编程模式:

在WIN32环境中,串口作为文件访问,但与其他文件不同,串口文件的操作是采用阻塞方式的,读写动作通常会在后台阻塞,用户可以通过响应串口事件,获知端口状态和控制读写动作。因此在WIN32环境中处理串口,应采用重叠I/0机制访问串口文件和在线程中完成读写操作,这样意味着当读写线程阻塞时,不会使主线程锁定而失去响应。

1、串口文件操作方式:根据如上要求,串口一般采用独占和重叠方式打开,如:CreateFile(_T("\\\\.\\COM1"),/*端口名称*/

GENERIC_READ|GENERIC_WRITE,/*文件可读写*/

0,/*独占方式*/

NULL,/*无权限属性*/

OPEN_EXISTING,/*端口必须存在*/

FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,/*重叠的操作方式*/

NULL/*不支持临时文件*/)。

有效的串口文件打开后,可以进行重叠的读写操作,其中要使用一个重叠操作结构OVERLAPPED:

struct { DWORD Internal; /*内部使用*/

DWORD InternalHigh; /*内部使用*/

DWORD Offset; /*操作开始的文件位置(低位),串口文件不支持*/

DWORD OffsetHigh;/* 操作开始的文件位置(高位),串口文件不支持*/

HANDLE hEvent; /*异步事件句柄,重叠操作完成或中断时被激发*/

} OVERLAPPED;

写串口的方式如下:

WriteFile(hCom,/*串口文件句柄*/

(void*)data,/*数据指针*/

dwDataBytes,/*请求写的数据字节数*/

&dwOperaBytes,/*函数返回的已写的字节数,在重叠I/O中通常返回0*/

&ov/*重叠操作结构指针*/);

读串口的方式如下:

ReadFile(hCom,/*串口文件句柄*/

(void*)buf,/*缓冲区指针*/

dwDataBytes,/*请求读的数据字节数*/

&dwOperaBytes,/*函数返回的已读的字节数,在重叠I/O中通常返回0*/

&ov/*重叠操作结构指针*/);

重叠方式调用读写函数后即返回,程序稍后调用等待事件函数进入阻塞状态,直至异步事件被激发,调用方式如下:

WaitForSingleObject(hEvent,/*OVERLAPPED中异步事件句柄*/

dwTimeouts/*读写超时毫秒数*/)

读写超时设置可以由串口配置超时参数COMMTIMEOUTS获得,读超时数 =ReadTotalTimeoutMultiplier * 读字节数 + ReadTotalTimeoutConstant; 写超时数 =WriteTotalTimeoutMultiplier * 写字节数 + WriteTotalTimeoutConstant;

异步事件返回后,可以调用重叠I/O查询函数查看后台读写状况:

GetOverlappedResult(hCom, /*端口文件句柄*/

&ov, /*重叠结构指针*/

&dwOperaBytes, /*重叠操作完成的字节数*/

FALSE/*是否需要等待重叠操作完成*/);

以上时串口文件的操作方式,需要注意的是,这些操作除了打开文件外,其他都应当在某个读写线程中调用,让线程在后台阻塞,主线程保持响应。

2、端口事件侦听:WIN32提供串口事件查询函数用以查看端口触发的事件,端口可侦听事件一般有:

EV_BREAK :端口中断信号

EV_CTS :CTS信号改变

EV_DSR :DSR信号改变

EV_RXCHAR :收到一个或多个字符

EV_RXFLAG :收到特殊字符

EV_ERR :端口错误信号

EV_TXEMPTY:输出缓冲区数据发送完成

可以通过SetCommMask(hCom/*端口文件句柄*/,dwMask/*事件组合*/)来设置需要侦听的事件,然后应采用重叠模式调用查询事件函数:

WaitCommEvent(hCom, /*端口文件句柄*/

&dwMask,/*端口事件组合*/

&ov/*重叠I/O结构*/);

该函数在重叠I/0方式调用后即返回,侦听例程稍后调用WaitForSingleObject进入阻塞状态,OVERLAPPED中的异步事件被激发后返回,程序可以根据dwMask中返回的事件标志做进一步的处理,如:

switch(dwMask)

{

case EV_BREAK:

/*向主线程发送端口中断消息*/break;

case EV_CTS:

case EV_DSR:

/*向主线程发送端口状态消息*/break;

case EV_ERR:

/*向主线程发送端口错误消息*/break;

case EV_RXFLAG:

/*向主线程发送接收特殊字符消息,通知主线程读*/break;

case EV_RXCHAR:

/*向主线程发送接收字符消息,通知主线程读*/break;

case EV_TXEMPTY:

/*向主线程发送数据已发送消息*/break;

}

3、侦听、读写线程的处理模式:在串口编程模式中主线程启动时创建侦听线程,在主线程结束时终止侦听线程。主线程根据读写要求创建读写线程,并在线程结束后返回。在线程处理中重点要保护主线程中的临界资源的使用,如串口文件句柄、主线程的控制变量,主线程退出前应当通知工作线程并等待其终止。

工作线程启动需要一个传入参数用来访问主线程的资源,通常这样定义传入参数:

struct {

BOOL bActive; /*主线程活动标志,通常用于通知后台常驻线程(如侦听线程),主线程即将退出*/

HANDLE hCom; /*串口文件句柄*/

HANDLE evTerm; /*用于通知主线程,本线程已经终止*/

CRITICAL_SECTION cs; /*用于控制临界资源访问*/

BYTE* data; /*读线程的数据指针或写线程的缓冲区指针*/

DWORD dwQueryBytes; /*请求读写操作的字节数*/

DWORD dwResultBytes; /*用于返回操作完成后的实际字节数*/

DWORD dwTimeouts; /*阻塞超时毫秒数*/

int nResultCode; /*用于返回操作的状态码*/

}ThreadParam;

1)、侦听线程的处理模式:

1-2)、主线程启动侦听线程:

ThreadParam tp_listen; /*主线程定义的侦听线程传入参数*/

tp_listen.bActive = TRUE; /*主线程当前活动*/

tp_listen.hCom = hCom; /*已打开的端口句柄*/

tp_listen.evTerm = CreateEvent(NULL,TRUE,FALSE,NULL); /*创建异步事件*/

tp_listen.cs = cs; /*已经创建的临界区*/

tp_listen.data = NULL; /*不使用*/

tp_listen.dwQueryBytes = tp.dwResultBytes = 0; /*不使用*/

tp_listen.dwTimeouts = nListenTimes; /*既定的侦听超时数*/

tp_listen.nResultCode = 0; /*初始状态码*/

/*创建侦听线程*/

CreateThread(NULL, /*无权限属性*/

0, /*默认线程堆栈大小*/

(LPTHREAD_START_ROUTINE)ListenProc, /*侦听线程回调函数*/

(LPVOID)&tp_listen, /*传入参数*/

0, /*线程创建后即运行*/

&dw/*返回线程ID*/);

1-2)、主线程终止侦听线程:

EnterCriticalSection(&tp_listen->cs); /*申请临界资源*/

ResetEvent(tp_listen->evTerm); /*重制异步事件*/

tp_listen.bActive = FALSE; /*通知后台线程,主线程准备退出*/

LeaveCriticalSection(&tp_listen->cs); /*释放临界资源*/

/*等待侦听线程中止*/

WaitForSingleObject(tp_listen->evTerm,INFINITE);

CloseHandle(tp_listen.evTerm); /*关闭打开时创建的异步事件*/

1-3)、侦听回调函数负责处理具体的端口事件响应,线程控制方式如下:

DWORD WINAPI ListenProc(LPVOID lpParam)

{

ThreadParam* pListen = (ThreadParam*)lpParam;

BOOL bActive;

OVERLAPPED ov; /*重叠I/O结构用于等待端口事件*/

EnterCriticalSection(&pListen->cs);

/*初始化工作,比如初始输入、输出缓冲区,设置事件标志*/

LeaveCriticalSection(&pListen->cs);

memset((void*)&ov,0,sizeof(ov));

ov.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);

bActive = pListen->bActive;

while(bActive)

{

/*异步等待端口事件*/

dwMask = 0;

/*重制信号*/

ResetEvent(ov.hEvent);

/*异步等待端口事件*/

EnterCriticalSection(&pListen->cs);

WaitCommEvent(pListen->hCom,&dwMask,&ov);

LeaveCriticalSection(&pListen->cs);

/*进入阻塞直至事件到来或超时*/

WaitForSingleObject(ov.hEvent,pListen->dwTimeout);

switch(dwMask)

{

/*事件分派处理*/

}

/*查询主线程终止信号*/

EnterCriticalSection(&pListen->cs);

bActive = pListen->bActive;

LeaveCriticalSection(&pListen->cs);

}

/*侦听循环停止后处理*/

CloseHandle(ov.hEvent);

EnterCriticalSection(&pListen->cs);

/*做些端口现场清理*/

LeaveCriticalSection(&pListen->cs);

/*通知住线程侦听线程结束*/

SetEvent(pListen->evListen);

ExitThread(0);

return 0;

}

2)、读线程的处理模式:

2-1)、端口读的接口函数

long ReadData(…,long size, BYTE* data)

{

COMTIMEOUTS to;

GetCommTimeouts(hCom,&to); /*取超时参数*/

ThreadParam tp_read; /*主线程定义的读线程传入参数*/

tp_read.bActive = TRUE; /*主线程当前活动*/

tp_read.hCom = hCom; /*已打开的端口句柄*/

tp_read.evTerm = CreateEvent(NULL,TRUE,FALSE,NULL); /*创建异步事件*/

tp_read.cs = cs; /*已经创建的临界区*/

tp_read.data = data; /*缓冲区指针*/

tp_read.dwQueryBytes = size;

tp_read.dwResultBytes = 0;

/*计算读的侦听超时数*/

tp_read.dwTimeouts = to.ReadTotalTimeoutConstant + to.ReadTotalTimeoutMultiplier * size;

tp_read.nResultCode = 0; /*初始状态码*/

/*创建读线程*/

CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ReadProc,(void*)&tp_read,0,&dw);

/*等待线程结束*/

WaitForSingleObject(tp_read.evTerm,INFINITE);

CloseHandle(tp_read.evTerm);

/*返回已经处理的字节数*/

return tp_read.dwResultBytes;

}

2-2)、端口读的线程回调函数

DWORD WINAPI ReadProc(LPVOID lpParam)

{

ThreadParam* pRead = (ThreadParam*)lpParam;

OVERLAPPED ov;

memset((void*)&ov,0,sizeof(OVERLAPPED));

ov.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);

/*端口异步读*/

EnterCriticalSection(&(pRead->cs));

ReadFile(hCom,(void*)pRead->data,pRead->dwQueryBytes,&(pRead->dwResultBytes),&ov);

LeaveCriticalSection(&(pRead->cs));

/*等待异步读结果*/

WaitForSingleObject(ov.hEvent,pRead->dwTimeouts)

/*取重叠操作结果*/

GetOverlappedResult(pRead->hCom,&ov,&pRead->dwResultBytes,FALSE);

CloseHandle(ov.hEvent);

/*通知主线程读操作完成*/

SetEvent(pRead->evRead);

ExitThread(0);

return 0;

}

3)、写线程的处理模式:

3-1)、端口写的接口函数

long WriteData(…,long size, BYTE* data)

{

COMTIMEOUTS to;

GetCommTimeouts(hCom,&to); /*取超时参数*/

ThreadParam tp_write; /*主线程定义的写线程传入参数*/

tp_write.bActive = TRUE; /*主线程当前活动*/

tp_write.hCom = hCom; /*已打开的端口句柄*/

tp_write.evTerm = CreateEvent(NULL,TRUE,FALSE,NULL); /*创建异步事件*/

tp_write.cs = cs; /*已经创建的临界区*/

tp_write.data = data; /*缓冲区指针*/

tp_write.dwQueryBytes = size;

tp_write.dwResultBytes = 0;

/*计算写的侦听超时数*/

tp_write.dwTimeouts = to.WriteTotalTimeoutConstant + to.WriteTotalTimeoutMultiplier * size;

tp_write.nResultCode = 0; /*初始状态码*/

/*创建写线程*/

CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)WriteProc,(void*)&tp_write,0,&dw);

/*等待线程结束*/

WaitForSingleObject(tp_write.evTerm,INFINITE);

CloseHandle(tp_write.evTerm);

/*返回已经处理的字节数*/

return tp_write.dwResultBytes;

}

3-2)、端口写的线程回调函数

DWORD WINAPI WriteProc(LPVOID lpParam)

{

ThreadParam* pWrite = (ThreadParam*)lpParam;

OVERLAPPED ov;

memset((void*)&ov,0,sizeof(OVERLAPPED));

ov.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);

/*端口异步写*/

EnterCriticalSection(&(pWrite->cs));

WriteFile(hCom,(void*)pWrite->data,pWrite->dwQueryBytes,&(pWrite->dwResultBytes),&ov);

LeaveCriticalSection(&(pWrite->cs));

/*等待异步写结果*/

WaitForSingleObject(ov.hEvent,pWrite->dwTimeouts)

/*取重叠操作结果*/

GetOverlappedResult(pWrite->hCom,&ov,&pWrite->dwResultBytes,FALSE);

CloseHandle(ov.hEvent);

/*通知主线程写操作完成*/

SetEvent(pWrite->evWrite);

ExitThread(0);

return 0;

}

4、EasyComm串口控件简介:EasyComm控件是适用于WIN32环境下的串口异步侦听、读写控件,采用前述的思路设计。主要特点在于为提高后台侦听线程的处理效率,在侦听线程中捕获的事件都被异步发送到主线程的窗口消息循环中,然后由主线程的窗口消息处理例程将串口事件消息通知给客户进程,客户进程根据事件类型决定下一步的动作。

EasyComm的开发库包括:EasyComm.h EasyComm.lib EasyComm.dll

1)、EasyComm库初始化和终结:

BOOL InitEasyComm(HINSTANCE hIns);

/*说明:初始化EasyComm运行库*/

/*hIns:调用进程的句柄*/

/*返回:零值失败,非零值成功*/

/*举例:可以在进程初始化时调用*/

BOOL CSomeApp::InitInstance()

{

if(!InitEasyComm(this->m_hInstance))

return FALSE;

}

void UnInitEasyComm(HINSTANCE hIns);

/*说明:终止EasyComm运行库*/

/*hIns:调用进程的句柄*/

/*举例:可以在进程退出时调用*/

BOOL CSomeApp::ExitInstance()

{

UnInitEasyComm(this->m_hInstance);

}

2)、EasyComm控件窗体的创建和销毁:

HWND CreateWindow(LPCTSTR lpClassName, LPCTSTR lpWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HANDLE hInstance, LPVOID lpParam );

/*说明:采用WIN32函数创建EasyComm控件窗体*/

/*lpClassName: 窗体类名 “EasyCommCtrl”*/

/*lpWindowName: 窗体名*/

/*dwStyle: 窗体样式*/

/*x: X位置*/

/*y: Y位置*/

/* nWidth: 宽度*/

/* nHeight: 高度*/

/*hWndParent: 父窗体句柄*/

/*hMenu: 忽略*/

/*hInstance: 忽略*/

/*lpParam: 忽略*/

/*举例: 可以选择在客户窗体创建后创建EasyComm控件*/

int CCustomerWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)

{

if (CWnd::OnCreate(lpCreateStruct) == -1)

return -1;

m_hCom=CreateWindow(“EasyCommCtrl”,NULL,WS_CHILD,0,0,20,20,m_hWnd,NULL,NULL,NULL);

if(::IsWindow(m_hCom))

{

::SetWindowLong(hCom,GWL_ID,IDC_COM);

return 0;

}else

return -1;

}

BOOL DestroyWindow(HWND hWnd);

/*说明:采用WIN32函数销毁控件*/

/*hWnd:EasyComm控件句柄*/

/*举例:可以选择在客户窗体销毁前销毁EasyComm控件*/

void CCustomerWnd::OnDestroy()

{

if(::IsWindow(m_hCom))

::DestroyWindow(m_hCom);

CWnd::OnDestroy();

}

4)、EasyComm控件消息:

COM_SETPORT:设置端口名称

wParam: 0

lParam: 端口号字符串指针

举例:SendMessage(hCom,COM_SETPORT,0,(LPARAM)_T(“COM1”));

COM_GETPORT:取端口号

wParam: 缓冲区大小

lParam:缓冲区指针

举例:TCHAR buf[10];

SendMessage(hCom,COM_GETPORT,9,(LPARAM)buf);

COM_SETBAUDRATE:设置端口波特率

wParam:波特率长整数值

lParam:0

举例:SendMessage(hCom,COM_SETBAUDRATE,4800,0);

COM_GETBAUDRATE:取端口波特率

wParam: 0

lParam: 0

举例:long nBuad = (long)SendMessage(hCom,COM_GETBAUDRATE,0,0);

COM_SETBYTESIZE:设置端口位长

wParam: 位长短整数值

lParam: 0

举例:SendMessage(hCom,COM_SETBYTESIZE,8,0);

COM_GETBYTESIZE: 取端口位长

wParam: 0

lParam: 0

举例:short nByteSize = (short)SendMessage(hCom,COM_GETBYTESIZE,0,0);

COM_SETSTOPBITS: 设置端口停止位

wParam: 停止位短整数值

lParam: 0

#define STOPBITS_ONE 1 /*1位停止位*/

#define STOPBITS_TWO 2 /*2位停止位*/

#define STOPBITS_ONEHALF 3/*1.5停止位*/

举例:SendMessage(hCom,COM_SETSTOPBITS,1,0);

COM_GETSTOPBITS: 取端口停止位

wParam: 0

lParam: 0

举例:short nStopBits = (short)SendMessage(hCom,COM_GETSTOPBITS,0,0);

COM_SETPARITY : 设置端口校验

wParam: 校验短整数值

lParam: 0

#define PY_NONE 0 /*无奇偶校验*/

#define PY_EVEN 1 /*偶校验*/

#define PY_ODD 2 /*奇校验*/

举例:SendMessage(hCom,COM_SETPARITY,0,0);

COM_GETPARITY: 取端口校验

wParam: 0

lParam: 0

举例:short nParity = (short)SendMessage(hCom,COM_GETPARITY,0,0);

COM_SETFCTRL: 设置端口流控制

wParam: 流模式短整数值

lParam: 0

#define FLOWCTRL_NONE 0 /*无流控制*/

#define FLOWCTRL_HARD 1 /*硬件控制*/

#define FLOWCTRL_SOFT 2 /*软件控制*/

举例:SendMessage(hCom,COM_SETCTRL,0,0);

COM_GETFCTRL: 取端口流控制

wParam: 0

lParam: 0

举例:short nCtrl = (short)SendMessage(hCom,COM_GETCTRL,0,0);

COM_SETTIMEOUTS: 设置读写每字节超时毫秒数

wParam: LOWORD为读超时,HIWORD为写超时

lParam: 0

举例:SendMessage(hCom,COM_SETTIMEOUTS,MAKEWPARAM(1,1),0);

COM_GETTIMEOUTS: 取读写每字节超时毫秒数

wParam: 0

lparam: 0

举例:DWORD dw = (DWORD)SendMessage(hCom,COM_GETTIMEOUTS,0,0);

short nReadPerByte = LOWORD(dw); short nWritePerByte = HIWORD(dw);

COM_SETACKCHAR: 设置端口回应字符

wParam: 回应字符

lParam: 0

举例:SendMessage(hCom,COM_SETACKCHAR,(WPARAM)0x06,0);

COM_GETACKCHAR: 取端口回应字符

wParam: 0

lParam: 0

举例: char chAck = (char)SendMessage(hCom,COM_GETACKCHAR,0,0);

COM_SETLISTIMER: 设置端口侦听超时毫秒数

wParam: 短整数毫秒

lParam: 0

举例:SendMessage(hCom,COM_SETLISTIMER,100,0);

COM_GETLISTIMER: 取端口侦听超时毫秒数

wParam: 0

lParam: 0

举例:short nListemTimer = (short)SendMessage(hCom,COM_GETLISTIMER,0,0);

COM_SETQUEUE: 设置端口内部读写缓冲区大小

wParam: 读缓冲区长整数值

lParam: 写缓冲区长整数值

举例:SendMessage(hCom,COM_SETQUEUE,1024,1024)

COM_SETACTIVE: 设置端口状态,打开或关闭

wParam: TRUE则打开端口,FALSE则关闭端口

lParam: 0

举例:SendMesage(hCom,COM_SETACTIVE,(WPARAM)TRUE,0);

SendMessage(hCom,COM_SETACTIVE,(WPARAM)FALSE,0);

COM_GETACTIVE: 取端口状态

wParam: 0

lParam: 0

举例:BOOL bActive = SendMessage(hCom,COM_GETACTIVE,0,0);

COM_SETDATA: 向端口写数据

wParam: 长整数值的数据大小

lParam: 数据指针

返回:已写的字节数

举例:long nWrited = SendMessage(hCom,COM_SETDATA,(WPARAM)size,(LPARAM)data);

COM_GETDATA: 从端口读数据

wParam: 长整数值的请求字节数

lParam: 缓冲区指针

返回:已读的字节数

举例:long nReaded = SendMessage(hCom,COM_GETDATA,(WPARAM)size,(LPARAM)buf);

5)、EasyComm的通知消息:控件通过WM_NOTIFY通知父客户窗体,该消息体的结构为:

struct {

HWND hwndFrom; /*控件的窗体句柄*/

UINT idFrom; /*控件的ID*/

UINT code; /*消息标识*/

WPARAM wParam; /*根据消息标识设置*/

LPARAM lParam; /*根据消息标识设置*/

}NMHDR_COMM;

用于通知端口状态的结构:

struct {

BOOL bRLSDHold; /*非零则端口等待RLSD信号,输出阻塞*/

BOOL bCTSHold; /*非零则端口等待CTS信号,输出阻塞*/

BOOL bDSRHold; /*非零则端口等待DSR信号,输出阻塞*/

BOOL bXOFFHold; /*非零则收到XOFF字符,输出阻塞*/

BOOL bXOFFSent; /*非零则送出XOFF字符,输出阻塞*/

int nInQueue; /*端口输入缓冲区字符数*/

int nOutQueue; /*端口输出缓冲区字符数*/

}CommMonitor;

具体消息标识(code)分述如下:

NC_COMMBREAK:端口中断通知

wParam: 忽略

lParam: 忽略

NC_COMMERROR:端口错误通知

wParam: 错误代码

lParam: 错误文本指针

NC_COMMMONITOR:端口状态通知

wParam: 忽略

lParam: 端口状态结构CommMonitor指针

NC_COMMACK:端口收到回应字符

wParam: 输入缓冲区可读的字符数

lParam: 忽略

NC_COMMRECIVE:端口收到字符

wParam: 输入缓冲区可读的字符数

lParam: 忽略

举例:在客户窗体中响应控件通知

BOOL CCustomerWnd::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)

{

NMHDR* phdr = (NMHDR*)lParam;

if(phdr->idFrom == IDC_COM)

{

NMHDR_COMM* pnc = (NMHDR_COMM*)lParam;

if(pnc->code == NC_COMMBREAK)

{

AfxMessageBox(_T("Comm Breaked"));

}else if(pnc->code == NC_COMMERROR)

{

AfxMessageBox((TCHAR*)pnc->lParam);

}else if(pnc->code == NC_COMMMONITOR)

{

CommMonitor* pcm = (CommMonitor*)pnc->lParam;

}else if(pnc->code == NC_COMMRECIVE)

{

if(pnc->wParam)

{

TCHAR *tmp = (TCHAR*)calloc((long)pnc->wParam + 1,sizeof(TCHAR));

::SendMessage(hCom,COM_GETDATA,(WPARAM)pnc->wParam,(LPARAM)tmp);

free(tmp);

}

}

}

return CWnd::OnNotify(wParam, lParam, pResult);

}

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有