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 索引 0x6400(INT16,16 位有符号,slave/cia401.h 宏 CIA401_OD_AI),0x6401 为同设备类型别名(CIA401_OD_AI_16BIT)。subindex 标识通道,仅读。无符号读取由 cia401_read_ai_unsigned() 包装同一索引完成。
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 (slave/cia401.h)
slave/cia401.h 提供一组 static inline 便捷函数, 把 SDO 索引/子索引封装为按通道访问的形式。
这些是头文件内联函数 (不是 ethercat_advanced.h, 也不在 dll_t 字段中), 首参不带 dll_t* —— 它们内部直接调 dx_sdo_read / dx_sdo_write 裸符号, 因此仅静态链接模式 (!DYNAMIC_LOAD) 可用。
读类函数直接返回值 (失败时返回 0); 写类函数返回 BOOL。
cia401_read_di / cia401_write_do
uint8_t cia401_read_di(uint16_t master, uint16_t slave, int channel);
uint8_t cia401_read_do(uint16_t master, uint16_t slave, int channel);
BOOL cia401_write_do(uint16_t master, uint16_t slave, int channel, uint8_t value);
按通道 (从 0 开始) 读数字输入 / 读回数字输出 / 写数字输出 (读-改-写, 不影响同组其他通道)。cia401_read_di / cia401_read_do 返回通道电平 (1/0)。
cia401_read_ai / cia401_write_ao
int16_t cia401_read_ai(uint16_t master, uint16_t slave, int channel);
uint16_t cia401_read_ai_unsigned(uint16_t master, uint16_t slave, int channel);
int32_t cia401_read_ai32(uint16_t master, uint16_t slave, int channel);
uint32_t cia401_read_ai32_unsigned(uint16_t master, uint16_t slave, int channel);
int16_t cia401_read_ao(uint16_t master, uint16_t slave, int channel);
BOOL cia401_write_ao(uint16_t master, uint16_t slave, int channel, int16_t value);
按通道读模拟输入 (有符号/无符号, 16/32 位; cia401_read_ai32 自适应 16/32 位返回) / 读回模拟输出 / 写 16 位模拟输出。
32 位模拟输出
int32_t cia401_read_ao32(uint16_t master, uint16_t slave, int channel);
BOOL cia401_write_ao32(uint16_t master, uint16_t slave, int channel, int32_t value);
32 位模拟输出 (0x6412) 读写。
模拟输入中断与限值 (slave/cia401.h)
cia401_get/set_global_interrupt_enable
BOOL cia401_get_global_interrupt_enable(uint16_t master, uint16_t slave);
BOOL cia401_set_global_interrupt_enable(uint16_t master, uint16_t slave, BOOL enabled);
模拟输入全局中断使能 (SDO 0x6423)。get 返回当前使能状态; set 返回写入是否成功。
cia401_get/set_ai_upper_limit
int16_t cia401_get_ai_upper_limit(uint16_t master, uint16_t slave, int channel);
BOOL cia401_set_ai_upper_limit(uint16_t master, uint16_t slave, int channel, int16_t value);
设置/读取通道上限告警值 (SDO 0x6424, 有符号 16 位),AI 值超过上限时触发中断。
cia401_get/set_ai_lower_limit
int16_t cia401_get_ai_lower_limit(uint16_t master, uint16_t slave, int channel);
BOOL cia401_set_ai_lower_limit(uint16_t master, uint16_t slave, int channel, int16_t value);
设置/读取通道下限告警值 (SDO 0x6425, 有符号 16 位),AI 值低于下限时触发中断。
批量 IO 函数 (slave/cia401.h)
以下函数 group 参数为 SDO 子索引 (1-based)。
uint16_t cia401_read_di16(uint16_t master, uint16_t slave, uint8_t group); /* 0x6001 */
uint32_t cia401_read_di32(uint16_t master, uint16_t slave, uint8_t group); /* 0x6020 */
uint16_t cia401_read_do16(uint16_t master, uint16_t slave, uint8_t group); /* 0x6201 */
BOOL cia401_write_do16(uint16_t master, uint16_t slave, uint8_t group, uint16_t value);
uint32_t cia401_read_do32(uint16_t master, uint16_t slave, uint8_t group); /* 0x6220 */
BOOL cia401_write_do32(uint16_t master, uint16_t slave, uint8_t group, uint32_t value);
读类函数直接返回值, 写类函数返回 BOOL。
数字输入配置 (slave/cia401.h)
uint16_t cia401_get_di_polarity(uint16_t master, uint16_t slave, uint8_t group); /* 0x6002 */
BOOL cia401_set_di_polarity(uint16_t master, uint16_t slave, uint8_t group, uint8_t polarity);
uint16_t cia401_get_di_filter(uint16_t master, uint16_t slave, uint8_t group); /* 0x6003 */
BOOL cia401_set_di_filter(uint16_t master, uint16_t slave, uint8_t group, uint8_t filter);
设置/读取数字输入极性 (0x6002, 每位 1=反转) 与滤波使能 (0x6003)。
错误状态读取 (slave/cia401.h)
/* 数字输出错误模式 (0=保持, 1=安全值) / 错误值 */
uint8_t cia401_get_do_error_mode(uint16_t master, uint16_t slave, uint8_t group);
BOOL cia401_set_do_error_mode(uint16_t master, uint16_t slave, uint8_t group, uint8_t mode);
uint16_t cia401_get_do_error_value(uint16_t master, uint16_t slave, uint8_t group);
BOOL cia401_set_do_error_value(uint16_t master, uint16_t slave, uint8_t group, uint8_t value);
/* 模拟输出错误模式 / 错误值 */
uint8_t cia401_get_ao_error_mode(uint16_t master, uint16_t slave, int channel);
BOOL cia401_set_ao_error_mode(uint16_t master, uint16_t slave, int channel, uint8_t mode);
int16_t cia401_get_ao_error_value(uint16_t master, uint16_t slave, int channel);
BOOL cia401_set_ao_error_value(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)。
标准对象索引常量
slave/cia401.h 中定义的对象索引宏 (注意带 CIA401_OD_ 前缀):
| 宏 | 值 | 说明 |
|---|---|---|
| CIA401_OD_DI | 0x6000 | 数字输入 (8 位组) |
| CIA401_OD_DI_16BIT | 0x6001 | 16 位数字输入组 |
| CIA401_OD_DI_POLARITY | 0x6002 | 数字输入极性 |
| CIA401_OD_DI_FILTER | 0x6003 | 数字输入滤波使能 |
| CIA401_OD_DI_INTERRUPT | 0x6005 | 数字输入中断触发 |
| CIA401_OD_DI_INTERRUPT_EDGE | 0x6006 | 数字输入中断边沿 |
| CIA401_OD_DI_32BIT | 0x6020 | 32 位数字输入组 |
| CIA401_OD_DO | 0x6200 | 数字输出 (8 位组) |
| CIA401_OD_DO_16BIT | 0x6201 | 16 位数字输出组 |
| CIA401_OD_DO_POLARITY | 0x6202 | 数字输出极性 |
| CIA401_OD_DO_ERROR_MODE | 0x6206 | 数字输出错误模式 |
| CIA401_OD_DO_ERROR_VALUE | 0x6207 | 数字输出错误值 |
| CIA401_OD_DO_32BIT | 0x6220 | 32 位数字输出组 |
| CIA401_OD_AI | 0x6400 | 模拟输入 (16 位有符号) |
| CIA401_OD_AI_16BIT | 0x6401 | 模拟输入 16 位 (别名) |
| CIA401_OD_AI_SI_UNIT | 0x6420 | 模拟输入量程 |
| CIA401_OD_AI_GLOBAL_INTERRUPT | 0x6423 | 模拟输入全局中断使能 |
| CIA401_OD_AI_UPPER_LIMIT | 0x6424 | 模拟输入中断上限 |
| CIA401_OD_AI_LOWER_LIMIT | 0x6425 | 模拟输入中断下限 |
| CIA401_OD_AO | 0x6411 | 模拟输出 (16 位有符号) |
| CIA401_OD_AO_32BIT | 0x6412 | 32 位模拟输出 |
| CIA401_OD_AO_SI_UNIT | 0x6430 | 模拟输出量程 |
| CIA401_OD_AO_ERROR_MODE | 0x6443 | 模拟输出错误模式 |
| CIA401_OD_AO_ERROR_VALUE | 0x6444 | 模拟输出错误值 |
错误模式枚举宏: CIA401_ERROR_MODE_HOLD (0) / CIA401_ERROR_MODE_SAFE_VALUE (1)。
类型化 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, "DarraEtherCAT.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);
/* 配置错误模式 (slave/cia401.h 内联函数, 首参不带 dll_t*) */
cia401_set_do_error_mode(master, slave, 0, CIA401_ERROR_MODE_SAFE_VALUE);
cia401_set_do_error_value(master, slave, 0, 0x00);
/* 模拟输入告警 */
cia401_set_global_interrupt_enable(master, slave, TRUE);
cia401_set_ai_upper_limit(master, slave, 0, 30000);
cia401_set_ai_lower_limit(master, slave, 0, 1000);
getchar();
dll.Stop(master);
dll.Dispose(master);
UNLOAD_DLL(&dll);
return 0;
}