CiA 401 — 通用 I/O 模块
CiA 401 (IEC 61131-9) 是基于 CoE 的通用数字/模拟 I/O 设备协议。
CiA 401 运行在 CoE (SDO) 之上,仅当从站支持 CoE 时可用。
通过 slave.cia401() 访问。
IO 属性
通过方法直接读写 IO 通道,所有通道号从 0 开始。
| 方法 | 读写 | 类型 | 说明 |
|---|---|---|---|
| read_di(n) | 只读 | bool | 数字输入通道 n |
| write_do(n, v) | 写入 | Result<()> | 数字输出通道 n |
| read_ai(n) | 只读 | i32 | 模拟输入通道 n |
| write_ao(n, v) | 写入 | Result<()> | 模拟输出通道 n |
示例:
let io = slave.cia401();
// 数字 IO
let sensor: bool = io.read_di(0);
io.write_do(0, true)?;
io.write_do(1, sensor)?;
// 模拟 IO
let adc: i32 = io.read_ai(0);
io.write_ao(0, 16384)?;
高频率 I/O 控制应使用 PDO 映射 而非 SDO。SDO 适合参数配置和诊断。
方法 API
read_di()
pub fn read_di(&self, channel: i32) -> bool
读取数字输入。内部按 8 通道一组自动计算组号和位偏移。
参数:
channel— 通道号(从 0 开始)
返回值:
bool— 通道状态(true = 高电平),读取失败时返回 false
write_do()
pub fn write_do(&self, channel: i32, state: bool) -> Result<()>
设置数字输出,不影响同组其他通道。内部使用读-改-写操作。
参数:
channel— 通道号(从 0 开始)state— 目标状态
read_ai()
pub fn read_ai(&self, channel: i32) -> i32
读取模拟输入值。自动适应 16 位和 32 位设备。
参数:
channel— 通道号(从 0 开始)
read_ai_unsigned()
pub fn read_ai_unsigned(&self, channel: i32) -> u16
读取 16 位无符号模拟输入值。与 read_ai() 不同, 将数据解释为无符号值, 适合单极性 ADC。
参数:
channel— 通道号 (从 0 开始)
read_ai32_unsigned()
pub fn read_ai32_unsigned(&self, channel: i32) -> u32
读取 32 位无符号模拟输入值, 适合高精度 ADC (如 24-bit / 32-bit 量程的传感器模块)。
参数:
channel— 通道号 (从 0 开始)
write_ao()
pub fn write_ao(&self, channel: i32, value: i16) -> Result<()>
写入模拟输出值。
参数:
channel— 通道号(从 0 开始)value— 16 位输出值
批量 IO 方法
除逐通道操作外,还支持 16/32 位批量读写,一次操作多个通道。
数字输入批量读取
read_di16()
pub fn read_di16(&self, group: i32) -> u16
读取 16 位数字输入(16 个通道)。
参数:
group— 组号(子索引,从 1 开始,每 16 个通道为一组)
返回值:
u16— 16 位输入值,每位对应一个通道
read_di32()
pub fn read_di32(&self, group: i32) -> u32
读取 32 位数字输入(32 个通道)。
参数:
group— 组号(子索引,从 1 开始,每 32 个通道为一组)
返回值:
u32— 32 位输入值,每位对应一个通道
示例:
let io = slave.cia401();
let di16 = io.read_di16(1); // 读取通道 0-15
let di32 = io.read_di32(1); // 读取通道 0-31
let ch5 = (di16 & (1 << 5)) != 0; // 检查通道 5
数字输出批量读写
read_do16() / write_do16()
pub fn read_do16(&self, group: i32) -> u16
pub fn write_do16(&self, group: i32, value: u16) -> Result<()>
读取或写入 16 位数字输出(16 个通道)。
参数:
group— 组号(子索引,从 1 开始,每 16 个通道为一组)value— 16 位输出值
read_do32() / write_do32()
pub fn read_do32(&self, group: i32) -> u32
pub fn write_do32(&self, group: i32, value: u32) -> Result<()>
读取或写入 32 位数字输出(32 个通道)。
参数:
group— 组号(子索引,从 1 开始,每 32 个通道为一组)value— 32 位输出值
示例:
let io = slave.cia401();
// 16 位批量操作
io.write_do16(1, 0x00FF)?; // 通道 0-7 输出高,8-15 输出低
let do16 = io.read_do16(1); // 读回当前值
// 32 位批量操作
io.write_do32(1, 0x0000FFFF)?; // 通道 0-15 输出高
let do32 = io.read_do32(1); // 读回当前值
模拟输出 32 位
read_ao32() / write_ao32()
pub fn read_ao32(&self, channel: i32) -> i32
pub fn write_ao32(&self, channel: i32, value: i32) -> Result<()>
读取或写入 32 位模拟输出值。适用于高精度模拟输出设备。
参数:
channel— 通道号(从 0 开始)value— 32 位输出值
示例:
let io = slave.cia401();
io.write_ao32(0, 65536)?; // 写入 32 位高精度值
let ao = io.read_ao32(0); // 读回当前值
数字输入配置
set_di_polarity() / di_polarity()
pub fn set_di_polarity(&self, group: i32, polarity: u8) -> Result<()>
pub fn di_polarity(&self, group: i32) -> u8
设置或读取数字输入极性 (0x6002)。可按位反转输入信号逻辑。
参数:
group— 组号(子索引,从 1 开始)polarity— 极性掩码,1 = 反转对应通道
示例:
let io = slave.cia401();
io.set_di_polarity(1, 0x0F)?; // 反转通道 0-3 的极性
let pol = io.di_polarity(1); // 读取当前极性配置
set_di_filter() / di_filter()
pub fn set_di_filter(&self, group: i32, filter_enable: u8) -> Result<()>
pub fn di_filter(&self, group: i32) -> u8
设置或读取数字输入滤波使能 (0x6003)。用于消除输入信号抖动。
参数:
group— 组号(子索引,从 1 开始)filter_enable— 滤波使能掩码
示例:
let io = slave.cia401();
io.set_di_filter(1, 10)?; // 设置滤波使能
let flt = io.di_filter(1); // 读取当前滤波配置
模拟输入配置
global_interrupt_enable() / set_global_interrupt_enable()
pub fn global_interrupt_enable(&self) -> bool
pub fn set_global_interrupt_enable(&self, enabled: bool) -> Result<()>
读取或设置模拟输入全局中断使能 (0x6423)。
ai_upper_limit() / set_ai_upper_limit()
pub fn ai_upper_limit(&self, channel: i32) -> i32
pub fn set_ai_upper_limit(&self, channel: i32, value: i16) -> Result<()>
读取或设置模拟输入中断上限 (0x6424)。
参数:
channel— 通道号(从 0 开始)value— 上限值
ai_lower_limit() / set_ai_lower_limit()
pub fn ai_lower_limit(&self, channel: i32) -> i32
pub fn set_ai_lower_limit(&self, channel: i32, value: i16) -> Result<()>
读取或设置模拟输入中断下限 (0x6425)。
参数:
channel— 通道号(从 0 开始)value— 下限值
错误状态读取
do_error_mode() / do_error_value()
pub fn do_error_mode(&self, group: i32) -> CiA401ErrorMode
pub fn do_error_value(&self, group: i32) -> u8
读取数字输出错误模式和错误安全值的当前配置。
参数:
group— 组号(从 0 开始)
示例:
let io = slave.cia401();
let mode = io.do_error_mode(0);
let safe_val = io.do_error_value(0);
println!("错误模式: {:?}, 安全值: 0x{:02X}", mode, safe_val);
get_ao_error_mode() / get_ao_error_value()
pub fn get_ao_error_mode(&self, channel: i32) -> CiA401ErrorMode
pub fn get_ao_error_value(&self, channel: i32) -> i16
读取模拟输出错误模式和错误安全值的当前配置。
参数:
channel— 通道号(从 0 开始)
错误处理
set_do_error_mode()
pub fn set_do_error_mode(&self, group: i32, mode: CiA401ErrorMode) -> Result<()>
设置数字输出错误模式。当 EtherCAT 通信丢失时,决定输出如何响应。
参数:
group— 组号(从 0 开始,每 8 个通道为一组:组 0 = 通道 0-7,组 1 = 通道 8-15)mode— 错误模式
相关结构:
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CiA401ErrorMode {
Hold = 0, // 保持当前输出值
SafeValue = 1, // 切换到预设的安全值
}
set_do_error_value()
pub fn set_do_error_value(&self, group: i32, value: u8) -> Result<()>
设置数字输出通信丢失时的安全值。仅在 SafeValue 模式下生效。
参数:
group— 组号(从 0 开始)value— 安全输出值(8 位,每位对应一个通道)
set_ao_error_mode()
pub fn set_ao_error_mode(&self, channel: i32, mode: CiA401ErrorMode) -> Result<()>
设置模拟输出错误模式。
参数:
channel— 通道号(从 0 开始)mode— 错误模式
set_ao_error_value()
pub fn set_ao_error_value(&self, channel: i32, value: i16) -> Result<()>
设置模拟输出通信丢失时的安全值。仅在 SafeValue 模式下生效。
参数:
channel— 通道号(从 0 开始)value— 16 位安全输出值
示例:
io.set_do_error_mode(0, CiA401ErrorMode::SafeValue)?;
io.set_do_error_value(0, 0x00)?;
io.set_ao_error_mode(0, CiA401ErrorMode::SafeValue)?;
io.set_ao_error_value(0, 0)?;
标准对象索引常量
CiA 401 IO 模块对象字典遵循 ETG.5001 标准索引划分: 数字输入 / 数字输出 /
模拟输入 / 模拟输出各占独立索引区, 子项还覆盖极性、滤波、中断、上下限、错误模式、错误值
等配置。SDK 在 ethercat::cia401 模块下导出 OD_DI / OD_DO / OD_AI / OD_AO 等
强类型常量, 直接搭配 slave.coe().sdo_read() / sdo_write() 使用, 无需手动记忆数字。
use ethercat::cia401 as od;
use ethercat::slave::coe::CoEAccess;
// 通过常量读取数字输入 (单字节通道 0)
let coe = slave.coe().expect("不支持 CoE");
let val: u8 = coe.sdo_read_value(od::OD_DI, 0x01)?;
// 通过常量写入数字输出全局极性
coe.sdo_write_value(od::OD_DO_POLARITY, 0x00, &0u32)?;
slave.cia401() 的关系日常开发推荐 slave.cia401() 高层 API (read_di, write_do, read_ai, ...);
仅在需要批量遍历或读取上述 API 未直接覆盖的子索引时, 才回落到常量 + SDO 方式。
完整示例
use ethercat::CiA401ErrorMode;
let io = slave.cia401();
// 数字 IO
let sensor = io.read_di(0);
let limit = io.read_di(5);
io.write_do(0, true)?;
io.write_do(1, sensor)?;
// 批量数字 IO
let di16 = io.read_di16(1);
io.write_do16(1, 0x00FF)?;
// 数字输入配置
io.set_di_polarity(1, 0x0F)?; // 反转通道 0-3
io.set_di_filter(1, 10)?; // 启用滤波
// 模拟 IO
let adc = io.read_ai(0);
let temp = adc as f64 * 0.1;
io.write_ao(0, if temp > 50.0 { 0 } else { 16384 })?;
// 32 位模拟输出
io.write_ao32(0, 65536)?;
// 错误状态读取
let mode = io.do_error_mode(0);
let safe_val = io.do_error_value(0);
println!("错误模式: {:?}, 安全值: 0x{:02X}", mode, safe_val);
// 安全配置
io.set_do_error_mode(0, CiA401ErrorMode::SafeValue)?;
io.set_do_error_value(0, 0x00)?;
io.set_ao_error_mode(0, CiA401ErrorMode::SafeValue)?;
io.set_ao_error_value(0, 0)?;