跳到主要内容

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)?;