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