如何转换双极性差分 ADC 值?
Posted
技术标签:
【中文标题】如何转换双极性差分 ADC 值?【英文标题】:How do I convert a bipolar differential ADC value? 【发布时间】:2022-01-07 13:35:23 【问题描述】:我正在尝试在 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
readMAXRegister() 的第二个输出:0000001010110010
readMAXADC_Differential_0_1() 的最后输出:0000001010110010 690
示例 2 输出数据:
当示波器读数为+1.28V时
readMAXRegister() 的第一个输出:1111110011111110
readMAXRegister() 的第二个输出:0000110011111110
来自 readMAXADC_Differential_0_1() 的最后输出:1111110011111011 -773
编辑:原理图
EDIT2:示波器图像示例 黄色波是信号 AIN0,而示波器 GND 连接到 AIN1(注意此图中的双极正弦波响应在 -800mV 和 920mV 之间。)蓝色方波表示每个 ADC 读数在峰值和谷值处的读取范围信号。
【问题讨论】:
Why is it that a value just under the midrange of 1.65V would produce a value of 0b111111111111 and not 0b100000000001?
- 在 DS 中明确说明,它是 two's complement 格式。 When oscilloscope reading is -1.16V
- 与什么终端有关? GND,虚拟地?请张贴原理图。
二进制补码格式?我不明白,但我会阅读它,看看我是否能弄清楚,但鉴于我的粗略阅读,这是有道理的。连接示波器时,我的意思是 AIN0 连接到示波器输入,而 AIN1(1.65v 虚拟 GND)连接到示波器地。我添加了一个电路原理图来显示 ADC 连接。
NOTE THIS IS A POSITIVE VALUE AND NOT THE EXPECTED NEGATIVE DIFFERENTIAL VALUE AND SEEMS TO CORRESPOND TO THE ACTUAL GND TO VDD VOLTAGE.
示波器和电源的接地是否分开?不确定您来自哪里(电源插座在不同国家/地区有所不同,因此我的描述可能对您没有任何意义)以及您的电源是什么,但在将示波器的接地连接到被测电路时,您是否没有短路某些东西,例如通过电源插座中的接地/安全端子?
@alagner,示波器在测试期间不会将信号接地。见附图。该电路和数据收集与 ADS1015 芯片配合良好,只是我需要切换到可以更快读取速度的不同芯片。
@alagner,看来我正在取得一些进展。你能告诉我这是否是将两个 8 位无符号字符字节转换为一个有符号整数值的正确方法吗? data[0] 和 data[1] 分别是 MSB 和 LSB 值。 uint16_t res = (data[0]
【参考方案1】:
使用最终工作细节更新原始代码。
我使用 pigpio 库来控制对芯片的读写。设置函数首先运行完成芯片设置和配置,然后根据需要调用读取。
非常感谢 alagner 协助审查代码和故障排除!
【讨论】:
以上是关于如何转换双极性差分 ADC 值?的主要内容,如果未能解决你的问题,请参考以下文章