C#编写Modbus协议加速度传感器上位机
Posted 虎鲸不是鱼
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C#编写Modbus协议加速度传感器上位机相关的知识,希望对你有一定的参考价值。
C#编写Modbus协议加速度传感器上位机
项目概述
笔者利用下班时间,编写了初版上位机软件。通过USB转RS485线,走Modbus协议,成功读取了串口加速度传感器数据。笔者在万能的X宝自费不到200软妹币购置了此款传感器。系虎彩全厂首次尝试编写上位机软件。
功能描述
将此传感器固定于印刷机等中大型设备的电机等位置处,即可实现对机器振动情况(对应传感器加速度)的在线监测,对峰值与峰峰值的监控可以确保机器的振动幅度在安全范围。当传动系统有异物进入或紧固件掉落导致电机堵转、轴类零件窜动时及时报警,防止损失扩大。对采样的数据进行可视化数据分析即可获知设备的劣化情况。利用Fourier变换还可得知时域的曲线,从而得知振动频率是否提高(项目搁置,暂未完成)。
上位机原理
使用NModbus库,读取出传感器寄存器中的数值,将寄存器中的二进制数转化为16位整数,并利用公式计算出实际的物理量。读取出的数据格式化为txt。
初始化连接
//初始化
private void Form1_Load(object sender, EventArgs e)
button4.Text= "开始自动更新";
comboBox2.SelectedIndex = 2;
comboBox5.SelectedIndex = 0;
comboBox3.SelectedIndex = 0;
comboBox4.SelectedIndex = 0;
functionCode = "03 Read Holding Registers";
private SerialPort InitSerialPortParameter()
portName = "COM3";
baudRate = 9600;
parity = Parity.None;
dataBits = 8;
stopBits = StopBits.One;
port = new SerialPort(portName, baudRate, parity, dataBits, stopBits);
return port;
private SerialPort InitSerialPortParameter()
portName = "COM3";
baudRate = 9600;
parity = Parity.None;
dataBits = 8;
stopBits = StopBits.One;
port = new SerialPort(portName, baudRate, parity, dataBits, stopBits);
return port;
private void button1_Click(object sender, EventArgs e)
richTextBox1.Clear();
richTextBox2.Clear();
private void button2_Click(object sender, EventArgs e)
try
//初始化串口参数
InitSerialPortParameter();
master = ModbusSerialMaster.CreateRtu(port);
ExecuteFunction();
catch (Exception)
MessageBox.Show("初始化异常");
private void SetReadParameters(int dataaddress_read)
slaveAddress = 80;
startAddress = (ushort)dataaddress_read;
numberOfPoints = 1;
由于本款传感器默认按16进制计算,很多参数需自行转化为10进制。Modbus地址为0x50,换算后为80。我选用波特率9600的低速模式,占用的端口为COM3。
读取寄存器原始数据
private async void ExecuteFunction()
try
//每次操作是要开启串口 操作完成后需要关闭串口
//目的是为了slave更换连接是不报错
if (port.IsOpen == false)
port.Open();
//读取保持寄存器
SetReadParameters(dataaddress_read);
registerBuffer = master.ReadHoldingRegisters(slaveAddress, startAddress, numberOfPoints);
str_register = registerBuffer[0].ToString();
str_register_int = int.Parse(str_register);
//求补码
if (str_register_int <= 32767)
//正数的原码=补码
else
str_register_int_short = (short)((~str_register_int - 0xFFFF0000) + 1);
str_register_int = -str_register_int_short;
for (int i = 0; i < registerBuffer.Length; i++)
SetMsg(registerBuffer[i] + "\\t");
// SetMsg("\\t\\n");
port.Close();
catch (Exception ex)
MessageBox.Show(ex.Message);
public void SetMsg(string msg)
richTextBox1.Invoke(new Action(() => richTextBox1.AppendText(msg); ));
由于C#中int为32位,传感器的寄存器是16位二进制补码且按大端存储,故按照字符串的方式读出后仍需要想办法计算出带±的原码,否则无法获取角度/加速度为-时的物理量。我采用了按位取反后减去高位并+1的方法获取到高位为0的int32数值,再强制转化为short(即int16)获取到正确的10进制原始数值。
为防止串口占用导致软件功能异常,每次读取后都要关闭串口。
SetMsg为委托更新数据,防止卡死。
换算为实际物理量
private void button3_Click(object sender, EventArgs e)
try
//61,62,63为角度寄存器地址;52,53,54为加速度寄存器地址
//显示时间
richTextBox1.Text = richTextBox1.Text + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")+"\\t";
richTextBox2.Text = richTextBox2.Text + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff") + "\\t";
for (dataaddress_read = 61; dataaddress_read < 64; dataaddress_read++)
ExecuteFunction();
if (dataaddress_read == 61)
angel_x = (double)str_register_int / 32768 * 180;
else if (dataaddress_read == 62)
angel_y = (double)str_register_int / 32768 * 180;
else
angel_z = (double)str_register_int / 32768 * 180;
label14.Text = angel_x.ToString();
label15.Text = angel_y.ToString();
label16.Text = angel_z.ToString();
// richTextBox1.Text = richTextBox1.Text + "\\n";
for (dataaddress_read = 52; dataaddress_read < 55; dataaddress_read++)
ExecuteFunction();
if (dataaddress_read == 52)
ax =- (double)str_register_int / 32768 * 16*9.8;
else if (dataaddress_read == 53)
ay =- (double)str_register_int / 32768 * 16 * 9.8;
else
az =- (double)str_register_int / 32768 * 16 * 9.8;
label19.Text = ax.ToString();
label18.Text = ay.ToString();
label17.Text = az.ToString();
richTextBox2.Text = richTextBox2.Text + angel_x.ToString()+ "\\t";
richTextBox2.Text = richTextBox2.Text + angel_y.ToString() + "\\t";
richTextBox2.Text = richTextBox2.Text + angel_z.ToString() + "\\t";
richTextBox2.Text = richTextBox2.Text + ax.ToString() + "\\t";
richTextBox2.Text = richTextBox2.Text + ay.ToString() + "\\t";
richTextBox2.Text = richTextBox2.Text + az.ToString() + "\\t";
richTextBox1.Text = richTextBox1.Text + "\\n";
richTextBox2.Text = richTextBox2.Text + "\\n";
catch (Exception)
MessageBox.Show("初始化异常");
此为手动模式下的换算及格式化。
Modbus RS458转USB加速度传感器上位机
自动模式
private void button3_Click(object sender, EventArgs e)
try
//61,62,63为角度寄存器地址;52,53,54为加速度寄存器地址
//显示时间
richTextBox1.Text = richTextBox1.Text + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff")+"\\t";
richTextBox2.Text = richTextBox2.Text + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff") + "\\t";
for (dataaddress_read = 61; dataaddress_read < 64; dataaddress_read++)
ExecuteFunction();
if (dataaddress_read == 61)
angel_x = (double)str_register_int / 32768 * 180;
else if (dataaddress_read == 62)
angel_y = (double)str_register_int / 32768 * 180;
else
angel_z = (double)str_register_int / 32768 * 180;
label14.Text = angel_x.ToString();
label15.Text = angel_y.ToString();
label16.Text = angel_z.ToString();
// richTextBox1.Text = richTextBox1.Text + "\\n";
for (dataaddress_read = 52; dataaddress_read < 55; dataaddress_read++)
ExecuteFunction();
if (dataaddress_read == 52)
ax =- (double)str_register_int / 32768 * 16*9.8;
else if (dataaddress_read == 53)
ay =- (double)str_register_int / 32768 * 16 * 9.8;
else
az =- (double)str_register_int / 32768 * 16 * 9.8;
label19.Text = ax.ToString();
label18.Text = ay.ToString();
label17.Text = az.ToString();
richTextBox2.Text = richTextBox2.Text + angel_x.ToString()+ "\\t";
richTextBox2.Text = richTextBox2.Text + angel_y.ToString() + "\\t";
richTextBox2.Text = richTextBox2.Text + angel_z.ToString() + "\\t";
richTextBox2.Text = richTextBox2.Text + ax.ToString() + "\\t";
richTextBox2.Text = richTextBox2.Text + ay.ToString() + "\\t";
richTextBox2.Text = richTextBox2.Text + az.ToString() + "\\t";
richTextBox1.Text = richTextBox1.Text + "\\n";
richTextBox2.Text = richTextBox2.Text + "\\n";
catch (Exception)
MessageBox.Show("初始化异常");
由于采用的是只读模式,传感器在9600波特率可达到50Hz采样频率,115200波特率可达到100H在采样频率,考虑到使用txt保存数据的方式不足以解决数据量过大的问题,暂且使用计时器2Hz自动刷新。
C#编写的ModbusRTU加速度传感器上位机
数据保存
private void button6_Click(object sender, EventArgs e)
//保存数据到txt
if (richTextBox2.Text == string.Empty)
MessageBox.Show("要写入的文件内容不能为空");
else
//设置保存文件的格式
saveFileDialog1.Filter = "文本文件(*.txt)|*.txt";
if (saveFileDialog1.ShowDialog() == DialogResult.OK)
//使用“另存为”对话框中输入的文件名实例化StreamWriter对象
StreamWriter sw = new StreamWriter(saveFileDialog1.FileName, true);
//向创建的文件中写入内容
sw.WriteLine(richTextBox2.Text);
//关闭当前文件写入流
sw.Close();
richTextBox2.Text = string.Empty;
数据可视化分析
将格式化后的txt手动粘贴到excel并链接到tableau。
利用获得的3轴角度及3轴加速度绘制曲线图。
容易看出笛卡尔坐标系下3个轴的振动情况。
尾言
使用costura可以将Nmodbus4.dll打包为一个exe,方便部署。
100Hz*86400s/d*365d=3153600000=31e条数据/年
可以看出,如果把数据全部保存,光是一个传感器的数据量就很庞大。如何保存如此庞大的数据量,并加以利用(如:拟合
出劣化曲线,预测
设备宕机的概率,实现预防性
机修与保养)?这就需要大数据
与机器学习
。
以上是关于C#编写Modbus协议加速度传感器上位机的主要内容,如果未能解决你的问题,请参考以下文章
本人想通过moxa nport5650实现下位机modbus与上位机wincc通讯,从wincc采集nport里数据该怎么做?