Ehercat代码解析中文摘录<2>

6. 应用程序

本章概述默认(示例)应用程序、应用程序接口,并提供自定义应用程序开发的入门指南。

6.1 应用程序设置

SSC 包含多个(示例)应用程序,可用于主站 / 从站测试或作为应用程序开发的基础。相关设置列于表 3 "应用程序相关设置"(位于 ecat_def.h 或 SSC 工具中)。

表 3:应用程序相关设置

定义 描述
TEST_APPLICATION 支持几乎所有 SSC 功能,可强制特定应用程序行为(见第 11 章)。注:不建议将此应用程序作为开发基础
EL9800_APPLICATION 基于 EL9800 EtherCAT 评估板的应用程序,包含 8 (4) 个 LED、8 (4) 个开关、16 位模拟输入
CiA402_DEVICE CiA402 驱动协议的示例实现,支持 2 个模块化轴,详见第 10 章
SAMPLE_APPLICATION 硬件无关应用程序,适用于目标平台无对应 SSC 工具配置的场景
SAMPLE_APPLICATION_INTERFACE 适用于 Win32 的示例应用程序,用于创建动态链接库

6.2 SSC 函数

这些函数由通用协议栈提供,需从应用程序层调用。

函数原型 参数 返回值 描述
UINT16 MainInit(void) 无 0:初始化成功;>0:初始化出错 初始化通用从站协议栈,需在平台(含操作系统和 ESC)就绪后调用
void MainLoop(void) 无 无 处理低优先级功能(如 EtherCAT 状态机、邮箱协议),未启用同步时还会处理应用程序。需由应用程序周期性调用
void ECAT_StateChange(UINT8 alStatus, UINT16 alStatusCode) alStatus:请求的 AL 状态;alStatusCode:AL 状态码(非 0 时设置错误标志) 无 应用程序发生错误或需完成挂起的状态转换时调用,错误解除后需再次调用。注:不允许请求高于当前状态的状态

6.3 接口函数

6.3.1 通用接口函数
函数原型 参数 返回值 描述
void APPL_Application(void) 无 无 启用同步时由同步 ISR 调用,未启用同步时由主循环调用
UINT16 APPL_GetDeviceID (void) 无 写入 AL 状态码寄存器的显式设备 ID 主站请求显式设备 ID 时调用,仅当从站支持显式设备 ID 处理(EXPLICIT_DEVICE_ID)时需要
6.3.2 EtherCAT 状态机

每个 ESM 函数返回 16 位值,反映状态转换结果:

  • 0:转换成功
  • 0xFF:状态转换挂起(应用程序需调用 ECAT_StateChange 完成)
  • 其他值:转换失败原因,有效返回码列表见 2
函数原型 参数 返回值 描述
UINT16 APPL_StartMailboxHandler(void) 无 见通用 ESM 返回码说明 状态从 INIT 转换到 PREOP 或 INIT 转换到 BOOT 时调用
UINT16 APPL_StopMailboxHandler(void) 无 见通用 ESM 返回码说明 状态从 PREOP 转换到 INIT 或 BOOT 转换到 INIT 时调用
UINT16 APPL_StartInputHandler (UINT16 *pIntMask) pIntMask:寄存器 0x204(AL 事件掩码)的值 见通用 ESM 返回码说明 状态从 PREOP 转换到 SAFEOP 时调用(即使无输入过程数据)
UINT16 APPL_StopInputHandler (void) 无 见通用 ESM 返回码说明 状态从 SAFEOP 转换到 PREOP 时调用(即使无输入过程数据)
UINT16 APPL_StartOutputHandler (void) 无 见通用 ESM 返回码说明 状态从 SAFEOP 转换到 OP 时调用(即使无输出过程数据)
UINT16 APPL_StopOutputHandler (void) 无 见通用 ESM 返回码说明 状态从 OP 转换到 SAFEOP 时调用(即使无输出过程数据)
UINT16 APPL_GenerateMapping (UINT16 *pInputSize, UINT16 *pOutputSize) pInputSize:输入过程数据大小(从站→主站);pOutputSize:输出过程数据大小(主站→从站) 见通用 ESM 返回码说明 主站请求从 PREOP 转换到 SAFEOP 时调用,需计算过程数据的字节数,用于校验同步管理器设置和通用过程数据处理
Void APPL_AckErrorInd(UINT16 stateTrans) stateTrans:当前状态转换 无 主站确认错误时调用
6.3.3 过程数据处理
函数原型 参数 返回值 描述
void APPL_InputMapping(UINT16 *pData) pData:指向输入过程数据的指针 无 应用程序调用后执行,将输入过程数据映射到通用协议栈(通用协议栈会将数据复制到 SM 缓冲区)
void APPL_OutputMapping(UINT16 *pData) pData:指向输出过程数据的指针 无 应用程序调用前执行,用于获取输出过程数据

6.4 接口变量

名称 类型 描述
ApplicationObjDic TOBJECT 结构数组(见 7.4 结构定义) 仅当从站支持 CoE 时需要,定义在应用程序头文件中,包含应用程序特定对象,数组最后一个元素的索引为 0xFFFF
pEEPROM UINT8 * 指向 EEPROM 缓冲区的指针,仅当启用 EEPROM 仿真(ESC_EEPROM_EMULATION = 1)时需要。定义在 ecatappl.h 中,需由应用程序在启动时(调用 MainInit () 前)设置,缓冲区大小由 ESC_EEPROM_SIZE 定义(默认 2048 字节)

6.5 创建应用程序

用户特定应用程序可从零开发,或基于现有示例应用程序修改(推荐后者)。

默认 SSC 示例应用程序见本章开头,其他厂商可能提供额外示例,可通过手动添加、应用程序厂商的补丁文件或 SSC 工具添加到从站项目,详见 6.5.1。

特殊配置说明
  • 无邮箱支持:建议复杂 EtherCAT 从站至少支持 CoE 邮箱协议;若需禁用邮箱处理,需将所有协议设置设为 0(AOE_SUPPORTED、COE_SUPPORTED、EOE_SUPPORTED、FOE_SUPPORTED、SOE_SUPPRTED、VOE_SUPPORTED)。注:即使无邮箱支持,同步管理器 0 和 1 也需禁用并保留给邮箱通信,移除 SM 需适配 SSC。
  • 仅输入 / 输出设备:创建仅输入 / 输出的 EtherCAT 从站时,需将 MAX_PD_INPUT_SIZE 或 MAX_PD_OUTPUT_SIZE 设为 0,否则需设为最大过程数据大小。注:未使用的过程数据同步管理器需禁用,移除 SM 需适配 SSC。
6.5.1 新增应用程序
  • 手动添加:禁用所有默认示例应用程序(见 6.1),在 coeappl.c、ecatappl.c、ecatslv.c 文件中(参考 "APPLICATION_FILE" 注释)包含应用程序头文件(含函数定义),从零创建或修改现有 ESI 文件。
  • 通过补丁文件添加:参考应用程序厂商说明,ESI 文件通常随应用程序源代码提供。
  • 通过 SSC 工具添加:创建新项目,在弹出对话框中选择应用程序;若应用程序未列出,可导入对应的 SSC 工具配置文件(见 12.6);无配置文件时需联系应用程序厂商。SSC 工具会生成应用程序特定的源代码文件和对应的 ESI 文件。
6.5.2 示例
6.5.2.1 示例应用程序过程数据增强

本示例基于 SSC 5.01 版本,说明如何为默认示例应用程序(SAMPLE_APPLICATION)添加新过程数据。

原有过程数据
  • 32 位输入计数器(0x6000)
  • 32 位输出计数器(0x7010):输出计数器为 0 时,输入计数器每个应用周期加 1;否则输入计数器 = 输出计数器 + 1
新增后过程数据
  • 32 位输入计数器(0x6000):每个应用周期自增 1
  • 32 位结果(0x6010):0x7010.1 与 0x7010.2 之和
  • 输出值(0x7010):包含两个 32 位值(SI1:Value1、SI2:Value2)
适配步骤
  1. 文件:sampleappl.h为 "32 位结果" 过程数据创建条目描述、对象名称和变量:

    复制代码
    /* 对象 0x6010:结果对象 */
    #ifdef _OBJD_
    /* 条目描述 */
    OBJCONST TSDOINFOENTRYDESC OBJMEM EntryDesc0x6010 = {DEFTYPE_UNSIGNED32, 0x10, ACCESS_READ | OBJACCESS_TXPDOMAPPING};
    /* 对象名称 */
    OBJCONST UCHAR OBJMEM aName0x6010[] = "Result";
    #endif // #ifdef _OBJD_
    /* 处理对象数据的变量 */
    PROTO UINT32 ResultObj6010;
  2. 文件:sampleappl.h修改现有对象 0x7010(32 位输出计数器)为记录对象,支持多个过程数据:

    复制代码
    /* 对象 0x7010:输出值对象 */
    #ifdef _OBJD_
    OBJCONST TSDOINFOENTRYDESC OBJMEM asEntryDesc0x7010[] = {
        /* 子索引 0 的条目描述 */
        {DEFTYPE_UNSIGNED8, 0x08, ACCESS_READ},
        /* 第一个条目"Value1"的描述 */
        {DEFTYPE_UNSIGNED32, 0x20, ACCESS_READ | OBJACCESS_RXPDOMAPPING},
        /* 第二个条目"Value2"的描述 */
        {DEFTYPE_UNSIGNED32, 0x20, ACCESS_READ | OBJACCESS_RXPDOMAPPING}};
    /* 对象及条目的名称(每个子名称以"\000"结尾,整体以"\377"结尾) */
    OBJCONST UCHAR OBJMEM aName0x7010[] = "Output values\000First value\000Second value\000\377";
    #endif // #ifdef _OBJD_
    /* 处理对象数据的结构 */
    typedef struct OBJ_STRUCT_PACKED_START {
        UINT16 u16SubIndex0;
        UINT32 Value1;
        UINT32 Value2;
    } OBJ_STRUCT_PACKED_END TOBJ7010;
    PROTO TOBJ7010 OutputData
    #ifdef _SAMPLE_APPLICATION_
    = {0x02, 0x00, 0x00} // 子索引 0 设为 2(表示 2 个条目)
    #endif
  3. 文件:sampleappl.h更新 PDO 映射对象中的新过程数据信息(RxPDO 0x1601,处理输出过程数据):

    复制代码
    /**************************************************************************
     * 对象 0x1601:RxPDO
     **************************************************************************/
    #ifdef _OBJD_
    OBJCONST TSDOINFOENTRYDESC OBJMEM asEntryDesc0x1601[] = {
        {DEFTYPE_UNSIGNED8, 0x8, ACCESS_READ},
        {DEFTYPE_UNSIGNED32, 0x20, ACCESS_READ},
        /* 新过程数据的引用(描述不涉及过程数据本身类型,即使是 UNSIGNED8 也填 UNSIGNED32) */
        {DEFTYPE_UNSIGNED32, 0x20, ACCESS_READ}};
    /* 仅描述对象名称,条目自动命名为"SubIndex 000"(依次递增) */
    OBJCONST UCHAR OBJMEM aName0x1601[] = "RxPDO-Map\000\377";
    #endif // #ifdef _OBJD_
    typedef struct OBJ_STRUCT_PACKED_START {
        UINT16 u16SubIndex0;
        /* 新增数组元素,用于引用新过程数据 */
        UINT32 aEntries[2];
    } OBJ_STRUCT_PACKED_END TOBJ1601;
    PROTO TOBJ1601 RxPDOMap
    #ifdef _SAMPLE_APPLICATION_
    = {0x02, {0x70100120, 0x70100220}} // 引用对象 0x7010 子索引 1 和 2,32 位长度
    #endif
  4. 文件:sampleappl.h更新 PDO 映射对象中的新过程数据信息(TxPDO 0x1A00,处理输入过程数据):

    复制代码
    /**************************************************************************
     * 对象 0x1A00:TxPDO
     **************************************************************************/
    #ifdef _OBJD_
    OBJCONST TSDOINFOENTRYDESC OBJMEM asEntryDesc0x1A00[] = {
        {DEFTYPE_UNSIGNED8, 0x8, ACCESS_READ},
        {DEFTYPE_UNSIGNED32, 0x20, ACCESS_READ},
        /* 新过程数据的引用(描述不涉及过程数据本身类型) */
        {DEFTYPE_UNSIGNED32, 0x20, ACCESS_READ}};
    /* 仅描述对象名称,条目自动命名为"SubIndex 000"(依次递增) */
    OBJCONST UCHAR OBJMEM aName0x1A00[] = "TxPDO-Map\000\377";
    #endif // #ifdef _OBJD_
    typedef struct OBJ_STRUCT_PACKED_START {
        UINT16 u16SubIndex0;
        /* 新增数组元素,用于引用新过程数据 */
        UINT32 aEntries[2];
    } OBJ_STRUCT_PACKED_END TOBJ1A00;
    PROTO TOBJ1A00 TxPDOMap
    #ifdef _SAMPLE_APPLICATION_
    = {0x02, {0x60000020, 0x60100020}} // 引用对象 0x6000 子索引 0 和 0x6010 子索引 0,32 位长度
    #endif
  5. 文件:sampleappl.h更新对象字典中的引用:

    复制代码
    TOBJECT OBJMEM ApplicationObjDic[] = {
        /* 对象 0x1601 */
        {NULL, NULL, 0x1601, {DEFTYPE_PDOMAPPING, 2 | (OBJCODE_REC << 8)}, asEntryDesc0x1601, aName0x1601, &RxPDOMap, NULL, NULL, 0x0000},
        /* 对象 0x1A00 */
        {NULL, NULL, 0x1A00, {DEFTYPE_PDOMAPPING, 2 | (OBJCODE_REC << 8)}, asEntryDesc0x1A00, aName0x1A00, &TxPDOMap, NULL, NULL, 0x0000},
        /* 对象 0x6010 */
        {NULL, NULL, 0x6010, {DEFTYPE_UNSIGNED32, 0 | (OBJCODE_VAR << 8)}, &EntryDesc0x6010, aName0x6010, &ResultObj6010, NULL, NULL, 0x0000},
        /* 对象 0x7010 */
        {NULL, NULL, 0x7010, {DEFTYPE_RECORD, 2 | (OBJCODE_REC << 8)}, asEntryDesc0x7010, aName0x7010, &OutputData, NULL, NULL, 0x0000},
        {NULL, NULL, 0xFFFF, {0, 0}, NULL, NULL, NULL, NULL, NULL, 0x0000}};
  6. 文件:sampleappl.c更新预期过程数据大小(需与 ESI 文件信息一致,否则从站从 PreOP 转换到 SafeOP 时会报错 0x1E 或 0x1D):

    复制代码
    UINT16 APPL_GenerateMapping(UINT16 *pInputSize, UINT16 *pOutputSize) {
        /* 32 位循环计数器(0x6000)和 32 位结果(0x6010) */
        *pInputSize = 8;
        /* 32 位 Value1(0x7010.1)和 32 位 Value2(0x7010.2) */
        *pOutputSize = 8;
        return ALSTATUSCODE_NOERROR;
    }
  7. 文件:sampleappl.c更新输入过程数据映射函数,复制新过程数据:

    复制代码
    void APPL_InputMapping(UINT16* pData) {
        MEMCPY(pData, &InputCounter, SIZEOF(InputCounter));
        /* 递增数据指针,写入下一个过程数据(pData 指向 SyncManager 3 控制的 ESC 内存缓冲区) */
        pData += 2;
        /* 复制结果值 */
        MEMCPY(pData, &ResultObj6010, SIZEOF(ResultObj6010));
    }
  8. 文件:sampleappl.c更新输出过程数据映射函数,更新输出过程数据变量:

    复制代码
    void APPL_OutputMapping(UINT16* pData) {
        /* 更新变量"Value1" */
        MEMCPY(&OutputData.Value1, pData, SIZEOF(OutputData.Value1));
        /* 递增数据指针,读取下一个过程数据(pData 指向 SyncManager 3 控制的 ESC 内存缓冲区) */
        pData += 2;
        /* 更新变量"Value2" */
        MEMCPY(&OutputData.Value2, pData, SIZEOF(OutputData.Value2));
    }
  9. 文件:sampleappl.c更新应用程序逻辑:

    复制代码
    void APPL_Application(void) {
        /* 硬件无关示例应用程序 */
        ResultObj6010 = OutputData.Value1 + OutputData.Value2;
        InputCounter++;
    }
  10. 文件:ESI 文件(XML 格式)根据步骤 3 和 4 更新 RxPdo 和 TxPdo 元素:

    复制代码
    <RxPdo Mandatory="true" Fixed="true" Sm="2">
        <Index>#x1601</Index>
        <Name>RxPDO</Name>
        <Entry>
            <Index>#x7010</Index>
            <SubIndex>1</SubIndex>
            <BitLen>32</BitLen>
            <Name>Value1</Name>
            <DataType>UDINT</DataType>
        </Entry>
        <Entry>
            <Index>#x7010</Index>
            <SubIndex>2</SubIndex>
            <BitLen>32</BitLen>
            <Name>Value2</Name>
            <DataType>UDINT</DataType>
        </Entry>
    </RxPdo>
    <TxPdo Mandatory="true" Fixed="true" Sm="3">
        <Index>#x1a00</Index>
        <Name>TXPDO</Name>
        <Entry>
            <Index>#x6000</Index>
            <SubIndex>0</SubIndex>
            <BitLen>32</BitLen>
            <Name>32Bit Input</Name>
            <DataType>UDINT</DataType>
        </Entry>
        <Entry>
            <Index>#x6010</Index>
            <SubIndex>0</SubIndex>
            <BitLen>32</BitLen>
            <Name>Result</Name>
            <DataType>UDINT</DataType>
        </Entry>
    </TxPdo>

    主站将使用该信息计算同步管理器大小(需与步骤 6 中指定的大小一致)并向用户显示过程数据。

  11. 文件:ESI 文件根据 RxPdo/TxPdo 条目的总位大小,更新同步管理器的默认大小:

    复制代码
    <Sm MinSize="34" MaxSize="192" DefaultSize="128" StartAddress="#x1000" ControlByte="#x26" Enable="1">MBoxOut</Sm>
    <Sm MinSize="34" MaxSize="192" DefaultSize="128" StartAddress="#x1400" ControlByte="#x22" Enable="1">MBoxIn</Sm>
    <Sm DefaultSize="8" StartAddress="#x1800" ControlByte="#x64" Enable="1">Outputs</Sm>
    <Sm DefaultSize="8" StartAddress="#x1c00" ControlByte="#x20" Enable="1">Inputs</Sm>

来源:AN_ET9300.pdf

用作个人学习和分享,侵删

相关推荐
Li_RuiQi5 小时前
DAgger与交互式模仿学习_ACT学习笔记
笔记·学习
He BianGu6 小时前
【笔记】C# 中BindingFlags的详细作用
笔记·c#
AI视觉网奇6 小时前
turtle 入门教程笔记
笔记
跨知易知识产权6 小时前
美国专利确权是什么,和专利诉讼有什么不一样?
笔记
杨逢昌工厂6S管理6 小时前
126-杨逢昌6S三环体系:越做越乱的现场熵增机理与基准化治理——一线现场诊断笔记
经验分享·笔记·职场和发展·学习方法
悟道书生6 小时前
若依 RBAC 权限控制学习笔记
java·网络·笔记·sql·学习·vue
陈哈哈11117 小时前
折腾了半天,总算把 Vim 9.2 装明白了
笔记
陈哈哈11117 小时前
折腾了半天,总算把 OpenGL 的开发环境给装明白了
笔记
深圳老胡8 小时前
STM32F103 硬件 SPI 与软件 IO 模拟 SPI 最高速度差异详解
笔记·stm32·单片机·代码规范·1024程序员节
正弦波_Wave8 小时前
【Orcad原理图打印Pdf】
笔记·pdf