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, // 开启DOclose = 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模块有所帮助!