构建EtherCAT从站:使用STM32和LAN9252

目录

(一):项目简介

EtherCAT及项目简述

LAN9252工作模式

整体开发流程

移植要处理的问题

代码层面的工作

开发中使用的工具

(二):SSC的使用

SSC简介和下载

SSC构建协议栈文件和XML

(三):LAN9252的XML文件

EtherCAT从站XML文件简介

XML中的设备基础信息

XML中的字典和IO数据

XML中的EEPROM内容

(四):STM32配置SPI

使用STM32CubeMX软件配置MCU外设

Keil5中适配SPI

SPI适配

总结

(五):STM32与LAN9252适配

1.硬件

2.软件

3.总结

(六):TwinCAT2的使用和从站测试

1. TwinCAT连接PLC

2 从站设备发现

3. 点位观察和强制

4. PLC测试

总结


(一):项目简介

EtherCAT及项目简述

EtherCAT是一种基于以太网的工业通信协议,类似于Profinet。

EterhCAT协议是一主多从模式,主站一般是由一个装有TwinCAT的PC机担任,PC机对网卡特殊要求,需要支持EtherCAT的网卡。本项目的主站是一台倍福CX9020(仅支持TwinCAT2.0),这是一台ARM架构的PC,内装Windows CE操作系统,操作系统中装了TwinCAT2.

项目需要开发其从站,周期交互IO:64入64出,选用STM32F103+LAN9252构建。

LAN9252工作模式

根据LAN9252的Datasheet所述,LAN9252一共有四种工作模式:

  • 自我工作模式(数字I/O模式),8入8出
  • SPI 串口通信模式,4线串行数据(或更多SQI)
  • 并行通信模式(HBI),16/8位数据交互
  • 扩展模式,LAN9252与MCU之间SPI通信,同时对外再提供一组MII接口,可扩展连接另一组PHY芯片,多接一个RJ45端子。
  • 根据需求,项目选择SPI串口模式。

    整体开发流程

    1. 淘宝购买相关学习板,得到文档和协议栈。
    2. 根据项目需求构建XML,该XML将会由TwinCAT2解析,并将相关特诊烧录进LAN9252连接的EEPROM中。
    3. 根据学习板附带的文档,尽可能理解EtherCAT协议栈和通信步骤。
    4. 根据项目需求绘制自选MCU与LAN9252的原理图和PCB。
    5. 移植相关代码到自己的MCU中,TwinCAT中编写PLC测试和调试。

    整个体系中,LAN9252起到以下作用:

  • PHY的作用,所有跟以太网RJ45交互的工作,都由LAN9252完成。
  • 网络交换作用,EtherCAT要求从站必须有一拖一的能力,不可以终结总线,LAN9252有2端口/3端口模式,内部做网络交换。
  • 数据解析及SPI下位机作用。MCU可以作为SPI主模式与LAN9252进行数据交互,其交互流程在协议栈中,非常复杂,没能完全理解。
  • 移植要处理的问题

    1. 首选需要初步理解TwinCAT使用的XML的作用,此XML是对设备的描述,类似于GSD文件。描述了通信时需要使用的对象字典,数据类型,长度等等。xml文件一般都有好几兆大小,但TwinCAT只会解析XML并将其中一部分特征数据烧录进LAN9252挂载的EEPROM中去,所以并不需要担心EEPROM大小问题,一般选择512KB的快速EEPROM(24FC512)。
    2. 根据自己的项目要求,设计XML,这个工作可以通过EtherCAT的开发工具SSC来简单实现,如果不使用SSC,手工修改XML将是一件非常麻烦的事情。
    3. SSC在生成XML的同时,还可以生成代码,这份代码是没法直接用的,但里面有关字典的.c文件非常有价值,可以参考并移植到开发板的代码中去,完成自己的逻辑。

    代码层面的工作

    整个EtherCAT协议栈相当复杂,几乎没办法阅读,只能从main()函数入手,简单地剥解一下代码,可以看到整个项目是由三个大函数构建而成的:

    HW_Init();
    MainInit();
    while (1){
        MainLoop();
    }

    以上就是整个EtherCAT协议跑起来的骨架。 此外,在MCU的GPIO和内部资源部分,需要做到以下几点:

    1. SPI四根线的使能,跟LAN9252的通信就靠它了。
    2. 一个定时器中断,1ms周期,调用ECAT_CheckTimer();函数,但不要一上来就初始化使能这个中断,根据接口定义好使能入口,让协议栈调用,以上电就开启这个定时器中断会导致连接失败。
    3. 三个外部中断,IRQ,SCY0,SCY1,其中IRQ必须实现,SCY0和SCY1是分布式时钟同步用的,可以选择使用,也可不使用,注意这三个中断的使能同样要根据代码中的接口定义入口,由协议栈使能和失能中断,万万不可一上电就来使能中断。中断中处理的代码如下:
      void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
       if (GPIO_Pin == LAN9252_IRQ_Pin) {
               PDI_Isr();
               return;
       }
       if (GPIO_Pin == LAN9252_SYC0_Pin) {
           DISABLE_ESC_INT();
           Sync0_Isr();
           ENABLE_ESC_INT();
           return;
       }
       if (GPIO_Pin == LAN9252_SYC1_Pin) {
           DISABLE_ESC_INT();
           Sync1_Isr();
           ENABLE_ESC_INT();
           return;
       }
      }

    开发中使用的工具

  • STM32CubeMX5.1, Keil5(TrustStudio), Sublime3
  • SSC, XMLSpy
  • TwinCAT2.0, VirtualBox
  • AltiumDesigner18
  • (二):SSC的使用

    SSC简介和下载

    SSC(Slave Stack Code Tool)从站协议栈代码工具,是EtherCAT协会为会员免费提供的,EtherCAT会员可以免费申请,可以致电其北京办事处寻求中文帮助,对方可以指导您与德国总部进行会员申请:EtherCAT Technology Group | 联系方式

    使用SSC,可以快速地构建EtherCAT从站代码,保证从站协议栈与最新的EtherCAT协议相匹配,同时还可以生成从站设备描述文件,这是一份XML文件,需要放在TwinCAT安装路径下的/Io/EtherCAT目录下,在使用TwinCAT对设备进行组态时需要使用。是EtherCAT从站设计过程中很重要的一个文件,关于从站设备传输多少数据,是否启用分布式时钟,PHY(LAN9252)与MCU之间如何通信等等重要数据都在这个描述文件中定义。这份XML如果全靠手工编辑,工作量非常大,并且极易出错,有了SSC后,构建XML将非常简单。

    在官网下载SSC时,需要用户提供VendorID,这是由EtherCAT协会为其会员企业提供的全球唯一标志,企业可以用其作为所生产设备的标志。

    SSC构建协议栈文件和XML

    我们的项目简单使用64入64出纯数字IO,制作一个由键盘和LED灯组成的EtherCAT从站面板,来跟BECKHOFF的PLC进行通信。LAN9252与MCU之间的通信方式我们选择使用SPI方式。

    打开SSC后,File->New,打开新建项目的对话框,这里让我们选择一个项目模板,可以使用默认选项创建,该选项提示我们All settings are available.,这里我们不选则默认模板,而是在点中Custom单选按钮中,下拉出一个EL9800 | 8Bit Digital I/O, 16Bit Analog Input,选中它,下方提示我们:

    This configuration provides the standard configuration for the new EL9800 EtherCAT Evaluation Kit.
    The corresponding device description is located in file "..\esi\SlaveStackCode.xml" (device: EL9800-SPI-PIC24) or will be created by this tool.

    显然这个模板更加适合我们,点击OK进入下一步。

    此时界面由左边的树状菜单和右边的内容条目组成,有许多可以配置的选项,包括VendorID和Image等LOGO的设置。如果有兴趣可以对其进行设置,也可以直接进入下一步。

    依次点击Tool->Application->Create New,提示需要先保存一下,随便找个路径保存一下本项目。保存成功后,会立刻弹出一个Excel文件(需要预先安装Excel)。

    这是一份模板Excel,用来设置EtherCAT的通信数据,我们将使用此Excel进行传输IO的点位设置。根据之前的计划,输入有64个BIT,输出有64个BIT,因此对该Excel的//0x6nnx//0x7nnx条目进行配置,配置方法如下: 按照上述三张图片的配置,熟练使用Excel的批量拖拽方法,可以快速地填入。不要忘了修改最后一个Maximum number of modules条目,改成3即可。 都修改好以后,保存Excel,SSC会自动打开导入该Excel的对话框,点击OK进行导入。 导入完成后界面并不会有太大变化,此时需要点击Project->Create new Slave Files进行协议栈文件的创建。 创建完成后整个工程项目如图所示: 至此,使用SSC的工作就都完成了。下面的工作是对其生成的XML文件进行微调,并对协议栈文件进行移植。

    本章所介绍的知识点大部分来自于SSC内置的一份帮助文档EtherCAT Slave Design Quick Guide.pdf,可以点击下载。我已经代表我们企业申请加入了EtherCAT协会,并注册了VendorID,在EtherCAT协会入会章程中不允许会员在互联网上扩散只有会员才可以下载到的资源,因此SSC的安装包我不方便上传,有需要的小伙伴可以私下交流,发邮件至newflydd#gmail.com。

    (三):LAN9252的XML文件

    EtherCAT从站XML文件简介

    每一个EtherCAT从站设备都需要有一个硬件描述的XML文件,用来给TwinCAT组态,XML文件中描述定义了通信时需要用到的各种数据。包括设备所属公司名,设备名,设备版本,LOGO等基础信息,亦包括通信时的点位,点位名称,大小,数量等信息,还包括一个非常特别的14ByteConfigData,这14个字节用来给PHY识别,像ET1100,LAN9252等芯片通过其来识别自身的工作方式,比如第一章STM32与LAN9252构建EtherCAT从站(一):项目简介中我们提到的LAN9252工作的四种方式就是通过这组数据进行确定的。

    TwinCAT对设备进行组态时,首先通过其硬件网卡搜索网络上所有的EtherCAT设备,发现设备后可以将XML文件烧录至LAN9252连接的EEPROM中,此后设备上电时,PHY就能根据EEPROM中的数据对自身进行相应的配置。关于TwinCAT的使用,我们在第六章STM32与LAN9252构建EtherCAT从站(六):TwinCAT2的使用和从站测试详细介绍。

    XML文件比较大,用普通的文本编辑器打开会显得有些凌乱,上下文结构也不能很好的体现。因此需要一些专门处理XML的工具来辅助编辑,推荐的有XMLSPY和XML Notepad,前者是收费的,破解版也很难找,后者是微软2007年出的,免费试用,但是年代有些久远,功能也不及前者多。

    XML中的设备基础信息

    如图使用XMLNotepad打开上一章STM32与LAN9252构建EtherCAT从站(二):使用SSC生成EtherCAT协议栈和XML文件生成的XML文件,可以粗略地观察到整个文档由两个节点组成,VendorDescriptions

    Vendor下面的idname来自于EtherCAT会员企业信息,我这里不方便用我们公司的真实信息,暂且用#x1EtherCAT来替代。

    Vendor下面的ImageData16x14节点,存储的是.bmp格式的16色深度的logo文件,可以使用微软画图或者Photoshop等软件制作,制作完成后使用任何16进制查看器(Notepad++和Sublime都有相关插件直接查看任何文件的16进制数据)将数据填入该节点。

    Descriptions->Groups->Group节点下方的TypeName两个节点描述的设备类型的种类和名称,这里根据自己的想法自定义即可。ImageData16x14是设备类型图标,可以直接用上面的数据。

    Descriptions->Devices->Device->Physics是以太网口类型,YY表示两个RJ45,一进一出,跟Y相对应的是K,表示EBUS网口,德国倍福的专用端口,不需要修改。

    Descriptions->Devices->Device->Type节点下的ProductCodeRevisonNo表示的是硬件编号和版本号,这里取一些有意义的名称,产品迭代升级时不要忘记这里的版本号也应该做相应的升级。TwinCAT通过这两个字段确定XML的唯一性,也就是说你如果两份XML这两个字段一样,放到TwinCAT/IO/EtherCAT文件夹下,只能识别其中一个。

    Descriptions->Devices->Device->Name设备名,任意取。

    Descriptions->Devices->Device->Info节点存储了一些超时限制的数据,没有特殊情况不需要修改,这里设置好了以后在TwinCAT界面可以看到设备在各种状态切换时的超时限制。

    Descriptions->Devices->Device->GroupType与上面Descriptions->Groups->Group->Type相对应。

    至此,有关设备基础信息的部分就结束了。

    XML中的字典和IO数据

    这部分数据超级复杂,包括字典定义和IO点位描述,但这部分数据已经由SSC创建完成了,SSC通过我们填写的Excel自动生成的,如果没有SSC,这里的数据全都由我们自己填写,将是一件非常恐怖的事情,不仅编写起来工作量非常巨大,而且极易出错。我们这里仅做简单地浏览认识一下。

    首先理解一下字典,所谓字典就是对数据结构的描述,XML里面每种数据集合都需要有它的类型定义,有些类型是简单的String,UINT等基本类型,有些类型是由多种基本类型组合而成的复合结构,在字典定义部分都需要对其进行定义。打开Descriptions->Devices->Device->Profile节点,里面有两个子节点DataTypeObjects,有点类似C语言中的typedef定义类型和int x定义变量,事实上在SSC生成的协议栈中的SSC-DeviceObjects.h文件也确实与这里的定义一一对应的,感兴趣的朋友可以提前去浏览一下,我们将会在STM32与LAN9252构建EtherCAT从站(五):STM32与LAN9252适配做详细介绍。

    举个例子,如图所示,在Objects节点下有一个Object名叫Device name, 其index为#x1008,type为STRING(10),这个STRING(10)就要从上面的DataTypes节点里面找对应的子项了,果然我们会发现一个DataType子节点名叫STRING(10),它的BitSize定义的是80个bit,应该是个uchar[10]的数组,那么这个字符串内容是什么呢,还记得我们之前在硬件基础信息部分定义的Device Name吗,我们去看看,上面定义的是SSC-Device,数一数正好10个字节。

    所以在XML中每一个元素都会有自己的数据结构,每一种数据结构都会在数据字典中定义,如果这之间的关系理得不顺,EtherCAT将无法建立连接,想要手工把这里面的关系搞定真的非常困难,SSC在之前帮我们全都搞定了。

    IO点位数据就更加复杂了,在Descriptions->Devices->Device节点下有四个Sm节点,这个表示通道,我们通信时一共有四个通道,除了过程传输数据输出和输入以外,还有两个通道用来控制EtherCAT自身状态的,也是EtherCAT协议中非常重要的MailBox概念,分别叫做MBoxOutMBoxIn,这里不需要管它,只需要了解过程传输数据InputsOutputs两个通道,这两个通道内部的数据又分别指向RxPdoTxPdo两个节点,这两个节点每个Entry节点都是我们之前在Excel中定义的一个IO点。SSC通过Excel帮我们完成了一项庞大的工作,在XML中生成了64+64个Entry,如果手工录入,这工作量将会非常恐怖。

    综上,XML中数据字典和IO点位我们就粗略的理解到这里了。这其中的还有很多深奥的地方,比如SM通道的size需要16位对齐,Entry节点的bitlen和subindex属性等等,如果您有兴趣理解透彻,可以去看一下CanOpen协议中关于字典和对象的描述,EtherCAT协议这部分内容完全脱胎于CanOPEN协议。

    XML中的EEPROM内容

    现在我们来到XML最后一部分内容,EEPROM节点,这个节点数据量非常少,只有两个子节点,ByteSize一般为2048,代表板载的EEPROM芯片容量是2KByte,其实我们一般使用512K的物理容量芯片,防止IO数据定义时数据量增加不够存储。这里插一句题外话,与LAN9252相连的EEPROM芯片尽量使用ATMEL家的24FC512,否则EtherCAT可能会有连接困难的现象。

    XML中大部分内容都由SSC帮我们生成,现在到了比较重要的最后14byte数据,也就是ConfigData节点,SSC帮我们构建的XML是按照ET1100芯片生成的,默认为050E03440A0000000000,这里使用的是LAN9252,打开LAN9252芯片手册AN1907-Microchip LAN9252 Migration from Beckhoff ET1100,看到2.3节,手册上让我们改成800E00CC8813F0000000800000,我们先跟着做,手册下面一行提示我们如果想进一步了解含义,需要阅读LAN9252 EEPROM章节。

    打开LAN9252 datasheet,在12.8 EEPROM Configurable Registers章节,有如下介绍: 可以看到这14个byte其实是由这张表组成的,上面的截图只是表格的前半部分,下面一页有后半部分,不过最重要的就是这前面第一个字节。看到第一个字节定义了芯片的0140h寄存器,这个寄存器叫做Process Data Interface,点击进入改寄存器的详细描述,如下图所示: 在12.14.24章节,有0140h寄存器的详细描述,可以看到这个寄存器配置为80h即为SPI通信方式,这与我们项目架构相匹配。回忆一下之前手册上让我们将ConfigData节点修改为800E00CC8813F0000000800000这第1个80其实就是指的SPI方式,至于后面这些数据代表什么含义,都可以在LAN9252 datasheet中查找到,如果暂时不理解就不要修改,保持默认就可以了。

    至此整个XML文档我们就浏览剖析结束了,这份XML后面会放到TwinCAT安装路径下的/Io/EtherCAT文件夹,然后在TwinCAT中给寻找到的EtherCAT设备烧录,LAN9252将其中关键数据存储到与自己相连的EEPROM中,供自己以后上电时给自己配置各项参数。

    花开两朵,各表一枝,XML文件我们暂且放在一边,下面一章,我们将给STM32F103配置一下SPI功能,并与之前SSC生成的协议栈做一下SPI部分的融合。

    (四):STM32配置SPI

    这一章主要讲解STM32的SPI配置,以及与LAN9252的SPI接口对接。 从2018年开始,几乎所有最新的STM32项目或者教程,都不约而同地开始使用HAL库,其原因主要是意法半导体推出的STM32CubeMx这款图形化配置软件太好用了。一定程度上弥补了HAL库与标准库在使用习惯,已有项目遗产上的差距。而且,官方声明最新的STM32F7系列将只支持HAL库。 在这里我建议大家以积极的态度拥抱变化,STM32 ARM所有家族产品尽量都使用HAL库进行开发,并使用CubeMX软件辅佐开发;对于寄存器模式开发,在项目中如果有所接触,可以去翻阅手册查看原理,有价值的一些快速寄存器操作也是有必要记下来的,在一些高速场合确实很适用,比如快速开关中断,快速GPIO操作等;对于标准库模式开发,建议放弃了,标准库很久不更新了,现在已经成老古董了,再过几年就彻底跟不上时代了,就好比没人愿意用Github上5年以上不更新的项目,即使它确实很优秀。有人说【HAL臃肿,F7性能好,而且只能用HAL,所以用HAL,F0,F1,F3还是继续用标准库合适】,这种想法确实没必要,对于所有系列,还是统一学习一种库方便,而且就我目前接触过的项目,还没有什么是HAL搞不定,标准库能搞定的。

    使用STM32CubeMX软件配置MCU外设

    我并不打算将本系列文章写成一个关于STM32,尤其是关于STM32、Keil、CubeMX大而全的基础教程,那种每个界面都有截图,每个按钮的点击都要介绍,篇幅拉得太长了。我这里关于这些知识只能用简要地说明一下,具体到每个软件或者技术的详细使用,列为感兴趣,或者追求细节的话,还是建议去搜一些颗粒度更小,更专业的教程。 打开STM32CubeMX,新建一个STM32F103ZExx工程,我们来配置一下与LAN9252通信的外设。

    与LAN9252通信,涉及到的外设包括以下几点:

    1. SPI:4线标准SPI,LAN9252支持SQI(6线高速SPI),但我们这里一切从简。标准模式下,SPI时钟频率最高支持30M。LAN9252还有高速SPI模式,时钟频率最高80M,这个自己去研究。

    2. 1ms的定时器:命名为ECAT_CheckTimer,协议栈的日常处理,包括看门狗喂狗行为,在定时器中断服务函数中进行,一般配置成1ms。

    3. 3个外部中断:包括1个EtherCAT主中断,命名为PDI_Isr;2个时钟同步IRQ,命名为Sync0_Isr,Sync1_Isr,EtherCAT主从通信中如果选择使用分布式时钟功能,这两个中断要配上。

    NVIC方面,使用CubeMX配置时注意以下几点:

    1. 对于MCU来说,SPI是主站,不需要中断读写,SPI的通信时序是读的同时写,写的同时读,读写不分离,所以没必要配置中断。

    2. 3个外部中断,在CubeMX中都配置成初始enable,这样生成的代码友好一点,但到了Keil中,需要把初始化函数中最后一行Enable的语句给注释掉。什么时候Enable中断,什么时候Disable中断,都要由协议栈决定,而不是一上电就打开外部中断,那样非常容易出错,基本连不上。

    3. 定时器中断,跟外部中断一样,CubeMX中配置好enable,代码生成后注释掉最后一行Enable,由协议栈来决定打开和关闭定时器中断。

    4. 向量表的详细介绍可以参考我的另一篇博客:STM32F4+DP83848以太网通信指南系列(三):中断向量。一个可行的中断向量表为2bit抢先,2bit响应: a). ECAT_CheckTimer 配置为 1抢先,0响应 b). PDI_Isr 配置为 1抢先,0响应 c). Sync0_Isr,Sync1_Isr 均配置成 2抢先,0响应

    CubeMX配置时的一些重要截图如下:

    时钟:

    SPI:

    外部中断:

    NVIC:

    KEIL5 工程模板:

    模块化代码:

    以上就是使用CubeMX配置的跟LAN9252通信的所有外设资源。点击右上方的【GENERATE CODE】按钮,自动生成Keil5 工程代码。下面的工作就跟CubeMX无关了,可以关掉了。

    Keil5中适配SPI

    CubeMX帮我们生成了Keil工程,我们的整个项目的后续开发也将以此套工程代码为蓝本继续下去。首先熟悉一下工程文件树。

    这是CubeMX帮我们生成的工程架构,其他都是浮云,中间的Application/User是主战场,我们自己的逻辑一般都在这个Group中,毫无疑问,main.c是主程序;gpio.c,spi.c,tim.c中有各个外设资源初始化的代码;stm32f1xx_it.c中有帮我们生成好的中断服务函数,里面有一些关键函数我们待会儿需要移动到main.c中;stm32f1xx_hal_msp.c中是外设资源与硬件资源的映射配置代码,如果有些外设,比如SPI,使用的是其他GPIO复用,将在这个文件中有所体现。此时点击Keil5中的编译按钮,应该能够顺利编译,无任何报警和错误的。

    所谓的EtherCAT协议栈移植,其实就是将上面讲的各个外设资源的接口与EtherCAT协议栈的内部接口进行对接,比如SPI部分,我们需要封装一些简单的SPI操作,命名为协议栈期望的函数名,供协议栈调用;再比如3个外部中断和1个时间中断,我们需要在这4个中断服务函数中调用协议栈暴露给我们的4个不同的函数来适配协议栈。我们这个教程的本章节,将主要介绍SPI的适配,其他适配将留到后面章节介绍。

    LAN9252 芯片的SSC模板

    之前我们在STM32与LAN9252构建EtherCAT从站(二):使用SSC生成EtherCAT协议栈和XML文件中,使用SSC生成的EtherCAT从站代码是基于EL9800学习板的,那个学习板上的PHY芯片是ET1100这颗倍福自己的PHY芯片。我们这里使用相对廉价的LAN9252作为从站PHY芯片,LAN9252的一些寄存器设置跟ET1100是有区别的,因此我们到microchip官网下载LAN9252的SSC SDK。

    下载回来以后,配合SSC5.11版本(5.12版本太新,跟LAN9252官方SDK兼容性不好),参考microchip的官方文档AN1916,生成的代码如下:

    跟之前SSC生成的标准协议栈有所区别的是图片中第1,第2个文件由el9800.c,el9800.h变成了9525_HW.c,9252_HW.h;另外在LAN9252的SSC SDK中有一个SPI的工程文件,里面有SPI驱动的两个文件SPIDriver.c,SPIDriver.h,如果生成协议栈时没有add进去,这里手动复制一下;此外最后三个文件,STM32_EtherCAT_Slave开头的,是根据SSC中配置IO时的Excel文件生成的,其中STM32_EtherCAT_SlaveObjects.h是最有价值的,跟XML文件是一一对应的。 将这些文件全都copy到STM32工程的一个目录中,比如新建一个EtherCAT目录。 在KEIL的工程结构中新建2个Group,比如命名为EtherCAT,和Porting,按照图示,引入以下文件: 至此,当前所看到的全部文件,均原封不动地来自于CubeMX,SSC和LAN9252 SDK,我们暂未对此进行任何修改。此时编译将引发大量错误,不过不要担心,根据Keil提示一定可以慢慢磨合掉的。 这里简单解释一下为什么此时编译,Keil会报大量错误。首先,EtherCAT协议虽然公开、免费,但倍福公司也要赚钱,于是他们自己设计生产了ET1100,ET1200等EtherCAT PHY芯片,同时还有EL9800开发板,并发布了与之配套的SSC软件与之适配。这套玩意儿价格确实很高,淘宝搜ET1100价格基本都在170左右,而且BGA封装的芯片对中小微企业也不太友好。于是MICROCHIP顺应时势,也想分一杯羹,设计制造了同样功能的LAN9252,淘宝售价在50元左右,而且有TQFP封装,中小微企业的福音,电烙铁直接能搞定。同时,为了推广自家的LAN9252,MICROCHIP还很体贴的提供了SSC SDK为大家辅助生成协议栈,但是有点不厚道的是,MICROCHIP为LAN9252提供的SDK,仅支持自家的PIC32单片机,这家伙跟STM32是竞争对手,所以不可能为他人做嫁衣,于是我们目前得到的所有代码,是基于PIC32单片机的,而不是STM32的。所以KEIL编译出来当然一大堆的错误,连MCU芯片型号都不一致。

    移植,移植,移植

    OK,这下思路明确了,下一步的任务就是要把基于PIC32的代码移植成STM32F1的代码,不要慌,稳住,相信自己一定可以的。 整体思路就是要充分利用KEIL的报错信息,以及Ctrl+F全局搜索,一步一步地去改源代码,我这里没法事无巨细地讲解,因为报错实在太多了,只能选几个典型的示例来做个示范。比如:

    function "INTDisableInterrupts" declared implicitly

    碰到的第一个错误应该是这个,定位到的代码应该是9252_HW.c的190行:

    static void GetInterruptRegister(void)
    {
          DISABLE_AL_EVENT_INT;
          HW_EscReadIsr((MEM_ADDR *)&EscALEvent.Word, 0x220, 2);
          ENABLE_AL_EVENT_INT;
    
    }

    DISABLE_AL_EVENT_INT这是一个宏定义,看名字应该是关闭所有中断,追踪到同文件第106行:

    #define DISABLE_GLOBAL_INT          INTDisableInterrupts()
    #define ENABLE_GLOBAL_INT           INTEnableInterrupts()
    #define DISABLE_AL_EVENT_INT        DISABLE_GLOBAL_INT
    #define ENABLE_AL_EVENT_INT         ENABLE_GLOBAL_INT

    于是看到INTDisableInterrupts()INTEnableInterrupts()这两个玩意儿,果然是PIC32中启用和禁用全局中断的函数,对应STM32,应该是下面这段:

    #include "stm32f1xx.h"
    #define   DISABLE_GLOBAL_INT        __disable_irq()
    #define   ENABLE_GLOBAL_INT            __enable_irq()

    argument of type "__packed unsigned short *" is incompatible with parameter of type "const void *restrict"

    这个错误比较隐蔽,是__packed关键字引发的,STM32中,使用__packed关键字可以强制结构体内的数据以1字节对齐(非常不推荐,M3内核通常情况下会保证最高效率进行4字节对齐),在进行一些函数传参时,会报错,意思是无法将一个1字节对齐的结构体指针,强制转成void*,因为void*这种泛型指针,默认是4字节对齐的。 KEIL跟踪这种错误比较难跟,考虑使用Ctrl+F进行全局搜索关键词packed,找到ecat_def.h第742,754行:

    可以发现定义了4个宏,分别是两个结构体的前缀和后缀,然后在两个结构体后缀宏上,打上了__attribute__((aligned(1), packed))的标记,看来原作者的意图是将这两个宏对应的结构体变成1字节对齐的数据结构,然而PIC32(或者KEIL内的编译器,没有详细去了解)的字节对齐语法跟STM32的还是有一些差异的,导致字节对齐的语法在这里并不适用,感兴趣的朋友可以去详细了解一下。我们这里就简单的将这个宏后面的映射语句删掉,将其变成空的宏定义。 但是要注意,这两个宏是对应邮箱和过程数据数据结构的,后面设计InputMap和OutputMap时,也要注意,不再是1字节对齐了,而是默认的4字节对齐。

    ..\EtherCAT\ecatappl.c(143): warning: #1215-D: #warning directive: "Define the timer ticks per ms"

    这个报警按照字面上的理解就是有个宏没有定义,我们搜一下这个名为ECAT_TIMER_INC_P_MS的宏。 在9252HW.h第146行确实定义了这个宏,但是KEIL帮我自动感应置灰了,因为这个宏定义在一个#ifdef PIC32_HW预编译语法内部,显然我们这里的库函数框架并没有谁会去定义一个PIC32_HW来,因此我们需要将这里面由#ifdef PIC32_HW包围的一大段宏定义,全部复制一份副本,然后用类似#ifdef STM32F1的预编译语法包围起来:

    需要说明的是,考虑到本项目定时器配置的具体情况,这里将ECAT_TIMER_INC_P_MS的定义改为与之前配置的1ms定时器完全匹配的数值,即1000,配图中的2000需要修订

    其他错误和警告

    其他还有若干错误和警告,不胜枚举,这里就不一一赘述了,像什么UINT8,UINT16类型没找到,协议栈需要的数据类型都在ecat_def.h里;参数为空的函数需要加void等小问题,相信聪明的你一定能自己修复。

    SPI适配

    这里着重讲一下SPI方面的报错处理,把这些报错处理掉,其实就相当于SPI的移植了。主要是SPIDriver.hSPIDriver.c两个文件的去警告和移植。

    SPIDriver.h

    SPIDriver.h中是相关函数的定义,我们看到:

    其中,SPIOpen(),SPIPut()两个函数对于STM32来说无意义,直接删掉,SPIRead(),SPIReadBurstMode()函数参数为空,需要加上void,否则有一个warning。其他就没什么变动了。

    SPIDriver.c

  • 打开SPIDriver.c,第一个函数居然是Delay(),这个函数是用PIC32编译器语法写的,显然没用,而且这个函数整个代码都没用到过,有点搞笑,果断删掉。
  • 继而删掉SPIPutSPIOpen两个函数。
  • SPIWriteSPIRead用STM32的常规语法代替:
  • void SPIWrite(UINT8 data) {
        HAL_SPI_Transmit(&hspi1, &data, 1, 2000);
    }
    
    UINT8 SPIRead() {
        UINT8 data;   
        HAL_SPI_Receive(&hspi1, &data, 1, 2000);
        return (data);
    }

    以上代码用过STM32 SPI通信和HAL库的朋友应该毫无压力。

  • CSLOW()CSHIGH()两个宏的修复:这两个宏是SPI的NSS使能引脚控制,一般我们做SPI通信都会设置成软件使能,这里也不例外,软件使能能够更灵活地控制读写位数。将这两个宏修复如下:
  • #define DESELECT_SPI    HAL_GPIO_WritePin(SPI1_NSS_GPIO_Port,SPI1_NSS_Pin,GPIO_PIN_SET)
    #define SELECT_SPI        HAL_GPIO_WritePin(SPI1_NSS_GPIO_Port,SPI1_NSS_Pin,GPIO_PIN_RESET) 
    
    #define CSHIGH()        DESELECT_SPI
    #define CSLOW()            SELECT_SPI

    其中SPI1_NSS_GPIO_PortSPI1_NSS_Pin的定义在CubeMX中已经设计好了,存于main.h文件中。

    总结

    本文讲解了通过CubeMX软件生成STM32工程,同时重新使用LAN9252的SDK,配合SSC软件生成了新的协议栈。将协议栈的相关代码混入工程文件,并尝试一步一步修复代码中的错误和警告。最后单独讲解了SPI部分的代码修复,这部分代码不算复杂,用好Keil的Go to Definition和Ctrl+F全局搜索,一步一步跟踪调试总归能搞定的,调试过程中做到胆大心细,及时保存和备份副本,感觉可以删掉的就大胆删,大不了回档重来。 下一章,我们将全面适配LAN9252,观察EtherCAT协议栈暴露给上层应用的接口,并在我们配置的各个中断中调用它们。

    (五):STM32与LAN9252适配

    这一章讲解STM32与LAN9252的全面适配。

    1.硬件

    既然是全面适配,那不得不略微提一下硬件连接,以下是相关区域的原理图:

    可以看到,LAN9252与STM32通信一共用了7根线,4根SPI,3根外部中断,这跟我们上文STM32与LAN9252构建EtherCAT从站(四):STM32配置SPI讲解的内容是一致的。

    2.软件

    软件的适配主要包括以下几点:

    1. 协议栈移植,至少做到.c文件没有报错。上一章我们介绍了方法,后续的步骤留给各位自行完成,千万不要拿来主义。
    2. SPI驱动移植,上一章我们已经完成。
    3. 对接接口。将协议栈暴露给我们的几个函数,在代码相应的位置进行调用。
    4. 编写业务逻辑。根据第二章在Excel中设计的IO交互数据,在指定的函数中编写业务逻辑。

    2.1对接接口

    整个EtherCAT协议栈期望的我们的程序主体框架的伪代码如下:

    void    APPL_AckErrorInd(UINT16 stateTrans) {
    }
    UINT16 APPL_StartMailboxHandler(void) {
        return ALSTATUSCODE_NOERROR;
    }
    UINT16 APPL_StopMailboxHandler(void) {
        return ALSTATUSCODE_NOERROR;
    }
    UINT16 APPL_StartInputHandler(UINT16 *pIntMask) {
        return ALSTATUSCODE_NOERROR;
    }
    UINT16 APPL_StopInputHandler(void) {
        return ALSTATUSCODE_NOERROR;
    }
    UINT16 APPL_StartOutputHandler(void) {
        return ALSTATUSCODE_NOERROR;
    }
    UINT16 APPL_StopOutputHandler(void) {
        return ALSTATUSCODE_NOERROR;
    }
    UINT16 APPL_GenerateMapping(UINT16 *pInputSize, UINT16 *pOutputSize){
        return ALSTATUSCODE_NOERROR;
    }
    void APPL_InputMapping(UINT16 *pData) {
    }
    void APPL_OutputMapping(UINT16 *pData) {
    }
    void APPL_Application(void) {
    }
    
    void EtherCatIRQ(){
        PDI_Isr();
    }
    
    void Sync0IRQ(){
        Sync0_Isr();
    }
    
    void Sync0IRQ(){
        Sync1_Isr();
    }
    
    void Timer1msIRQ(){
        ECAT_CheckTimer();
    }
    
    int main(){
        HW_Init();
        MainInit();
        while(1){
            MainLoop();
        }
    }

    其中,这些函数均由协议栈提供:

  • PDI_Isr():EtherCAT主中断响应,需要配置到外部中断中,跟LAN9252的44脚对应,下降沿触发。
  • Sync0_Isr():分布式时钟同步信号0,需要配置到外部中断中,跟LAN9252的18脚对应,下降沿触发。
  • Sync1_Isr():分布式时钟同步信号1,需要配置到外部中断中,跟LAN9252的34脚对应,下降沿触发。
  • ECAT_CheckTimer():1ms定时器溢出中断,我这边配置在STM32的TIM8的break interrupt上。
  • HW_Init():硬件初始化函数,MCU通过此函数感应LAN9252设备的存在与否。
  • MainInit():协议栈初始化函数。
  • MainLoop():协议栈主循环,主while(1)中尽量只放此函数,其他业务逻辑在APPL_Application(void)函数中编写,后面介绍。
  • 这些函数需要根据自己的业务逻辑编写:

  • APPL_InputMapping(UINT16 *pData) 输入数据映射
  • APPL_OutputMapping(UINT16 *pData) 输出数据映射
  • APPL_Application(void) 主业务逻辑
  • 这些函数保持默认即可,也可添加自己的业务逻辑:

  • APPL_AckErrorInd(UINT16 stateTrans) EtherCAT通信故障时回调
  • APPL_StartMailboxHandler(void) 邮箱消息接收前回调
  • APPL_StopMailboxHandler(void) 邮箱消息接收后回调
  • APPL_StartInputHandler(UINT16 *pIntMask) 输入映射前回调
  • APPL_StopInputHandler(void) 输入映射后回调
  • APPL_StartOutputHandler(void)输出映射前回调
  • APPL_StopOutputHandler(void) 输出映射后回调
  • 最后一个APPL_GenerateMapping()函数有固定的模板,我们后面介绍。

    2.2 中断接口

    2.2.1 PDI_Isr()

    这个函数来自于ecatappl.c文件,头文件定义取自ecatappl.h,我们在主程序中直接#include applInterface.h即可。

    将此函数配置到外部中断服务函数中去,我这边使用的是EXTI0_IRQHandler,并且根据习惯,我将这个服务函数从stm32f1xx_it.c中移动到main.c中去了,仅做参考。 需要再次提醒的是,上一章已经说过,CubeMX生成的中断初始化函数,在gpio.c中,有以下代码: 正如我所说,设备上电后我们不可以直接调用HAL_NVIC_EnableIRQ函数将各种中断使能,因为此时协议栈相关数据都没初始化好,直接使能这些中断将导致严重的逻辑问题。因此上述代码后面的使能语句,都需要注释掉。

    2.2.2 Sync0_Isr() 和 Sync1_Isr()

    这个函数来自于ecatappl.c文件,头文件定义取自ecatappl.h,我们在主程序中直接#include applInterface.h即可。 我们将这个函数配置到EXTI9_5_IRQHandlerEXTI4_IRQHandler中:

    void EXTI9_5_IRQHandler(void) {
        /* USER CODE BEGIN EXTI9_5_IRQn 0 */
        DISABLE_ESC_INT();
        Sync0_Isr();
        ENABLE_ESC_INT();
        /* USER CODE END EXTI9_5_IRQn 0 */
        HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_5);
        /* USER CODE BEGIN EXTI9_5_IRQn 1 */
    
        /* USER CODE END EXTI9_5_IRQn 1 */
    }
    
    void EXTI4_IRQHandler(void) {
        /* USER CODE BEGIN EXTI4_IRQn 0 */
        DISABLE_ESC_INT();
        Sync1_Isr();
        ENABLE_ESC_INT();
        /* USER CODE END EXTI4_IRQn 0 */
        HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_4);
        /* USER CODE BEGIN EXTI4_IRQn 1 */
    
        /* USER CODE END EXTI4_IRQn 1 */
    }

    2.2.3 ECAT_CheckTimer()

    这个函数来自于ecatappl.c文件,头文件定义取自ecatappl.h,我们在主程序中直接#include applInterface.h即可。 我们将其配置到TIM8的break interrupt服务函数中去:

    void TIM8_BRK_IRQHandler(void) {
        /* USER CODE BEGIN TIM8_BRK_IRQn 0 */
        ECAT_CheckTimer();
        /* USER CODE END TIM8_BRK_IRQn 0 */
        HAL_TIM_IRQHandler(&htim8);
        /* USER CODE BEGIN TIM8_BRK_IRQn 1 */
    
        /* USER CODE END TIM8_BRK_IRQn 1 */
    }

    2.3 主程序接口

    2.3.1 HW_Init()

    这个函数来自9252_HW.c, 在9252HW.h中有其定义,主程序中直接#include ecatslv.h即可。

    2.3.2 HW_Init()

    这个函数来自ecatappl.c, 在applInterface.h中有其定义,主程序中直接#include applInterface.h即可。

    2.3.2 MainLoop()

    同上。

    2.4 业务逻辑接口

    上面提到很多回调函数,在EtherCAT协议栈中,使用了extern关键字来调用那些函数,因此我们需要有这些函数的实体。

    2.4.1 APPL_GenerateMapping()

    这个函数是根据我们定义的过程通信数据,与内存中的数据进行映射的函数,这个函数不需要自己写,说实话如果靠我们自己写,要对EtherCAT协议栈深入理解才行。所幸SSC生成的代码中已经帮我写好了,但是并不归属于协议栈,在项目文件中有其实现,我这边项目命名为STM32_EtherCAT_Slave,因此在STM32_EtherCAT_Slave.c中可以找到,复制粘贴到main.c中即可。

    2.4.2 APPL_InputMapping(UINT16 *pData)

    这个函数是输入数据映射函数。这里的【输入】是相对于主站来说,也就是我们这里从站的输出数据。我们这里定义了输入数据是64个bit,因此这里就要将内存中64个bit的数据赋值给pData指针指向的首地址。 又因为我们在SSC配置的Excel中,输入数据定义的是InputS0x6000地址,因此在我的工程文件STM32_EtherCAT_SlaveObjects.h中就会有INPUTS0x6000这个变量的定义。 那么这个函数的实现也就不难了,深入理解C语言指针的同学一定不难看懂以下代码:

    void APPL_InputMapping(UINT16 *pData) {
        *pData++ = (((UINT16 *) &INPUTS0x6000)[1]);
        *pData++ = (((UINT16 *) &INPUTS0x6000)[2]);
        *pData++ = (((UINT16 *) &INPUTS0x6000)[3]);
        *pData = (((UINT16 *) &INPUTS0x6000)[4]);
    }

    2.4.3 APPL_OutputMapping(UINT16 *pData)

    同理,该函数这么编写:

    void APPL_OutputMapping(UINT16 *pData) {
        ((UINT16 *) &OUTPUTS0x7000)[1] = (*pData++);
        ((UINT16 *) &OUTPUTS0x7000)[2] = (*pData++);
        ((UINT16 *) &OUTPUTS0x7000)[3] = (*pData++);
        ((UINT16 *) &OUTPUTS0x7000)[4] = (*pData);
    }

    3.总结

    至此STM32与LAN9252对接的所有接口都完成了,编译无误的话可以试着下载到设备中去。观察看看LAN9252的RUN灯是否可以常亮。 其实移植的最主要难点还在于是否能将一开始KEIL的所有报错,有耐心地一一排除掉。到了这一步对接接口,就好比一个萝卜一个坑,在正确的位置调用正确的API就可以了。 下一章,我们将结束这篇系列教程,在TwinCAT2上配置从站,并验证我们编写的代码。

    (六):TwinCAT2的使用和从站测试

    这一章讲解在XP虚拟机里使用TwinCAT2的一些知识。内容主要包括:

    1. TwinCAT连接PLC
    2. 从站设备发现
    3. 点位观察和强制
    4. PLC测试

    1. TwinCAT连接PLC

    1.1 TwinCAT简介

    TwinCAT是德国倍福开发的工业控制程序,有PLC控制,NC控制,HMI等丰富的功能,最厉害的地方是它可以将一台普通PC变成一台工业控制器,在上面可以跑诸如法那科,西门子,三菱等NC控制系统。TwinCAT2跟TwinCAT3本质上没什么特别大的区别,这二者的取舍大多数时候并不由用户决定,而是由设备决定。TwinCAT的授权机制比较复杂,TwinCAT2有30天免费试用,想授权的话需要电话、传真或者email跟倍福联系,比较原始,感觉跟Win98年代的激活码一样;TwinCAT3官网介绍分为很多类型,有部分用途是无需授权的,因为硬件产品的价格已经集成了,这里就不去详细了解了,感兴趣的朋友可以去倍福官网详细了解一下。 我这边测试环境有一台倍福CX9020-0111,这是一台倍福的PLC控制器,集成有TwinCAT2主站,官网介绍如下:

    ![cx9020](https://files.hexcode.cn/stm32lan9252sec5-cx9020.png) TwinCAT2的主站,我试过很多次,用TwinCAT3是连不上去的,后来装了个XP虚拟机,虚拟机里面装了TwinCAT2,一下子就连上了,因此我认为TwinCAT2和TwinCAT3连通性上并不兼容。 此外TwinCAT3是以Virtual Studio插件的形式发布的,可以配合VS的强大能力开发出很多基于C#和Windows GUI的EtherCAT工控程序,但鉴于Windows本身并非实时操作系统,开发一些采集型的看板还可以,如果需要开发运动控制型的工控程序,是不太合适的,这方面还是寻求嵌入式解决方案比较靠谱。 ### 1.2 TwinCAT2连接CX9020 我这边的环境并不是想让个人PC当做PLC控制器,因此安装TwinCAT仅仅是用来连接控制第三方主站设备CX9020。安装完TwinCAT2后,打开TwinCAT System Manager,选择Choose Target,弹出的列表中,如果没有目标设备,则需要点击Search(Ethernet),然后Brodadcast Search,找到设备节点,点击Add Route,这时候会弹出用户名密码的对话框,如果目标设备是WinCE的系统,用户名密码都为空,如果是XP系统,则用户名为Administrator,密码为1。添加完成后,即可在Choose Target中找到设备节点。相关截图如下: ![tc01](https://files.hexcode.cn/stm32lan9252sec5-tc201.png) ![tc02](https://files.hexcode.cn/stm32lan9252sec5-tc202.png) ![tc03](https://files.hexcode.cn/stm32lan9252sec5-tc203.png) 再次提醒一下,TwinCAT2和TwinCAT3不通用,目标设备如果是TwinCAT2作为主站,则一定要用TwinCAT2去连接控制它。

    2 从站设备发现

    2.1 Run Mode 和 Config Mode

    TwinCAT设备分为Run Mode和Config Mode,两种运行状态。最显著的区别就是设备本身会有一个LED灯,绿色代表RunMode,蓝色代表ConfigMode。 一般我们对设备进行【从站发现】、【IO关联】、【IO强制】等操作时,只可以在ConfigMode下进行;让设备开始跑PLC程序时,只可以在RunMode下进行。

    2.2 发现从站

    首先,确保您已经将前面章节配置的XML设备描述文件放入【TwinCAT安装目录/IO/EtherCAT】路径下。 在TwinCAT System Manager中,Choose Target选择远程CX9020设备后,点击菜单栏这个按钮,进入Config Mode:

    然后在左边菜单栏选中【I/O Devices】,右击,选择【Scan Devices】进行设备扫描。

    稍等一会儿,弹出对话框,告诉你当前主站发现有列表中的设备,点击【OK】进入下一步。

    系统弹出一个对话框,询问是否自动搜索boxes,点击【是】

    此时就可以找到我们定义的LAN9252设备了,这个设备是以EtherCAT总线的一个【Box】节点来体现的。

    2.3 烧录EEPROM

    在LAN8252设备的父节点【Device2】上选中,然后右边主界面选择【Online】,下方列表中选择节点,然后右击,选择【EEPROM Update】,即可烧录我们制定的XML文件。

    烧录过程比较缓慢,完成后,需要删除设备,重新扫描设备。

    3. 点位观察和强制

    烧录好的EtherCAT从站设备,会有图标和名称信息显示。 点击左侧+号键,可以看到这个设备有【INPUTS process data mapping】和【OUTPUTS process data mapping】两个主节点,展开后,可发现各有64bit输入输出数据。

    不出问题的情况下,此时LAN9252控制的RUN LED灯已经可以常亮了,代表设备主从设备正在正常通信。我们仍然保持设备在ConfigMode下运行,下面我们来强制一下点位,看看硬件设备是否能正常工作。

    在强制数据之前,我们编写一套测试逻辑,在上一篇 STM32与LAN9252构建EtherCAT从站(五):STM32与LAN9252适配 介绍了需要适配的几个函数,其中有一个最核心的函数APPL_Application(void),这个是编写主业务逻辑的地方。我们编写如下代码:

    void APPL_Application(void) {
        OUTPUTS0x7000.LED0 ? ( HAL_GPIO_WritePin( USER_OUT_GPIO_Port, USER_OUT_Pin, GPIO_PIN_RESET) ) : ( HAL_GPIO_WritePin( USER_OUT_GPIO_Port, USER_OUT_Pin, GPIO_PIN_SET) );
    }

    这段代码很简单,如果OUTPUTS0x7000.LED0这个变量是真,那么USER_OUT这个口置低电平,否则置高电平,PCB上这个LED设计的低电平有效。

    强制数据的方法很简单,在TwinCAT中,找到需要强制的点位,右击,【Online Write】,输入1,点击OK即可。 此时可以观察到,随着TwinCAT强制【LED0】点位1和0,PCB板上的USER_OUT这个LED也同时点亮和熄灭。

    4. PLC测试

    4.1 APPL_Application()中的输入逻辑

    继续完善APPL_Application()函数,LED是输出,至少需要完成1个点位的输入。 这里顺带提一下,如果场景跟我一样,输入信号全是按键,那么要注意了,一般PCB设计的时候,按键都是扫描的,比如64个bit的输入,那么至少需要8+8=16个IO。同时,扫描是需要时间的,还需要考虑防抖,因此当把8条线全都扫描出来,可能已经耗时5ms还多了,这里要注意一下,尽可能保证APPL_Application()函数最短耗时,实测当APPL_Application()函数所需时间大于3ms时,连接极为困难。所以如果有耗时操作需要在APPL_Application()中完成,可以考虑分时完成,比如扫描这种操作,可以一个周期只扫描两根或者四根线。如果有更复杂的操作,也不能分时完成,那就要考虑使用RTOS来加持了,多线程通信,消息队列这些机制,或者选用性能更强的芯片。 假设我们的APPL_Application()有如下逻辑:

    void APPL_Application(void){
        INPUTS0x6000.B0 =  ((KeylineValue[0] & ((u8)1 << 0)) == ((u8)1 << 0)) ? 1 : 0;
        OUTPUTS0x7000.LED0 ? ( HAL_GPIO_WritePin( USER_OUT_GPIO_Port, USER_OUT_Pin, GPIO_PIN_RESET) ) : ( HAL_GPIO_WritePin( USER_OUT_GPIO_Port, USER_OUT_Pin, GPIO_PIN_SET) );
    }

    其中,INPUTS0x6000.B0是输入赋值,OUTPUTS0x7000.LED0是输出赋值。接下来我们可以用PLC来测试系统了。

    4.2 PLC

    打开TwinCAT PLC Control,File->New,弹出系统选择对话框。我们的设备是CX9020,这是一台基于ARM WinCE的控制系统,因此选择ARM平台。

    弹出PLC语言类型选择对话框,我们试着使用结构化文本来写PLC,因此选择ST模式。

    新建MAIN文件后,主体界面切换成上下两个编辑区,上面编辑区用来定义变量,下面编辑区用来编写逻辑。测试代码如下:

    PROGRAM MAIN
    VAR
        B0 AT%IX0.0: BOOL;
        L0 AT%QX0.0: BOOL;
    END_VAR
    L0 := B0;

    保存工程文件后,菜单栏【Online】->【Choose Run-Time System】选中CX9020这台远程设备,然后点击Login登陆进入,按下F5,即可开始跑PLC程序。实验现象应该是由STM32扫描得到的键值bit0位如果是1的话,LED亮,bit0位如果是0的话,LED灭。 这种方式仅仅是模拟PLC进行测试,要想将PLC真正烧录进倍福控制器,并且配置PLC的点位跟物理点位进行link还需要到TwinCAT System Manager中进行设置。详细的TwinCAT教程我上传到这里:TwinCAT2教程TwinCAT3教程,有需要的朋友可以自行阅读。

    总结

    最后回顾总结一下,结束我们这个系列的教程。 本系列教程,我们首先全面地对STM32和LAN9252两款芯片的介绍,继而结合EtherCAT协会推出的SSC EtherCAT从站代码生成工具,然后以及有针对性地对生成的代码进行平台移植,从PIC32芯片的代码移植到了STM32的架构中去,最后我们通过对TwinCAT的简单介绍,在CX9020平台上对我们设计的整个从站系统进行了简单测试。 通过本系列教程,我们可以掌握以下几点:

  • STM32的基础用法,包括SPI,定时器,外部中断等,并学习了如何通过STM32CubeMX图形化生成HAL库开发环境。

  • LAN9252的基本用法,包括原理图,软件SDK配合SSC生成LAN9252的EtherCAT从站协议栈等用法。

  • EtherCAT从站协议栈的简单认知,我们了解了协议栈的相关接口,针对平台的移植其实就是将相应的接口在不同的平台上,合理地利用其硬件资源,调度起来。

  • TwinCAT2的简单使用。

    本系列教程就到此结束,期待以后有更好玩的系列教程跟大家分享。

  • 转载自 丁丁的个人网站:https://www.hexcode.cn/article/5e3ee9a835616641b2daef

    物联沃分享整理
    物联沃-IOTWORD物联网 » 构建EtherCAT从站:使用STM32和LAN9252

    发表评论