ZLG致遠(yuǎn)電子的PCIe EtherCAT通訊卡該如何使用?PDO過(guò)程數(shù)據(jù)該如何操作?具體編程又該如何實(shí)現(xiàn)?續(xù)接上一章節(jié),本文將為您詳細(xì)講解。
EtherCAT工業(yè)總線技術(shù)在工業(yè)自動(dòng)化領(lǐng)域展現(xiàn)出了廣泛的應(yīng)用價(jià)值,特別是在運(yùn)動(dòng)控制、機(jī)器人技術(shù)和測(cè)量技術(shù)等方面。ZLG致遠(yuǎn)電子 PCIe EtherCAT通訊卡 基于自主知識(shí)產(chǎn)權(quán)的系統(tǒng)之上開發(fā),實(shí)現(xiàn)了軟硬件間的無(wú)縫連接,極大地提升了系統(tǒng)的穩(wěn)定性、可靠性以及安全性。同時(shí),該通訊卡還支持線路冗余以及熱插拔功能,可輕松實(shí)現(xiàn)多軸同步控制和數(shù)據(jù)的高速傳輸。此外,ZLG致遠(yuǎn)電子PCIe EtherCAT通訊卡還為用戶提供了便捷的二次開發(fā)庫(kù),支持VC、C#、Linux、Python等各類主流開發(fā)環(huán)境,滿足客戶不同層次的開發(fā)需求。值得一提的是,ZLG致遠(yuǎn)電子PCIe EtherCAT通訊卡通過(guò)將商業(yè)級(jí)EtherCAT主站協(xié)議和實(shí)時(shí)內(nèi)核相結(jié)合的方式,有效釋放主機(jī)資源,完美解決傳統(tǒng)EtherCAT主站在非實(shí)時(shí)操作系統(tǒng)下運(yùn)行所帶來(lái)的各類問(wèn)題,為用戶帶來(lái)了更加高效、穩(wěn)定的解決方案。圖1PCIeEtherCAT通訊卡表1PCIeEtherCAT通訊卡型號(hào)
基于上一章《使用PCIe EtherCAT通訊卡控制IO從站step by step(一)》中所講訴的內(nèi)容,我們已經(jīng)完成了開發(fā)環(huán)境的搭建,以及主函數(shù)的建立,接下來(lái),我們將會(huì)進(jìn)一步完善主函數(shù)中的代碼,實(shí)現(xiàn)對(duì)從站的PDO數(shù)據(jù)讀寫。
1. 代碼編寫
打開ecat_api_io_test.cpp文件。根據(jù)AWStudio軟件導(dǎo)出的eni文件定義過(guò)程數(shù)據(jù)的結(jié)構(gòu)體,打開eni文件,移動(dòng)光標(biāo)到文件尾部,找到注釋的節(jié)點(diǎn)ENI_PDO_LIST。圖2ENI文件(1)圖3ENI文件(2)節(jié)點(diǎn)中的inputs為從站返回的PDO過(guò)程數(shù)據(jù),outputs為主站發(fā)送到從站的PDO過(guò)程數(shù)據(jù),根據(jù)每個(gè)變量的位寬bit_size,我們可以定義對(duì)應(yīng)的類型。
根據(jù)圖2的信息,我們可以看出輸出有三個(gè)變量,DI_1,AI_1,AI_2,長(zhǎng)度分別為8位,8位,16位,輸入有三個(gè)變量DO_1,AO_1,AO_2,長(zhǎng)度分別位8位,8位,16位,定義結(jié)構(gòu)體:
//過(guò)程數(shù)據(jù),寫入從站的數(shù)據(jù)格式typedef struct{ uint8_t DI_1; uint8_t AI_1; uint16_t AI_2;}PDO_OUTPUTS_T;
//過(guò)程數(shù)據(jù),從站返回的數(shù)據(jù)格式typedef struct{ uint8_t DO_1; uint8_t AO_1; uint16_t AO_2;}PDO_INPUTS_T;
定義完過(guò)程數(shù)據(jù)的結(jié)構(gòu)體后。
第一步,輸入需要控制的pcie卡別名以及通道號(hào),獲取Ecat控制句柄。
EXIT_IF_FAIL(EcatOpen(&hHandle, BOARD_ALIAS(buff, alias), channel));
第二步,輸入上位機(jī)程序?qū)С龅膃ni文件,啟動(dòng)Ecat主站。
EXIT_IF_FAIL(EcatBusRun(hHandle, fileName));
第三步,將Ecat主站狀態(tài)切換為8(Operational)。
EXIT_IF_FAIL(EcatRequestMasterState(hHandle, EcatStateO));
等待主站切換狀態(tài)。
uint8_t query = EcatStateNotSet;do{ EXIT_IF_FAIL(EcatGetMasterState(hHandle, &query)); //輸出當(dāng)前狀態(tài) _DBG_("request_state=%d, query_state=%d", EcatStateO, query); if (query == EcatStateO){ break;; } std::sleep_for(std::seconds(1));}while(1);
第四步,定義PDO過(guò)程數(shù)據(jù)的指針并指向本地緩存空間,這一步將會(huì)讓我們更加方便快捷地讀寫PDO數(shù)據(jù)。
圖4PDO數(shù)據(jù)的收發(fā)原理執(zhí)行EcatPINMap函數(shù),將會(huì)修改第3個(gè)參數(shù)inputBuff,outputBuff的指向,讓其直接指向本地輸入輸出緩存區(qū),固不需要再額外申請(qǐng)空間。
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));
第五步,向發(fā)送隊(duì)列中添加空數(shù)據(jù),添加空數(shù)據(jù)的數(shù)量取決于PC系統(tǒng)抖動(dòng)的程度,抖動(dòng)越小,添加的空數(shù)據(jù)越少,控制指令的滯后性越小。
for(auto i = 0; i < 2; i++){ ? ?EcatPIOutputQueuePush(hHandle, false, 100);}
第六步,使能過(guò)程數(shù)據(jù)PDO通信。
EXIT_IF_FAIL(EcatPIEnable(hHandle));
第七步,通過(guò)EcatPIInputQueuePop接口,等待從站數(shù)據(jù)返回,然后讀寫PDO過(guò)程數(shù)據(jù),最后調(diào)用EcatPIOutputQueuePush接口將數(shù)據(jù)添加到發(fā)送隊(duì)列。當(dāng)前例子中,在收到從站返回的數(shù)據(jù)后,主站會(huì)將收到的輸入數(shù)據(jù)寫到輸出的變量。
bool loopFlag = true;while(loopFlag){ //阻塞式等待PDO數(shù)據(jù) if (!EcatPIInputQueuePop(hHandle, false, 100)){ /*********************************************************/ //修改過(guò)程數(shù)據(jù) 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; /*********************************************************/ //將數(shù)據(jù)添加到PDO的發(fā)送隊(duì)列中 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"
//過(guò)程數(shù)據(jù),寫入從站的數(shù)據(jù)格式typedef struct{ uint8_t DI_1; uint8_t AI_1; uint16_t AI_2;}PDO_OUTPUTS_T;
//過(guò)程數(shù)據(jù),從站返回的數(shù)據(jù)格式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)); //啟動(dòng)主站 EXIT_IF_FAIL(EcatBusRun(hHandle, fileName)); //將狀態(tài)切換為8(Operational) EXIT_IF_FAIL(EcatRequestMasterState(hHandle, EcatStateO));
//等待主站切換狀態(tài) uint8_t query = EcatStateNotSet; do{ EXIT_IF_FAIL(EcatGetMasterState(hHandle, &query)); //輸出當(dāng)前狀態(tài) _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));
//向發(fā)送隊(duì)列中添加空數(shù)據(jù),添加空數(shù)據(jù)的數(shù)量取決于PC系統(tǒng)抖動(dòng)的程度,抖動(dòng)越小,添加的空數(shù)據(jù)越少,控制指令的滯后性越小 for(auto i = 0; i < 2; i++){ EcatPIOutputQueuePush(hHandle, false, 100); } //使能過(guò)程數(shù)據(jù)PDO通信 EXIT_IF_FAIL(EcatPIEnable(hHandle));
bool loopFlag = true; while(loopFlag){ //阻塞式等待PDO數(shù)據(jù) if (!EcatPIInputQueuePop(hHandle, false, 100)){ /*********************************************************/ //修改過(guò)程數(shù)據(jù) 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; /*********************************************************/ //將數(shù)據(jù)添加到PDO的發(fā)送隊(duì)列中 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;}
編譯
運(yùn)行測(cè)試
輸出,程序?qū)⒊掷m(xù)打印從站的輸入狀態(tài)
但真正開發(fā)的時(shí)候,建議將打印信息等耗時(shí)的操作注釋后再編譯,否則,程序?qū)⒖赡軙?huì)因?yàn)榇蛴?dòng)作耗時(shí)過(guò)長(zhǎng)而導(dǎo)致主機(jī)無(wú)法快速填充pdo數(shù)據(jù),最終將產(chǎn)生控制抖動(dòng)等問(wèn)題。
-
總線
+關(guān)注
關(guān)注
10文章
2881瀏覽量
88095 -
PCIe
+關(guān)注
關(guān)注
15文章
1239瀏覽量
82663 -
通訊卡
+關(guān)注
關(guān)注
0文章
6瀏覽量
5848
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論