This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] ADS1255:ADS1255连续读取毛刺脉冲

Guru**** 2614265 points
Other Parts Discussed in Thread: ADS1255, ADS1256

请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/data-converters-group/data-converters/f/data-converters-forum/684032/ads1255-ads1255-continuous-read-glitch

器件型号:ADS1255
主题中讨论的其他器件: ADS1256

你好!

关于 ADS1255:我一直在尝试使其与 ESP32 (但平台并不重要)配合使用、其最大电位为30kSPS。
遗憾的是、在连续模式(RDATAC)下读取数据会产生一些奇怪的行为: 与使用正常读取模式(RDATA)相比、我获得的原始 ADC 值在很大程度上不稳定(幅度超过5000000)、其变化不超过数千(对应于指定的噪声性能)。  
我正在使用 Arduino IDE 和通过 SPI 连接的 ESP32与 ADC 进行通信。  
其他一些组件包括 AD8555运算放大器和+2.5V 低噪声电压源 ADR431BRZ。 (请参阅折页 原理图)。

我用于设置 ADC 的代码可在下面找到、它是 Darioslavi 在这里发布的代码的自适应值。

显然、这些寄存器似乎没有正确设置。 例如、在状态寄存器(0x00h)中写入0B00000001后、我将读回0而不是1。 为什么会这样?
此外、在 LOOP 函数中、我是否 以正确的方式连续读取 ADC 输出? 我缺少什么吗?

感谢您的帮助! 这里是我使用的代码。

#include 
#include 

#define SCK 14
#define MOSI 12
#define MISO 27
#define DRDY 26
#define CS 5


#define SPISPEED 1200000

#define WREG 0x50
#define RDATA 0x01
#define RDATAC 0x03
#define RREG 0x10

#define ENABLE_OP_AMP_SETUP 0

unsigned long ADC_val = 0;//存储读
数 outPIN = 19; //引脚


AD8555运算放大器(outpin)中的运算放大器数据;

void setup()
{
Serial.begin(2000000);

if (ENABLE_OP_AMP_Setup){
//Start--------------- 运算放大器设置---

//获取第二级增益代码
serial.println ("输入第二级增益代码(0..7)");
//等待用户输入值
while (!Serial.available ());

//设置第二级增益代码
if (!opamp.setSecondStageGain(Serial.parseInt ()){
//如果代码超出范围,运算放大器将返回 false
serial.println ("第二级增益代码无效。 有效范围为0..7");
返回;
}


//第一级增益代码
serial.println ("输入第一级增益代码(0..127)");
while (!Serial.available ());

if (!opamp.setFirstStageGain(Serial.parseInt ()){
serial.println ("第一级增益代码无效。 有效范围为0..127");
返回;
}


//偏移代码
serial.println ("输入偏移代码(0..255)");
while (!Serial.available ());
if (!opamp.setOffset(Serial.parseInt ()){
serial.println ("偏移代码无效。 有效范围为0..255");
返回;
}

//编程模式
serial.println ("选择编程模式:输入"0\"进行仿真、输入"1\"进行永久编程");

while (!Serial.available ());
int mode = Serial.parseInt();
如果(MODE = 0){
//模拟模式
OPAMP.Simulate();
serial.println ("完成!");
} 如果(MODE = 1){
//永久编程模式
serial.println ("确保满足 AD8555数据表中描述的编程要求:");
serial.println ("需要5.5V 电源");
serial.println ("电源必须能够提供250mA 的电流");
serial.println ("-器件电源引脚上需要至少0.1uF 的去耦电容);

serial.println ("\n 警告:此操作无法撤消、所有编程值都是永久性的");
serial.println ("继续吗? [Y/N]");

while (!Serial.available ());
if (Serial.read ()='y'){
opamp.program();
serial.println ("编程...完成");
} 否则{
serial.println ("操作已取消");
}
}

//完成--- 运算放大器设置--------------------------------}-->


引脚模式(MISO、输入);
引脚模式(MOSI、输出);
引脚模式(SCK、 输出);
pinMode (CS、输出);
pinMode (DRDY、输入);
延迟(1);

延迟(500);
SPI.begin(SCK、MISO、MOSI、 cs);//启动 SPI 总线
延迟(500);

//初始

化 while (digitalRead (DRDY)){}//等待 READY_LINE 变为低
电平 SPI.beginTransaction(SPISettings(SPISPEED、MSBFIRST、SPI_MODE1);//启动 SPI
delayMicroseconds (10);

//重置为加电值(FEH);{sbid_transfer



(


SPI.beginTransaction(SPISettings(SPISPEED);//等待 SPI deleMicro 秒(SPI);//待传输(SPI deleMicro);(SPI deleMicro);//待传输();// DDIRx) //开始 SPI

字节 STATUS_reg = 0x00;//状态寄存器的地址(数据表第30页)
字节 STATUS_DATA = 0B0000001;
字节 STATUS_READ;
//000 0 0 0 1
//000 -出厂编程标识位
//0 -设置 MSB 传输
//0 -自动校准禁用
//0 -缓冲器禁用
//1 - DRDY 引脚
SPI.transfer (WREG | STATUS_reg)的重复状态;
SPI.transfer (0x00);//第二个命令字节、仅写入一个寄存器
SPI.transfer (STATUS_DATA); //将数据字节写入寄存
器 delayMicroseconds (10);



Serial.println ("状态寄存器值:");
spi.transfer (RREG | STATUS_reg);
spi.transfer (0x00);//第二个命令字节,只读一个寄存器
spi.transfer (status_read);
delayMicroseconds (10);
Serial.print ("
status);print"应为 Serial in (data.);
serial.print ("已接收:");
serial.println (STATUS_READ);


//PGA 设置
//1±5V
/2±2.5V
///4±1.25V
// 8±0.625V
// 16±312.5mV
// 32±156.25mV
// 64±78.125mV

0000adcon_reg = 0x02;/0000控制寄存
器字节0x02 =/A/D
// 0 00 00 000
// 0始终保留0
// 00 -时钟输出关闭
// 00 -传感器锁定关闭
// 000 - PGA 增益= 1
SPI.transfer (WREG | adcon_reg);
SPI.transfer (0x00);//第二个命令字节,只写一个寄存器
SPI.transfer (adcon_data);//将数据库写入微
秒(10);



字节 drate_reg = 3;//数据速率寄存器地址:0x03
字节 drate_data = 0B11110000;
// 11110000
//将数据速率设置为最大值 (30000 SPS)
SPI.transfer (WREG | DRAT_reg);
SPI.transfer (0x00);//第二个命令字节、只写入一个寄存器
SPI.transfer (DRAT_DATA);//将数据字节写入寄存
器 delayMicroseconds (10);



字节 mux_reg = 0x01;// Mux 寄存器(地址01h);//将数据




写入 IDMx (01111)/ IN0000 - IN01111 / INREG/ IN01111 / INx (默认值) //多路复用器寄存
器 SPI.transfer (0x00);//第二个命令字节,只写入一个寄存器
SPI.transfer (mux_data);//将数据字节写入寄存器
delayMicroseconds (10);

字节通道= 0;
字节数据= 0B00001000;// AINCHANNEL 和 AINCOM
//配置为 AIN0V/REVFP
= 2.5V

spi.transfer (0x50 | mux_reg);//多路复用器寄存
器 spi.transfer (0x00);//第二个命令字节,只写入一个寄存器
spi.transfer (data);//将数据字节写入寄存
器 delayMicroseconds (10);

//同步命令1111 1100
spi.transfer (0xFC);
delayMicroseconds (10);

// SPI rewait_transfer





(sble.SPI);// SPI rewakeSPI (dle.0000);// SPI rewake1 (dumn);// SPI rewakeSPI (dle.deltend

SPI.beginTransaction(SPISettings(SPISPEED);// SPI (dle.deleSPI) //启动 SPI
spi.transfer (RDATAC);//读取数据连续命令0000 0011 (03h)
delayMicroseconds (10);
spi.endTransaction ();

Serial.println ("ADC configured、starting sampling");
}


void loop ()
{
while (digitalRead (DRDY));};

SPI.beginTransaction(SPISettings(SPISPEED、MSBFP_transfer
=
0;spi_transfer =

0;/spi_transfer = 0;/spi_transfer = nval (spi_transfer = 0)
;
SPI.endTransaction ();

//ADS1255/6以二进制二进制
/补码格式输出24位数据。 LSB 的权重为
/2VREF/(PGA (223−1))。 正满量程输入会产生
输出代码7FFFFFh、负满量程
//输入会产生输出代码800000h。
如果(ADC_val > 0x7fff){//if MSB = 1
ADC_val =(16777215ul - ADC_val)+ 1;//do 2的补码
}
Serial.println (ADC_val);
}

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Alin、

    欢迎访问 TI E2E 论坛!

    使用 RDATAC 模式时需要注意的一点是、如果 MCU 无法快速读取数据、则很容易损坏数据。 发生的情况是、输出移位寄存器时钟输出数据将开始移出转换数据、但在此过程的中间、新的 ADC 转换完成、然后加载到该移位寄存器中。 其结果是您读取了一个损坏的结果、该结果是旧数据和新数据的组合。

    使用"RDATA"命令时、输出移位寄存器中的数据首先被缓冲、然后随时钟移出、以防止数据损坏。 因此、如果您的 MCU 无法快速响应/DRDY 中断并在下一个/DRDY 下降沿之前读取数据、则可能应使用 RDATA 命令来检索数据。

    为了测试这种情况是否确实如此、您可能会尝试降低输出数据速率、并查看输出数据完整性是否在更低的数据速率下得到改善。

    [引用 user="Alin Paun"]显然、这些寄存器设置不正确。 例如、在状态寄存器(0x00h)中写入0B00000001后、我将读回0而不是1。 为什么会这样?[/报价]

    关于此行为、状态寄存器的位0反映了/DRDY 引脚的状态、且该引脚为只读。 因此、您可能会读回与为该寄存器编程的结果不同的结果。

    [引用 user="Alin Paun"]此外、在 loop 函数中、我 是否以正确的方式连续读取 ADC 输出? 我是否遗漏了什么?[/引述]

    轮询/DRDY 是可以的、但如果可能、我会尝试实现/DRDY 下降沿中断、因为这通常比轮询速度快一点。

    关于数据格式、我建议将"ADC_val"设置为32位有符号整数、并简单地将有符号24位转换结果符号扩展到有符号32位数据类型中。 如果 MSB 为0、您只需查看最高有效位并在数据前添加一个额外的"0x00";如果 MSB 为1、则在数据前添加"0xFF"。

    此致、
    Chris

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    显然,我毕竟在读取一个登记册的过程中遗漏了一些东西。 根据 RREG 的时序图(数据表第31页顶部)、RREG 命令和数据请求之间必须出现等于 T6的延迟。 我在第1个帖子中发布的代码中错过了该延迟。 此外,我通过执行  spi.transfer (register_values)而不是  register_values= spi.transfer (0)来请求错误的数据。  现在、一切正常、我获得以下输出:

    状态寄存器值:
    接收:110000
    
    控制寄存器值:
    预期:0
    接收:0
    
    数据速率寄存器值:
    预期:11110000
    接收:11110000
    
    多路复用器寄存器值:
    预期:1111
    接收:1111
    
    已配置 ADC、连接中断
    

    如上所示、数据速率设置为 max 输出速率、即30kSPS。
    遗憾的是、串行监视器中的干扰仍然与之前以30kSPS 运行时的干扰相同。

    13451
    11234
    3667930 <-干扰
    3684890 <- 毛刺
    脉冲13540
    8817
    8539
    10400
    11970
    12013
    10797
    7612
    7774
    8519
    9311
    12377
    11000
    12283
    10557
    7618
    7561
    13645
    12240
    7590
    10393
    9836
    9599
    9158
    9582
    9497
    9564
    13705
    12662
    15112
    11116
    7191
    6132
    7784
    10656
    9640
    15089 15393 16734 1897 1397 1397 1395 1395 13705 1296 1896 1897 13192 13192 13192 13192 13192 13192 13192 13192 13192 13192 13192 13192 13192 13192 13192 13
    
    
    
    
    
    
    
    
    
    
    
    
    10893
    16876
    16560
    13794
    9830
    10799
    12213
    11915
    11972
    11491
    12462
    14596
    12919
    8567
    11307
    11115
    10402
    6334
    3503
    5102
    8721
    13790
    11200
    9905
    12333
    13817
    13270
    14175
    17417
    19000
    16631
    
    10038
    12735
    12860
    3559
    10500
    13251
    379946干扰<-
    
    
    ———8137 3138 6365 12365 12365 1273 1273 1276 1276 1276 1276 1276 1276 1276 1276 1276 1296
    
    
    
    

    但是,如果我切换到较低的速率,正如 克里斯托弗所说的,我一点也不会有任何干扰:)
    我想用于 Arduino IDE 的 ESP32的 SPI 驱动程序与此相关、对于 max 而言、速度有点慢 ADC 的输出数据速率。  

    下面是我使用的代码。 我有:
    1.已切换到 var 的 uint32_t  
    2. 通过执行一个/DRDY 下降沿中断来处理 DRDY 事件
    3.注释了 var 转换结构,以减少延迟,并在串行控制台中获得原始输出。  

    但设置似乎仍无法处理30kSPS。 要获得完整的30kSPS、是否还有改进的余地?

    代码:

    #include 
    #include 
    
    #define SCK 14
    #define MOSI 12
    #define MISO 27
    #define DRDY 26
    #define CS 5
    
    
    #define SPISPEED 1800000
    #define CLKIN 7680000 //7.68MHz (外部晶振频率)
    
    #define WREG 0x50
    #define RDATA 0x01
    #define RDATAC 0x03
    #define RREG 0x10 #define REGATE
    SDATAC_INTOP_32 #define
    
    INTACT_ENABLE
    
    //将读数
    int outpin = 19;//引脚
    int inputpin = 25中的运算放大器数据;//运算放大器数据输出引脚
    字节 opAmpData;
    字节 register_Values;
    字节 buf[24];
    
    //根据数据表第6页应该处于50倍时 CLKIN (主时钟)周期
    int T6 = round (CLKIN)(* 1000000)* 1 *浮点;//根据数据表第6页
    
    int 计数器= 0;
    unsigned long start_time;
    
    AD8555运算放大器(outpin、inputpin);
    
    void setup()
    {
    Serial.begin(2000000);
    
    if (enable_op_AMP_Setup){
    //Start--------------- 运算放大器设置---
    
    //获取第二级增益代码
    serial.println ("输入第二级增益代码(0..7)");
    //等待用户输入值
    while (!Serial.available ());
    
    //设置第二级增益代码
    if (!opamp.setSecondStageGain(Serial.parseInt ()){
    //如果代码超出范围,运算放大器将返回 false
    serial.println ("第二级增益代码无效。 有效范围为0..7");
    返回;
    }
    
    
    //第一级增益代码
    serial.println ("输入第一级增益代码(0..127)");
    while (!Serial.available ());
    
    if (!opamp.setFirstStageGain(Serial.parseInt ()){
    serial.println ("第一级增益代码无效。 有效范围为0..127");
    返回;
    }
    
    
    //偏移代码
    serial.println ("输入偏移代码(0..255)");
    while (!Serial.available ());
    if (!opamp.setOffset(Serial.parseInt ()){
    serial.println ("偏移代码无效。 有效范围为0..255");
    返回;
    }
    
    //编程模式
    serial.println ("选择编程模式:输入"0\"进行仿真、输入"1\"进行永久编程");
    
    while (!Serial.available ());
    int mode = Serial.parseInt();
    如果(MODE = 0){
    //模拟模式
    OPAMP.Simulate();
    serial.println ("完成!");
    } 如果(MODE = 1){
    //永久编程模式
    serial.println ("确保满足 AD8555数据表中描述的编程要求:");
    serial.println ("需要5.5V 电源");
    serial.println ("电源必须能够提供250mA 的电流");
    serial.println ("-器件电源引脚上需要至少0.1uF 的去耦电容);
    
    serial.println ("\n 警告:此操作无法撤消、所有编程值都是永久性的");
    serial.println ("继续吗? [Y/N]");
    
    while (!Serial.available ());
    if (Serial.read ()='y'){
    opamp.program();
    serial.println ("编程...完成");
    } 否则{
    serial.println ("操作已取消");
    }
    }
    opAmpData = opamp.ReadData (PAR_SSG_code);
    serial.println ("OP-Amp offset code=");
    serial.println (opAmpData、bin);
    //完成--- 运算放大器设置--------------------------------}-->
    
    
    
    
    引脚模式(MISO、INPUT_PULLUP);
    引脚模式(MOSI、输出);
    引脚模式(SCK、 输出);
    pinMode (CS、输出);
    pinMode (DRDY、输入);
    
    //init SPI 总线
    延迟(500);
    SPI.begin(SCK、MISO、MOSI、CS); //启动 SPI 总线
    延迟(500);
    
    
    
    while (digitalRead (DRDY)){}//等待 READY_LINE 变为低电平
    SPI.beginTransaction(SPISettings(SPISPEED、MSBFIRST、SPI_MODE1);//启动 SPI
    
    //发送 SDATAC 命令
    SPI.transfer (SDATAC);
    delayMicroseconds (100);
    
    //将
    
    
    
    SPI transfer (SPI_MODE1
    
    )设置为低电平;//将 SPI transfer (
    
    SPI)(SPI)(sbot.transfer (SPI)(SPI)(SPI)(sbotelf.delayMicro 秒)(SPI.beginTransaction(SPISettings(SPISPEED);// //开始 SPI
    
    字节 STATUS_reg = 0x00;//状态寄存器的地址(数据表第30页)
    字节 STATUS_DATA = 0B0000001;
    //000 0 0 0 1
    //000 -出厂编程标识位
    //0 -设置 MSB 传输
    //0 -自动校准禁用
    //0 -缓冲器禁用
    //1 - DRDY 引脚
    SPI.transfer (WREG | STATUS_reg)的重复状态;
    SPI.transfer (0x00);//第二个命令字节、仅写入一个寄存器
    SPI.transfer (STATUS_DATA); //将数据字节写入寄存
    器 delayMicroseconds (10);
    
    
    register_values = 0;
    Serial.println ("状态寄存器值:");
    spi.transfer (RREG | STATUS_reg);
    spi.transfer (0x00);//第二个命令字节,只读一个寄存器
    delayMicroseconds (T6);
    register_values = spi.transfer (0x00);
    
    sery.print.bin
    (Serial received);"(Serial);print register 0);
    
    
    //PGA 设置
    //1±5V
    //2±2.5V
    //4±1.25V
    //8±0.625V
    //16±312.5mV
    // 32±156.25mV
    // 64±78.125mV
    
    字节 adcon_reg = 0x02;//A/D 控制寄存器地址:0x02
    字节 adcon_data = 0B00000000;
    // 0 00 00 000
    // 0始终保留0
    // 00 -时钟输出关闭
    // 00 -传感器锁定关闭
    // 000 - PGA 增益= 1
    SPI.transfer (WREG | adcon_reg);
    SPI.transfer (0x00);//第二个命令字节,只写一个寄存器
    SPI.transfer (adcon_data);//将数据库写入微
    秒(10);
    
    register_values = 0;
    Serial.println ("控制寄存器值:");
    spi.transfer (RREG | adcon_reg);
    spi.transfer (0x00);//第二个命令字节,只读一个寄存器
    delayMicroseconds (T6);
    register_values = spi.transfer (0);
    
    Serial.print ("预期:");
    Serial.printn、printature.data (tprintn);
    serial.print ("已接收:");
    serial.println (register_values、bin);
    
    
    字节 drate_reg = 0x03;//数据速率寄存器地址:0x03
    字节 maxSampleRate = 0B11110000;
    //将
    数据速率设置为 max (30000 SPS)
    byte minSampleRate = 0B00000011;
    // 00000011
    //将数据速率设置为最小值(2.5SPS)
    SPI.transfer (WREG | drate_reg);
    SPI.transfer (0x00);//第二个命令字节,只写入一个寄存器
    SPI.transfer (maxSampleRate);//将数据库写入寄存器:
    
    
    
    "SPI
    transfer (rature.rate");"SPI transfer (
    0x00)"(rature_seconds);"SPI transfer (rature.rature.rate"(SPI);"SPI transfer (rature.r.r.rature.rate"(r.r.r //第二个命令字节,只读一个寄存器
    delayMicroseconds (T6);
    register_values = spi.transfer (0);
    
    Serial.print ("预期:");
    Serial.println (maxSampleRate,bin);
    serial.print ("已接收:");
    serial.println (register_values、bin);
    
    
    字节 mux_reg = 0x01;//Mux 寄存器(地址01h)
    字节 mux_data = 0B00001111;
    // 0000 1111
    // 0000 - AIN0 (默认)
    // 1111 - AINCOM
    SPI.transfer (WREG | mux_transfer);//
    仅限一个 SPI 命令/ SPI transfer (byte);/SPI 命令0x00
    //将数据字节写入寄存
    器 delayMicroseconds (10);
    
    register_Values = 0;
    Serial.println ("Mux 寄存器值:");
    spi.transfer (RREG | mux_reg);
    spi.transfer (0x00);//第二个命令字节,只读一个寄存器
    delayMicroseconds (T6);
    register_values = SPI (sery.transfer (0x00);
    
    //串行
    数据 print.bin (0);
    serial.print ("已接收:");
    serial.println (register_values、bin);
    
    //sync 命令1111 1100
    spi.transfer (0xFC);
    delayMicroseconds (10);
    
    //wake0000
    spi.transfer (0x00);
    delayMicroseconds (10);
    
    
    
    while (DRRead (DRDDRDnT)(DRDtnT)
    
    
    
    
    
    
    
    
    (031n);tSPI)、tidtintran1 (SPI)、t1)、tinrupt/SPI (tidt1)、tintran1)、t1 (SPI.beginTransaction(SPISettings(SPISPEED)、inrupt/delt1 (datn_transfer (t/SPI)、intract/SPI)、insh/ t/tidt.transfer (tidt/t/t.transfer (tidt/SPI)、intract/t/t/t/tidt. samplpleADC、Falling);
    
    }
    
    
    void loop()
    {
    
    }
    
    void samplpleADC(){
    
    SPI.beginTransaction(SPISettings(SPISPEED、MSBFIRST、SPI_MODE1);//启动 SPI
    var = SPI.transfer (0);
    var <<= 8;//向左移动
    var |= SPI.transfer (0);
    var <<= 8;
    var |= SPI.transfer (spi.transfer (end);
    
    
    // if (var > 0x7ffff){//if MSB = 1
    // var =(16777215ul - var)+ 1;// do 2的补码
    //}
    sery.println (var、DEC);
    }
    

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Alin、

    "T6"延迟时间的好赶上!

    我不确定您能以多快的速度制作代码、但以下是一些值得尝试的建议...

    1.  尽量避免,或至少减少向控制台打印数据的频率。

      串行打印功能可能会很慢、因此如果您可以避免调用它、我会这么做。 但是、如果您需要将数据从控制台获取、我建议将数据存储到阵列中(例如大小为10或20)、并且仅在阵列已满时批量将数据打印到控制台。 这样,您将最大限度地减少执行串行打印所需的开销时间。

    2. 如果您还没有为 ADS1256使用最快的 SCLK 频率、那么我会增加您的 SCLK 频率以更快地读取数据。 SCLK 可高达1/4 ADC 的时钟频率(因此、当使用7.68MHz ADC 时钟时为1.92MHz)。


    3. 这可能起作用、也可能不起作用、但可以尝试使用"RDATA"命令读取集合循环中的数据。

      使用"RDATA"的优点是有助于防止在/DRDY 下降沿读取数据时数据损坏。 但是、这还需要发送额外的 SPI 字节、这会进一步降低读取操作的速度。 因此、随着时间的推移、如果您的读取操作无法保持30kSPS 数据速率、您可能会开始丢失数据。

    此致、
    Chris