关键词:PLC VC++ MFC 通讯模式
1 概述
PLC(Programmable Logic Controller)作为新一代工业控制器,以其高性能价格比在工业测控系统中获得了广泛应用。随着微电子及控制技术的不断发展,PLC已逐渐成为一种智能型、综合型控制器,由PLC构成的集散控制是现代工业控制的一个重要组成部分。在众多的小型集散控制系统中,若使用专业工控组态软件,如INTOUCH、FIX等,制作上位机的监控界面,而以专用的PLC通信接口模块以及其厂家推荐的DDE Server作为联系上位机和PLC的桥梁,则成本较高、投资较大。所以上位机直接与PLC的通讯是一种很好的技术方案。
在Windows环境下开发与工业PLC通讯,可以利用C并借助Windows SDK提供的应用程序接口函数来完成软件的设计,但这样开发的程序很复杂;也可以利用Visual Basic提供的通讯控件来开发串行通讯程序,程序的编制十分简单,但在现实中,许多大的应用系统都是基于VC++平台开发的,VC++是现今最复杂、但也是最强大的一种Windows应用程序开发工程软件。它在图形处理和数据库管理等方面具有较强的优势,并且用它来实现底层的通讯控制有着更快的效率,使用MFC设计的界面与Visual Basic设计的界面一样简练。因此我们利用VC++6.0提供的通讯控件MSComm,以MFC来设计界面编制程序,构造与PLC的通讯系统。系统中的PLC为西门子公司的S7-200系列CPU226型。
2 系统的通讯原理
西门子S7-226型PLC是一种模块化结构的小型PLC,具有较高的性能价格比,它带有两个RS485通讯口,而上位机即工控机的串行口是RS232,所以采用西门子公司专用的PC/PPI编程电缆作为上下位机的连接电缆,它实现了RS232和RS485的转换,并且具有隔离抗干扰功能。整个系统原理图如图1所示。
图1 通讯系统原理
CPU226自带的通讯口RS485采用半双工通讯,只需用两根数据线TXD和RXD来发送数据和接收数据,所以通讯中没有硬件握手信号,而只能采用软件握手的通讯方式保持数据传输的同步。为了保证通讯的安全性,必须对发送的数据帧中加入帧校验码(FCS),采取的方法是:把所发送的数据帧中的数据按照字节进行异或运算后得到的FCS连同数据一起发送。接收方收到后,进行同样的运算,并把结果与FCS比较,如果两者不相等,则认为传输数据出错。对于检验到出错的数据采取放弃的措施,并立即发送反馈信号要求发送方重发数据。因此上位机和PLC发送数据的格式分别为表1和表2所示。控制命令如请求、应答等信号另有则不必加上校验码。
表1上位机数据格式
表2 PLC数据格式
3 系统的软件设计
3.1系统的控制流程
整个通讯由上位机触发开始,首先由上位机发送握手信号,PLC接收到握手信号后,发送回握信号;上位机收到回握信号,则开始发送请求指令,PLC收到指令后发送数据给上位机;上位机收到数据进行校验,出错则要求PLC重发,没有错误则处理输出显示。下面图2和图3分别就是上位机和PLC的通讯程序流程图。
图2 上位机程序流程图 图3 PLC程序流程图
3.2 PLC软件设计
S7-200系列PLC有两种通讯模式:一种是点对点(PPI)通讯模式,另一种是对用户完全开放的自由口通讯模式(free port mode),PPI模式用于PLC间直接连接的通讯,可以组成网络,自由口模式应用于PLC与计算机间以及PLC间无线通讯等方面。本通讯系统采用自由口通讯模式。在通讯之前通过改写SMB30或SMB130来选择通讯模式,设定波特率以及数据长度和校验位。对于数据发送,采用专用发送指令XMT TABLE, PORT,其中TABLE为发送缓冲区的首地址,首地址中保存要发送的字节数,即数据长度,最大为255,其后的地址中保存要发送的数据,PORT指定用于发送的端口。对于数据接收,使用接收指令RCV TABLE, PORT,接收指令激活初始化或结束接收信息,通过指定端口(PORT)接收信息并存储于数据缓冲区(TABLE),数据缓冲区的第一个数据指明了接收的字节数。在西门子PLC编程语言中,共有33个中断事件,其中用于通讯口的中断事件就有6个。在通讯过程中,我们利用中断来实现发送数据和接收数据的切换,当数据发送完成,会产生发送字符中断事件,在中断程序中切换到接收状态;当接收数据完成,会产生接收信息完成中断事件,在中断程序中切换到发送状态,由于收发切换有一定的间隔,所以必须延时一段时间再发送数据,我们用定时中断来产生延时。为了产生接收信息完成中断事件,必须要对RCV指令设定结束信息作为判断接收完成的条件,通过向SMB89或SMB189中装入字符来设置,这个字符必须与上位机发送来的结束信息相吻合。
以下是PLC的部分程序:
MAIN(主程序)
NETWORK 1
LD SM0.1
MOVB 16#09, SMB30//初始化自由端口,选择9600波特率,8位数据,无校验
MOVB 16#A0, SMB87//RCV允许,检测信息结束字符
MOVB ‘@’, SMB89//设定信息结束字符为‘@’
MOVB 10, SMB94//设定最大字符数为10
MOVB 5, SMB34 //定时中断0为5ms
ATCH 0,23//接收完成事件连接到中断0
ENI//允许全局中断
NETWORK 2
RCV VB300, 0//接收数据
NETWORK 3
LD SM0.0
MOVB 16,VB200//发送16个字符
MOVD 16#4521347E, VD201//以下是实验数据
MOVW +9860, VW205
MOVD 16#12345678, VD207
MOVW +10562, VW211
MOVW +8568, VW213
MOVB 8, VB215
CALL SBR_0
INT_0(中断0子程序)
NETWORK 1//如果接收到的字符为‘K‘,则继续接收
LDB= VB302, ‘K‘
RCV VB300, 0
NETWORK 2//如果接收到的字符为‘A‘、‘C‘或者‘R‘,则发送数据
LDB= VB302, ‘A‘
OB= VB302, ‘R‘
OB= VB302, ‘C‘
ATCH INT_1, 10//启动定时中断
NETWORK 3 //如果接收到的字符为“Z”,则
停止延时发送
LDB= VB302, ‘Z‘
DTCH 10
INT_1(中断1子程序)
LD SM0.0
XMT VB200, 0//发送数据
DTCH 10//关定时中断
3.3 上位机软件设计
系统中上位机的软件部分利用VC++提供的通讯控件MSComm,以MFC为基础编制通讯程序。MSComm通讯控件提供了使用RS232开发串行通讯软件的细则,它使用事件驱动或查询方式来解决开发通讯软件中遇到的问题。事件驱动是一种功能强大的处理问题的方法,对事件发生的跟踪和处理在通讯控件中是用OnComm来实现的,它包括检测和处理通讯错误以及数据的处理显示等。为了清楚了解现场的工作状态,可以在界面上实时显示摄像机观察到的内容,为此,需要对图像采集卡采集到的图像进行分析处理,这里就不再详述。图4为通讯界面。
程序设计方法如下:
(1)建立项目:启动VC++6.0,利用MFC AppWizard(exe)应用向导建立一个基于对话框的应用程序ScommTest。
图4 通讯界面
(2)在项目中插入MSComm控件:选择Project菜单下Add To Project子菜单中的 Components and Controls…选项,在弹出的对话框中双击Registered ActiveX Controls项,选择Microsoft Communications Control version 6.0,单击Insert按钮将它插入到Project中来,接受缺省的选项。
(3)在对话框中添加控件:向主对话框中添加通讯控件、按钮、文本框、编辑框和组合框,其中部分属性如表3所示。
表3控件属性表
(4)初始化串口:在OnInitDialog()函数中添加初始化串口参数的代码
// TODO: Add extra initialization here
if(m_ctrlComm.GetPortOpen())
m_ctrlComm.SetPortOpen(FALSE);
m_ctrlComm.SetCommPort(1); //选择com1
if( !m_ctrlComm.GetPortOpen())
m_ctrlComm.SetPortOpen(TRUE);//打开串口
else
AfxMessageBox("cannot open serial port");
m_ctrlComm.SetSettings("9600,n,8,1"); //波特率9600,无校验,8个数据位,1个停止位
m_ctrlComm.SetInputMode(1); //1:表示以二进制方式检取数据
m_ctrlComm.SetRThreshold(16); //参数15表示每当串口接收缓冲区中有多于或等于15个字符时将引发一个接收数据的OnComm事件
m_ctrlComm.SetInputLen(0); //设置当前接收区数据长度为0
m_ctrlComm.GetInput();//先预读缓冲区以清除残留数据
(5)编写帧校验函数:首先在CSCommTestDlg类中加入公共成员函数说明
BYTE PLCData[30];//定义输入数据存储区
Void verfun(BYTE vdata[],int n);//定义校验函数
然后写帧校验函数:
void CSCommTestDlg::verfun(BYTE vdata[],int n)
{
int i;
BYTE sum=vdata[0];
for(i=1;i<=n-2;i++)
sum︿=vdata[i];//计算校验码
vdata[n]=sum;//保存帧校验码
}
(6)为通讯控件IDC_MSComm1添加OnComm消息处理函数OnComm()
void CSCommTestDlg::OnComm()
{
VARIANT variant_inp;
COleSafeArray safearray_inp;
LONG len,k;
BYTE rxdata[2048]; //设置BYTE数组(8位无符号整数)
CString strtemp;
if(m_ctrlComm.GetCommEvent()==2) //事件值为2表示接收缓冲区内有字符
{
variant_inp=m_ctrlComm.GetInput();//读缓冲区
safearray_inp=variant_inp; //VARIANT型变量转换为ColeSafeArray型变量
len=safearray_inp.GetOneDimSize(); //得到有效数据长度
for(k=0;k
safearray_inp.GetElement(&k,rxdata+k);//转换为BYTE型数组
for(k=0;k
{
PLCData[k]=rxdata[k];
}
verfun(PLCData,16);//计算校验码
if(PLCData[15]==PLCData[16])
{ //接收数据正确发送确认信号
m_ctrlComm.SetOutput(COleVariant(“K@”));
//可以在下面自行加上对数据的处理
if(!m_quit)//如果没有结束信号则续传数据
m_ctrlComm.SetOutput(COleVariant(“C@”));
else
m_ctrlComm.SetOutput(COleVariant(“Z@”));
}
else //接收数据出错要求重发数据
m_ctrlComm.SetOutput(COleVariant(“R@”));
(7)为按钮IDC_BUTTON_START和IDC_BUTTON_QUIT添加消息处理函数OnButtonStart()和OnButtonQuit()
void CSCommTestDlg::OnButtonQuit()
{
m_quit=TRUE;
}
void CSCommTestDlg::OnButtonStart()
{
m_quit=FALSE;
m_ctrlComm.SetOutput(COleVariant("A@"));
//发送请求信号
}
4 结束语
本文运用VC++和MFC开发了计算机与PLC的通讯系统,充分利用计算机和PLC本身的资源实现了上位机对PLC的实时监控,可以有效地对作业工具进行监控和管理。本文介绍的通讯系统用于超高压带电作业机器人的控制系统,实践表明,系统简练、稳定,取得了令人满意的效果。
参考文献
[1] 李志虎等.基于Visual C++的上位机和PLC的通信实现.计算机工程,2000(8)
[2] 朱正礼等.基于VC++的PLC与上位机的通讯.电气传动,2002(2)
[3] 西门子有限公司.西门子S7-200可编程序控制器系统手册,1999