跳到主要内容

CiA 401 -- 通用 I/O 模块

CiA 401 (IEC 61131-9) 是基于 CoE 的通用数字/模拟 I/O 设备协议。

备注

CiA 401 运行在 CoE (SDO) 之上,仅当从站支持 CoE 时可用。通过 GetSlaveCoEDetails(master, slave) 返回值判断从站是否支持 CoE。

IO 属性

CiA 401 设备有 4 类标准 IO,每类通过 SDO 索引和 PDO 偏移访问。

DI

数字输入(Digital Input)。SDO 索引 0x6000(UINT8 8位)/ 0x6001(UINT16 16位)/ 0x6020(UINT32 32位)。subindex 标识通道(1-based)。每个通道返回一个 bit 状态。

DO

数字输出(Digital Output)。SDO 索引 0x6200(UINT8)/ 0x6201(UINT16)/ 0x6220(UINT32)。subindex 标识通道,可读可写。

AI

模拟输入(Analog Input)。SDO 索引 0x6401(INT16,16 位有符号)。subindex 标识通道,仅读。0x6402(UINT16)为无符号读取。

AO

模拟输出(Analog Output)。SDO 索引 0x6411(INT16)/ 0x6412(INT32)。subindex 标识通道,可读可写。

PDO 数据访问

CiA 401 的数字/模拟 IO 数据通过 PDO 映射交换。具体偏移量取决于从站的 PDO 映射配置。使用 GetIO() 获取 IO 指针后,根据从站手册确定各通道的偏移量;类型化 PDO 读写函数可直接按偏移量访问:

uint8_t di = dll.PDOReadInputU8(master, slave, 0);   /* 数字输入 */
dll.PDOWriteOutputU8(master, slave, 0, 0xFF); /* 数字输出 */
int16_t ai = dll.PDOReadInputI16(master, slave, 2); /* 模拟输入 */
dll.PDOWriteOutputI16(master, slave, 0, 16384); /* 模拟输出 */
实时控制

高频率 I/O 控制应使用 PDO 映射 而非 SDO。SDO 适合参数配置和诊断。

方法 API

便捷函数 (在 ethercat_advanced.h 中) 把 SDO 索引/子索引封装为按通道访问的形式,所有函数返回 0 成功、非 0 失败。

ReadDI

int cia401_read_di(dll_t* dll, uint16_t master, uint16_t slave,
int channel, BOOL* out);

按通道读取数字输入。通道号从 0 开始。

WriteDO

int cia401_write_do(dll_t* dll, uint16_t master, uint16_t slave,
int channel, BOOL value);

按通道写数字输出。

ReadAI

int cia401_read_ai(dll_t* dll, uint16_t master, uint16_t slave,
int channel, int16_t* out);

按通道读取模拟输入(INT16,16 位有符号)。

WriteAO

int cia401_write_ao(dll_t* dll, uint16_t master, uint16_t slave,
int channel, int16_t value);

按通道写模拟输出(INT16)。

ReadAIUnsigned

int cia401_read_ai_unsigned(dll_t* dll, uint16_t master, uint16_t slave,
int channel, uint16_t* out);

按通道读取无符号模拟输入(UINT16)。

ReadAI32Unsigned

int cia401_read_ao32(dll_t* dll, uint16_t master, uint16_t slave,
int channel, int32_t* out);
int cia401_write_ao32(dll_t* dll, uint16_t master, uint16_t slave,
int channel, int32_t value);

32 位模拟输出读写(INT32)。32 位模拟输入用 sdo_read_u32(&dll, master, slave, 0x6403, ch, &out)

模拟输入中断与限值

ReadGlobalInterruptEnable / WriteGlobalInterruptEnable

int cia401_set_global_interrupt_enable(dll_t* dll, uint16_t master,
uint16_t slave, BOOL enable);
int cia401_get_global_interrupt_enable(dll_t* dll, uint16_t master,
uint16_t slave, BOOL* out);

模拟输入全局中断使能(SDO 0x6423)。

ReadAIUpperLimit / WriteAIUpperLimit

int cia401_set_ai_upper_limit(dll_t* dll, uint16_t master, uint16_t slave,
int channel, int32_t limit);
int cia401_get_ai_upper_limit(dll_t* dll, uint16_t master, uint16_t slave,
int channel, int32_t* out);

设置/读取通道上限告警值(SDO 0x6424),AI 值超过上限时触发中断。

ReadAILowerLimit / WriteAILowerLimit

int cia401_set_ai_lower_limit(dll_t* dll, uint16_t master, uint16_t slave,
int channel, int32_t limit);
int cia401_get_ai_lower_limit(dll_t* dll, uint16_t master, uint16_t slave,
int channel, int32_t* out);

设置/读取通道下限告警值(SDO 0x6425),AI 值低于下限时触发中断。

批量 IO 方法

ReadDI16(int group)

int cia401_read_di16(dll_t* dll, uint16_t master, uint16_t slave,
int channel, uint16_t* out);

一次读 16 位数字输入(SDO 0x6001),channel 为 group 索引(1-based)。

ReadDI32(int group)

int cia401_read_di32(dll_t* dll, uint16_t master, uint16_t slave,
int channel, uint32_t* out);

一次读 32 位数字输入(SDO 0x6020)。

ReadDO16 / WriteDO16

int cia401_read_do16(dll_t* dll, uint16_t master, uint16_t slave,
int channel, uint16_t* out);
int cia401_write_do16(dll_t* dll, uint16_t master, uint16_t slave,
int channel, uint16_t value);

16 位数字输出读写(SDO 0x6201)。

ReadDO32 / WriteDO32

int cia401_read_do32(dll_t* dll, uint16_t master, uint16_t slave,
int channel, uint32_t* out);
int cia401_write_do32(dll_t* dll, uint16_t master, uint16_t slave,
int channel, uint32_t value);

32 位数字输出读写(SDO 0x6220)。

ReadAO32 / WriteAO32

参见 ReadAI32Unsigned

数字输入配置

SetDIPolarity / GetDIPolarity

int cia401_set_di_polarity(dll_t* dll, uint16_t master, uint16_t slave,
int channel, BOOL inverted);
int cia401_get_di_polarity(dll_t* dll, uint16_t master, uint16_t slave,
int channel, BOOL* out);

设置/读取数字输入极性(SDO 0x6002)。inverted=TRUE 反相。

SetDIFilter / GetDIFilter

int cia401_set_di_filter(dll_t* dll, uint16_t master, uint16_t slave,
int channel, uint16_t filter_ms);
int cia401_get_di_filter(dll_t* dll, uint16_t master, uint16_t slave,
int channel, uint16_t* out);

设置/读取数字输入软件滤波时间(SDO 0x6003),毫秒单位。

错误状态读取

GetDOErrorMode / GetDOErrorValue

/* 数字输出错误模式 (0=保持, 1=安全值) */
int cia401_set_do_error_mode(dll_t* dll, uint16_t master, uint16_t slave,
int channel, uint8_t mode);
int cia401_get_do_error_mode(dll_t* dll, uint16_t master, uint16_t slave,
int channel, uint8_t* out);

/* 数字输出错误值 */
int cia401_set_do_error_value(dll_t* dll, uint16_t master, uint16_t slave,
int channel, uint8_t value);
int cia401_get_do_error_value(dll_t* dll, uint16_t master, uint16_t slave,
int channel, uint8_t* out);

/* 模拟输出错误模式/值 */
int cia401_set_ao_error_mode(dll_t* dll, uint16_t master, uint16_t slave,
int channel, uint8_t mode);
int cia401_set_ao_error_value(dll_t* dll, uint16_t master, uint16_t slave,
int channel, int16_t value);

错误处理

DOErrorMode

数字输出错误模式(SDO 0x6206)。0=保持最后值,1=切换到安全值。

#define CIA401_ERROR_MODE_HOLD       0
#define CIA401_ERROR_MODE_SAFE_VALUE 1

DOErrorValue

数字输出错误值(SDO 0x6207)。错误模式为 1 时使用此值作为安全输出。

AOErrorMode

模拟输出错误模式(SDO 0x6443),同 DOErrorMode 语义。

AOErrorValue

模拟输出错误值(SDO 0x6444)。

标准对象索引常量

常量说明
OD_DI0x6000数字输入
OD_DI_16BIT0x600116 位数字输入
OD_DI_POLARITY0x6002数字输入极性
OD_DI_FILTER0x6003数字输入滤波使能
OD_DI_INTERRUPT0x6005数字输入中断触发
OD_DI_INTERRUPT_EDGE0x6006数字输入中断边沿
OD_DI_32BIT0x602032 位数字输入
OD_DO0x6200数字输出
OD_DO_16BIT0x620116 位数字输出
OD_DO_POLARITY0x6202数字输出极性
OD_DO_ERROR_MODE0x6206数字输出错误模式
OD_DO_ERROR_VALUE0x6207数字输出错误值
OD_DO_32BIT0x622032 位数字输出
OD_AI0x6400模拟输入
OD_AI_SI_UNIT0x6420模拟输入量程
OD_AI_GLOBAL_INTERRUPT0x6423模拟输入全局中断使能
OD_AI_UPPER_LIMIT0x6424模拟输入中断上限
OD_AI_LOWER_LIMIT0x6425模拟输入中断下限
OD_AO0x6411模拟输出
OD_AO_32BIT0x641232 位模拟输出
OD_AO_SI_UNIT0x6430模拟输出量程
OD_AO_ERROR_MODE0x6443模拟输出错误模式
OD_AO_ERROR_VALUE0x6444模拟输出错误值

类型化 SDO 读写

ethercat_advanced.h 提供类型化 SDO 包装:

#include "ethercat_advanced.h"

uint8_t polarity;
sdo_read_u8(&dll, master, 1, 0x6002, 0x01, &polarity);

int16_t ai;
sdo_read_i16(&dll, master, 1, 0x6401, 0x01, &ai);

sdo_write_i16(&dll, master, 1, 0x6411, 0x01, 16384);

完整示例

#define DYNAMIC_LOAD
#include "ethercat.h"
#include "ethercat_advanced.h"
#include <stdio.h>

int main(void) {
dll_t dll;
LOAD_DLL(&dll, "Darra.Core.dll");
uint16_t master = dll.Initialize();
dll.SetNetwork(master, "\\Device\\NPF_{GUID}", "");
dll.SetStateSequence(master, EC_STATE_OPERATIONAL, 10000);
dll.Start(master);

uint16_t slave = 1;

/* PDO 数字 / 模拟 IO */
uint8_t di = dll.PDOReadInputU8(master, slave, 0);
int16_t ai = dll.PDOReadInputI16(master, slave, 2);
dll.PDOWriteOutputU8(master, slave, 0, 0xFF);
dll.PDOWriteOutputI16(master, slave, 0, 16384);
printf("DI=0x%02X AI=%d\n", di, ai);

/* 配置错误模式 */
cia401_set_do_error_mode(&dll, master, slave, 0, CIA401_ERROR_MODE_SAFE_VALUE);
cia401_set_do_error_value(&dll, master, slave, 0, 0x00);

/* 模拟输入告警 */
cia401_set_global_interrupt_enable(&dll, master, slave, TRUE);
cia401_set_ai_upper_limit(&dll, master, slave, 0, 30000);
cia401_set_ai_lower_limit(&dll, master, slave, 0, 1000);

getchar();
dll.Stop(master);
dll.Dispose(master);
UNLOAD_DLL(&dll);
return 0;
}