我可以发送一个2字节大小的变量作为1个字节大小的变量吗?

2024-10-01 17:31:49 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在处理一些ADC(模拟到数字)值转换,需要通过UART发送这些值,但由于速度和其他大小限制,我想将这些值转换为一个字节大小

ADC为12位,范围为0.0至5.0。在

目前,我正在将2字节变量拆分为两个独立的字节,并将它们重新连接到receiver部分

发送(C)

// i am trying to send 0xFF8 (4088) which is read from that register 
send[0] = (VADC_G5RES4.B.RESULT) >> 8 ;
send[1] = (VADC_G5RES4.B.RESULT) & 0x0FF;
 .
send[30] = .....

接收(Python)

^{pr2}$

有没有什么方法可以只在一个字节内发送值(也许通过在发送端执行计算)

小数点后(4.99)只有2位数就可以了


Tags: tosendwhich字节is数字resultam
3条回答

如果有什么神奇的方法能把两个字节的值塞进一个字节的值,我们会对所有的东西都这样做,然后再做一次,我们会继续这样做,并不断地将所有的大小减半,直到我们把世界上所有的信息都压缩成一个字节。这样的魔法是不可能的。在

如果你放弃了一半的数据,你可以缩小数据的大小,但你说你希望在小数点后至少有2位数。一个字节只能编码256个不同的值,而从0.00到9.99的所有值都需要1000个不同的值,所以您仍然不能这样做。在


更新:有了附加信息,这些值只有12位,而不是16位,最大值是5.0,我们可以做得更好,尽管仍然不是8位的3位有效数字。在

首先,我们可以将2个值压缩成3个字节,而不是每个值浪费4位。看起来像是

def pack(val1, val2):
    byte1 = val1 >> 4
    byte2 = ((val1 & 0xf) << 4) | (val2 >> 8)
    byte3 = val2 & 0xff
    return byte1, byte2, byte3

您可能需要处理尾随的半字节。在

如果每个值1.5个字节仍然太多,则存在有损编码选项。例如,我们可以丢弃每个值的4个最低有效位:

^{pr2}$

并适当解码:

decoded = encoded * 5.0 / 256

这使精度保持在5/256,即0.02左右。其他编码的性能可能更好,这取决于您期望信号的外观。例如,chux's solution只要值变化不太快,chux's solution就对值进行精确编码,但是当值快速变化时,它的精度只有0.04左右。在

它不能不失去位,因此精度。基本上你需要把你的ADC当作8位来处理。这可能没有听起来那么糟糕,例如,如果你的ADC是12位(在你的问题中不清楚),你只会失去4位。在

uint8_t send = (adc_high_byte << 6) | (adc_low_byte >> 2) ;

然后在接收器中:

^{pr2}$

在您的示例中,4088被发送为4088/16=255,并且在接收器处它被转换:

(255 * 5.0) / 256 = 4.98

但请注意

(254 * 5.0) / 256= 4.96, 

所以最终得到的精度约为0.02(确切地说,如果255表示的最大值为5.0,则精度为5.0/256=0.01953125)。这与原始精度5/4096=0.00122相比

可以使用companding进一步细化。在某些应用程序中,例如音频,保留小信号电平的细节比保留高信号电平更重要,因此可以使用非线性编码将12位数据转换为8,这样0和1之间的差远小于254和255之间的差。它的适用性和成功将取决于应用程序-它适用于音频。在其他应用中,不同的非线性编码可能是合适的,例如,对于电池监测,您可以在放电曲线的拐点处使用高分辨率,在这里电压下降率迅速增加(在某些电池化学中)。在

最后,正如@chux所建议的那样,你可以用更少的比特来传输delta(电平的变化),并保留完整的分辨率(但会损失一些绝对精度),但这是他的建议,所以我不会详细说明,只是说这种技术可以与压扩一起使用。在

使用时间压缩。在

用时间换取准确性。当ADC快速变化时,发送7位近似值。当它变化缓慢时,发送delta。在

下面是一个粗略的实现思路。在

假设2字节ADC值在0-3FFF范围内。在

 sample = ADC();
 encode_value = sample >> 7;
 send(encode_value);
 diff = sample - (encode_value << 7);

 loop:
   previous_sample = sample
   sample = ADC();
   diff = previous_sample - sample;
   if (diff >= -64 && diff <= 63)  {
     send(diff | 0x80);
     diff = 0;
   } else {
     encode_value = sample >> 7;
     send(encode_value);
     diff = sample - (encode_value << 7);
   }

//接收

^{pr2}$

在发送delta时,可能应该预留另一个位来检测丢失的序列。其他的考虑也适用,但在这里,它是给行动的另一个观点。在

优化包括让delta放弃mantissa的2位,以获得2位指数。在


[编辑]

12位随机数据不适合8位。一些想法:

  1. 放弃精确。简单地将12位值除以16,发送8位,然后在接收端乘以16。

  2. 通过将12位值分成2个6位的两半,发送第一个A/D样本。使用MSB来区分发送的是上限还是下限。接收端需要两个样品来把东西放在一起。传输端的第二个A/D样本被丢弃。

  3. 像2个,但是每3个样品中送2个。3个8位消息中的24位数据。

  4. 正如这个答案开头的回答。有时发送航向值,有时发送增量。

  5. 正如下面评论的@Clifford总是发送有符号的8位增量。可能需要一个小的调整,以确保任何偏差的接收金额最终会得到解决。

  6. 取1000(百万)个样本,将其作为压缩的12位数据写入文件。压缩文件。每一个压缩比的发现,都是我们能得到的最佳压缩方案的一个指标。如果它不是至少33%,那么您最好接受这样一个事实:数据太动态,无法按照给定的要求完全传输。

相关问题 更多 >

    热门问题