|
1.WT901C-485姿态传感器的控制和数据协议说明
1 、读取指令和数据回传格式
2 拼接获取xyz轴角度指令:
0x50 0x03 0x00 0x3d 0x00 0x3e 0x00 0x3f 0x00 0x33 0x00 0x003
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.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轴经过校准之后是直接可以表示与北方夹角。
版权声明:本文为CSDN博主「春风十里不如你9527」的原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接及本声明。
|
|