ProfiNet应用实例

 2023-11-6     作者:Lee Leen        

本文为ProfiNet介绍文章《嵌入式环境 实现ProfiNet/PN工业以太网》的应用实例,使用ESM7000+ETA104+UR205PN


1 硬件安装:

如图1,将ETA104V5和UR205PN,以及EM7000核心板,安装至SBC884底板

2.png

图1


如图2,连接编程电脑,交换机,组态用PC,及SBC884板卡系统。

3.png

图2,系统组成



2 PC端组态并配置PLC

2.1 在博图中安装设备GSD

将GSD压缩文件解压并放置到任意目录中,目录中有如下三个文件

4.png


打开博图,并在菜单栏中,通过“选项->管理通用站点描述文件”进入gsd管理。

5.png

 

选择第一步GSD文件的解压路径,并勾选文件,安装。

6.png


完成后,可以在博图的硬件目录中,“其他现场设备-> PROFINETIO -> I/O-> UreateAutomatic -> VARIABLE I/O ->前端模块”中找到新添加的设备。


2.2 博图中组态最简PLC系统

首先新建一个博图项目,然后在拓扑视图中,添加PLC,交换机,和PN模块。我这里选择的PLC是1211C。而模块的位置如下图:

7.png


将PLC和UR205PN模块连接起来。

8.png


然后转到网络视图中,添加他们的连接关系,如图:

9.png


接着双击UR205PN模块,进入设备视图,并在设备插槽中,添加4个数据交换模块

10.png


设备插槽中插入数据交换模块,数据交换模块中插入数据对象。数据对象可以从“1/2/4字节输入”或者“1/2/4字节输出”中选择。

接下来分别为每个数据模块添加数据对象,如下:

13.png

分别是1个1字节输入(两路DI输入),1个1字节输出(对应一路继电器输出),两个2字节输入(对应4-20MA输入)。


这里添加的四个模块,对应的是ETA104模块的输入输出通路。其对应关系如下:

ETA104

UR205PN

信息备注


PKW module_1

PKW问询式通信通道

1路继电器输出

inpupt 1 byte(bit0)

继电器0=数据位0

2路空触头输入

Output 1byte(bit0 ,bit1)

输入0= 数据位0

输入1= 数据位1

电流输入1

Input 2 byte

16位电流输入值

电流输入2

Input 2 byte

16位电流输入值

 

为模块添加变量。

首先我们要找到UR205PN各模块的数据地址。

在博图的设备视图中选择UR205PN模块,并点击各模块,即可查看模块数据在PLC中的位置.例如下图展示的是PKW模块的示意图:

12.png


上图中,说明PKW模块的输入,是从PLC数据地址68到75,共8个字节。PKW模块的输出,是从64到71,共8个字节。

以此类推,可以找到所有数据的地址.本例中数据地址如下表

数据模块

输入地址

输出地址

PKW

68-75

64-71

DI :Input 1 byte

76

--

Do:Output 1byte

--

72

AI0:Input 2 byte

77,78

--

AI1:Input 2 byte

79,80

--

根据数据表,我们在PLC中建立如下变量表:

13.png


建立项目的强制列表,该表用于设置输出值。

14.png


建立项目的监视表,该表用于读取输入值。

15.png


数据变量分为两个区域:PKW 和 周期通信。 周期通信比较好理解,就是每次通信都会交换的周期数据,也是我们在插槽中插入的模块数据:如DI,DO,AI,AO。

PKW_开头的数据对象,则属于PKW访问过程。该访问基于一问一答,过程和定义如下:

16.png

17.png

 

所以,PLC如果要发起PKW通信,需要如下步骤:

1.     PKW_RW_req 设为“0:读”  或者  “1:写”

2.     PKW_INDEX_req 设为需要访问的数据索引

3.     PKW_VALUE_req 如果为写操作,这里需要输入写入的值

4.     PKW_COUNT_req 自增1,以表明是新的PKW访问,触发PN操作

当接收数据时:

1.     等待PKW_COUNT_rsp与PKW_COUNT_req一致

2.     对比回应的INDEX是否等于请求INDEX

3.     若是读取操作的回应帧,则获取PKW_VALUE_rsp


2.3 组态下载到PLC

完成后将组态编译并下载到PLC。

18.png



3 嵌入式端程序编译及运行

3.1 在PC上建立代码编译系统

本案例使用的嵌入式编译开发环境式如下:

操作系统

WIN11 64位

虚拟机操作系统

WSL+Ubuntu-20.04

开发环境

VSCODE WSL 远程连接

C编译链接

arm-poky-linux-gnueabi-gcc

其搭建过程可参考如下文档:《VSCODE嵌入式编译环境搭建》


3.2 PC连接嵌入式板

PC连接嵌入式板的过程,参考英创工控板使用说明。

 

3.3 案例程序文件

解压缩案例代码:test_DIO_pn.rar

通过VSCODE ,WSL方式远程打开该项目。

项目的文件组成如下图所示:

19.png


3.4 应用层通信协议简介

对应用层而言,通信都是建立在周期数据交换帧上。其内部划分为两个功能区:PKW,和周期通信区。这两个功能区在周期通信帧中,他们的位置如下:

20.png


这两个功能区,对应了嵌入式内的两种通信对象:PKW索引访问对象和周期通信访问对象。

21.png


PKW: 数据以<索引-值>的方式存放在嵌入式端,用户可以为某个参数指明特定的索引号,PLC通过问答方式,访问该索引。这种方式适用于交换时间不敏感的数据。例如一些参数。其通信帧定义如下:、

22.png

23.png


周期通信对象:数据每个通信周期都会交换一次,适合时间敏感的通信对象,往往都是一些输入输出值,如DI,DO,AI,AO等。其在帧中定义如下:

24.png


3.5 用户需要实现的代码

在案例中,用户代码区域主要有以下代码段需要维护:

1. 周期通信模块定义

uint8_t UMList[4]={
       //模块类型  模块数据存储区
       MODULE_1BYTE_INPUT,          //1个字节的DI输入
       MODULE_1BYTE_OUTPUT,         //1个字节的DO输出
       MODULE_2BYTE_INPUT,          //16位AI输入
       MODULE_2BYTE_INPUT           //16位AI输出
};


用户通过该数组定义周期通信模块的数量和类型。本案例中,模块如下表:

模块序号

模块类型

模块描述

对应数据对象

0

MODULE_1BYTE_INPUT

一个字节的输入模块

BIT0 = DI0

BIT1 = DI1

1

MODULE_1BYTE_OUTPUT

一个字节的输处模块

BIT0=DO0

2

MODULE_2BYTE_INPUT

两个字节的输入

4-20MA输入1

3

MODULE_2BYTE_INPUT

两个字节的输入

4-20MA输入2

我们目前支持的模块类型有:

#define MODULE_1BYTE_INPUT 0X01  //1字节输入
#define MODULE_2BYTE_INPUT 0X02  //2字节输入
#define MODULE_4BYTE_INPUT 0X04  //4字节输入
#define MODULE_1BYTE_OUTPUT 0X81 //1字节输出
#define MODULE_2BYTE_OUTPUT 0X82 //2字节输出
#define MODULE_4BYTE_OUTPUT 0X84 //4字节输出

(注意这里的输出是以PLC为主站视角,从PLC到嵌入式为输出;从嵌入式到PLC为输入。)

 

2. PKW索引访问区域模块定义

sPKWNode UPKWList[]=
{
    {0x0001,PKW_R|PKW_W,0}, //索引为1的可读写寄存器
    {0x0012,PKW_R,0},   //索引为8001H的只读寄存器
    {0x8002,PKW_W,0}    //索引为8002H的只写寄存器
};

 

3. 周期通信回调函数user_Oncycle

当周期通信发生时,会调用该回调函数,用户在这里将需要传输的值,与PN上的通信值做交换。

例如在本案例中,回调函数如下:

//切换大小端
//pDes 指向切换后的结果存储区
//pSrc 来源
//SIZE 数据字节长度
void sw_bigsmall(uint8_t *pDes, uint8_t *pSrc, uint8_t size)
{
    uint8_t *pD;
    uint8_t *pS;
    for(int i=0;i<size;i++)
    {
          pD = pDes+i;
          pS = pSrc+size-1-i;
          *pD = *pS;
    }
}
 
//用户在该函数中,交换模块和外部设备之间的数据
void user_Oncycle(sPNModule *pModule, int modulecount)
{
    uint8_t *src8;
    uint8_t *des8;
 
    //这里处理周期数据
    if(pModule[0].moduletype == MODULE_1BYTE_INPUT)//确保模块类型正确
    {
          *pModule[0].pmoduleBuff =   ETA105_DI ;
         
    }
    if(pModule[1].moduletype == MODULE_1BYTE_OUTPUT)//确保模块类型正确
          ETA105_DO = *(pModule[1].pmoduleBuff) ;
    if(pModule[2].moduletype == MODULE_2BYTE_INPUT)//确保模块类型正确
          sw_bigsmall((pModule[2].pmoduleBuff),(uint8_t*)&(ETA105_AI[0]),2);
    if(pModule[3].moduletype == MODULE_2BYTE_INPUT)//确保模块类型正确
          sw_bigsmall((pModule[3].pmoduleBuff),(uint8_t*)&(ETA105_AI[1]),2);
}


      4. PKW读索引回调函数user_onReadIndex

当PKW中有新的读取请求时,会执行该回调函数。用户在次函数对该索引数据赋值并执行一些自定义操作。本案例中程序如下

void   user_onReadIndex(sPKWNode *pNode)
{
    uint8_t *src8;
    uint8_t *des8;
    if(pNode == NULL) return ;
    switch(pNode->index)
    {
          case 0x0001:
              //这里添加读0001索引对象时的程序
              break;
          case 0x0012:
              //这里添加读0012索引对象时的程序 假定是波特率
              //这里注意从小端切换成大端
              sw_bigsmall((uint8_t*)&(pNode->value),(uint8_t*)&(m_Serial.baudrate),4);
              break;
          case 0x8002:
              //0x8002不可读,不操作
              break;
 
    }
}


       5 .PKW写操作回调函数

       当有PKW写请求时,系统调用该回调函数,用户在此函数中,将PLC传输来得值写入,并执行相应得自定义操作。

//用户定义的写缩影回调函数
void   user_onWriteIndex(sPKWNode *pNode)
{
    if(pNode == NULL) return ;
    switch(pNode->index)
    {
          case 0x0001:
              //
              break;
          case 0x0012:
              //该对象只读,不操作
              break;
          case 0x8002:
              //
              break;
 
    }
}

   

3.6 PN程序的入口及退出处理:

入口:

      m_Serial.CDC_ACM_number =0; //初始化通信对象
      m_Serial.baudrate = 115200;
      m_Serial.oncycle = user_Oncycle; //注册回调函数
      m_Serial.onPKWRead = user_onReadIndex;
      m_Serial.onPKWWrite = user_onWriteIndex;
      m_Serial.startPN(); //创建PN工作线程


退出处理:

      m_Serial.stopPN( );


本项目为英创公司与第三方公司合作项目。ProfiNet专业技术支持可以联系:

电子邮件          99@ureate.com

电话                 028-85550280-815