目前有许多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 00000 00 011…………………………………7F FF FF838860780 00 00-838860880 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位有符号型。 //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( )即可。因此 整个python代码看起来非常简单。
import matplotlib.pyplot as plt fin open( F://bottom-2000-1-1-0-37-41.hex , mode rb ) # 跳过前9字节的文件头。如果你的文件没有文件头 可以删掉下面这一行 fin.seek(9) hex_dat fin.read() 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) 删除即可。



