问题描述
我是 C# 的初学者,想要一些有关如何解决以下问题的建议:
我的代码从 ADC 真 FTDI ic 读取 3 个字节并计算值。问题是有时我得到的值低于零(小于 0000 0000 0000 0000 0000 0000)并且我的计算值跳到一个很大的数字。我需要实现二进制补码,但我和我不知道如何实现。
byte[] readData1 = new byte[3];
ftStatus = myFtdiDevice.Read(readData1,numBytesAvailable,ref numBytesRead); //read data from FTDI
int vrednost1 = (readData1[2] << 16) | (readData1[1] << 8) | (readData1[0]); //convert LSB MSB
int v = ((((4.096 / 16777216) * vrednost1) / 4) * 250); //calculate
解决方法
转换数据左对齐,以便您的符号位落在您的 PC 处理器将其视为符号位的位置。然后右移返回,这将自动执行符号扩展。
int left_justified = (readData[2] << 24) | (readData[1] << 16) | (readData[0] << 8);
int result = left_justified >> 8;
等效地,可以将包含符号位的字节标记为有符号,因此处理器将执行符号扩展:
int result = (unchecked((sbyte)readData[2]) << 16) | (readData[1] << 8) | readData[0];
第二种转换方法仅在符号位已在任一字节内左对齐时才有效。左对齐方法适用于任意大小,例如 18 位二进制补码读数。在这种情况下,对 sbyte
的强制转换无法完成这项工作。
int left_justified18 = (readData[2] << 30) | (readData[1] << 22) | (readData[0] << 14);
int result18 = left_justified >> 14;
,
好吧,这里唯一模糊的时刻是字节序(或大或小)。假设 byte[0]
代表您可以放置的最低有效字节
private static int FromInt24(byte[] data) {
int result = (data[2] << 16) | (data[1] << 8) | data[0];
return data[2] < 128
? result // positive number
: -((~result & 0xFFFFFF) + 1); // negative number,its abs value is 2-complement
}
演示:
byte[][] tests = new byte[][] {
new byte[] { 255,255,255},new byte[] { 44,1,0},};
string report = string.Join(Environment.NewLine,tests
.Select(test => $"[{string.Join(",",test.Select(x => $"0x{x:X2}"))}] == {FromInt24(test)}"));
Console.Write(report);
结果:
[0xFF,0xFF,0xFF] == -1
[0x2C,0x01,0x00] == 300
如果你有大字节序(例如300
== {0,44}
),你必须交换字节:
private static int FromInt24(byte[] data) {
int result = (data[0] << 16) | (data[1] << 8) | data[2];
return data[0] < 128
? result
: -((~result & 0xFFFFFF) + 1);
}