当前位置:网站首页>基于AM4377的EtherCAT主站控制stm32从站
基于AM4377的EtherCAT主站控制stm32从站
2022-06-21 16:19:00 【拉松】
本文为一个igh小例程,用于控制EtherCAT从站。主站控制3个倍福EL2008从站每秒钟实现1次亮灭,每秒读取stm32从站的AD数据并在串口中打印出来,stm32从站的8路输出由8路输入控制(用key控制led亮灭)。
程序参考了igh提供的example。
实验设备为安装了xenomai和igh的am4377开发板、倍福EL2008从站和淘宝店家“易元素电子”的stm32从站。
igh 主站代码
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <sys/resource.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/mman.h>
#include <rtdm/rtdm.h>
#include <native/task.h>
#include <native/sem.h>
#include <native/mutex.h>
#include <native/timer.h>
#include <rtdk.h>
#include <pthread.h>
#include "ecrt.h"
RT_TASK my_task;
static int run = 1;
/****************************************************************************/
// EtherCAT
static ec_master_t *master = NULL;
static ec_master_state_t master_state = {
};
static ec_domain_t *domain1 = NULL;
static ec_domain_state_t domain1_state = {
};
static uint8_t *domain1_pd = NULL;
static ec_slave_config_t *sc_el2008_1 = NULL;
static ec_slave_config_t *sc_el2008_2 = NULL;
static ec_slave_config_t *sc_el2008_3 = NULL;
static ec_slave_config_t *sc_stm = NULL;
/****************************************************************************/
// process data
#define BusCoupler01_Pos 0, 0
#define DigOutSlave01_Pos 0, 1
#define DigOutSlave02_Pos 0, 2
#define DigOutSlave03_Pos 0, 3
#define DigOutSlave04_Pos 0, 4
#define Beckhoff_EK1100 0x00000002, 0x044c2c52
#define Beckhoff_EL2008 0x00000002, 0x07d83052
#define stm32_lan9252 0x00000009, 0x00009252
// offsets for PDO entries 所谓偏移,也相当于一个操作符号,不需要去写初始化,用户层只使用其地址
static unsigned int off_dig_out0;
static unsigned int off_dig_out1;
static unsigned int off_dig_out2;
static unsigned int off_dig_out3;
static unsigned int off_dig_out4;
static unsigned int off_dig_out5;
// process data
const static ec_pdo_entry_reg_t domain1_regs[] = {
{
DigOutSlave01_Pos, Beckhoff_EL2008, 0x7000, 0x01, &off_dig_out0, NULL},
{
DigOutSlave02_Pos, Beckhoff_EL2008, 0x7000, 0x01, &off_dig_out1, NULL},
{
DigOutSlave03_Pos, Beckhoff_EL2008, 0x7000, 0x01, &off_dig_out2, NULL},
{
DigOutSlave04_Pos, stm32_lan9252, 0x7010, 0x01, &off_dig_out3, NULL},
{
DigOutSlave04_Pos, stm32_lan9252, 0x6000, 0x01, &off_dig_out4, NULL},
{
DigOutSlave04_Pos, stm32_lan9252, 0x6020, 0x11, &off_dig_out5, NULL},
{
}
};
/****************************************************************************/
/* Slave 1, "EL2008" * Vendor ID: 0x00000002 * Product code: 0x07d83052 * Revision number:"#x00100000" */
ec_pdo_entry_info_t slave_1_pdo_entries[] = {
{
0x7000, 0x01, 1}, /* Output */
{
0x7010, 0x01, 1}, /* Output */
{
0x7020, 0x01, 1}, /* Output */
{
0x7030, 0x01, 1}, /* Output */
{
0x7040, 0x01, 1}, /* Output */
{
0x7050, 0x01, 1}, /* Output */
{
0x7060, 0x01, 1}, /* Output */
{
0x7070, 0x01, 1} /* Output */
};
ec_pdo_info_t slave_1_pdos[] = {
{
0x1600, 1, slave_1_pdo_entries + 0}, /* Channel 1 */
{
0x1601, 1, slave_1_pdo_entries + 1}, /* Channel 2 */
{
0x1602, 1, slave_1_pdo_entries + 2}, /* Channel 3 */
{
0x1603, 1, slave_1_pdo_entries + 3}, /* Channel 4 */
{
0x1604, 1, slave_1_pdo_entries + 4},
{
0x1605, 1, slave_1_pdo_entries + 5},
{
0x1606, 1, slave_1_pdo_entries + 6},
{
0x1607, 1, slave_1_pdo_entries + 7} /* Channel 8 */
};
ec_sync_info_t slave_el2008_syncs[] = {
{
0, EC_DIR_OUTPUT, 8, slave_1_pdos + 0, EC_WD_ENABLE},
{
0xff}
};
/* Master 0, Slave 4, "LAN9252-EVB-HBI" * Vendor ID: 0x00000009 * Product code: 0x00009252 * Revision number: 0x00000001 */
ec_pdo_entry_info_t slave_stm_pdo_entries[] = {
{
0x7010, 0x01, 1}, /* LED 1 */
{
0x7010, 0x02, 1}, /* LED 2 */
{
0x7010, 0x03, 1}, /* LED 3 */
{
0x7010, 0x04, 1}, /* LED 4 */
{
0x7010, 0x05, 1}, /* LED 5 */
{
0x7010, 0x06, 1}, /* LED 6 */
{
0x7010, 0x07, 1}, /* LED 7 */
{
0x7010, 0x08, 1}, /* LED 8 */
{
0x0000, 0x00, 8}, /* Gap */
{
0x6000, 0x01, 1}, /* Switch 1 */
{
0x6000, 0x02, 1}, /* Switch 2 */
{
0x6000, 0x03, 1}, /* Switch 3 */
{
0x6000, 0x04, 1}, /* Switch 4 */
{
0x6000, 0x05, 1}, /* Switch 5 */
{
0x6000, 0x06, 1}, /* Switch 6 */
{
0x6000, 0x07, 1}, /* Switch 7 */
{
0x6000, 0x08, 1}, /* Switch 8 */
{
0x0000, 0x00, 8}, /* Gap */
{
0x6020, 0x01, 1}, /* Underrange */
{
0x6020, 0x02, 1}, /* Overrange */
{
0x6020, 0x03, 2}, /* Limit 1 */
{
0x6020, 0x05, 2}, /* Limit 2 */
{
0x0000, 0x00, 8}, /* Gap */
{
0x1802, 0x07, 1}, /* TxPDOState */
{
0x1802, 0x09, 1}, /* TxPDO Toggle */
{
0x6020, 0x11, 16}, /* Analog input */
};
ec_pdo_info_t slave_stm_pdos[] = {
{
0x1601, 9, slave_stm_pdo_entries + 0}, /* DO RxPDO-Map */
{
0x1a00, 9, slave_stm_pdo_entries + 9}, /* DI TxPDO-Map */
{
0x1a02, 8, slave_stm_pdo_entries + 18}, /* AI TxPDO-Map */
};
//sm0 for MBoxOut;sm1 for MBoxIn;sm2 for Outputs;sm3 for Inputs
ec_sync_info_t slave_stm_syncs[] = {
{
0, EC_DIR_OUTPUT, 0, NULL, EC_WD_DISABLE},
{
1, EC_DIR_INPUT, 0, NULL, EC_WD_DISABLE},
{
2, EC_DIR_OUTPUT, 1, slave_stm_pdos + 0, EC_WD_ENABLE},
{
3, EC_DIR_INPUT, 2, slave_stm_pdos + 1, EC_WD_DISABLE},
{
0xff}
};
/***************************************************************************** * Realtime task ****************************************************************************/
void rt_check_domain_state(void)
{
ec_domain_state_t ds = {
};
ecrt_domain_state(domain1, &ds);
if (ds.working_counter != domain1_state.working_counter) {
rt_printf("Domain1: WC %u.\n", ds.working_counter);
}
if (ds.wc_state != domain1_state.wc_state) {
rt_printf("Domain1: State %u.\n", ds.wc_state);
}
domain1_state = ds;
}
/****************************************************************************/
void rt_check_master_state(void)
{
ec_master_state_t ms;
ecrt_master_state(master, &ms);
if (ms.slaves_responding != master_state.slaves_responding) {
rt_printf("%u slave(s).\n", ms.slaves_responding);
}
if (ms.al_states != master_state.al_states) {
rt_printf("AL states: 0x%02X.\n", ms.al_states);
}
if (ms.link_up != master_state.link_up) {
rt_printf("Link is %s.\n", ms.link_up ? "up" : "down");
}
master_state = ms;
}
/****************************************************************************/
#define _ms 1000000
void my_task_proc(void *arg)
{
int cycle_counter = 0;
unsigned int blink = 0;
rt_task_set_periodic(NULL, TM_NOW, 1*_ms); // ns
while (cycle_counter<10000) {
rt_task_wait_period(NULL);
cycle_counter++;
// receive EtherCAT frames
ecrt_master_receive(master);
ecrt_domain_process(domain1);
rt_check_domain_state();
if (!(cycle_counter % 1000)) {
rt_check_master_state();
}
if (!(cycle_counter % 1000)) {
blink = !blink;
printf("ad input... %d\n",EC_READ_U16(domain1_pd + off_dig_out5));
}
EC_WRITE_U8(domain1_pd + off_dig_out0, blink ? 0xFF: 0x00);
EC_WRITE_U8(domain1_pd + off_dig_out1, blink ? 0xFF: 0x00);
EC_WRITE_U8(domain1_pd + off_dig_out2, blink ? 0xFF: 0x00);
EC_WRITE_U8(domain1_pd + off_dig_out3, EC_READ_U8(domain1_pd + off_dig_out4));
// send process data
ecrt_domain_queue(domain1);
ecrt_master_send(master);
}
run = 0;
}
/**************************************************************************** * Signal handler ***************************************************************************/
void signal_handler(int sig)
{
run = 0;
}
/**************************************************************************** * Main function= ***************************************************************************/
int main(int argc, char *argv[])
{
int ret;
/* Perform auto-init of rt_print buffers if the task doesn't do so */
rt_print_auto_init(1);
// rt_print_init(1000,"LEE_RT");
signal(SIGTERM, signal_handler);
signal(SIGINT, signal_handler);
mlockall(MCL_CURRENT | MCL_FUTURE);
printf("Requesting master...\n");
master = ecrt_request_master(0);
if (!master) {
return -1;
}
printf("Creating slave configurations...\n");
// Create configuration for bus coupler EK1100
ec_slave_config_t *sc;
sc = ecrt_master_slave_config(master, BusCoupler01_Pos, Beckhoff_EK1100);
if (!sc) {
return -1;
}
//获从站服配置
sc_el2008_1 = ecrt_master_slave_config(master, DigOutSlave01_Pos, Beckhoff_EL2008);
sc_el2008_2 = ecrt_master_slave_config(master, DigOutSlave02_Pos, Beckhoff_EL2008);
sc_el2008_3 = ecrt_master_slave_config(master, DigOutSlave03_Pos, Beckhoff_EL2008);
sc_stm = ecrt_master_slave_config(master, DigOutSlave04_Pos, stm32_lan9252);
//过程数据SM配置
ecrt_slave_config_pdos(sc_el2008_1, EC_END, slave_el2008_syncs);
ecrt_slave_config_pdos(sc_el2008_2, EC_END, slave_el2008_syncs);
ecrt_slave_config_pdos(sc_el2008_3, EC_END, slave_el2008_syncs);
ecrt_slave_config_pdos(sc_stm, EC_END, slave_stm_syncs);
//创建过程数据域
domain1 = ecrt_master_create_domain(master);
ecrt_domain_reg_pdo_entry_list(domain1, domain1_regs);
printf("Activating master...\n");
ecrt_master_activate(master);
if (!(domain1_pd = ecrt_domain_data(domain1))) {
fprintf(stderr, "Failed to get domain1 data pointer.\n");
return -1;
}
ret = rt_task_create(&my_task, "my_task", 0, 99, T_FPU);
if (ret < 0) {
fprintf(stderr, "Failed to create task: %s\n", strerror(-ret));
return -1;
}
printf("Starting my_task...\n");
ret = rt_task_start(&my_task, &my_task_proc, NULL);
if (ret < 0) {
fprintf(stderr, "Failed to start task: %s\n", strerror(-ret));
return -1;
}
while (run) {
sched_yield();
}
printf("Deleting realtime task...\n");
rt_task_delete(&my_task);
printf("End of Program\n");
ecrt_release_master(master);
return 0;
}
makefile
CC = arm-linux-gnueabihf-gcc
INCPATH = -I./igh-output/include -I./xenomai-Output/include -I./xenomai-Output/include/posix
LIBS = -L./igh-output/lib -lethercat_rtdm -L./xenomai-Output/lib -lrtdm -lpthread_rt -lnative -lxenomai -lpthread -lrt -lm
LFLAGS = -Wl,@./xenomai-Output/lib/posix.wrappers
DEFINES = -D_GNU_SOURCE -D_REENTRANT -D__XENO__
CFLAGS = $(DEFINES)
TARGET = overwatch
####### Output directory
OBJECTS_DIR = ./
####### Files
SOURCES = overwatch.c
OBJECTS = overwatch.o
####### Build rules
$(TARGET): $(OBJECTS)
$(CC) $(LFLAGS) -o $(TARGET) $(OBJECTS) $(LIBS)
####### Compile
$(OBJECTS): $(SOURCES)
$(CC) $(INCPATH) $(CFLAGS) -o $(OBJECTS) -c $(SOURCES)
clean:
rm overwatch *.o
控制部分的代码
if (!(cycle_counter % 1000)) {
blink = !blink;
printf("ad input... %d\n",EC_READ_U16(domain1_pd + off_dig_out5));
}
EC_WRITE_U8(domain1_pd + off_dig_out0, blink ? 0xFF: 0x00);
EC_WRITE_U8(domain1_pd + off_dig_out1, blink ? 0xFF: 0x00);
EC_WRITE_U8(domain1_pd + off_dig_out2, blink ? 0xFF: 0x00);
EC_WRITE_U8(domain1_pd + off_dig_out3, EC_READ_U8(domain1_pd + off_dig_out4));
实验结果


边栏推荐
猜你喜欢

What is the process of en 1101 flammability test for curtains?

STM32F1与STM32CubeIDE编程实例-线性霍尔效应传感器驱动

Nacos注册中心-----从0开始搭建和使用

Runmaide medical passed the listing hearing: it is expected that the loss will increase, with huoyunfei brothers holding about 33%

Stack cognition -- basic use of reverse IDA tools

Your cache folder contains root-owned files, due to a bug in npm ERR! previous versions of npm which

【ORACLE】Oracle里有“time”数据类型吗?--关于对Oracle数据类型的一点研究

Software test system learning and construction (13) - basic requirements for test engineers of test foundation

潤邁德醫療通過上市聆訊:預計虧損將增加,霍雲飛兄弟持股約33%

Stack cognition - Introduction to heap
随机推荐
润迈德医疗通过上市聆讯:预计亏损将增加,霍云飞兄弟持股约33%
Hain's law and Feynman's learning method
Pingcap was selected as the "voice of customers" of Gartner cloud database in 2022, and won the highest score of "outstanding performer"
Software test system learning and construction (13) - basic requirements for test engineers of test foundation
Technical architecture of large websites | information encryption technology and key security management
Stack cognition - stack overflow instance (ret2shellcode)
Side effects in compose
Go corn timing task simple application
Application architecture principles
焱融科技 YRCloudFile 与安腾普完成兼容认证,共创存储新蓝图
3DE motion contour data modification
正则表达式
Differences between WCDMA and LTE
Interceptor to realize web user login
LeetCode_ String_ Simple_ 387. first unique character in string
Accelerate the implementation of cloud native applications, and Yanrong yrcloudfile and Tianyi cloud have completed the Compatibility Certification
Reids面试题集合 数据结构+穿透雪崩+持久化+内存淘汰策略+数据库双写+哨兵
AttributeError: module ‘cv2‘ has no attribute ‘gapi_ wip_ gst_ GStreamerPipeline‘
Class, interface, function
数字藏品系统开发,NFT艺术品交易平台搭建