CiA 401 — 通用 I/O 模块
CiA 401 (IEC 61131-9) 是基于 CoE 的通用数字/模拟 I/O 设备协议。
CiA 401 运行在 CoE (SDO) 之上,仅当从站支持 CoE 时可用。
通过 slave.cia401 访问(首次取用时自动创建,任何从站都拿得到)。从站实际是否支持 CiA 401 取决于其对象字典:对象不存在时读接口返回 0 / False,写接口返回 False。
快速开始
通过方法读写 IO 通道。逐通道 API 的 channel 从 0 开始;16/32 位批量 API 与极性/滤波 API 的 group 直接用 SDO 子索引(从 1 开始);错误模式/安全值 API 的 group 从 0 开始(内部换算子索引)。
| 类别 | 方法 | 类型 | 读写 | 说明 |
|---|---|---|---|---|
| 数字 IO | read_di(n) | bool | 只读 | 读取数字输入通道 n |
| write_do(n, state) | bool | 只写 | 写入数字输出通道 n,返回 SDO 写入结果 | |
| 模拟 IO | read_ai(n) | int | 只读 | 读取模拟输入通道 n |
| write_ao(n, value) | bool | 只写 | 写入模拟输出通道 n,返回 SDO 写入结果 |
示例:
io = slave.cia401
# 数字 IO
sensor: bool = io.read_di(0)
io.write_do(0, True)
io.write_do(1, sensor)
# 模拟 IO
adc: int = io.read_ai(0)
io.write_ao(0, 16384)
高频率 I/O 控制应使用 PDO 映射 而非 SDO。SDO 适合参数配置和诊断。
方法 API
所有 write_* / set_* 方法返回 bool(SDO 写入是否成功,失败不抛异常)。
read_di()
def read_di(self, channel: int) -> bool
读取数字输入。内部按 8 通道一组自动计算组号和位偏移。
参数:
channel(int) — 通道号(从 0 开始)
read_do()
def read_do(self, channel: int) -> bool
读回上次写入的数字输出状态 (SDO 0x6200)。
参数:
channel(int) — 通道号 (从 0 开始)
write_do()
def write_do(self, channel: int, state: bool) -> bool
设置数字输出,不影响同组其他通道(读改写)。读当前值失败时不写入,直接返回 False。
参数:
channel(int) — 通道号(从 0 开始)state(bool) — 目标状态
返回值:
bool— SDO 写入是否成功
read_ai()
def read_ai(self, channel: int) -> int
读取模拟输入值。自动适应 16 位和 32 位设备,返回有符号值。
参数:
channel(int) — 通道号(从 0 开始)
read_ao()
def read_ao(self, channel: int) -> int
读回当前模拟输出设定值 (SDO 0x6411),有符号 16 位。
参数:
channel(int) — 通道号 (从 0 开始)
write_ao()
def write_ao(self, channel: int, value: int) -> bool
写入模拟输出值(有符号 16 位)。
参数:
channel(int) — 通道号(从 0 开始)value(int) — 有符号 16 位输出值
返回值:
bool— SDO 写入是否成功
write_ao_raw()
def write_ao_raw(self, channel: int, value: int) -> bool
写入模拟输出原始值(无符号 16 位),适用于输出范围 0~65535 的设备。
参数:
channel(int) — 通道号(从 0 开始)value(int) — 无符号 16 位输出值
返回值:
bool— SDO 写入是否成功
read_ai_raw()
def read_ai_raw(self, channel: int) -> int
读取模拟输入原始值(无符号 16 位)。适用于 AI 数据范围为 0~65535 的设备。
参数:
channel(int) — 通道号(从 0 开始)
返回值:
int— 无符号 16 位模拟值
read_ai32()
def read_ai32(self, channel: int) -> int
读取 32 位模拟输入值(无符号)。适用于高精度 AI 设备,数据范围 0~4294967295。
参数:
channel(int) — 通道号(从 0 开始)
返回值:
int— 无符号 32 位模拟值
示例:
io = slave.cia401
# 有符号读取 (默认, 可能高位值变负数)
ai_signed = io.read_ai(0)
# 无符号 16 位原始读取 (0~65535)
ai_u16 = io.read_ai_raw(0)
# 无符号 32 位读取 (高精度设备)
ai_u32 = io.read_ai32(0)
批量 IO 方法
除逐通道操作外,还支持 16/32 位批量读写,一次操作多个通道。批量 API 的 group 直接作为 SDO 子索引,从 1 开始。
read_di16()
def read_di16(self, group: int) -> int
读取 16 位数字输入 (16 个通道)。
参数:
group(int) — 组号(即 SDO 子索引,从 1 开始)
返回值:
int— 16 位输入值, 每位对应一个通道
read_di32()
def read_di32(self, group: int) -> int
读取 32 位数字输入 (32 个通道)。
参数:
group(int) — 组号(即 SDO 子索引,从 1 开始)
返回值:
int— 32 位输入值, 每位对应一个通道
read_do16() / write_do16()
def read_do16(self, group: int) -> int
def write_do16(self, group: int, value: int) -> bool
读取或写入 16 位数字输出 (16 个通道)。
参数:
group(int) — 组号(即 SDO 子索引,从 1 开始)value(int) — 16 位输出值(仅write_do16)
返回值:
read_do16→int— 16 位输出值write_do16→bool— SDO 写入是否成功
示例:
io.write_do16(1, 0x00FF) # 组 1: 低 8 位输出高, 高 8 位输出低
do16 = io.read_do16(1)
read_do32() / write_do32()
def read_do32(self, group: int) -> int
def write_do32(self, group: int, value: int) -> bool
读取或写入 32 位数字输出 (32 个通道)。参数同 read_do16 / write_do16。
read_ao32() / write_ao32()
def read_ao32(self, channel: int) -> int
def write_ao32(self, channel: int, value: int) -> bool
读取或写入 32 位模拟输出值(有符号)。适用于高精度模拟输出设备。
参数:
channel(int) — 通道号(从 0 开始)value(int) — 有符号 32 位输出值(仅write_ao32)
示例:
io.write_ao32(0, 65536) # 写入 32 位高精度值
ao = io.read_ao32(0) # 读回当前值
按字节与整体访问
read_di_byte() / write_do_byte()
def read_di_byte(self, index: int) -> int
def write_do_byte(self, index: int, value: int) -> bool
按字节索引读数字输入 (0x6000) / 写数字输出 (0x6200)。
参数:
index(int) — 字节索引(即 SDO 子索引,从 1 开始)value(int) — 8 位输出值(仅write_do_byte)
read_all_di() / write_all_do()
def read_all_di(self) -> Optional[bytes]
def write_all_do(self, data: bytes) -> bool
完整访问(complete access)一次读写全部数字输入/输出字节。
参数:
data(bytes) — 全部数字输出数据字节(仅write_all_do)
返回值:
read_all_di→Optional[bytes]— 全部输入数据,失败返回Nonewrite_all_do→bool— SDO 写入是否成功
模拟输入中断与限值
read_global_interrupt_enable() / write_global_interrupt_enable()
def read_global_interrupt_enable(self) -> bool
def write_global_interrupt_enable(self, enable: bool) -> bool
读取或设置模拟输入全局中断使能 (0x6423)。
参数:
enable(bool) —True= 使能,False= 禁用(仅write_global_interrupt_enable)
read_ai_upper_limit() / write_ai_upper_limit()
def read_ai_upper_limit(self, channel: int) -> int
def write_ai_upper_limit(self, channel: int, value: int) -> bool
读取或写入模拟输入中断上限值 (0x6424)。当 AI 值超过上限时触发中断。写入为有符号 16 位,读取自适应 16/32 位。
参数:
channel(int) — 通道号(从 0 开始)value(int) — 有符号 16 位上限值(仅write_ai_upper_limit)
read_ai_lower_limit() / write_ai_lower_limit()
def read_ai_lower_limit(self, channel: int) -> int
def write_ai_lower_limit(self, channel: int, value: int) -> bool
读取或写入模拟输入中断下限值 (0x6425)。当 AI 值低于下限时触发中断。写入为有符号 16 位,读取自适应 16/32 位。
参数:
channel(int) — 通道号(从 0 开始)value(int) — 有符号 16 位下限值(仅write_ai_lower_limit)
示例:
io = slave.cia401
# 启用全局中断
io.write_global_interrupt_enable(True)
# 设置通道 0 的上下限
io.write_ai_upper_limit(0, 30000)
io.write_ai_lower_limit(0, 1000)
# 读取当前限值配置
upper = io.read_ai_upper_limit(0)
lower = io.read_ai_lower_limit(0)
enabled = io.read_global_interrupt_enable()
数字输入配置
set_di_polarity() / get_di_polarity()
def set_di_polarity(self, group: int, polarity: int) -> bool
def get_di_polarity(self, group: int) -> int
设置或读取数字输入极性 (0x6002)。可按位反转输入信号逻辑。
参数:
group(int) — 组号(即 SDO 子索引,从 1 开始)polarity(int) — 8 位极性掩码,每位对应一个通道,1=反转(仅set_di_polarity)
set_di_filter() / get_di_filter()
def set_di_filter(self, group: int, filter_enable: int) -> bool
def get_di_filter(self, group: int) -> int
设置或读取数字输入滤波使能 (0x6003)。用于消除输入信号抖动。
参数:
group(int) — 组号(即 SDO 子索引,从 1 开始)filter_enable(int) — 8 位滤波使能掩码(仅set_di_filter)
虚拟 DI
write_virtual_di()
def write_virtual_di(self, di_index: int, state: bool) -> bool
写入虚拟 DI 命令 (0x2120:0x)。0x2120 是 PdoMapped 对象,SDO 写会被 abort 0x06020000,方法内部自动回退 PDO 写入并记日志(首次 abort 后缓存判定,后续直接走 PDO)。
参数:
di_index(int) — 虚拟 DI 子索引(1-4 → 0x2120:01-04)state(bool) — 目标状态(True= 1)
返回值:
bool—True= 写入成功(SDO 或 PDO);False= SDO 与 PDO 均失败(当前无 0x2120 的 PDO 映射)
错误状态读取
get_do_error_mode() / get_do_error_value()
def get_do_error_mode(self, group: int) -> int
def get_do_error_value(self, group: int) -> int
读取数字输出错误模式和错误安全值的当前配置。group 从 0 开始(每 8 个通道一组)。get_do_error_mode() 返回整数 (0=HOLD / 1=SAFE_VALUE)。
错误处理
set_do_error_mode()
def set_do_error_mode(self, group: int, mode: int) -> bool
设置数字输出错误模式。当 EtherCAT 通信丢失时,决定输出如何响应。
参数:
group(int) — 组号(从 0 开始,每 8 个通道为一组:组 0 = 通道 0-7,组 1 = 通道 8-15)mode(int) — 错误模式 (传CiA401ErrorMode.HOLD/CiA401ErrorMode.SAFE_VALUE, 即整数0/1)
CiA401ErrorMode 常量类:
CiA401ErrorMode 是普通常量类 (非 IntEnum), 成员即整数常量。
from darra_ethercat import CiA401ErrorMode
class CiA401ErrorMode:
HOLD = 0 # 保持当前输出值
SAFE_VALUE = 1 # 切换到预设的安全值
set_do_error_mode() / set_ao_error_mode() 的 mode 参数与 get_do_error_mode() / get_ao_error_mode() 的返回值类型均为 int。传入 CiA401ErrorMode.SAFE_VALUE 即整数 1, 读回的也是整数 0 / 1, 与该常量类的成员值直接比较即可。
set_do_error_value()
def set_do_error_value(self, group: int, value: int) -> bool
设置数字输出通信丢失时的安全值。仅在 SAFE_VALUE 模式下生效。
参数:
group(int) — 组号(从 0 开始)value(int) — 安全输出值(8 位,每位对应一个通道)
set_ao_error_mode()
def set_ao_error_mode(self, channel: int, mode: int) -> bool
设置模拟输出错误模式。
参数:
channel(int) — 通道号(从 0 开始)mode(int) — 错误模式 (传CiA401ErrorMode.HOLD/CiA401ErrorMode.SAFE_VALUE, 即整数0/1)
set_ao_error_value()
def set_ao_error_value(self, channel: int, value: int) -> bool
设置模拟输出通信丢失时的安全值。仅在 SAFE_VALUE 模式下生效。
参数:
channel(int) — 通道号(从 0 开始)value(int) — 有符号 16 位安全输出值
get_ao_error_mode() / get_ao_error_value()
def get_ao_error_mode(self, channel: int) -> int
def get_ao_error_value(self, channel: int) -> int
读取模拟输出错误模式和错误安全值的当前配置。get_ao_error_mode() 返回整数 (0=HOLD / 1=SAFE_VALUE),get_ao_error_value() 返回有符号 16 位安全值。
示例:
io.set_do_error_mode(0, CiA401ErrorMode.SAFE_VALUE)
io.set_do_error_value(0, 0x00)
io.set_ao_error_mode(0, CiA401ErrorMode.SAFE_VALUE)
io.set_ao_error_value(0, 0)
标准对象索引常量
下列常量是 CiA401 类的类属性 (经 CiA401.OD_DI 等访问), 可搭配 slave.coe.sdo_read / sdo_write 直接访问对象字典。表中「读写」指该对象经 SDO 访问的能力:
| 类别 | 常量 | 值 | 读写 | 说明 |
|---|---|---|---|---|
| 数字输入 | OD_DI | 0x6000 | 只读 | 数字输入 |
| 虚拟 DI | OD_VIRTUAL_DI | 0x2120 | 只写 | 虚拟 DI 命令 (PdoMapped; SDO 写 abort 0x06020000, 须走 PDO) |
| 数字输入 | OD_DI_16BIT | 0x6001 | 只读 | 16 位数字输入 |
| 数字输入 | OD_DI_POLARITY | 0x6002 | 读写 | 数字输入极性 |
| 数字输入 | OD_DI_FILTER | 0x6003 | 读写 | 数字输入滤波使能 |
| 数字输入 | OD_DI_32BIT | 0x6020 | 只读 | 32 位数字输入 |
| 数字输出 | OD_DO | 0x6200 | 读写 | 数字输出 |
| 数字输出 | OD_DO_16BIT | 0x6201 | 读写 | 16 位数字输出 |
| 数字输出 | OD_DO_ERROR_MODE | 0x6206 | 读写 | 数字输出错误模式 |
| 数字输出 | OD_DO_ERROR_VALUE | 0x6207 | 读写 | 数字输出错误值 |
| 数字输出 | OD_DO_32BIT | 0x6220 | 读写 | 32 位数字输出 |
| 模拟输入 | OD_AI | 0x6400 | 只读 | 模拟输入 |
| 模拟输入 | OD_AI_SI_UNIT | 0x6420 | 只读 | 模拟输入量程 |
| 模拟输入 | OD_AI_GLOBAL_INTERRUPT | 0x6423 | 读写 | 模拟输入全局中断使能 |
| 模拟输入 | OD_AI_UPPER_LIMIT | 0x6424 | 读写 | 模拟输入中断上限 |
| 模拟输入 | OD_AI_LOWER_LIMIT | 0x6425 | 读写 | 模拟输入中断下限 |
| 模拟输出 | OD_AO | 0x6411 | 读写 | 模拟输出 |
| 模拟输出 | OD_AO_32BIT | 0x6412 | 读写 | 32 位模拟输出 |
| 模拟输出 | OD_AO_SI_UNIT | 0x6430 | 只读 | 模拟输出量程 |
| 模拟输出 | OD_AO_ERROR_MODE | 0x6443 | 读写 | 模拟输出错误模式 |
| 模拟输出 | OD_AO_ERROR_VALUE | 0x6444 | 读写 | 模拟输出错误值 |
完整示例
from darra_ethercat import CiA401ErrorMode
io = slave.cia401
# 数字 IO
sensor = io.read_di(0)
limit = io.read_di(5)
io.write_do(0, True)
io.write_do(1, sensor)
# 批量数字 IO
di16 = io.read_di16(1) # 读取组 1 (16 个通道)
io.write_do16(1, 0x00FF) # 组 1: 低 8 位输出高
# 模拟 IO
adc = io.read_ai(0)
temp = adc * 0.1
io.write_ao(0, 0 if temp > 50 else 16384)
# 无符号读取
ai_u16 = io.read_ai_raw(0)
ai_u32 = io.read_ai32(0)
# 模拟输入限值配置
io.write_global_interrupt_enable(True)
io.write_ai_upper_limit(0, 30000)
io.write_ai_lower_limit(0, 1000)
# 安全配置
io.set_do_error_mode(0, CiA401ErrorMode.SAFE_VALUE)
io.set_do_error_value(0, 0x00)
io.set_ao_error_mode(0, CiA401ErrorMode.SAFE_VALUE)
io.set_ao_error_value(0, 0)