C#开发串口调试助手实现modbusRTU通信

今天给大家搞个项目,跟我来,走过路过不要错过,看大V如何玩C#工业软件开发,搞事的目的是:掌握MODBUSRTU通信协议,掌握简单型串口调试助手开发,掌握串口通信过程

硬件产品:串口RS232温湿度传感器,用来测试外界温湿度的,如仓库,大棚,车间等,直接在T宝上买

 USB转232线一根,用来连接设备和电脑的

 硬件连接如图:主机USB口多的,可不用那个USB扩展器,直接插电脑

 硬件连接成功后,查看“设备管理器”中串口

软件环境:VS2019,C#,WINFORM,厂家工具软件

1、从厂家获取说明书,工具软件,检测下设备,这个pdf是说明书,仔细看,不懂问厂家

安装厂家给的工具软件,

 测试方式一: 打开 DL-MDM 采集监控平台,可以看到得到温度和湿度2个数据,说明设备工作正常

 测试方式二:用串口调试助手, 

注意:要关闭退出前面的工具软件

按厂家说明书,发送的指令进行测试

测试三:自己写C#winform程序,实现modbusrtu通信,这是重点,核心,关键,前面的测试只是测试设备正常是否,这里的目的是自己写c#上位机程序,实现以上类似功能,开搞。

1、vs2019创建项目,我的项目叫DaLingFormApp

 2、UI布局

 用到了类AlgorithmHelper

 用到了类SerialPortHelper

 3、按钮事件代码

 

 完整代码是:

using DaLingFormApp.Helper;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace DaLingFormApp
{
    public partial class Form1 : Form
    {
        //创建串口操作助手对象
        private SerialPortHelper serialPortHelper = new SerialPortHelper();
        //创建进制转换助手对象
        private AlgorithmHelper algorithmHelper = new AlgorithmHelper();
        public Form1()
        {
            InitializeComponent();
            //串口基本参数初始化
            this.cboBaudRrate.SelectedIndex = 5;   //波特率默认9600
            this.cboCheckBit.SelectedIndex = 0;      //校验位默认NONE
            this.cboDataBit.SelectedIndex = 2;         //数据位默认8
            this.cboStopBit.SelectedIndex = 0;         //停止位默认1

            //获取当前计算机的端口
            if (this.serialPortHelper.PortNames.Length == 0)
            {
                MessageBox.Show("当前计算机上没有找到可用的端口!", "警告信息");
                this.btnOperatePort.Enabled = false;//禁用打开端口按钮
            }
            else
            {
                //将端口添加到下拉框
                this.cboCOMList.Items.AddRange(this.serialPortHelper.PortNames);
                this.cboCOMList.SelectedIndex = 0;
            }

            //串口对象委托和串口接收数据事件关联
            this.serialPortHelper.SerialPortObject.DataReceived += new SerialDataReceivedEventHandler(this.SerialPort_DataReceived);
        }

        /// <summary>
        /// 接收数据
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            try
            {
                ReceiveData(this.serialPortHelper.ReceiveData());
            }
            catch (Exception ex)
            {
                MessageBox.Show("接收数据出现错误:" + ex.Message);
            }
        }

        /// <summary>
        /// 接收数据的具体实现过程
        /// </summary>
        /// <param name="byteData"></param>
        private void ReceiveData(byte[] byteData)
        {
            string data = string.Empty;
            if (this.ckb16Receive.Checked)//十六机制接收
            {
                data = algorithmHelper.BytesTo16(byteData, Enum16Hex.Blank);
                //在这里编写具体的数据处理过程。。。可以保存到数据库,或其他文件...
            }
            else
            {
                data = algorithmHelper.BytesToString(byteData, Enum16Hex.None);
            }

            //显示到当前文本框中
            //因为接收数据的事件是一个独立显存,所有必须通过跨线程访问可视化控件的方法来完成展示
            //Invoke()方法的第一个参数必须是返回值为void的委托,第二个参数是给委托对应方法传递的参数
            this.txtReceiver.Invoke(new Action<string>(
                s =>
                {
                    this.txtReceiver.Text += s + Environment.NewLine;
                }), data);
        }



        #region 串口参数设置

        //波特率的设置
        private void cboBaudRrate_SelectedIndexChanged(object sender, EventArgs e)
        {
            this.serialPortHelper.SerialPortObject.BaudRate = Convert.ToInt32(this.cboBaudRrate.Text);
        }
        //设置奇偶校验
        private void cboCheckBit_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (cboCheckBit.Text == "EVEN")
            {
                serialPortHelper.SerialPortObject.Parity = System.IO.Ports.Parity.Even;
            }
            else if (cboCheckBit.Text == "NONE")
            {
                serialPortHelper.SerialPortObject.Parity = System.IO.Ports.Parity.None;
            }
            else if (cboCheckBit.Text == "0DD")
            {
                serialPortHelper.SerialPortObject.Parity = System.IO.Ports.Parity.Odd;
            }
        }
        //设置数据位
        private void cboDataBit_SelectedIndexChanged(object sender, EventArgs e)
        {
            this.serialPortHelper.SerialPortObject.DataBits = Convert.ToInt32(cboDataBit.Text);
        }
        //设置停止位
        private void cboStopBit_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (cboStopBit.Text == "1")
            {
                serialPortHelper.SerialPortObject.StopBits = System.IO.Ports.StopBits.One;
            }
            else if (cboStopBit.Text == "2")
            {
                serialPortHelper.SerialPortObject.StopBits = System.IO.Ports.StopBits.Two;
            }
        }

        #endregion

        /// <summary>
        /// 打开端口
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnOperatePort_Click(object sender, EventArgs e)
        {
            try
            {
                if (this.btnOperatePort.Text.Trim() == "打开端口")
                {
                    this.serialPortHelper.OpenSerialPort(this.cboCOMList.Text.Trim(), 1);
                    this.lblSerialPortStatus.Text = "端口已打开";
                    this.lblStatusShow.BackColor = Color.Green;
                    this.btnOperatePort.Text = "关闭端口";
                    this.btnOperatePort.Image = this.imageList.Images[0];
                }
                else
                {
                    this.serialPortHelper.OpenSerialPort(this.cboCOMList.Text.Trim(), 0);
                    this.lblSerialPortStatus.Text = "端口未打开";
                    this.lblStatusShow.BackColor = Color.Red;
                    this.btnOperatePort.Text = "打开端口";
                    this.btnOperatePort.Image = this.imageList.Images[1];
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("端口操作异常:" + ex.Message);
            }
        }

        /// <summary>
        /// 发送数据
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnSend_Click(object sender, EventArgs e)
        {
            if (this.txtSender.Text.Trim().Length == 0)
            {
                MessageBox.Show("发送内容不能为空!", "提示信息");
            }
            else
            {
                string txt = this.txtSender.Text.Trim();
                if (txt.Length != 17)
                {
                    txt = txt.Replace(" ", "");
                    StringBuilder sb = new StringBuilder();
                    for (int i = 0; i < txt.Length; i = i + 2)
                    {
                        sb.Append(txt.Substring(i, 2));
                        sb.Append(" ");
                    }
                    txt = sb.ToString();//去掉尾部的空格 
                }
                string crctxt = algorithmHelper.Crc16(txt);
                string sendMsg = txt = txt + crctxt;
                SendData(sendMsg);  //开始发送
            }
        }

        /// <summary>
        /// 发送命令
        /// </summary>
        /// <param name="data"></param>
        private void SendData(string data)
        {
            try
            {
                if (this.ckb16Send.Checked)//发送十六进制数据
                {
                    this.serialPortHelper.SendData(data, SendFormat.Hex);
                }
                else  //发送字符串
                {
                    this.serialPortHelper.SendData(data, SendFormat.String);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("发送数据出现错误:" + ex.Message, "错误提示!");
            }
        }

        /// <summary>
        /// 清空数据
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnClear_Click(object sender, EventArgs e)
        {
            this.txtReceiver.Clear();
            this.txtSender.Clear();
        }
    }
}

这里就用到了串口数据接收事件DataReceived,委托,进制转换,Invoke等技术,

4、运行程序

 

 

 

 我们做这个实战的目的是就是掌握C#开发上位机工业软件,虽然这个工具简单,但核心掌握了RS232接口上的MODBUSRTU通信,中华民族精英战斗团。

猜你喜欢

转载自blog.csdn.net/hqwest/article/details/131002997