CiA 401 — 通用 I/O 模块
CiA 401 (IEC 61131-9) 是基于 CoE 的通用数字/模拟 I/O 设备协议。
CiA 401 运行在 CoE (SDO) 之上,仅当从站支持 CoE 时可用。
通过 CiA401(coe) 创建实例,传入 CoE& 引用。使用 coe.IsCiA401() 检查从站是否为 CiA 401 设备。
快速开始
auto& coe = master.GetSlave(1).GetCoE();
if (coe.IsCiA401()) {
CiA401 io(coe);
// 数字 IO
bool sensor = io.ReadDI(0);
io.WriteDO(0, true);
io.WriteDO(1, sensor);
// 模拟 IO
int32_t adc = io.ReadAI(0);
io.WriteAO(0, 16384);
}
实时控制
高频率 I/O 控制应使用 PDO 映射 而非 SDO。SDO 适合参数配置和诊断。
数字输入
ReadDI()
bool ReadDI(int channel) const;
读取数字输入。内部按 8 通道一组自动计算组号和位偏移。
参数:
channel(int) — 通道号(从 0 开始)
返回值:
bool— 通道状态(true = 高电平)
ReadDIByte()
uint8_t ReadDIByte(int byteIndex) const;
读取 8 位数字输入组。
参数:
byteIndex(int) — 字节组号(子索引,从 1 开始)
返回值:
uint8_t— 8 位输入值
ReadAllDI()
std::vector<uint8_t> ReadAllDI() const;
读取所有 8 位数字输入组(最多 32 组)。
ReadDI16()
uint16_t ReadDI16(int group) const;
读取 16 位数字输入(16 个通道)。
参数:
group(int) — 组号(从 0 开始,每 16 个通道为一组)
ReadDI32()
uint32_t ReadDI32(int group) const;
读取 32 位数字输入(32 个通道)。
参数:
group(int) — 组号(从 0 开始,每 32 个通道为一组)
示例:
CiA401 io(coe);
// 逐通道读取
bool ch0 = io.ReadDI(0);
bool ch5 = io.ReadDI(5);
// 16/32 位批量读取
uint16_t di16 = io.ReadDI16(0); // 通道 0-15
uint32_t di32 = io.ReadDI32(0); // 通道 0-31
bool ch5_alt = (di16 & (1 << 5)) != 0;
数字输出
WriteDO()
bool WriteDO(int channel, bool value) const;
设置数字输出,不影响同组其他通道(内部使用读-改-写)。
参数:
channel(int) — 通道号(从 0 开始)value(bool) — 目标状态
返回值:
bool— 是否成功
WriteDOByte()
bool WriteDOByte(int byteIndex, uint8_t value) const;
写入 8 位数字输出组。
参数:
byteIndex(int) — 字节组号(子索引,从 1 开始)value(uint8_t) — 8 位输出值
WriteAllDO()
bool WriteAllDO(const std::vector<uint8_t>& data) const;
写入所有数字输出组。
ReadDO16() / WriteDO16()
uint16_t ReadDO16(int group) const;
bool WriteDO16(int group, uint16_t value) const;
读取或写入 16 位数字输出(16 个通道)。
ReadDO32() / WriteDO32()
uint32_t ReadDO32(int group) const;
bool WriteDO32(int group, uint32_t value) const;
读取或写入 32 位数字输出(32 个通道)。
示例:
CiA401 io(coe);
// 逐通道操作
io.WriteDO(0, true);
io.WriteDO(1, false);
// 16 位批量操作
io.WriteDO16(0, 0x00FF); // 通道 0-7 输出高,8-15 输出低
uint16_t do16 = io.ReadDO16(0); // 读回当前值
// 32 位批量操作
io.WriteDO32(0, 0x0000FFFF); // 通道 0-15 输出高
uint32_t do32 = io.ReadDO32(0); // 读回当前值
模拟输入
ReadAI()
int32_t ReadAI(int channel) const;
读取模拟输入值。自动适应 16 位和 32 位设备。
参数:
channel(int) — 通道号(从 0 开始)
返回值:
int32_t— 模拟值(有符号)
ReadAIRaw()
uint16_t ReadAIRaw(int channel) const;
读取模拟输入原始值(无符号 16 位)。
ReadAI32Unsigned()
uint32_t ReadAI32Unsigned(int channel) const;
读取无符号 32 位模拟输入。
示例:
CiA401 io(coe);
int32_t adc = io.ReadAI(0);
double voltage = adc * 10.0 / 32767.0;
printf("电压: %.3f V\n", voltage);
模拟输出
WriteAO()
bool WriteAO(int channel, int16_t value) const;
写入 16 位模拟输出值。
参数:
channel(int) — 通道号(从 0 开始)value(int16_t) — 16 位输出值
WriteAORaw()
bool WriteAORaw(int channel, uint16_t value) const;
写入模拟输出原始值(无符号 16 位)。
ReadAO()
int16_t ReadAO(int channel) const;
读取 16 位模拟输出值。
ReadAO32() / WriteAO32()
int32_t ReadAO32(int channel) const;
bool WriteAO32(int channel, int32_t value) const;
读取或写入 32 位模拟输出值。适用于高精度模拟输出设备。
示例:
CiA401 io(coe);
// 16 位模拟输出
io.WriteAO(0, 16384);
int16_t ao = io.ReadAO(0);
// 32 位模拟输出(高精度设备)
io.WriteAO32(0, 65536);
int32_t ao32 = io.ReadAO32(0);
数字输入配置
GetDIPolarity() / SetDIPolarity()
uint8_t GetDIPolarity(int group) const;
bool SetDIPolarity(int group, uint8_t polarity) const;
读取或设置数字输入极性 (0x6002)。可按位反转输入信号逻辑。
参数:
group(int) — 组号(子索引,从 1 开始)polarity(uint8_t) — 极性掩码,1 = 反转对应通道
示例:
CiA401 io(coe);
io.SetDIPolarity(1, 0x0F); // 反转通道 0-3 的极性
uint8_t pol = io.GetDIPolarity(1); // 读取当前极性配置
GetDIFilter() / SetDIFilter()
uint8_t GetDIFilter(int group) const;
bool SetDIFilter(int group, uint8_t filterEnable) const;
读取或设置数字输入滤波使能 (0x6003)。用于消除输入信号抖动。
参数:
group(int) — 组号(子索引,从 1 开始)filterEnable(uint8_t) — 滤波使能掩码
示例:
CiA401 io(coe);
io.SetDIFilter(1, 10); // 设置滤波使能
uint8_t flt = io.GetDIFilter(1); // 读取当前滤波配置
模拟输入中断与限值
CiA401 io(coe);
// 全局中断使能
bool intEnabled = io.ReadGlobalInterruptEnable();
io.WriteGlobalInterruptEnable(true);
// 中断上限/下限
int32_t upper = io.ReadAIUpperLimit(0);
int32_t lower = io.ReadAILowerLimit(0);
io.WriteAIUpperLimit(0, 30000);
io.WriteAILowerLimit(0, -30000);
错误处理
通信丢失时数字 / 模拟输出的行为由 CiA401ErrorMode 枚举控制:
enum class CiA401ErrorMode : uint8_t {
Hold = 0, // 保持当前输出值
SafeValue = 1 // 切换到预设的安全值
};
数字输出错误模式
CiA401ErrorMode GetDOErrorMode(int group) const;
bool SetDOErrorMode(int group, CiA401ErrorMode mode) const;
uint8_t GetDOErrorValue(int group) const;
bool SetDOErrorValue(int group, uint8_t value) const;
设置数字输出错误模式和安全值。当 EtherCAT 通信丢失时,决定输出如何响应。
参数:
group(int) — 组号(从 0 开始,每 8 个通道为一组:组 0 = 通道 0-7,组 1 = 通道 8-15)mode(CiA401ErrorMode) — 错误模式value(uint8_t) — 安全输出值(8 位,每位对应一个通道)
模拟输出错误模式
CiA401ErrorMode GetAOErrorMode(int channel) const;
bool SetAOErrorMode(int channel, CiA401ErrorMode mode) const;
int16_t GetAOErrorValue(int channel) const;
bool SetAOErrorValue(int channel, int16_t value) const;
设置模拟输出错误模式和安全值。
参数:
channel(int) — 通道号(从 0 开始)mode(CiA401ErrorMode) — 错误模式value(int16_t) — 16 位安全输出值
示例:
CiA401 io(coe);
// 数字输出安全配置
io.SetDOErrorMode(0, CiA401ErrorMode::SafeValue);
io.SetDOErrorValue(0, 0x00); // 通信丢失时全部输出低
// 模拟输出安全配置
io.SetAOErrorMode(0, CiA401ErrorMode::SafeValue);
io.SetAOErrorValue(0, 0); // 通信丢失时输出 0
// 读取当前错误配置
auto mode = io.GetDOErrorMode(0);
uint8_t safeVal = io.GetDOErrorValue(0);
printf("错误模式: %d, 安全值: 0x%02X\n",
static_cast<int>(mode), safeVal);
CiA401Obj 常量
struct CiA401Obj {
// 数字输入
static constexpr uint16_t DI = 0x6000; // 数字输入 (8位组)
static constexpr uint16_t DI_16BIT = 0x6001; // 16位数字输入
static constexpr uint16_t DI_POLARITY = 0x6002; // 数字输入极性
static constexpr uint16_t DI_FILTER = 0x6003; // 数字输入滤波使能
static constexpr uint16_t DI_32BIT = 0x6020; // 32位数字输入
// 数字输出
static constexpr uint16_t DO = 0x6200; // 数字输出 (8位组)
static constexpr uint16_t DO_16BIT = 0x6201; // 16位数字输出
static constexpr uint16_t DO_ERROR_MODE = 0x6206; // 数字输出错误模式
static constexpr uint16_t DO_ERROR_VALUE = 0x6207; // 数字输出错误值
static constexpr uint16_t DO_32BIT = 0x6220; // 32位数字输出
// 模拟输入
static constexpr uint16_t AI = 0x6400; // 模拟输入 (16位)
static constexpr uint16_t AI_GLOBAL_INT = 0x6423; // 模拟输入全局中断使能
static constexpr uint16_t AI_UPPER_LIMIT = 0x6424; // 模拟输入中断上限
static constexpr uint16_t AI_LOWER_LIMIT = 0x6425; // 模拟输入中断下限
// 模拟输出
static constexpr uint16_t AO = 0x6411; // 模拟输出 (16位)
static constexpr uint16_t AO_32BIT = 0x6412; // 32位模拟输出
static constexpr uint16_t AO_ERROR_MODE = 0x6443; // 模拟输出错误模式
static constexpr uint16_t AO_ERROR_VALUE = 0x6444; // 模拟输出错误值
};
完整示例
#include "ethercat.hpp"
using namespace darra;
void cia401_demo(EtherCATMaster& master) {
auto& coe = master.GetSlave(1).GetCoE();
if (!coe.IsCiA401()) {
printf("从站不是 CiA 401 设备\n");
return;
}
CiA401 io(coe);
// 数字 IO
bool sensor = io.ReadDI(0);
bool limit = io.ReadDI(5);
io.WriteDO(0, true);
io.WriteDO(1, sensor);
// 模拟 IO
int32_t adc = io.ReadAI(0);
double temp = adc * 0.1;
io.WriteAO(0, static_cast<int16_t>(temp > 50 ? 0 : 16384));
// 安全配置
io.SetDOErrorMode(0, CiA401ErrorMode::SafeValue);
io.SetDOErrorValue(0, 0x00);
}