如何转换双极性差分 ADC 值?

How do I convert a bipolar differential ADC value?

我正在尝试用 C++ 转换 ADC 双极性差分信号。我使用的设备是 12 位 MAX11613 (datasheet),微控制器是 Raspberry PI 3B+。到目前为止,我能够捕获值,但是结果不是我期望的 AIN0 和 AIN1 的差分结果。

该设备是 3.3V 电源,AIN0 上的输入是 0-3.3V。 AIN1 上的输入是 1.65V 输入信号的虚地。

下面显示的设备的双极性传递函数可能是我的困惑来源。为什么恰好低于 1.65V 中间范围的值会产生 0b111111111111 而不是 0b100000000001 的值?如果这实际上是正确的,那么如何调整它以反映与虚拟接地输入 (AIN1) 相比的实际负电压?

关于它的价值,这是我的代码:

max11613.h

#include <sys/ioctl.h>
#include <unistd.h>
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
extern "C" {
    #include <linux/i2c.h>
   #include <linux/i2c-dev.h>
   #include <i2c/smbus.h>
}
#define MAX_ADDRESS  (0x34)//binary: 0110100
#define MAX_READ        (0x01)
#define MAX_WRITE       (0x00)
#define MAX_SETUP       (0x8E)//0x8E
//REG SEL2 SEL1 SEL0 CLK BIP/UNI RST X
//1000 1110=0x8E SEL2=0, SEL1=0, SEL0=0, VDD REF, EXTERNAL CLOCK, BIPOLAR, RESET 
#define MAX_CONFIG  (0x00)//0x00
//REG SCAN1 SCAN0 CS3 CS2 CS1 CS0 SGL/DIFF
//0000 0000=0x00 DIFFERENTIAL CHANNEL 0, 1 NO SCAN
class MAX11613 {
    protected:
        uint8_t   m_i2cAddress;
        uint32_t  m_conversionDelay;
    public:
        MAX11613(uint8_t i2cAddress = MAX_ADDRESS);
        void setup(void);
        int16_t readMAXADC_Differential_0_1(void);
    private:
};

max11613.cpp

#include "max11613.h"
#include <iostream>
int i2cMAXHandle;
float mv_conversion = float(3300.0/4095);
static void beginMAXTransmission(uint8_t i2cAddress) {
  i2cMAXHandle = i2cOpen(1, i2cAddress, 0);//USE pigpio FUNCTION SEE https://abyz.me.uk/rpi/pigpio/cif.html
  if(i2cMAXHandle < 0) {
    std::cout << "HANDLE ERROR: " << stderr << " " << strerror(errno) << std::endl;
    exit(1);
  }
}
static void endMAXTransmission(void) {
    i2cClose(i2cMAXHandle);
}
static void writeMAXRegister(uint8_t i2cAddress, uint8_t reg, uint8_t value) {
    uint8_t payload = value;
    beginMAXTransmission(i2cAddress);
    i2cWriteByteData(i2cMAXHandle, reg, payload);
    endMAXTransmission();
}
static int16_t readMAXRegister(uint8_t i2cAddress, uint8_t reg) {
    const uint8_t datalength = 2;
    char data[datalength];
    beginMAXTransmission(i2cAddress);
    i2cReadI2CBlockData(i2cMAXHandle, reg, data, datalength);
    endMAXTransmission();
    int16_t res = (uint16_t)(data[0] << 8) & ((data[0] & 0x08) ? 0xffff: ~0xf000) | (uint16_t)data[1];//strip preceding 1111 bits and combine data[0] and data[1] to int16_t value
    float mv = float(mv_conversion * float(res));//convert adc result to mv
    return mv;
}
MAX11613::MAX11613(uint8_t i2cAddress) {
    m_i2cAddress = i2cAddress;
    m_conversionDelay = int(0);
}
void MAX11613::setup() {
    writeMAXRegister(m_i2cAddress, 1, MAX_SETUP);
    writeMAXRegister(m_i2cAddress, 1, MAX_CONFIG);// Write config register to the ADC
}
int16_t MAX11613::readMAXADC_Differential_0_1() {
    int16_t res = readMAXRegister(m_i2cAddress, 0);// Read the conversion results AND SHIFT RIGHT TO GET 12 BIT RESULT
    usleep(100);
    return res;
}

例1输出数据: 当示波器读数为-1.16V

readMAXRegister() 的第一个输出:1111001010110010 << 前四位始终由芯片写入 1111

readMAXRegister() 的第二个输出:0000001010110010 << 调整为删除前 4 位 (1111)

readMAXADC_Differential_0_1() 的最后输出:0000001010110010 690 << 注意这是一个正值而不是预期的负差分值,似乎对应于实际 GND 到 VDD 电压。

示例 2 输出数据:

示波器读数为+1.28V时

readMAXRegister() 的第一个输出:1111110011111110 << 前四位始终由芯片写入 1111

readMAXRegister() 的第二个输出:0000110011111110 << 调整为删除前 4 位 (1111)

readMAXADC_Differential_0_1() 的最后输出:1111110011111011 -773 << 注意这个负值应该是正值

编辑:示意图

EDIT2:示例示波器图像 黄色波是信号 AIN0,而示波器 GND 连接到 AIN1(请注意该图中 -800mV 和 920mV 之间的双极性正弦波响应。)蓝色方波表示每个 ADC 读数在波峰和波谷处的读取范围信号。

更新了带有最终工作细节的原始代码。

我用pigpio库来控制对芯片的读写。设置功能首先运行以完成芯片设置和配置,然后根据需要调用读取。

非常非常感谢 alagner 协助审查代码和故障排除!