24位ADC数据转换,并利⽤python解析hex⽂件画图
 ⽬前有许多ADC芯⽚都是24位精度的,这个位数稍显尴尬,因为在常⽤的变量类型中,有8bit、16bit、32bit,唯独没有24bit,这就导致我们在很多情况下,需要⾃⼰敲代码去处理这个24bit的有符号数据。
⼗六进制 -> ⼗进制
 在开始之前,需要清楚计算机中是如何表⽰负数的。
 对于有符号24位整型值,0x000001~0x7FFFFF是对应⼗进制的正数区间0~8388607,达到正的最⼤值之后,再往后加1,就来到了负数的地盘。负数有些不同,0x800000表⽰的是负的最⼤值,~0xFFFFFF则对应⼗进制的负数区间~-1。如下表:
 ⼗六进制数从0x000000开始逐渐增⼤,表⽰的⼗进制也是从0开始逐渐增⼤。⼀直增⼤到0x7FFFFF时,来到了正负数的分界点。
0x7FFFFF是正数的最⼤值,再往后+1,就变成了0x800000,这是负数的最⼩值。⼗六进制数继续增⼤,表⽰的⼗进制负数也随之增⼤,⼀直增⼤到0xFFFFFF时,这个⼗六进制数的范围到了尽头,对应⼗进制的值也到了负数区间的尽头:-1。具体值见下表:
⼗六进制⼗进制
00 00 000
00 00 011
…………………………………
7F FF FF8388607
80 00 00-8388608
80 00 01-8388607
…………………………………
FF FF FF-1
 以上是对24bit有符号数据的描述,32bit有符号数据的正负区间规律类似,只不过正负分界点多了8位,变成了0x7F FF FF FF和0x80 00 00 00。
 在⼤部分编译器中,并没有24bit这样⼀个尴尬的数据类型,因此我们需要⽤⼀个32bit的变量来将就⼀下,⽐如在⼤部分X86、X64的PC,以及32位单⽚机中的int,下⾯我们就以int为例。
 int是32位(XX XX XX XX),⽽我们的数据是24位(XX XX XX),最⾼位缺了⼀个字节(XX),⽽这个字节恰恰决定了数据的正负号。因此,我们在⽤32位变量来装24位数据时,为了确保不把符号弄丢,要进⾏补位:
如果24位数据的最⾼位⼤于等于0x80,表明这是⼀个负数,要在前⾯补上⼀个8个1(0xFF)构成32位变量。
如果24位数据的最⾼位⼩于0x80,表明这是⼀个正数,在前⾯补上⼀个8个0(0x00)即可。
⼗进制 -> 实际电压
 将⼗六进制转换到我们熟悉的⼗进制后,还需要将其转换成实际的电压值。⼀些24位AD芯⽚的⼿册上是这样写的:
 读上表,可以看到该芯⽚的测量范围Vrang是单倍参考电压(有些芯⽚可能是⼆倍参考电压,或者参考电压减去⼏伏,需要注意),不难得到换算公式:实际电压 =⼗进制原始值* 测量范围/0x7FFFFF
参考代码
 以下代码是在STM32上通过SPI实现24位AD数据的采集,并将其转换为实际值(单位mV)的过程。
//AD_DEC的数据类型应定义为32位有符号型。
我的地盘mv//int对于⼤部分X86、X64的PC,以及32位单⽚机来说都是32位
int AD_DEC;
double AD_mV;
long double get_AD_data()
{
char data1,data2,data3;
//……
//其余代码略
//……
//读24位数据(⾼位在前)
HAL_SPI_Receive(&hspi1,&data1,1,10);
HAL_SPI_Receive(&hspi1,&data2,1,10);
HAL_SPI_Receive(&hspi1,&data3,1,10);
//转换为⼗进制
AD_DEC =(unsigned int)(data1<<16)|(data2<<8)|data3;
//如果⼤于800000,说明是负数,最⾼位补⼀个FF
if(data1&0x80)
AD_DEC |=0xFF000000;
//⼗进制转换为mV (这⾥以测量范围-5V~5V为例)
AD_mV = AD_DEC*0.000596046518808;
return AD_mV;
}
利⽤python解析24位原始AD数据的hex⽂件并绘图
 AD采集到数据之后,我们往往想要画出AD数据的变化趋势图来直观地分析问题。
 在⼀些对采样率要求较⾼的场景下,我们往往不是保存转换后的实际电压值,因为这样太耗费时间了,⽽是直接将原始的⼗六进制数据放进HEX⽂件,存⼊⼤容量的SD卡中。
 接下来就介绍如何使⽤python解析存有原始24位AD数据的HEX⽂件,并绘出曲线。
 本⽂⽤来举例的hex⽂件格式如下图所⽰。前9字节是⽂件头,存储了⼀些信息,从第10字节开始,就是⼀个挨⼀个密集存放的24位原始数据。
 在python中,不需要我们亲⾃处理24bit有符号数据,直接使⽤int.from_bytes( )即可。因此,整个py
thon代码看起来⾮常简单。
import matplotlib.pyplot as plt
fin =open('F://bottom-2000-1-1-0-37-41.hex', mode ='rb')
# 跳过前9字节的⽂件头。如果你的⽂件没有⽂件头,可以删掉下⾯这⼀⾏
fin.seek(9)
hex_dat = ad()
fin.close()
value =[]
for i in range(0,len(hex_dat),3):
# 读取三个Byte组成⼀个24bit数
value.append(0.000596046518808*int.from_bytes(hex_dat[i:i+3], byteorder ='big', signed ='true'))
plt.plot(value)
plt.show()
 如果你的hex⽂件没有前9个字节的⽂件头,将程序中的fin.seek(9) 删除即可。
 运⾏结果如下图: