C#有人IO模块USR-IO808的完整指南
·
C#有人IO模块USR-IO808的完整指南
概述
有人USR-IO808是一款8通道数字输入输出模块,支持Modbus RTU协议,通过RS485接口进行通信。本文将介绍如何使用C#语言通过串口操作该模块,实现数字输入(DI)状态的读取和数字输出(DO)的控制。
硬件连接与配置
在开始编程前,请确保:
-
USR-IO808模块已正确供电
-
RS485接口与计算机正确连接(通常通过USB转485转换器)
-
模块的波特率、数据位、停止位和校验位与软件设置一致
-
模块地址已正确设置(默认为0x11)
核心代码解析
1. 数据包构建类(DataPacketIO808)
public class DataPacketIO808
{
// 模块默认地址
public const byte AddressDefault = 0x11;
// 功能码定义
public enum EfunctionNum
{
read0x02 = 0x02, // 读取DI状态
read0x01 = 0x01, // 读取DO状态
read0x05 = 0x05, // 控制DO状态
}
// 控制状态定义
public enum EcontrolStatus
{
open = 0xFF00, // 开启DO
close = 0x0000, // 关闭DO
}
// DI/DO寄存器地址定义
public enum EDIDOAddress
{
DI1 = 0x0020, DI2 = 0x0021, DI3 = 0x0022, DI4 = 0x0023,
DI5 = 0x0024, DI6 = 0x0025, DI7 = 0x0026, DI8 = 0x0027,
DO1 = 0x0000, DO2 = 0x0001, DO3 = 0x0002, DO4 = 0x0003,
DO5 = 0x0004, DO6 = 0x0005, DO7 = 0x0006, DO8 = 0x0007,
}
// 构建读取DI状态的数据包
public static DataPacketIO808 GetDIStatus(byte address)
{
return BuildReadParam(address, EfunctionNum.read0x02, EDIDOAddress.DI1, 8);
}
// 构建读取DO状态的数据包
public static DataPacketIO808 GetDOStatus(byte address)
{
return BuildReadParam(address, EfunctionNum.read0x01, EDIDOAddress.DO1, 8);
}
// 构建开启DO的数据包
public static DataPacketIO808 OpenDO(byte address, ushort DONum)
{
return BuildControlParam(address, EfunctionNum.read0x05, DONum, EcontrolStatus.open);
}
// 构建关闭DO的数据包
public static DataPacketIO808 CloseDO(byte address, ushort DONum)
{
return BuildControlParam(address, EfunctionNum.read0x05, DONum, EcontrolStatus.close);
}
// 将数据包转换为字节数组
public byte[] ToBytes()
{
lock (Locker)
{
List<byte> bts = new List<byte>
{
Serialaddress,
functionNum,
};
// 添加地址数据(大端模式)
byte[] startArr = BitConverter.GetBytes(startAddress);
Array.Reverse(startArr, 0, startArr.Length);
bts.AddRange(startArr);
// 添加参数数据(大端模式)
byte[] controlsta = BitConverter.GetBytes(param);
Array.Reverse(controlsta, 0, controlsta.Length);
bts.AddRange(controlsta);
// 计算并添加CRC校验
byte[] checkList = CalcChecksum(bts);
bts.AddRange(checkList);
return bts.ToArray();
}
}
// CRC校验计算
public byte[] CalcChecksum(List<byte> content)
{
UInt16 wCrc = 0xFFFF;
for (int i = 0; i < content.Count; i++)
{
wCrc ^= Convert.ToUInt16(content[i]);
for (int j = 0; j < 8; j++)
{
if ((wCrc & 0x0001) == 1)
{
wCrc >>= 1;
wCrc ^= 0xA001;
}
else
{
wCrc >>= 1;
}
}
}
byte[] arr = BitConverter.GetBytes((ushort)wCrc);
return arr;
}
}
2. 数据解析类(DataParseIO808)
public class DataParseIO808
{
// 解析返回数据
public static bool parseData(byte[] param, byte address, byte funNo)
{
if (param[0] == address && param[1] == funNo)
{
bool crcStatus = CRC_Check(param);
if (crcStatus)
{
return true;
}
}
return false;
}
// CRC校验检查
public static bool CRC_Check(byte[] byteData)
{
bool Flag = false;
byte[] CRC = new byte[2];
UInt16 wCrc = 0xFFFF;
for (int i = 0; i < byteData.Length - 2; i++)
{
wCrc ^= Convert.ToUInt16(byteData[i]);
for (int j = 0; j < 8; j++)
{
if ((wCrc & 0x0001) == 1)
{
wCrc >>= 1;
wCrc ^= 0xA001;
}
else
{
wCrc >>= 1;
}
}
}
CRC[1] = (byte)((wCrc & 0xFF00) >> 8);
CRC[0] = (byte)(wCrc & 0x00FF);
if (CRC[1] == byteData[byteData.Length - 1] && CRC[0] == byteData[byteData.Length - 2])
{
Flag = true;
}
return Flag;
}
}
3. 应用层方法
// 获取所有DI状态
public void GetALLDIStatus(out bool oneStatus, out bool twoStatus, out bool threeStatus,
out bool fourStatus, out bool fiveStatus, out bool sixStatus,
out bool sevenStatus, out bool eightStatus)
{
oneStatus = twoStatus = threeStatus = fourStatus =
fiveStatus = sixStatus = sevenStatus = eightStatus = false;
try
{
oneStatus = GetDIStatus(1);
twoStatus = GetDIStatus(2);
threeStatus = GetDIStatus(3);
fourStatus = GetDIStatus(4);
fiveStatus = GetDIStatus(5);
sixStatus = GetDIStatus(6);
sevenStatus = GetDIStatus(7);
eightStatus = GetDIStatus(8);
}
catch (Exception ex)
{
// 异常处理
Console.WriteLine("获取DI状态时发生错误: " + ex.Message);
}
}
// 获取所有DO状态
public void GetALLDOStatus(out bool oneStatus, out bool twoStatus, out bool threeStatus,
out bool fourStatus, out bool fiveStatus, out bool sixStatus,
out bool sevenStatus, out bool eightStatus)
{
oneStatus = twoStatus = threeStatus = fourStatus =
fiveStatus = sixStatus = sevenStatus = eightStatus = false;
try
{
oneStatus = GetDOStatus(1);
twoStatus = GetDOStatus(2);
threeStatus = GetDOStatus(3);
fourStatus = GetDOStatus(4);
fiveStatus = GetDOStatus(5);
sixStatus = GetDOStatus(6);
sevenStatus = GetDOStatus(7);
eightStatus = GetDOStatus(8);
}
catch (Exception ex)
{
// 异常处理
Console.WriteLine("获取DO状态时发生错误: " + ex.Message);
}
}
完整使用示例
// 创建串口对象
SerialPort serialPort = new SerialPort("COM3", 9600, Parity.None, 8, StopBits.One);
serialPort.Open();
// 读取所有DI状态
bool di1, di2, di3, di4, di5, di6, di7, di8;
GetALLDIStatus(out di1, out di2, out di3, out di4, out di5, out di6, out di7, out di8);
Console.WriteLine("DI状态:");
Console.WriteLine($"DI1: {di1}, DI2: {di2}, DI3: {di3}, DI4: {di4}");
Console.WriteLine($"DI5: {di5}, DI6: {di6}, DI7: {di7}, DI8: {di8}");
// 控制DO1开启
DataPacketIO808 openPacket = DataPacketIO808.OpenDO(0x11, 1);
byte[] openData = openPacket.ToBytes();
serialPort.Write(openData, 0, openData.Length);
// 等待并读取响应
Thread.Sleep(100);
byte[] response = new byte[serialPort.BytesToRead];
serialPort.Read(response, 0, response.Length);
// 验证响应
bool success = DataParseIO808.parseData(response, 0x11, 0x05);
if (success)
{
Console.WriteLine("DO1开启成功");
}
// 关闭串口
serialPort.Close();
注意事项
-
线程安全:使用lock确保在多线程环境下串口操作的线程安全
-
异常处理:妥善处理可能出现的串口通信异常
-
超时设置:合理设置读取超时,避免程序无响应
-
CRC校验:务必验证CRC确保数据完整性
-
地址匹配:确保程序中使用的模块地址与实际硬件设置一致
常见问题排查
-
通信失败:检查硬件连接、串口参数和模块地址
-
CRC校验错误:检查数据传输过程中是否受到干扰
-
无响应:检查模块供电和通信线路
总结
通过上述C#代码,我们可以方便地操作有人USR-IO808模块,实现数字输入状态的读取和数字输出状态的控制。代码采用了面向对象的设计,提供了良好的封装性和可扩展性,可以根据实际需求进一步扩展功能。
希望本文对您使用USR-IO808模块有所帮助!
更多推荐
所有评论(0)