如何转换双极性差分 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 协助审查代码和故障排除!
我正在尝试用 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 协助审查代码和故障排除!