C#获取感JY901M_485姿态传器的X Y Z角度

1.JY901M_485姿态传器的控制和数据协议说明

1.1 读取指令和数据回传格式


1.2 xyz轴角度所在寄存器地址


2 拼接获取xyz轴角度指令

0x50 0x03 0x00 0x3d 0x00 0x3e 0x00 0x3f 0x00 0x33 0x00 0x00

3 编写代码

3.1 查看串口

win10环境直接在左下输入设备管理进入设备管理器查看设备所在串口

3.2 建立 wpf 项目——modbus 


3.3 串口代码Comm.cs

using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;

namespace Modbus
{
    public class Comm
    {
        public delegate void EventHandle(byte[] readBuffer);
        public event EventHandle DataReceived;

        public SerialPort serialPort;
        Thread thread;
        volatile bool _keepReading;

        public Comm()
        {
            serialPort = new SerialPort();
            thread = null;
            _keepReading = false;
        }

        public bool IsOpen
        {
            get
            {
                return serialPort.IsOpen;
            }
        }

        private void StartReading()
        {
            if (!_keepReading)
            {
                _keepReading = true;
                thread = new Thread(new ThreadStart(ReadPort));
                thread.Start();
            }
        }

        private void StopReading()
        {
            if (_keepReading)
            {
                _keepReading = false;
                thread.Join();
                thread = null;
            }
        }

        private void ReadPort()
        {
            while (_keepReading)
            {
                if (serialPort.IsOpen)
                {
                    int count = serialPort.BytesToRead;
                    if (count > 0)
                    {
                        byte[] readBuffer = new byte[count];
                        try
                        {
                            //Application.DoEvents();
                            serialPort.Read(readBuffer, 0, count);
                            if (DataReceived != null)
                                DataReceived(readBuffer);
                            Thread.Sleep(100);
                        }
                        catch (TimeoutException)
                        {
                        }
                    }
                }
            }
        }

        public void Open()
        {
            Close();
            try
            {
                serialPort.Open();
            }
            catch (Exception e)
            {
            }
            if (serialPort.IsOpen)
            {
                StartReading();
            }
            else
            {
                MessageBox.Show("串口打开失败!");
            }
        }

        public void Close()
        {
            StopReading();
            serialPort.Close();
        }

        public void WritePort(byte[] send, int offSet, int count)
        {
            if (IsOpen)
            {
                serialPort.Write(send, offSet, count);
            }
        }
    }
}

3.4 modbus协议代码 单一指令 获取xyz

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Modbus
{
    //读取从机数据
    class modbus
    {
        private const byte devAddr = 0x50;//设备地址,默认
        private const byte funCode = 0x03;//读功能码

        private const byte regHxH = 0x00;
        private const byte regHxL = 0x3d;//x轴角度
        private const byte regHyH = 0x00;
        private const byte regHyL = 0x3e;//y轴角度
        private const byte regVzH = 0x00;
        private const byte regVzL = 0x3f;//z轴角度

        private const byte regNumH = 0x00;
        private const byte regNumL = 0x03;//寄存器个数
        private const byte CRCH = 0x00;
        private const byte CRCL = 0x00;


        public byte[] getXYZ() {
            return new byte[] { devAddr,funCode, regHxH, regHxL,regNumH, regNumL, CRCH, CRCL };
        }
    }
}

3.5 界面查询按钮触发获取xyz

<Window x:Class="Modbus.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Button Content="查询" HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Margin="10,117,0,0" Click="select"/>
        <Label Content="x" HorizontalAlignment="Left" Margin="119,24,0,0" VerticalAlignment="Top"/>
        <Label Content="y" HorizontalAlignment="Left" Margin="258,24,0,0" VerticalAlignment="Top" Width="19"/>
        <Label Content="z" HorizontalAlignment="Left" Margin="396,24,0,0" VerticalAlignment="Top" RenderTransformOrigin="2.625,0.32" Width="18"/>
        <TextBlock  x:Name="x" HorizontalAlignment="Left" Margin="150,24,0,0" TextWrapping="Wrap" VerticalAlignment="Top" RenderTransformOrigin="0.927,0.267" Height="25" Width="97"><Run Language="zh-cn" Text="1111"/></TextBlock>
        <TextBlock  x:Name="y" HorizontalAlignment="Left" Margin="277,24,0,0" TextWrapping="Wrap" VerticalAlignment="Top" RenderTransformOrigin="0.927,0.267" Height="25" Width="114"><Run Language="zh-cn" Text="1111"/></TextBlock>
        <TextBlock  x:Name="z" HorizontalAlignment="Left" Margin="424,24,0,0" TextWrapping="Wrap" VerticalAlignment="Top" RenderTransformOrigin="0.927,0.267" Height="25" Width="90"><Run Language="zh-cn" Text="1111"/></TextBlock>
        <Label Content="水平x" x:Name="hX" HorizontalAlignment="Left" Margin="106,168,0,0" VerticalAlignment="Top" Width="43" Height="24"/>
        <Label Content="水平y" x:Name="hY" HorizontalAlignment="Left" Margin="241,168,0,0" VerticalAlignment="Top" Width="43" Height="24"/>
        <Label Content="垂直z" x:Name="vZ" HorizontalAlignment="Left" Margin="386,168,0,0" VerticalAlignment="Top" Width="43" Height="24"/>
        <TextBlock HorizontalAlignment="Left" Margin="149,167,0,0" TextWrapping="Wrap" VerticalAlignment="Top" RenderTransformOrigin="0.927,0.267" Height="25" Width="97"><Run Language="zh-cn" Text="1111"/></TextBlock>
        <TextBlock HorizontalAlignment="Left" Margin="284,167,0,0" TextWrapping="Wrap" VerticalAlignment="Top" RenderTransformOrigin="0.927,0.267" Height="25" Width="97"><Run Language="zh-cn" Text="1111"/></TextBlock>
        <TextBlock HorizontalAlignment="Left" Margin="424,167,0,0" TextWrapping="Wrap" VerticalAlignment="Top" RenderTransformOrigin="0.927,0.267" Height="25" Width="90"><Run Language="zh-cn" Text="1111"/></TextBlock>
        <TextBox x:Name="recv" HorizontalAlignment="Left" Height="44" Margin="173,67,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="284"/>
        <Label Content="recv" HorizontalAlignment="Left" Margin="119,67,0,0" VerticalAlignment="Top" RenderTransformOrigin="0.938,2.04" Height="23" Width="49"/>

    </Grid>
</Window><Window x:Class="Modbus.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Button Content="查询" HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Margin="10,117,0,0" Click="select"/>
        <Label Content="x" HorizontalAlignment="Left" Margin="119,24,0,0" VerticalAlignment="Top"/>
        <Label Content="y" HorizontalAlignment="Left" Margin="258,24,0,0" VerticalAlignment="Top" Width="19"/>
        <Label Content="z" HorizontalAlignment="Left" Margin="396,24,0,0" VerticalAlignment="Top" RenderTransformOrigin="2.625,0.32" Width="18"/>
        <TextBlock  x:Name="x" HorizontalAlignment="Left" Margin="150,24,0,0" TextWrapping="Wrap" VerticalAlignment="Top" RenderTransformOrigin="0.927,0.267" Height="25" Width="97"><Run Language="zh-cn" Text="1111"/></TextBlock>
        <TextBlock  x:Name="y" HorizontalAlignment="Left" Margin="277,24,0,0" TextWrapping="Wrap" VerticalAlignment="Top" RenderTransformOrigin="0.927,0.267" Height="25" Width="114"><Run Language="zh-cn" Text="1111"/></TextBlock>
        <TextBlock  x:Name="z" HorizontalAlignment="Left" Margin="424,24,0,0" TextWrapping="Wrap" VerticalAlignment="Top" RenderTransformOrigin="0.927,0.267" Height="25" Width="90"><Run Language="zh-cn" Text="1111"/></TextBlock>
        <Label Content="水平x"  HorizontalAlignment="Left" Margin="106,168,0,0" VerticalAlignment="Top" Width="43" Height="24"/>
        <Label Content="水平y"  HorizontalAlignment="Left" Margin="241,168,0,0" VerticalAlignment="Top" Width="43" Height="24"/>
        <Label Content="垂直z"  HorizontalAlignment="Left" Margin="386,168,0,0" VerticalAlignment="Top" Width="43" Height="24"/>
        <TextBlock x:Name="hX" HorizontalAlignment="Left" Margin="149,167,0,0" TextWrapping="Wrap" VerticalAlignment="Top" RenderTransformOrigin="0.927,0.267" Height="69" Width="97"><Run Language="zh-cn" Text="1111"/></TextBlock>
        <TextBlock x:Name="hY" HorizontalAlignment="Left" Margin="284,167,0,0" TextWrapping="Wrap" VerticalAlignment="Top" RenderTransformOrigin="0.927,0.267" Height="69" Width="97"><Run Language="zh-cn" Text="1111"/></TextBlock>
        <TextBlock x:Name="vZ" HorizontalAlignment="Left" Margin="424,167,0,0" TextWrapping="Wrap" VerticalAlignment="Top" RenderTransformOrigin="0.927,0.267" Height="69" Width="90"><Run Language="zh-cn" Text="1111"/></TextBlock>
        <TextBox x:Name="recv" HorizontalAlignment="Left" Height="44" Margin="173,67,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="284"/>
        <Label Content="recv" HorizontalAlignment="Left" Margin="119,67,0,0" VerticalAlignment="Top" RenderTransformOrigin="0.938,2.04" Height="23" Width="49"/>


    </Grid>
</Window>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;


namespace Modbus
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        private Comm comm;
        private modbus modbus = new modbus();
        public MainWindow()
        {
            InitializeComponent();
            initComPort("COM4");
        }


        private void initComPort(String portName)
        {
            comm = new Comm();
            comm.serialPort.PortName = portName;
            //波特率
            comm.serialPort.BaudRate = 9600;
            //数据位
            comm.serialPort.DataBits = 8;
            //两个停止位
            comm.serialPort.StopBits = System.IO.Ports.StopBits.One;
            //无奇偶校验位
            comm.serialPort.Parity = System.IO.Ports.Parity.None;
            comm.serialPort.ReadTimeout = 100;
            comm.serialPort.WriteTimeout = -1;


            comm.Open();
            if (comm.IsOpen)
            {
                comm.DataReceived += new Comm.EventHandle(comm_DataReceived);
            }
        }


        void comm_DataReceived(byte[] readBuffer)
        {
            if (readBuffer[0] == 80) return;
            if (readBuffer[0] == 3) 
            {
                StringBuilder pp = new StringBuilder();
                for (int i = 0; i < readBuffer.Length; i++)
                {
                    pp.Append("0x" + readBuffer[i].ToString("X2") + " ");
                }
                Array.Reverse(readBuffer, 2, 2);
                int x = BitConverter.ToInt16(readBuffer, 2);


                Array.Reverse(readBuffer, 4, 2);
                int y = BitConverter.ToInt16(readBuffer, 4);


                Array.Reverse(readBuffer, 6, 2);
                int z = BitConverter.ToInt16(readBuffer, 6);


                double angleX = x* 180.0 / 32768.0;
                double angleY = y * 180.0 / 32768;
                double angleZ = z * 180.0 / 32768.0;
                //更新界面数据
               Dispatcher.BeginInvoke(new Action(() =>
               {
                   this.recv.Text = pp.ToString() + "\n";


                   this.hX.Text = angleX.ToString();
                   this.hY.Text = angleY.ToString();
                   this.vZ.Text = angleZ.ToString();


                   this.x.Text = x.ToString();
                   this.y.Text = y.ToString();
                   this.z.Text = z.ToString();
               }));
            }
            }
        }
        private void select(object sender, RoutedEventArgs e)
        {
            byte[] contol = modbus.getXYZ();
            comm.WritePort(contol, 0, contol.Length);
        }
    }
}

3.6 代码解释说明

程序初始化,实例化串口,打开串口。点击select按钮触发事件,向comm口发送控制指令getXYZ,获取xyz轴角度。comm口的DataReceived收到传感器数据后,调用函数comm_DataReceive.

comm_DataReceive解析回传数据

数据回传第一个包为0x50,表示设备地址,忽略。

第二个包格式 0x03 0x06 ... ... ...  

06表示有6个寄存器回传数据,这里是x,y,z.每个数据占两个寄存器,分高低位。具体转换办法如下:

(官方说明):
输出数据的正负号是按照补码的方式表示的,也就是其二进制数据的最高位如果为1则表示负数。程序编写的时候,可以采用强制转化为有符号的short类型来解决符号的问题,具体做法是,将数据的高位强制DataH转化为short类型,然后再左移8位,和低字节DataL进行与操作。例如角速度包的解析方法:
角速度包一共有11个字节,chrTemp[11],其中chrTemp[3]为X轴角速度的高8位,chrTemp[2]为X轴角速度的低8位,那么角速度的解析代码如下:
float w[0];
w[0]=(( ((short)chrTemp[3])«8)|chrTemp[2])/32768*2000;
其中( ((short)chrTemp[3])«8)|chrTemp[2]得到short类型的有符号数据,short类型的数据表示范围是-32768~32767之间,角速度的量程范围是正负2000°,所以需要除以32768再乘以2000。这样处理以后,得到的数据就是有符号的float类型数据了。
这里转换x轴的代码,y,z相同。
(((short)readBuffer[2] << 8) | readBuffer[3]) * 180 / 32768; 
有些小问题,这个代码计算出来的都是整数,不是确切值。需要的自己改啊,哈哈哈!

3.7 修改

经过实际测试(((short)readBuffer[2] << 8) | readBuffer[3]) * 180 / 32768,只在值为正数的时候才是正确的值,与传感器回传值不符合。上面代码已经修改为:

Array.Reverse(readBuffer, 2, 2);

int x = BitConverter.ToInt16(readBuffer, 2);

把回传值高低位转换后利用c#的API ToInt16直接读取两个字节进行转换,得到的是有符号的10进制数据。

计算角度的时候,采用下面在数据后面加0的方式得到double型数据,然后根据需要截取数据的精度。

double angleX = x* 180.0 / 32768.0;

3.8 实际运行效果图:



附加说明:

实际z轴经过校准之后是直接可以表示与北方夹角。


猜你喜欢

转载自blog.csdn.net/ido1ok/article/details/80789339
今日推荐