0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

使用PCIE主站卡控制IO从站step by step(二)

ZLG致远电子 2024-05-24 08:25 次阅读

ZLG致远电子的PCIe EtherCAT通讯卡该如何使用?PDO过程数据该如何操作?具体编程又该如何实现?续接上一章节,本文将为您详细讲解。

EtherCAT工业总线技术工业自动化领域展现出了广泛的应用价值,特别是在运动控制、机器人技术和测量技术等方面。ZLG致远电子 PCIe EtherCAT通讯卡 基于自主知识产权的系统之上开发,实现了软硬件间的无缝连接,极大地提升了系统的稳定性、可靠性以及安全性。同时,该通讯卡还支持线路冗余以及热插拔功能,可轻松实现多轴同步控制和数据的高速传输。此外,ZLG致远电子PCIe EtherCAT通讯卡还为用户提供了便捷的二次开发库,支持VC、C#LinuxPython等各类主流开发环境,满足客户不同层次的开发需求。值得一提的是,ZLG致远电子PCIe EtherCAT通讯卡通过将商业级EtherCAT主站协议和实时内核相结合的方式,有效释放主机资源,完美解决传统EtherCAT主站在非实时操作系统下运行所带来的各类问题,为用户带来了更加高效、稳定的解决方案。0d7904f2-1964-11ef-bebc-92fbcf53809c.png图1PCIeEtherCAT通讯卡表1PCIeEtherCAT通讯卡型号

0d9ad726-1964-11ef-bebc-92fbcf53809c.png

基于上一章《使用PCIe EtherCAT通讯卡控制IO从站step by step(一)》中所讲诉的内容,我们已经完成了开发环境的搭建,以及主函数的建立,接下来,我们将会进一步完善主函数中的代码,实现对从站的PDO数据读写。

1. 代码编写

打开ecat_api_io_test.cpp文件。根据AWStudio软件导出的eni文件定义过程数据的结构体,打开eni文件,移动光标到文件尾部,找到注释的节点ENI_PDO_LIST。0dbc29c6-1964-11ef-bebc-92fbcf53809c.png图2ENI文件(1)0dd7b498-1964-11ef-bebc-92fbcf53809c.png图3ENI文件(2)节点中的inputs为从站返回的PDO过程数据,outputs为主站发送到从站的PDO过程数据,根据每个变量的位宽bit_size,我们可以定义对应的类型。

根据图2的信息,我们可以看出输出有三个变量,DI_1,AI_1,AI_2,长度分别为8位,8位,16位,输入有三个变量DO_1,AO_1,AO_2,长度分别位8位,8位,16位,定义结构体:

//过程数据,写入从站的数据格式typedef struct{ uint8_t DI_1; uint8_t AI_1; uint16_t AI_2;}PDO_OUTPUTS_T;
//过程数据,从站返回的数据格式typedef struct{ uint8_t DO_1; uint8_t AO_1; uint16_t AO_2;}PDO_INPUTS_T;

定义完过程数据的结构体后。

第一步,输入需要控制的pcie卡别名以及通道号,获取Ecat控制句柄。

EXIT_IF_FAIL(EcatOpen(&hHandle, BOARD_ALIAS(buff, alias), channel));

第二步,输入上位机程序导出的eni文件,启动Ecat主站。

EXIT_IF_FAIL(EcatBusRun(hHandle, fileName));

第三步,将Ecat主站状态切换为8(Operational)。

EXIT_IF_FAIL(EcatRequestMasterState(hHandle, EcatStateO));

等待主站切换状态。

uint8_t query = EcatStateNotSet;do{ EXIT_IF_FAIL(EcatGetMasterState(hHandle, &query)); //输出当前状态 _DBG_("request_state=%d, query_state=%d", EcatStateO, query); if (query == EcatStateO){ break;; } std::sleep_for(std::seconds(1));}while(1);

第四步,定义PDO过程数据的指针并指向本地缓存空间,这一步将会让我们更加方便快捷地读写PDO数据。

0df5f5b6-1964-11ef-bebc-92fbcf53809c.png图4PDO数据的收发原理执行EcatPINMap函数,将会修改第3个参数inputBuff,outputBuff的指向,让其直接指向本地输入输出缓存区,固不需要再额外申请空间。

PDO_OUTPUTS_T *outputBuff;PDO_INPUTS_T *inputBuff;//将指针inputBuff,outputBuff分别指向本地缓存的空间EXIT_IF_FAIL(EcatPINMap(hHandle, PI_AREA_LOCAL_INPUT, (void**)&inputBuff));EXIT_IF_FAIL(EcatPINMap(hHandle, PI_AREA_LOCAL_OUTPUT, (void**)&outputBuff));

第五步,向发送队列中添加空数据,添加空数据的数量取决于PC系统抖动的程度,抖动越小,添加的空数据越少,控制指令的滞后性越小。

for(auto i = 0; i < 2; i++){    EcatPIOutputQueuePush(hHandle, false, 100);}

第六步,使能过程数据PDO通信

EXIT_IF_FAIL(EcatPIEnable(hHandle));

第七步,通过EcatPIInputQueuePop接口,等待从站数据返回,然后读写PDO过程数据,最后调用EcatPIOutputQueuePush接口将数据添加到发送队列。当前例子中,在收到从站返回的数据后,主站会将收到的输入数据写到输出的变量。

bool loopFlag = true;while(loopFlag){ //阻塞式等待PDO数据 if (!EcatPIInputQueuePop(hHandle, false, 100)){ /*********************************************************/ //修改过程数据 printf("0x%02x, 0x%02x, 0x%04x\r\n", inputBuff->DO_1, inputBuff->AO_1, inputBuff->AO_2); outputBuff->DI_1 = inputBuff->DO_1; outputBuff->AI_1 = inputBuff->AO_1; outputBuff->AI_2 = inputBuff->AO_2; /*********************************************************/ //将数据添加到PDO的发送队列中 if (EcatPIOutputQueuePush(hHandle, false, 100)){ _ERR_("PI push error."); break; } }}

第八步,释放句柄。

EXIT_IF_FAIL(EcatClose(hHandle));

完整的ecat_api_io_test.cpp文件。

#include #include //用于sleep#include //用于sleep#include "pci_errno.h"#include "pci_zecm.h"#include "pci_dbg.h"
//过程数据,写入从站的数据格式typedef struct{ uint8_t DI_1; uint8_t AI_1; uint16_t AI_2;}PDO_OUTPUTS_T;
//过程数据,从站返回的数据格式typedef struct{ uint8_t DO_1; uint8_t AO_1; uint16_t AO_2}PDO_INPUTS_T;
int32_t testDemo(int alias, int channel, const char* fileName){ int32_t result = 0; char buff[256]; ECAT_HANDLE hHandle; //初始化hHandle句柄 EXIT_IF_FAIL(EcatOpen(&hHandle, BOARD_ALIAS(buff, alias), channel)); //启动主站 EXIT_IF_FAIL(EcatBusRun(hHandle, fileName)); //将状态切换为8(Operational) EXIT_IF_FAIL(EcatRequestMasterState(hHandle, EcatStateO));
//等待主站切换状态 uint8_t query = EcatStateNotSet; do{ EXIT_IF_FAIL(EcatGetMasterState(hHandle, &query)); //输出当前状态 _DBG_("request_state=%d, query_state=%d", EcatStateO, query); if (query == EcatStateO){ break;; } std::sleep_for(std::seconds(1)); }while(1);
PDO_OUTPUTS_T *outputBuff; PDO_INPUTS_T *inputBuff; //将指针inputBuff,outputBuff分别指向本地缓存的空间 EXIT_IF_FAIL(EcatPINMap(hHandle, PI_AREA_LOCAL_INPUT, (void**)&inputBuff)); EXIT_IF_FAIL(EcatPINMap(hHandle, PI_AREA_LOCAL_OUTPUT, (void**)&outputBuff));
//向发送队列中添加空数据,添加空数据的数量取决于PC系统抖动的程度,抖动越小,添加的空数据越少,控制指令的滞后性越小 for(auto i = 0; i < 2; i++){ EcatPIOutputQueuePush(hHandle, false, 100); } //使能过程数据PDO通信 EXIT_IF_FAIL(EcatPIEnable(hHandle));
bool loopFlag = true; while(loopFlag){ //阻塞式等待PDO数据 if (!EcatPIInputQueuePop(hHandle, false, 100)){ /*********************************************************/ //修改过程数据 printf("0x%02x, 0x%02x, 0x%04x\r\n", inputBuff->DO_1,inputBuff->AO_1, inputBuff->AO_2); outputBuff->DI_1 = inputBuff->DO_1; outputBuff->AI_1 = inputBuff->AO_1; outputBuff->AI_2 = inputBuff->AO_2; /*********************************************************/ //将数据添加到PDO的发送队列中 if (EcatPIOutputQueuePush(hHandle, false, 100)){ _ERR_("PI push error."); break; } } }
//释放句柄 EXIT_IF_FAIL(EcatClose(hHandle)); return result;}
int main(int argc, char* argv[]){ ECAT_HANDLE hHandle; char buff[256]; uint32_t channel = 0, alias = 0; std::string eniFile; if (argc != 4){ std::cout << "usage: " << argv[0] << " encoder_id channel eni.xml" << std::endl;        return 1;    }    alias = atoi(argv[1]);    channel = atoi(argv[2]);    eniFile = argv[3];    if (channel > 1){ channel = 1; } testDemo(alias, channel, eniFile.c_str()); return 0;}

编译

0e191078-1964-11ef-bebc-92fbcf53809c.png

运行测试

0e3396b4-1964-11ef-bebc-92fbcf53809c.png

输出,程序将持续打印从站的输入状态

0e4b7d06-1964-11ef-bebc-92fbcf53809c.png

但真正开发的时候,建议将打印信息等耗时的操作注释后再编译,否则,程序将可能会因为打印动作耗时过长而导致主机无法快速填充pdo数据,最终将产生控制抖动等问题。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 总线
    +关注

    关注

    10

    文章

    2735

    浏览量

    87389
  • PCIe
    +关注

    关注

    13

    文章

    1103

    浏览量

    81255
  • 通讯卡
    +关注

    关注

    0

    文章

    6

    浏览量

    5824
收藏 人收藏

    评论

    相关推荐

    Step7 Micro Win v4.0.4.16 最新版下载

    与Modbus的通讯简单易行。使用Modbus协议指令,您可以将S7-200组态作为Modbus RTU
    发表于 04-25 07:25

    C语言step-by-step

    C语言step-by-step
    发表于 12-27 09:59

    基于EtherCAT的通信控制器设计

    基于EtherCAT的通信控制器设计
    发表于 09-20 16:05

    Modbus多问题

    ModbusRTU两之间如何交互数据? 工业控制中,一般都是主从通讯方式居多,有时也会碰到两个之间通讯。例如某工作站上位机(
    发表于 11-24 16:36

    PLC分享

    总站是主控制单元,含有CPU,可以不加CPU,可以作为远程,用
    发表于 07-02 08:20

    CAN的功能是什么

    基于 STM32 和 CAN总线的温度监控系统的设计,通过上位机与下位机的通信,实现对温度数据的监控,并经初步实验达到了设计的要求。1 系统总体方案概述系统总体框图如图 1 所示,本系统采用+
    发表于 08-19 07:47

    PLC具有哪些功能

    PLC具有哪些功能?PLC具有哪些功能?
    发表于 09-29 07:22

    开源!ZYNQ IgH EtherCAT方案分享

    前 言:创龙科技已基于IMX8、ZYNQ、AM5728、AM5708、AM437x、AM335x、T3/A40i等平台提供了开源EtherCATIgH案例。本文主要演示
    发表于 10-29 11:17

    通过Mbus发送信息,无法收到信息怎么解决?

    通过Mbus发送信息,无法收到信息怎么解决?
    发表于 01-20 06:42

    请问在RT-thread系统里运行4个和1个是否稳定

    请问这个协议包,在RT-thread系统里,如果运行4个small modbus和1个small modbus,是否稳定
    发表于 11-25 10:28

    esp32当modbus-rtu slave通讯,收不到的响应报文是为何?

    有朋友测试过esp32当 modbus slave(我拿的esp32当,用的是RTU模式)吗? 我用modbus poll软件测试下来,
    发表于 02-14 07:11

    lightech mbus完整指令库

    lightech mbus完整指令库
    发表于 10-09 06:20

    STEP7 IO冗余编程方法 (S7-400 )

    elecfans.com-STEP7 IO冗余编程方法
    发表于 07-03 16:15 30次下载

    S7-400作为PROFINET IO控制器(STEP7)

    S7-400集成PN口和CP443-1均可作为PROFINET IO控制器。本文以CPU 414-3 PN/DP作为IO设备,分别阐述以CPU 416-3 PN/DP和CP443-1作为IO
    的头像 发表于 12-16 11:35 1352次阅读

    使用PCIe EtherCAT通讯卡控制IO从站step by step(一)

    卡是一款高性能的总线控制卡,专为满足高实时的工业控制需求而设计。基于PCIExpress技术,该卡通过使用实时内核+商业授权EtherCAT协议栈的方式,实现了高达
    的头像 发表于 05-21 08:24 121次阅读
    使用<b class='flag-5'>PCIe</b> EtherCAT通讯卡<b class='flag-5'>控制</b><b class='flag-5'>IO</b>从站<b class='flag-5'>step</b> by <b class='flag-5'>step</b>(一)