• 基于C#SerialPort通信控件的PLC、工控机MODBUS通信方法研究

    0310000000020400000000F817

    *:地址信息为地址范围-1,并省略最高位,如30001的地址为0000

    其中需要注意,“地址信息为地址范围-1,并省略最高位,如30001的地址为0000”;这一条规则在PLC中体现。

    2. 西门子PLC程序搭建

    本方法采用的是西门子S-200系列的226 CN CPU模块,其特点是有两个RS485通信口,均可以实现MODBUS通信和自由口通信(同时使用时只有一个能用于MODBUS通信),出于简便,我们使用西门子编程软件自带的MODBUS通信协议库来完成通信程序的编写。其程序如下所示(通信部分):

    【摘要】针对西门子PLC Modbus通信提出一种基于C# SerialPort控件的简便的通信方式,以实现通过工控机对PLC程序进行仿真、调试和监控等功能,此通信方式和采用西门子专属硬件的通信方式相比有较大的成本优势,而且其程序简便灵活,也可以用于其他类型PLC、智能仪表、I/O卡等智能控制器和工控机的通信。

    【关键词】西门子PLC;Modbus通信;C#;SerialPort;

    引言

    随着科技的进步和生产效率的提高,现代企业的工业生产现场对生产线自动化水平的要求已经越来越高,PLC系统的使用成为了一种灵活、廉价的自动化实现方法,而对于现代化企业来说,光有PLC还是不够,因为不仅仅是生产现场的操作人员需要了解实时的车间生产状况,其他相关部门,如生产、设备、质管以及公司决策者均需要掌握工厂的实时监控,这就引申出了MES虚拟工厂的概念,所以,为实现这样一种高度自动化的工厂生产模式,PLC等控制器需要有一种方便、廉价的组网方法来实现系统数据的整合、控制。

    基于这方面的考虑,本文就通过C#语言的SerialPort控件实现和PLC的MODBUS通讯提出了一种简便的方法。

    1. 基于西门子S-200系列PLC的MODBUS通信规约

    关于西门子MODBUS通信的内容较为复杂繁多,限于篇幅,这里仅总结其基本规则和常用数据帧格式,以对其通信程序的编制提供依据。

    1.1西门子MODBUS通信基本规则

    1.1.1 所有RS485通讯回路都应遵照主/从方式,数据可以在一个主站(如:PC)和32个子站之间传递。

    1.1.2 在RS485回路上的所有通讯都以“信息帧”方式传递,按照不同的指令有不同格式。

    1.1.3 如果主站或子站接收到含有未知命令或错误的信息帧,则不予以响应。

    1.1.4 MODBUS有两种传输方式,一种为ASCII模式,另一种为RTU模式,本文讨论RTU模式。

    1.1.5 MODBUS数据帧采用CRC校验。

    1.2西门子MODBUS通信数据帧格式

    西门子S7-200系列PLC采用Modbus RTU通信模式,常用的指令如下表所示:

    表1 S7-200系列常用PLC Modbus RTU通信数据帧格式表

    地址范围

    R/W

    功能号

    请求数据帧格式

    数据帧范例

    回应数据帧格式

    00001-00xxx

    R

    01H

    站号(1)+功能号(1)+地址*(2)+数量(2)+CRC(2)

    0301000000083C2E

    00001-00xxx

    W

    05H

    站号(1)+功能号(1)+地址*(2)+数据(2)+CRC(2)

    0305000000010DE8

    00001-01xxx

    W

    0FH

    站号(1)+功能号(1)+地址*(2)+数量(2)+数据(N)+CRC(2)

    030F0000000801007F4C

    10001-10xxx

    R

    02H

    站号(1)+功能号(1)+地址*(2)+数量(2)+CRC(2)

    030200000008782E

    10001-11xxx

    W

    -

    -

    -

    30001-30xxx

    R

    04H

    站号(1)+功能号(1)+地址*(2)+数量(2)+CRC(2)

    030400000008F02E

    30001-31xxx

    W

    -

    -

    -

    40001-40xxx

    R

    03H

    站号(1)+功能号(1)+地址*(2)+数量(2)+CRC(2)

    03030000000845EE

    站号(1)+功能号(1)+数量(1)+数据(N)+CRC(2)

    40001-41xxx

    W

    06H

    站号(1)+功能号(1)+地址*(2)+数据(2)+CRC(2)

    0306000000008828

    站号(1)+功能号(1)+地址*(2)+数据(2)+CRC(2)

    40001-41xxx

    W

    10H

    站号(1)+功能号(1)+地址*(2)+数量1**(2)+数量2**(1)+数据(N)+CRC(2)


    图2.1 西门子PLC程序Modbus通信初始化指令
    此条指令为MODBUS通信的主站初始化设置指令,其中“Baud”为通信频率,“Parity”为校验位设置,“Timeout”为报错时间,“Done”为完成位,“Error”为故障位。

    主程序是作为一个高压变频器仿真软件实现PLC的脱机联调功能,其简略的操作界面如下图所示:

    图2.2 西门子PLC程序Modbus通信数据传送指令

    该指令读取从站的数据,从地址41027读取一个字的数据送往地址&Val_Read02:&VB400开始的存储区。其中“Slave”表示需要读取从站的地址;“RW”用于区分读取还是写入,0为读取1为写入;“Addr”为从站地址;“Count”为读取字数量;“DataPtr”为存储区首地址。

    本方法使用的PLC程序的主控制部分是通过和HMI的配合实现高压变频器的运行控制,其数据存储如下所示:

    表2 PLC程序读写数据地址表

    PLC读取首地址

    PLC写入首地址

    变频器运行频率

    0402H

    设定频率

    0482H

    A相各单元状态

    0404H

    加速时间常数

    0483H

    B相各单元状态

    0406H

    减速时间常数

    0484H

    C相各单元状态

    0408H

    转矩补偿

    0485H

    第9单元状态

    040AH

    正/反转

    0481H

    通信子板定时器

    0410H

    启动/停止

    0480H

    我们将根据以上数据利用C#设计一个基于MODBUS通信方式的高压变频器模拟程序,通过该程序我们可以很方便的对该PLC程序进行调试,而不需实际连接高压变频器,以节省时间和成本。

    3. CRC校验程序的编写3.1CRC校验原理

    冗余循环码(CRC)包含2个字节,即16位二进制。CRC码由发送端计算,放置于发送信息的尾部。接收端的设备再重新计算接收到信息的CRC码,比较计算得到的CRC码是否与接收到的相符,如果二者不相符,则表明出错。

    CRC码的计算方法是,先预置16位寄存器全为。再逐渐把每8位数据信息进行处理。在进行CRC码计算时只用8位数据位,起始位及停止位,如有奇偶校验位的话也包括奇偶校验位,都不参与CRC码计算。

    在计算CRC码时,8位数据与寄存器的数据相异或,得到的结果向低位移一位,用0填补最高位。再检查最低位,如果最低位为1,把寄存器的内容与预置数相异或,如果最低位为0,不进行异或运算。

    这个过程一直重复8次。第8次移位后,下一个8位再与现在寄存器的内容相异或,这个过程与上以上一样重复8次。当所有的数据信息处理完后,最后寄存器的内容即为CRC码值。

    3.2CRC校验的计算方法

    CRC校验的计算基本步骤如下:

    1,置16位寄存器为十六进制FFFF(即全为1)。称此寄存器为CRC寄存器。

    2,把一个8位数据与16位CRC寄存器的低位相异或,把结果放于CRC寄存器。

    3,把寄存器的内容右移一位(朝低位),用0填补最高位,检查最低位(移出位)。

    4,如果最低位为0:复第3步(再次移位)。

    5,如果最低位为1:CRC寄存器与多项式A001(10100000 0000 0001)进行异或。

    6,重复步骤3和4,直到右移8次,这样整个8位数据全部进行了处理。

    7,重复步骤2到步骤5,进行下一个8位的处理。

    8,最后得到的CRC寄存器即为CRC码,低字节在前,高字节在后。

    16位CRC校验实际程序如下所示:

    static int crc16_modbus(Byte[] modbusdate, uintLength)

    {

    uint i, j;

    int crc16 = 0xFFFF;

    for (i = 0; i < Length; i++)
    {

    crc16 ^= modbusdate[i];

    for(j = 0; j < 8; j++)
    {

    if((crc16 & 0x01) == 1)

    crc16 = ((crc16)>> 1) ^ 0xA001;

    else

    crc16 = crc16 >>1;

    }

    }

    returncrc16;

    }

    4. 通信程序的编写

    C#是微软公司推出的一种语法简洁、类型安全的面向对象的编程语言,开发人员可以通过它编写在.NET Framework上运行的各种安全可靠的应用程序,一般用于开发桌面程序,是当前应用最广、最全面的高级开发语言之一。

    4.1 应用程序窗口

    C#

    11 10 04 82 00 01 02 01 F430 65 ;PLC发出写设定频率命令

    11 10 04 82 00 01 A241 ;程序回应

    11 10 04 83 00 01 02 00 05 F1 A0 ;PLC发出写加速时间命令

    11 10 04 83 00 01 F381 ;程序回应

    11 10 04 84 00 01 02 00 10 31 D8 ;PLC发出写减速时间命令

    11 10 04 84 00 01 42 40 ;程序回应

    11 10 04 85 00 01 02 00 01 F0 05 ;PLC发出写转矩补偿命令

    11 10 04 85 00 01 13 80 ;程序回应

    11 10 04 80 00 01 02 00 0F 71 94 ;PLC发出写启停命令

    11 10 04 80 00 01 03 81 ;程序回应

    实际写程序如下所示(段落):

    int Addr_W;

    stringWriStr = "1";

    string[]WRITEN= new string[8];

    byte[]Writener = new byte[10];

    for(int i = 0; i < 8; i++)
    {

    WRITEN [i] = Convert.ToString(Byte[i]);

    }

    WriStr = Convert.ToString(Convert.ToInt16(WRITEN[4])*256 + Convert.ToInt16(WRITEN[5]));

    Addr_W = Byte[2] * 256 + Byte[3];

    5. 结论

    通过本通信方式的探讨我们可以发现,在越来越多的PLC应用实例中,通过C#或者其他高级编程语言可以很方便的根据现有的通信协议实现PLC和工控机之间的通信,考虑到现有PLC产品配套软件尤其是一些大牌器厂商的高昂价格,这种通信方式有很大的经济价值,也能更灵活多变的适应不同的应用场合。

    参考文献

    【1】明日科技.C#开发入门及项目实战[ M].北京:清华大学出版社,2012.

    【2】刘强,张战宁,徐昊.用C#实现PC与西门子PLC串行通信[ J].自动化与仪器仪表,2008.5(139).60-62.

    图4.1 变频器主板仿真器程序界面

    通过该程序我们可以模拟高压变频器的运行以测试与其连机的PLC中程序的实用性和完善性,通过上图所示操作界面我们可以方便的模拟各种故障异常,也能够监控PLC下达的各种指令。

    4.2 SerialPort控件的使用

    在C#编程环境中通信控件为SerialPort,其设置和使用比较简单方便。其初始化设置方法如下所示:

    serialPort1.DataBits =8;//设置每个字节标准数据位长度;

    serialPort1.Parity =System.IO.Ports.Parity.None;//设置校验位检查协议;

    serialPort1.ReceivedBytesThreshold= 2;//设置接收DataReceived事件发生前内部输入缓冲区中的字节数;

    serialPort1.ReadBufferSize= 10;//设置数据缓冲区大小;

    serialPort1.Open();//打开串口连接;

    在打开连接后可以检查串口是否打开,使用:“serialPort1.IsOpen”进行检查,调用“MessageBox.Show("串口"+ serialPort1.PortName + "已经打开!", "系统提示")”进行提示。另外还可以通过“serialPort1.PortName”指令选择不同的端口。

    4.2 收发数据程序

    4.2.1 主站读程序

    读数据子程序为“public voidSeriaPort_R( byte[] Byte”,地址计算指令“Addr =Byte[2] * 256 + Byte[3]”,我们通过其计算实际的地址值,通过程序判断读取界面设置的模拟值(也可以是程序的计算模拟值)。

    实际在PLC主站发出读取指令时,SerialPort收到的数据如下(“即时接收数据”监控数据):

    11 03 04 02 00 01 26 6A ;PLC发出读运行频率命令

    此时程序的回应值为:

    11 03 02 00 00 79 87 ;程序回应

    与此类似的还有:

    11 03 04 04 00 01 C66B ;PLC发出读A相状态命令

    11 03 02 00 00 79 87 ;程序回应

    11 03 04 06 00 01 67 AB ;PLC发出读B相状态命令

    11 03 02 00 00 79 87 ;程序回应

    11 03 04 08 00 01 06 68 ;PLC发出读C相状态命令

    11 03 02 00 00 79 87 ;程序回应

    11 03 04 10 00 01 86 6F ;PLC发出读通讯定时器命令

    11 03 02 09 BC 7E 66 ;程序回应

    11 03 04 0A00 01 A7 A8 ;PLC发出读第9单元状态命令

    11 03 02 00 00 79 87 ;程序回应

    实际通信程序发送段部分代码如下:

    SenInt =Convert.ToInt16(SenStr,10 );

    Sender[0] = Byte[0];

    Sender[1] = Byte[1];

    Sender[2] = 2;

    Sender[3] = Convert.ToByte((SenInt >> 8)& 0x00FF);

    Sender[4] = Convert .ToByte(SenInt&0x00FF);

    CRC_Sen = crc16_modbus(Sender,5);

    Sender[6] = Convert.ToByte((CRC_Sen >> 8)& 0x00FF);

    Sender[5] = Convert.ToByte(CRC_Sen & 0x00FF);

    for (int i = 0; i < 7; i++)
    {

    SEND[i] = Convert.ToString(Sender[i],16);

    }

    SENDER = SEND[0] + SEND[1] + SEND[2] + SEND[3] +SEND[4] + SEND[5] + SEND[6];

    serialPort1.Write(Sender,0,7);

    4.2.1 主站写程序

    PLC写程序和读程序类似,其实际数据交换如下所示:

    11 10 04 81 00 01 02 00 0F 70 45 ;PLC发出写正反转命令

    11 10 04 81 00 01 52 41 ;程序回应
    2014/8/31 19:28:31
举报不良信息

 

 大  小