modbus串口通讯C#

您所在的位置:网站首页 modbusRTU报文解析 modbus串口通讯C#

modbus串口通讯C#

2024-07-07 01:26| 来源: 网络整理| 查看: 265

简介

公司给的一个小任务,这篇文章进行详细讲解

题目: modbus串口通讯

主要内容如下: 1、实现使用modbus通讯规约的测试软件; 2、具有通信超时功能; 3、分主站从站,并能编辑报文、生成报文等; 4、计算发送报文次数,接收报文次数,失败通信次数; 5、对接收的数据进行解析。

下面图片可以看出具体的内容:

知识点讲解

该小软件使用的知识如下: 1、modbus通信规约; 2、串口通讯; 3、定时器; 4、多线程;

1、modbus通讯规约

modbus是一个工业上常用的通讯协议,一个通讯约定,包括RTU,ASCII,TCP。该软件使用的RTU。

主站设备查询: 查询消肿的功能号告知被选中的设备要执行何种功能。数据段包括了从站设备要执行的功能的任何附加信息。

从站设备回应: 当从站设备正常回应后,在回应数据里也包括这功能号,并直接截取从站设备收集的数据。如果发生错误,功能号将被修改为用于指出回应消息为错误消息。并在数据段包括该描述的错误信息。错误校测域允许主设备确认消息的内容是否可用,是否正确。

下面的图片解释了modbus的规约的组成:

mobus通讯规约是由从机地址+功能号+数据地址+数据+CRC校验。

从机地址:该规约是单主站/多从站,主站轮询向从站请求的方式进行传输数据,并使用从机地址的方式区分从机。

功能号: 某指令是干啥,一目了然。接收方将通过功能号进行相应的执行功能。 下面为常用功能号:

数据地址:意思是数据存储的地址,从该存储的地址的获取数据。

CRC校验:循环冗余校验码,是数据通信领域中最常用的一种查错校验码,其特征是信息字段和校验字段的长度可以任意选定。

对于校验,网上资料很多,这里直接上代码:

#region CRC16 public static byte[] CRC16(byte[] data) { int len = data.Length; if (len > 0) { ushort crc = 0xFFFF; for (int i = 0; i < len; i++) { crc = (ushort)(crc ^ (data[i])); for (int j = 0; j < 8; j++) { crc = (crc & 1) != 0 ? (ushort)((crc >> 1) ^ 0xA001) : (ushort)(crc >> 1); } } byte hi = (byte)((crc & 0xFF00) >> 8); //高位置 byte lo = (byte)(crc & 0x00FF); //低位置 return new byte[] { hi, lo }; } return new byte[] { 0, 0 }; } #endregion 串口通讯

在C#中实现串口通讯,由于C#微软封装的很好,提供了SerialPort类,命名空间为system.IO.Ports.

下面解释serialPort类编程中常用到的关键字和方法:

常用字段: PortName 获取或设置通信端口 BaudRate 获取或设置串行波特率 DataBits 获取或设置每个字节的标准数据位长度 Parity 获取或设置奇偶校验检查协议 StopBits 获取或设置每个字节的标准停止位数

常用方法: Close 关闭端口连接,将IsOpen 属性设置为false,并释放内部 Stream 对象 GetPortNames 获取当前计算机的串行端口名称数组 Open 打开一个新的串行端口连接 Read 从 SerialPort 输入缓冲区中读取 Write 将数据写入串行端口输出缓冲区

串口通信简介

串口是一种可以接受来自CPU的并行数据字符转换为连续的的串行数据流发送出去,同时可将接受的串行数据流转换为并行的数据字符供给CPU的器件,也就是说硬件称为串行接口电路。

串口通讯重要的参数有波特率,数据位,停止位,奇偶校验。

1、波特率,这是一个衡量符号传输速率的参数,指的是信号被调制以后在单位时间内的变化,即单位时间内载波参数变化的次数,如每秒钟传960个字符,而每个字符格式包含10位(1个起始位,1个停止位,8个数据位)这是波特率为960Bd,比特率就是9600bps,

2、数据位:这是衡量通信中实际数据位的参数,当计算机发送一个信息包,实际的数据往往不会是8位,标准的是6、7和8位,标准的ASCII码是0127(7位),扩展的ASCII码是0255(8位),

3、停止位:用于表示单个包的最后几位,典型的值为1,1.5和2位。作用就是数据在传输线上定时的,并且每一个有其自己的时钟,很可能在通信中两台设备出现不同步的情况,停止位可以解决这个问题,它不仅表示传输结束,还可以提供计算机矫正同步时钟的机会。

4、校验位:在串口通信中一种简单的检错方式,有四种检错方式:奇,偶,高、低。

下面是我写的串口通讯的代码:

1、加载串口配置

#region 加载串口配置 public bool LoadSerialConfig(string com, string BAUDRATE, string DATABITS, string STOP, string PARITY) { if (!sp1.IsOpen) //没打开 { try { //设置串口号 string serialName = com; sp1.PortName = serialName; //设置各“串口设置” string strBaudRate = BAUDRATE; string strDateBits = DATABITS; string strStopBits = STOP; Int32 iBaudRate = Convert.ToInt32(strBaudRate); Int32 iDateBits = Convert.ToInt32(strDateBits); sp1.BaudRate = iBaudRate; //波特率 sp1.DataBits = iDateBits; //数据位 switch (STOP) //停止位 { case "1": sp1.StopBits = StopBits.One; break; case "1.5": sp1.StopBits = StopBits.OnePointFive; break; case "2": sp1.StopBits = StopBits.Two; break; default: //MessageBox.Show("Error:参数不正确!", "Error"); break; } switch (PARITY) //校验位 { case "NONE": sp1.Parity = Parity.None; break; case "奇校验": sp1.Parity = Parity.Odd; break; case "偶校验": sp1.Parity = Parity.Even; break; default: //MessageBox.Show("Error:参数不正确!", "Error"); break; } //如果打开状态,则先关闭一下 if (sp1.IsOpen == true) { sp1.Close(); } sp1.Open(); //打开串口 return true; } catch (System.Exception ex) { SetSerialOpenFlag(false); Form1.ShowThrow(ex); return false; } } else //已经打开 { return true; } } #endregion

2、处理数据的定时器,在定时器里面对接收到的数据进行压到队列里面,后期对队列进行再次的处理。

public void StartTimeOutTimer( UInt16 SendDataShowTimer,bool autoFlag) { //实例化Timer类,设置间隔时间为10000毫秒; timeOutTimer = new System.Timers.Timer(SendDataShowTimer); timeOutTimer.Elapsed += new System.Timers.ElapsedEventHandler(EndTimeProcess); timeOutTimer.AutoReset = autoFlag;//设置是执行一次(false)还是一直执行(rtue); timeOutTimer.Enabled = true;//是否执行System.Timers.Timer.Elapsed事件; } private void EndTimeProcess(Object sender, EventArgs e) { if (GetSerialOpenFlag()) { recvBytesNum = (UInt16)sp1.BytesToRead; if (recvBytesNum == 0 && delayTime 0) //有数据,下面接收数据并校验数据 { //接收16进制 try { lock (Recvlock) //加锁 { Byte[] receiveddata = new Byte[sp1.BytesToRead]; //创接建收字节数组 sp1.Read(receiveddata, 0, receiveddata.Length); //读取数据 sp1.DiscardInBuffer(); //清空SerialPort控件的Buffer if (receiveddata.Length


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3