该章作为 串口调试助手及结构体的收发的补充,主要用于自定义协议中的负数,浮点数等的收发(我们以前用的浮点数等,是直接使用的字符串的收发,从字符串中进行解析的,这里主要使用十六进制,对其收发原理及使用操作进行剖析)。
一般来说,电脑的外部设备可以用过各种端口和电脑连接。常见的有USB,VGA,DVI等等。在工业领域或者是软件开发领域,我们常常需要用简单低成本快捷的方式,完成电脑和设备的连接。那么串口就是非常好的选择
在开发阶段,也许设备端也许还没有就绪,PC软件需要先进行开发,我们就可以通过软件虚拟一个串口出来。用来替代设备的实体。供学习使用
using System.Runtime.CompilerServices;
namespace ConsoleApp1
{
internal class Program
{
static void Main(string[] args)
{
byte[] dataByte = new byte[120];
int count = 0;
//将double型数据存入databyte中。
double data1 = -123.125;
//C# BitConverter 类用来字节数组转换 可以转换成字节 也可以字节转换成int、double等
byte[] buf = BitConverter.GetBytes((double)data1);//单精度浮点型用 BitConverter.ToSingle
Console.WriteLine(BitConverter.ToDouble(buf));
}
}
}
#include
/*
*function:ftoc(float fvalue,unsigned char*arr)
*decription: 浮点数转化成四个字节
*input: 浮点数
*output: 4个字节的字节数组
*/
//例如12.5--0x41 48 00 00;转换完之后,arr[0]-00,arr[1]-00,arr[2]-48,arr[3]-41
void ftoc(float fvalue,unsigned char*arr)
{
unsigned char *pf;
unsigned char *px;
unsigned char i; //计数器
pf =(unsigned char *)&fvalue; /*unsigned char型指针取得浮点数的首地址*/
px = arr; /*字符数组arr准备存储浮点数的四个字节,px指针指向字节数组arr*/
for(i=0;i<4;i++)
{
*(px+i)=*(pf+i); /*使用unsigned char型指针从低地址一个字节一个字节取出*/
}
}
/*
*function:float ByteToFloat(unsigned char* byteArray)
*decription: 将字节型转化成32bits浮点型
*input: 长度为4的字节数组
*output:
*/
float ByteToFloat(unsigned char* byteArray)
{
return *((float*)byteArray); //强制类型转换 然后取值
}
int main(int argc, char *argv[])
{
int i;
unsigned char byteArray[4];
ftoc(-12.5,byteArray);//浮点数转化成四个字节
for(i=0;i<4;i++)
printf("%x ",byteArray[i]);//%x即按十六进制输出,英文字母小写,右对齐
float x=0;
x = ByteToFloat(byteArray);
printf("\n%f ",x);
return 0;
}
其中头两个字节,尾一个字节,中间数据4个字节,使用的是c语言转换过来的单精度4字节 可见上面c实现
public static int cnt = 0;
private void serialPort1_DataReceived2(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
cnt++;
this.Invoke((EventHandler)delegate
{
uiRichTextBox1.AppendText("\r\n" + "cnt:" + cnt);
});
Thread.Sleep(40);
int len = serialPort1.BytesToRead;//一共接收到多少数据
Byte[] readBuffer = new Byte[100];
serialPort1.Read(readBuffer, 0, len);
//2+4+1 80 81 0 0 48 c1 ff 就是-12.5
//获得一帧掐头去尾的数据
for (int ptr = 0; ptr < len; ptr++)
{
if ((readBuffer[ptr] == HEAD1) && (readBuffer[ptr + 1] == HEAD2))
{
if (readBuffer[ptr + 6] == 0xff)
{
int index = ptr + 2;
byte[] fdata = new byte[4];
for (int i = 0; i < 4; i++)//这样就把尾巴给去掉了
{
fdata[i] = readBuffer[index + i];
}
this.Invoke((EventHandler)delegate
{
uiRichTextBox1.AppendText("\r\n" + "接收数据值:" + BitConverter.ToSingle(fdata,0).ToString());
});
}
}
}
}
//直接调用ReadDate函数,接收到的数据会自动保存入 ushort[] value1 中
//一个ushort占用两个字节,一共接收到2个ushort,共四个字节
//调用GetFloat即可实现转换
public static void ReadDate()
{
ushort startAddress = 0x0066;
ushort numberOfPoints = 2;
ushort[] value1 = master.ReadHoldingRegisters(1, startAddress, numberOfPoints);
log.SaveLog("value1字节数:"+value1.Length.ToString());
float valuefloat;
valuefloat = GetFloat(value1[0], value1[1]);
log.SaveLog("流量" + valuefloat);
}
public static float GetFloat(ushort P1, ushort P2)
{
int intSign, intSignRest, intExponent, intExponentRest;
float faResult, faDigit;
intSign = P1 / 32768;
intSignRest = P1 % 32768;
intExponent = intSignRest / 128;
intExponentRest = intSignRest % 128;
faDigit = (float)(intExponentRest * 65536 + P2) / 8388608;
faResult = (float)Math.Pow(-1, intSign) * (float)Math.Pow(2, intExponent - 127) * (faDigit + 1);
return faResult;
}