首页 | 源码下载 | 编程控件 | 书籍教程 | 应用方案 | 设计素材 | 项目交易 | 开发文档 | 商业源码 | 我的帐号
登陆我的帐号
帐 号:
密 码:
我还不是会员,需要注册!

截止2004年12月16日
本站源码总量(商业源码除外)RAR压缩为 4,206,733 KB。其中免费源码为 1,124,495 KB,会员源码为 3,082,238 KB
C/C++ 129,555 KB
Delphi 1,258,381 KB
Java 120,937 KB
.Net 36,886 KB
PowerBuilder 954,525 KB
Visual Basic 923,454 KB
ASP 259,795 KB
JSP 4,987 KB
其他 94,723 KB

本站是中国频道、中资源、时代互联顶级代理:注册国际域名70元,国内域名130元,各类ASP、PHP、JSP空间8折优惠!
本站承担各类网站制作开发及方案策划,项目经验丰富,欢迎洽谈!

网站动态
网站春节前夕再次改版!
现在下载速度大幅提高!
想免费下载源码吗?
还有众多资源恭候大家免费…
道歉!
关于资源更新的说明
关于下载错误的原因!
源码资源网新版网站投入运…

当前位置:源码资源网首页 > 开发文档首页 > C/C++ >工控系统串口通讯设计

工控系统串口通讯设计
人气:33 文字大小:     作者:

工控系统通常由工控仪器和计算机终端组成,工控仪器和计算机终端之间通过符合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;
}




 

文章出处:   发表时间:2004-11-20 12:14:47

3条数据记录,分3页显示 上一页 < [1] 2 3 > 下一页
相关文章  
[源码下载] · comicq源代码
[书籍教程] · VC++ 6.0数据库系统开发实例导航
[书籍教程] · Delphi 7数据库编程学习捷径
[书籍教程] · Delphi百例精解
[书籍教程] · DELPHI综合开发文档

相关评论  
 当前没有评论!
请登陆后再来发表评论!
当前位置:源码资源网首页 > 开发文档首页 > 工控系统串口通讯设计
会员升级 | 广告服务 | 网站开发 | 联系我们 | 网站动态 | 客户反馈

CodeRes.com 保留所有权利 2004
本站所有资源仅供学习参考,版权归原作者所有,如侵犯了您的权益请与我们联系