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协议加速度传感器上位机的主要内容,如果未能解决你的问题,请参考以下文章

Modbus协议初探(C#实现)

2021-11-22 WPF上位机 88-了解Modbus

本人想通过moxa nport5650实现下位机modbus与上位机wincc通讯,从wincc采集nport里数据该怎么做?

2021-11-22 WPF上位机 89-Modbus协议

2021-11-27 WPF上位机 100-西门子S7协议之modbus读取数据

2021-11-22 WPF上位机 90-Modbus协议的分类