c# SerialPort RS485 modbusRTU 直接通信

关键词:SerialPort,RS485,ModbusRTU,delegate(委托),BeginInvoke,

本文使用VS2015,.net版本是4--因为考虑要在XP生产用机器上使用。

最初,公司需要做RS485的IAP程序用来给设备升级(原来有相关升级程序,是使用USB口的串口直接IAP代码,那个例程我也看过,比modbusRTU的要简单的很多,当然,我没测试过,只是简单看了一下,感觉比用modbusRTU逻辑上一样,但代码要少的多),但是原来的代码时第三方做的,在时间和可控性上有点延误,于是决定我们自己搞一个。于是有了下文。

本文是RS485的modbusRTU基本通信,IAP升级相关的会在以后更新。

c#我不熟啊,可以说基本不会,于是我开始了网上搜索过程,从CSDN下载了几个代码(花了不少),然后分析了一顿代码,对IAP和串口升级代码都有了一定理解,而一直没找到相关可用的RS485 modbusRTU IAP代码,modbusRTU用了有一段时间了,那就干脆用c#来搞一下RS485通信吧。

用以上找到的代码看了一下,都是使用NModbus,NModbus4,NModbus.Serial来搞,而这个程序包在使用上基本都是从站地址,指令,数据,CRC这样的组合方式,在基本的modbusRTU来说足够用了,但是如果用一些基于RS485的特殊指令就有点困难了(也许我没查到相关方法),于是决定直接用SerialPort来写。

代码上用了很多其他人写的函数方法,毕竟通用性强,而且我懒,还有何必重复造。

整体思路:

打开程序,自动扫描设备,并按照默认参数设置相关参数,点击“打开串口”按钮直接按默认参数打开连接,

 设置参数:添加菜单,可以设置串口参数,并在关闭窗口的时候把参数传回Form1的相关参数,

 打开串口后,点击“发送”按钮,可以发送文本框中的指令(为什么用文本字符串?因为很多指令都是现成的,我就是想直接发送,而不要再拆分到NModbus的参数中,这样不香吗,我认为很香,而且这样的限制几乎没有,我们有很多自定义的指令可以使用,如果限定在那写modbusRTU指令中,特殊指令就没法操作了),从机方面收到相关指令就会返回相应数据。

以上是主要流程,再来补充一下细节:

1,指令的HEX转码,因为指令是ASCII码文本,需要转换为HEX字节集才能正常发送到从机并被正确理解和返回数据,直接上代码,拿去用

        //转换成HEX格式数据,即16进制数据
        public byte[] HexStringToBytes(string hs)
        {

            string[] strArr = hs.Trim().Split(' ');
            byte[] b = new byte[strArr.Length];
            if (!sending) { return b; }
            //逐个字符变为16进制字节数据
            for (int i = 0; i < strArr.Length; i++)
            {
                b[i] = Convert.ToByte(strArr[i], 16);
            }
            //按照指定编码将字节数组变为字符串
            comlength = strArr.Length;
            return b;
        }

2,SerialPort的码率,必须和从机一致,在本机使用虚拟串口可以不用限制,我的本机测试是这样。

3,异步收到数据的处理,

声明委托和串口参数:

public delegate void MyDelegate(string s);
public string portName;//连接参数,串口名
public int baudRate;//连接参数,波特率
public Parity parity;//连接参数,奇偶校验
public int dataBits;//连接参数,数据位
public StopBits stopBits;//连接参数,停止位

 可以看到,parity和stopBits是专用类型,需要处理,其他几个参数直接使用即可。

设置串口:

switch (f2parity)//奇偶校验索引
{
    case 0:
        parity = Parity.Odd;
        break;
    case 1:
        parity = Parity.Even;
        break;
    case 2:
        parity = Parity.None;
        break;
    default:
        break;
}
// dataBits  数据位  已经赋值,Form2返回也会赋值
switch (f2stopBits)//停止位
{
    case 0:
        stopBits = StopBits.One;
        break;
    case 1:
        stopBits = StopBits.Two;
        break;
    default:
        break;
}
comport = new SerialPort(portName, baudRate, parity, dataBits, stopBits);
//收到返回数据的事件处理绑定函数
comport.DataReceived += new SerialDataReceivedEventHandler(DataReceived_Simplea);

发送数据:

comport.Open(); 
comport.Write(HexStringToBytes(textBox1.Text), 0, comlength);

comport.Write(HexStringToBytes(textBox1.Text), 0, comlength);

Write三个参数分别是转换位HEX字节集的函数调用返回数据,开始发送的位置,发送长度

 相应串口收到数据事件的代码:

public void DataReceived_Simplea(object sender, SerialDataReceivedEventArgs e)
{
    MyDelegate mydele1 = new MyDelegate(xianshitextbox2);
    MyDelegate mydele2 = new MyDelegate(xianshitextbox3);
    shoudaocishu ++;
    textBox3.BeginInvoke(mydele2, shoudaocishu.ToString());
    DateTime dt = DateTime.Now;
    //16进制发送数据还原
    int i_InNum;//输入缓冲区中字节数
    i_InNum = comport.BytesToRead;
    Byte[] ReceivedData = new Byte[comport.BytesToRead];//创建接收字节数组
    comport.Read(ReceivedData, 0, ReceivedData.Length);//读取接收的数据
    String RecvDataText = null;
    for (int i = 0; i < ReceivedData.Length; i++)
    {
        RecvDataText += (ReceivedData[i].ToString("X2") + "");
    }
    textBox3.BeginInvoke(mydele1, RecvDataText);//使用delegate委托更新textbox2
    //丢弃接收缓冲区数据
    comport.DiscardInBuffer();
}

委托函数:

public void xianshitextbox2(string s)
{
    textBox2.Text += s + "\r\n";
}
public void xianshitextbox3(string s)
{
    textBox3.Text = s;
}

如果在设置textBox.text的时候直接使用textBox.text = 数据 会报线程安全错误,所以需要做以上代码中的处理:

声明委托,然后实例化委托,然后给相关控件执行BeginInvoke(不推荐用Invoke,会造成阻塞),

途中是和从机通信返回的数据,数据正确不用较真,只是模拟数据。

题外话:再来说说从机的使用----

 还是另起一个文章说说我的从机使用吧。

  • 10
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
MODBUS是一种通信协议,用于在工业自动化系统中连接电子设备。MODBUS RTUMODBUS协议的一种变体,它使用二进制编码,可以通过串行通信进行传输。在C#中实现MODBUS RTU通信需要使用串口通信库和MODBUS库。以下是实现MODBUS RTU通信的一些步骤: 1. 首先,需要在C#项目中添加System.IO.Ports命名空间,以便使用串口通信库。 2. 然后,需要使用MODBUS库,例如NModbus库,可以通过NuGet包管理器安装。 3. 接下来,需要创建一个SerialPort对象,设置串口参数,例如波特率、数据位、停止位和奇偶校验等。 4. 然后,需要创建一个ModbusMaster对象,用于发送和接收MODBUS RTU消息。可以使用ModbusFactory类创建ModbusMaster对象。 5. 然后,可以使用ModbusMaster对象的ReadCoils、ReadInputs、ReadHoldingRegisters和ReadInputRegisters等方法读取MODBUS设备的状态和寄存器值。 6. 最后,需要关闭串口和释放ModbusMaster对象。 以下是一个简单的示例代码,用于读取MODBUS设备的保持寄存器值: ```csharp using System; using System.IO.Ports; using Modbus.Device; namespace ModbusRtuExample { class Program { static void Main(string[] args) { // 创建SerialPort对象 SerialPort port = new SerialPort("COM1", 9600, Parity.None, 8, StopBits.One); port.Open(); // 创建ModbusMaster对象 IModbusMaster master = ModbusSerialMaster.CreateRtu(port); // 读取保持寄存器值 ushort[] values = master.ReadHoldingRegisters(1, 0, 10); // 输出结果 foreach (ushort value in values) { Console.WriteLine(value); } // 关闭串口和ModbusMaster对象 port.Close(); master.Dispose(); } } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值