一、从补码说起
计算机是如何表示负数的呢?这要从补码说起。
在数学中,任意基数的负数都在最前面加上"−"符号(负号)来表示。
然而,在计算机硬件中,数字都以无符号的二进制形式表示,因此我们需要一种编码负号,表示负数的方法。
补码是一种用二进制表示有符号数的方法。
对于正数而言,正数的补码就是该数字本身。
对于0而言,0的补码同样也是该数字本身。
对于负数而言,负数的补码则是将其对应正数按位取反再加1。
举个例子,十进制数6,其二进制为0000 0110,则其补码为(1111 1001)+1,即1111 1010,这个1111 1010就是-6的补码。
如果我现在有一个十进制数-7,要想写出-7 的补码,我们先写出7的二进制,7的二进制为0000 0111,则其补码为(1111 1000)+1,即1111 1001,这个1111 1001就是用补码的形式表示-7了
同样地,如果我现在有一个数,是以补码的形式表示的,即1111 1001,我们首先看到这个数的首位是1,也就表示这个数是负数,这里先做一个判别。然后我们再将其取反加1,即(0000 0110)+1,也就是0000 0111,对应的十进制就是7,又因为前面我们知道这个数是负数了,所以这个数就是-7。这样就可以在知道一个数的补码的情况下,知道其实际对应的十进制了。
注意,十进制数6的二进制为0110,十进制数-6的二进制可不是单纯地将第一位符号位0改为1就可以了(单纯这样改的结果是1110),而应该按照上面红色部分的方法去做。
对于补码的计算,可以在这个网站里做验证:
原码,反码,补码相互转换在线计算器
二、ADC的读取
1. 16位的ADC
对于外接ADC芯片,我们在使用微处理器进行读取时,通常是用SPI或I2C协议。以ADS1115这块芯片为例,使用I2C接口读取其采样值。
可以看到,在读取时,一次的读取我们是读了8个 bit,也就是这里的一个unit8_t变量,这个是一个最基础的读取操作
在实际读取一个16位的寄存器时,我们的操作是这样的,也就是连续读取2次,一次读8位,分别放在高8位和低8位。这里的ConversionResult是s16类型,也就是有符号16位数。
接下来进行一轮变量的赋值,赋予通道属性,即,将读取到的s16赋值给Get_ADS1115_Reture函数的返回值,其类型仍然为s16
最后,将这个s16强制转换为float类型。
注意:以上强制转换是用Signed Char 16转float,而float是32位的,强制转换时,若Signed Char最高位是0,则按正常转。若Signed Char最高位是1,则高16位全部补1。
C 强制类型转换 char转int的小陷阱_木凡辰的博客-CSDN博客_c语言强制类型转换char转int
备注:2的16位是65536,2的15次是32768。
2. 24位的ADC
以ADS1256为例,使用SPI读取数据
类似地,这是接受8个bit
实际读取时,应接收24bit。我们用一个uint32来存放这一数据,高8位是无意义的,存放为0
注意此处,我们对负数进行扩展,若读到的数据的最高位是1,表示此时ADC的读书是一个负数,因此,将其高8位全部填充为1,若读到的数据的最高位是0,表示此时ADC的读书是一个正数,不作任何处理。
单端模式下,轮番地读取8个通道,对于读到的每个通道的数据,先判断其是否为负数,若为负数,则按位取反后+1,否则不做任何处理
封装一层,可以直接输入参数为通道数
在main函数中轮番采集各个通道
再将其强制转换为float
提供参考:
ADC偏移二进制码与实际电压的换算_CCCMiyagi的博客-CSDN博客_偏移二进制码