windows visual studio2022 EtherCAT Demo
知识:
1. EtherCAT的运行需要硬件支持;
2. 上位机作为主机通过网卡直接向各个从机(板子)发送命令,从机中有芯片处理命令转发给各驱动。
一、配置 Npcap
1. 下载Npcap(不要用WinPcap太老了已经不维护了):https://npcap.com/#download

2. 配置lib和include目录:
2.1 在visual studio中新建一个控制台程序PcapTest(也可以是其他名字)。
2.2 将压缩包中的lib和include拷贝出来放在控制台程序下:

2.3 配置附加目录、库目录文件(不懂的话问问AI):


↑注意,这里配置的是lib/x64(如果你是x86或者是其他arm之类的里面也有不同的文件类型)。

这四个:wpcap.lib;Packet.lib;ws2_32.lib;winmm.lib;
2.4 在main函数中运行这段代码:
#include <iostream>
#include <pcap.h>
#pragma comment(lib, "wpcap.lib")
#pragma comment(lib, "Packet.lib")
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "winmm.lib")
int main()
{
/*std::cout << "Hello World!\n";*/
pcap_if_t* alldevs;
char errbuf[PCAP_ERRBUF_SIZE];
if (pcap_findalldevs(&alldevs, errbuf) == 0)
printf("Found network devices!\n");
pcap_freealldevs(alldevs);
return 0;
}
可得结果:

至此 Npcap配置结束。
二、配置SOEM.
1. 下载SOEM:https://github.com/OpenEtherCATsociety/SOEM
2. 运行编译SOEM库:
阅读此文章并配置:https://wxflamy.github.io/2019/09/25/EtherCAT-SOEM/
↑这个文章比较老了,但是运行配置之后在install中出现的是sample_ng.exe,使用这个运行即可。(如果找不到install问问AI。
visual studio 2022中在最上方:生成-build install。
运行代码一闪而过,善用截图找到你的device:

3.在生成文件夹里找到sample_ng.exe,cmd打开后输入你的device地址:

4. 然后找到你的生成文件夹里的lib和include库,参照npcap同样在项目中新建文件引入:



5. main函数:
#include <iostream>
#include <iomanip>
#include <cstring>
#include "soem/soem.h"
#include <bitset>
// 全局 I/O 映射缓冲区
char IOmap[4096];
// 辅助:打印输入输出二进制
void print_bits(uint16_t val, int width = 8)
{
for (int i = width - 1; i >= 0; --i)
std::cout << ((val >> i) & 1);
}
// 主函数
int main()
{
const char* ifname = "\\Device\\NPF_{7E6E850D-B177-4719-A409-3FF991DC1577}";
std::cout << "Initializing EtherCAT on " << ifname << "...\n";
// 创建上下文并清零
ecx_contextt context;
memset(&context, 0, sizeof(context));
memset(IOmap, 0, sizeof(IOmap));
// 初始化主站
if (!ecx_init(&context, ifname))
{
std::cerr << "Failed to initialize SOEM on " << ifname << "\n";
return -1;
}
// 扫描从站
int slave_count = ecx_config_init(&context);
if (slave_count <= 0)
{
std::cerr << "No slaves found!\n";
ecx_close(&context);
return -1;
}
std::cout << "there are " << slave_count << " slaves found.\n";
std::cout << "Slave[1] name: " << context.slavelist[1].name << "\n";
// 映射 PDO & DC
ecx_config_map_group(&context, IOmap, 0); //在内存中分配一块地址给context用来更新input和output
ecx_configdc(&context);
std::cout << "Ibytes=" << context.slavelist[1].Ibytes
<< ", Obytes=" << context.slavelist[1].Obytes << "\n";
// 进入 OP 状态
context.slavelist[0].state = EC_STATE_OPERATIONAL;
ecx_writestate(&context, 0);
for (int i = 0; i < 50; ++i)
{
ecx_send_processdata(&context);
ecx_receive_processdata(&context, EC_TIMEOUTRET);
ecx_statecheck(&context, 0, EC_STATE_OPERATIONAL, EC_TIMEOUTSTATE / 10);
if (context.slavelist[0].state == EC_STATE_OPERATIONAL)
{
std::cout << "All slaves are now OPERATIONAL.\n";
break;
}
osal_usleep(10000);
}
// 进入 PDO 循环
std::cout << "Starting PDO loop...\n";
//uint8_t* in = context.slavelist[1].inputs; //指向内存地址中的context,之后会动态更新
//uint8_t* out = context.slavelist[1].outputs;
// —— 主循环:读取输入、控制输出 ——
for (int cycle = 0; cycle < 1000; ++cycle)
{
// 所有从站更新输出缓冲区(准备发出去的数据)
for (int i = 1; i <= context.slavecount; ++i)
{
uint8_t* out = context.slavelist[i].outputs;
if (!out) continue;
// 控制输出-这里是输出逻辑,换成自己的,不懂就问AI
//if ((cycle / 50) % 2 == 0)
//out[0] = 0x01; // LED1亮
//else
//out[0] = 0x02; // LED2亮
}
// 发出帧(所有从站同步更新输出)
ecx_send_processdata(&context);
// 接收帧(更新所有从站输入缓冲区)
int wkc = ecx_receive_processdata(&context, EC_TIMEOUTRET);
// 现在 inputs 才是最新的,可以安全打印
std::cout << "Cycle " << std::setw(4) << cycle << " | WKC=" << wkc << "\n";
for (int i = 1; i <= context.slavecount; ++i)
{
uint8_t* in = context.slavelist[i].inputs;
if (!in) continue;
uint8_t inputs = in[0];
std::cout << " Slave " << i << " inputs: ";
print_bits(inputs, 8);
std::cout << "\n";
}
osal_usleep(5000); // 5ms周期
}
// 停止主站
context.slavelist[0].state = EC_STATE_INIT;
ecx_writestate(&context, 0);
ecx_close(&context);
std::cout << "EtherCAT master stopped.\n";
return 0;
}
结束。
更多推荐


所有评论(0)