2015-12-18 55 views
3

我工作的一些ADC(模拟到数字)值的转换,需要在UART但由于发送这些值我希望将这些转换为一个字节大小我可以发送一个2字节大小的变量作为1字节大小变量吗?

ADC的速度和其他大小限制是0.0至5.0范围内的12位。

目前我分裂2字节变量到两个独立的字节和在接收器部分

连接它们回到发送(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)的

adc1 = data[3] 
adc1 = adc1 << 8 | data[4] 
adc1 = (float(adc1 * 5)/4096) 
# gives me 4.990234 as the value 

有没有什么办法可以发送一个字节的值(也许通过在发送端进行计算)

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

+0

我不明白你怎么可以在一个单字节编码。 - 0-5需要3位,而0-99需要5位以上。 – NadavL

+1

高位字节有多少位有意义?即这实际上是一个16位ADC或更少的东西。 – Clifford

+0

其12位ADC –

回答

7

如果有一些神奇的方法来将两字节值填充到一个字节值中,我们会把它做到一切,然后我们会再做一次,我们会继续这样做,并将所有事物的大小减半,直到我们将全世界的信息推送到一个字节中。这种魔力是不可能的。

如果不是丢掉一半的数据,可以减少大小的东西,但你说你要小数点后至少2个数字。一个字节只能编码256个不同的值,编码从0.00到9.99的所有值需要1000个不同的值,所以你仍然不能这样做。


UPDATE:随着更多的信息,这些仅仅是12位的值,而不是16位,而最大值为5.0,我们可以做的好了很多,虽然还是不太3 8位有效数字。首先,我们可以将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个最低-显著位:

encoded = val >> 4 

和适当地解码:

decoded = encoded * 5.0/256 

这保持的二百五十六分之五精度,或约0.02。其它的编码可能会表现得更好,这取决于你所期望的信号是什么样子。例如,chux's solution正好只要编码值值不变化太快,但只有约0.04当值快速变化的精度。

+3

Hahahahahhaahahahah! +1。我希望我能多+。 –

+0

我只是想代表(或假的代表),两个字节的值设置为一个字节,我din't意味着馅两个字节为一个字节,只是在寻找一种可能性 –

+1

@SaiGanesh:埃姆,......它到底是什么你问:“我可以发送一个2字节大小的变量作为1字节大小变量” – Olaf

0

您可以将那些在发送端和2个繁殖,并加入一个“”在第二位..此方法适用(但不是非常准确)

(4088*5)/4096 = 4.990234 

使用前3位数字,并通过2去掉小数点

499 

鸿沟值,以便它可以使用一个符号的字节被发送(0 -255)

499/2 = 249 

使用常规的数据传输方法发送的值

send[0] = 249 

在接收部分乘以值2,并添加一个小数点

adc1 = 249*2 
newvalue= adc1[:1]+'.'+adc1[1:] 
# you get newvalue = 4.98 (But you loose the accuracy of the converted adc values) 
+1

这会降低分辨率。 OP似乎想要保留它,尽管 – Olaf

+1

这是一种不必要地丢失数据的低效方法。最好以二进制格式工作 - 在演示文稿/显示之前不需要使用十进制格式。实质上,要将12位转换为8位,可以将值除以16,并精确地分配4位,以便最有效地使用可用的8位。 – Clifford

1

如果我正确破译你的问题,看来:

  • 您具有范围值0x000 - 0xfff
  • 你会做一些数学与值((val * 5)/4096),你不会在乎结果数字
  • 的逗号后的头两个小数后会发生什么

如果这是你的问题,你可以首先是验证你多少信息丢失,如果你数学之后,从自己的价值观扔掉至少显著十六进制数字:

>>> (0x010 * 5)/4096 
0.01953125 

这意味着,如果你备用它,你将有一个〜0.02的错误。

如果你都OK使用,你可以然后在单字节编码你的价值。 你只需要4您的值右移发送前:

0 f f 8  >> 4 = [ 0 0 ] f f 
0000 1111 1111 1000    [ 0000 0000]1111 1111 

这是可能的,因为你已经有一个空的领先半个字节, 现在在年底腾出另一半。

在接收端,你会再次离开移,然后做了计算:

>>> b = 0xff << 4 
>>> (b * 5)/4096 
4.98046875 
2

它不能没有松动位,因此精度来完成。基本上你需要把你的ADC看作8位。因为它的声音,例如,如果你的ADC是12位(而不是在你的问题清楚),这可能不是那么糟糕,你失去了仅有4位。

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

然后在接收器中:

adc1 = (data * 5.0)/256 ; 

在您的示例4088被发送作为一十六分之四千零八十八= 255和在接收器处它被变换:

(255 * 5.0)/256 = 4.98 

但请注意,

(254 * 5.0)/256= 4.96, 

所以你最终用PRECIS的约0.02离子(准确地说,如果您的最大值由表示255是5。0,那么精度为5.0/256 = 0.01953125)。这与原始精确度5/4096 = 0.00122相比较

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

最后,正如@chux所建议的那样,您可以用较少的位传输delta(水平变化)并保留完整分辨率(绝对准确度会有所下降),但这是他的建议,所以我不会详细说明这种技术可以用于压扩。

3

使用时间压缩。

准确交易时间。当ADC快速变化时,发送一个7位近似值。当它变慢时,发送增量。

以下是一个粗糙的实现想法。

假定范围为0-3FFF的2字节ADC值。

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); 
    } 

//接收

valid = 0; 
loop: 
    sample = receive() 
    if (sample & 0x80) { 
    delta = sample & 0x7F 
    if (delta & 0x40) delta -= 128; 
    ADC += delta; 
    } else { 
    ADC = sample << 9; 
    valid = 1; 
    } 

发送增量可能的时候应该保留另一位检测错过序列。其他考虑因素适用,但这里给予OP另一个观点。

改进包括让delta放弃2位指数的mantissa的2位。


[编辑]随机数据的

12位不适合在8位。一些想法:

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

  2. 通过将12位值切分为2个6位半部分,将2个部分中的第一个A/D采样发送出去。使用MSB来区分是发送上限还是下限。接收端需要2个样本来重新组合。发送端的第二个A/D采样被丢弃。

  3. 赞#2,但每3个样本发送2个。 3个8位消息中的24位数据。

  4. 正如本答案开头的答案。有时会发送课程价值,其他时间则是三角洲。

  5. 正如以下注释@Clifford总是发送一个有符号的8位增量。可能需要做一些小的调整,以确保收款金额的任何偏差最终能够奏效。

  6. 采取一对夫妇1000(元)样本,并将其写入作为打包的12位数据到一个文件中。压缩(压缩)文件。压缩的每一个配给都被发现,是我们可以推导出的最佳压缩方案的一个指标。如果它不是至少33%,那么你最好接受的是,数据太动态,不能按照给定的要求完全传输。

+1

非常好 - 希望我建议 - 我甚至在几年前发送8ksps和4位样本的电话质量音频。 – Clifford

+0

@Clifford类似的经验。诀窍在于定期确保发件人发送非delta值以防接收方错过消息。 – chux

+0

对于已知带宽的音频信号,不需要发送非delta值,只需获得可以数字或模拟方式删除的DC偏移量。或者,您在开始发送数据之前等待过零点。在这种情况下,实际上所有工作都是通过一个编解码芯片完成的,项目中的12MHz 8051不会达到这个效果 - 这大约是1990年。 – Clifford

相关问题