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

news2025/1/13 15:40:44

今天给大家搞个项目,跟我来,走过路过不要错过,看大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通信,中华民族精英战斗团。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/601680.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

中移链资源管理介绍

中移链是基于EOS底层框架&#xff0c;在满足我国信息化监管需求、合规可控的前提下&#xff0c;打造的中国移动区块链服务平台。在中移链中主要包括CPU、RAM和NET三种资源。CPU资源是用于执行智能合约的计算能力&#xff0c;RAM资源用于存储智能合约和其它数据&#xff0c;NET资…

【京东API】京东app获得JD商品详情原数据接口

京东是中国最大的综合型电商网站之一&#xff0c;其app端是用户购买商品的主要途径之一。为了更好地满足用户的需求&#xff0c;开发人员提供了商品原数据接口&#xff0c;让第三方开发者可以获取京东商品的详细信息。 开发背景&#xff1a; 随着移动设备用户数量的不断增加&a…

2023最新 如何修改appstroe的开发者名称?

1、输入账号密码登录 http://itunesconnect.apple.com 2、点击app 3、点击我的账户account 4、页面往下滑动&#xff0c;点击更新信息 5、点击提供更新信息 6、根据需要修改新的信息 Hello, I want to change the company name in Chinese, according to changed to “xxx…

MySQL内存

结构 xtradb-innodb-internals-in-drawing InnoDB存储引擎体系结构 内存结构与磁盘结构 InnoDB存储结构 内存相关参数 在MySQL中&#xff0c;可以通过一些参数来控制内存的使用和管理。以下是一些常用的控制内存的参数&#xff1a; innodb_buffer_pool_size: 这是控制InnoD…

商场室内导航制作,商场导览图怎么做的?

商场导览图怎么做的&#xff1f;现在很多商场都比较大&#xff0c;往往需要借助地图才能快速找到想要去的店铺&#xff0c;比如在商场大厅展示商场楼层规划以及楼层具体商户等&#xff0c;让消费者了解商场的整体结构&#xff0c;有逛下去的欲望。重点标记出逃生通道、厕所、进…

是时候搭建一个自己的ChatGPT 了!

ChatGPT客户端-ChatBox https://github.com/Bin-Huang/chatbox 开源的 ChatGPT API (OpenAI API) 跨平台桌面客户端&#xff0c;Prompt 的调试与管理工具&#xff0c;也可以用作 ChatGPT Plus 平替。 如需找不到下载地址&#xff0c;可以私信留言。 ChatGPT Next Web https…

MySQL 自增列使用上的一些 “坑”

文章目录 前言1. 自增列空洞1.1 手动指定2.2 分配未使用 2. 自增列监控2.1 sys 库监控2.2 通用查询 3. 一些 BUG3.1 重启失效3.2 冲突问题 前言 MySQL 的规范中&#xff0c;一般都会建议表要有主键&#xff0c;常使用自增列作为主键字段&#xff0c;这和 MySQL 属于聚簇索引表…

【FlatpanelsHD】HDR生态系统追踪器

Dolby Vision被称为Profile 8.4&#xff0c;与基于pq(杜比实验室开发的感知量化技术&#xff0c;也是无处不在的HDR10的基础)的所有其他口味不同&#xff0c;它基于HLG或Hybrid Log Gamma&#xff0c;由BBC和NHK开发&#xff0c;主要用于电视直播。 用HLG捕捉HDR视频的相机并不…

选择自动化测试工具的主要考虑点是什么?

在软件开发生命周期中&#xff0c;测试是非常重要的一部分。测试的目的是确保软件系统的质量和可靠性。而随着软件开发越来越复杂&#xff0c;传统的手动测试方式已经无法满足测试的要求。自动化测试工具的出现就为测试工作提供了更高效、更准确的解决方案&#xff0c;那选择自…

基于AT89C51单片机的6位电子密码锁详细设计

点击链接获取Keil源码与Project Backups仿真图: https://download.csdn.net/download/qq_64505944/87855657?spm=1001.2014.3001.5503 源码获取 目录 1绪论 1 1.1 课题背景 1 1.2 课题设计目标 1 2系统方案论证 2 2.1 主控部分的选择 2 2.2 密码输入方式的选择 2 3 系统总体…

day8 -- 全文本搜索

brief InnoDB存储引擎从MySQL 5.6开始支持全文本搜索。具体来说&#xff0c;MySQL使用InnoDB存储引擎的全文本搜索功能称为InnoDB全文本搜索&#xff08;InnoDB Full-Text Search&#xff09;。InnoDB全文本搜索支持标准的全文本搜索查询语法和多语言分词器&#xff0c;因此可…

useCallback使用注意

背景 useCallback的作用时基于依赖项缓存函数&#xff0c;但是这个缓存时取值缓存而不是按照地址缓存&#xff0c;这导致了如果缓存的函数使用的值依赖外部某个变量&#xff0c;这个变量只会取第一次用到的值 例子 具体可以看https://codesandbox.io/s/misty-night-vds9oo?…

JavaScript:箭头函数与普通函数的区别与适用场景

文章目录 1 箭头函数与普通函数的区别1.1 语法上的区别1.2 this指向的区别1.3 arguments对象的区别1.4 箭头函数不能用作构造函数 2 箭头函数和普通函数的适用场景2.1 普通函数的适用场景2.1.1 构造函数2.1.2 方法2.1.3 回调函数 2.2 箭头函数的适用场景2.2.1 简答的回调函数2.…

IIS配置URL重写,http重定向https

文章目录 1️⃣ URL重写1.1 URL重写插件下载1.2 URL重写插件安装1.3 URL重写插件配置 优质资源分享 作者&#xff1a;xcLeigh 文章地址&#xff1a;https://blog.csdn.net/weixin_43151418/article/details/131004077 IIS配置URL重写&#xff0c;http重定向https&#xff0c;ht…

【计算机图形学】【代码复现】A-SDF中的数据集制作与数据生成

Follow A-SDF 的Data Generation部分&#xff1a; We follow (1) ANSCH to create URDF for shape2motion dataset (1-2) URDF2OBJ&#xff08;本人认为是1-2之间需要进行的重要的过渡部分&#xff09; (2) Manifold to create watertight meshes (3) and modified mesh_to_sdf…

CPLEX Studio 集成开发环境 (IDE) 介绍

CPLEX Studio 集成开发环境 (IDE) 介绍 参考B站视频&#xff1a;cplex入门到精通 1.CPLEX Studio IDE 实现的功能 IBM ILOG CPLEX Studio IDE 是一个用于数学规划、约束规划以及一般组合优化应用程序的集成开发环境。 它是适用于 OPL&#xff08;优化编程语言&#xff09;和…

PointNetGPD使用手册

1.创建环境配置环境变量 mkdir -p $HOME/code/ cd $HOME/code/ - Set environment variable PointNetGPD_FOLDER in your $HOME/.bashrc file. export PointNetGPD_FOLDER$HOME/code/PointNetGPD 2.安装 1. Install pcl-tools via sudo apt install pcl-tools. 2. An e…

在家当了几年废物,庆幸自己当初进了软件测试这行~

为什么会学习软件测试&#xff1f; 28岁了&#xff0c;仔细算一下6年了&#xff0c;工作了一年&#xff0c;没去工作就一直待在家&#xff0c;家里固定每个月给几千元&#xff0c;偶尔会都给一些&#xff0c;但依旧没钱&#xff0c;家里给我买了一套房子&#xff0c;出门300米…

【刷题之路Ⅱ】LeetCode 739. 每日温度

【刷题之路Ⅱ】LeetCode 739. 每日温度 一、题目描述二、解题1、方法1——暴力法1.1、思路分析1.2、代码实现 2、方法2——单调栈2.1、思路分析2.2、先将栈实现一下2.3、代码实现 一、题目描述 原题连接&#xff1a; 739. 每日温度 题目描述&#xff1a; 给定一个整数数组 tem…

ChatGPT 使用 拓展资料:吴恩达大咖 基于LangChain的LLM应用程序开发-1

ChatGPT 使用 拓展资料:吴恩达大咖 基于LangChain的LLM应用程序开发 基于LangChain的LLM应用程序开发 LangChain for LLM Application Development [https://www.deeplearning.ai/short-courses/langchain-for-llm-application-development/] 基于LangChain的LLM应用程序开发…