zoukankan      html  css  js  c++  java
  • ADS1256使用心得及其驱动编写 [原创www.cnblogs.com/helesheng]

    最近培训学生做大学生电子设计竞赛,有学生用到TI的24位Sigma-delta模数转换器ADS1256。虽然这款芯片在能找到的介绍性文章很多,但大多属于简单翻译手册,很多实际问题没有提及。现在电子设计竞赛结束了,将学生在用STM32调试中遇到各种问题以及我的解决办法总结如下,以方便在未来的工程项目中使用,同时与各位网友共享。

    以下原创内容欢迎网友转载,但请注明出处: https://www.cnblogs.com/helesheng

    一、差分驱动电路

    ADS1256具有差分输入能力,可以产生二进制补码输出,这让很多学生误以为ADS1256支持双极性输入,想从模拟输入端输入±5V范围的模拟电压。其实ADS1256与AD7606这样真正支持双极性(Bipolar Input)输入的模数转换器是不一样的:当你细看数据手册时就会发现,其每个模拟输入管脚的绝对输入电压(Absolute input voltage)只能在0到电源电压之间,能够达到负电压输入的是输入的差分电压(AINP减去AINN的值)——即输入为负值是指AINN大于AINP的电压,而此时AINN和AINP的绝对值都是正电压

    ADS1256的数据手册并未给出驱动电路,原因是ADS1256这类的高分辨率ADC经常用来对电桥等差分输入的传感器进行测量,其内部含有的可编程差分放大器(PGA)还可以对这类传感器的输入进行程控放大。但更常见的情况是:你需要的是对真正的双极性单端信号(只有一根信号线,其值相对于地有可能是正电压,也有可能是负电压)进行测量,那么你就需要通过运算放大器将单端的双极性信号转换为双端的差分信号。但常见的差分ADC的驱动办法无非有二:

    1、使用专用的差分驱动芯片,如TI的INA132、INA216,ADI的ADA4941、AD8138等等。关于这些芯片的使用,读者可以参考其数据手册,这里不再赘述。专用差分驱动芯片的优点在于增益(GAIN)和共模抑制比(CMRR),非常准确;缺点是小众芯片供货不稳定且价格较高。

    2、我自己设计了以下差分驱动电路:

    图1

    上图中所有的电阻,除实现滤波的R11和R12之外,全部为100KΩ,精度为千分之一。运算放大器由单极性低压轨到轨输入输出(RIRO)运放构成,我是用了国产的低成本运放RS622,你也可以使用MCP6002、AD8632或OPA2335等进口型号,由于ADS1256的输入阻抗极高,你甚至可以使用更低成本的LMV358替代。双极性单端信号从接插件CNT输入。

    图1所示的电路对双极性单端信号(图中蓝色虚线)完成的变换如图2所示。图1下半部分的反向放大电路对蓝色信号首先缩小为原来的一半;其次增加2.5V的偏置,使其变为图2中绿色的信号(图1中网络标号为IN_N_B)。图1上半部分的电路再次对绿色的信号反相得到图2中的红色信号。这样ADS1256的差分输入端对红色和绿色信号求差时,就可以恢复蓝色虚线所示的单端双极性信号,且红色和绿色信号的绝对电压都在0~5V之间。

    图2 

    不熟悉模拟电路的读者会问:为什么要让图1的运放N4B的同相端连接到5V的2/3电位?请读者回忆模拟电路课程学习过的叠加原理:将电路的两个输入端(信号端Ain和+5V输入端)分别接到0电位,在将两种情况下电路的输出叠加在一起,就可以得到电路在Ain和+5V同时输入时的输出。其中为达到将信号缩小为原来的一半的目的,R5、R6、R7构成的负反馈通路的增益为1/2;而同相输入端(管脚5)的电势将决定图2绿色信号叠加的直流偏置,具体来说根据叠加原理,绿色信号叠加的直流偏置等于同相端电压的3/2倍(反馈通路的增益,对于同相输入的电压为3/2)。这样只有当R8、R9、R10构成的分压电路对5V的分压比为1/3时,在输出端得到的绿色信号直流偏置才为 (1/3)*(3/2)*5V = 2.5V。

    图1上部,由运放N4A为主构成的反向放大电路的增益为-1,其工作点为R3、R4产生的2.5V。其产生如图2所示的红色信号。

    图1所示电路的偏置(OFFSET)、增益(GAIN)和共模抑制比(CMRR)全部由电阻R1~R10决定,为保证ADS1256的精度,这些电阻全部选用了100K@1‰的电阻。这种精度显然无法达到24bits绝对精度的要求,不过索性的是对于连续采样最看重的信噪比(SNR、THD)和信号动态范围(ENOB)却没有损失。这个电路适合高分辨率音响、模式识别等应用,以及具有出厂整机校准环节的采集系统。

    另外,这里之所以串联使用两只一样的100KΩ@1‰电阻串联,是为了获得精确的获得一只100KΩ@1‰阻值的两倍。且使用一样的电阻,有利于高精度电阻供应链的管理。

    使用上述差分驱动电路后,我的初始化代码如下所示:

     1 AD_RST = 0; //复位ADS1256
     2     AD_RST = 1;
     3     while(ADS1256_DRDY);//当前转换完成才能进一步配置
     4     ADS1256WREG(ADS1256_STATUS,0x06);               // 高位在前、使用缓冲
     5     ADS1256WREG(ADS1256_ADCON,ADS1256_GAIN_1);                // 增益为1
     6     ADS1256WREG(ADS1256_DRATE,ADS1256_DRATE_1000SPS);  // 数据1ksps
     7     ADS1256WREG(ADS1256_IO,0x00);               
     8     while(ADS1256_DRDY);//当前转换完成才能进一步配置
     9     CS_0();
    10     SPI_WriteByte(ADS1256_CMD_SELFCAL); //自校准
    11     while(ADS1256_DRDY);
    12     CS_1();
    13     temp = (chp << 4)|(chn + 1);//chp为同相输入,chn为反相输入
    14     ADS1256WREG(ADS1256_MUX,temp);        //设置通道
    15     CS_0();
    16     SPI_WriteByte(ADS1256_CMD_SYNC);
    17     SPI_WriteByte(ADS1256_CMD_WAKEUP);    
    18     CS_1();
    初始化代码

    二、Sigma-Delta模数转换器的特点及其对驱动程序的影响

    本质上说Sigma-Delta模数转换器是一个数字器件,其执行的是一个有限长冲击响应滤波器(FIR),包含一系列复杂的乘加运算,需要较长的计算时间。这一本质造成的影响包括:

    1、Sigma-Delta转换器处理时间较慢,采样率较低;且存在一次转换的输出的“潜伏期”,数据手册提供的时序图如下。

    图3

    请注意我用红色圈住的部分,当你的代码在本次转换开始时DRDY变低后,将输入通道配置为AINP=AIN2,AINN=AIN3时,当前这次输出的结果将仍然是上个通道配置的结果(MUX = 01h)。这需要在进行多通道轮流采样的应用中得到足够的重视。实际上由于FIR滤波器是一个与过去的输出高度相关的因果系统,Sigma-Delta转换器并不特别适合实现多通道轮换采样的任务(这比较适合使用逐次逼近SAR式的模数转换器)。而TI公司的ADS12xx系列Sigma-Delta也是市面上能够看到的进行通道切换后,能够最快速度达到所需精度的模数转换器。下表是ADS1256数据手册中给出的在不同输出速度下切换通道后的建立时间(以转换周期为单位)。

     

    2、进行通道轮换时的采样率

    很多小伙伴想当然的认为在数据率寄存器(DRATE,03h)里配置的数据率就是所有情况下的采样率。其实当你知道Sigma-Delta器件内部的FIR滤波器本质时你就会知道,当你进行通道切换并重新对器件进行同步(synchronize)和唤醒(wakeup)后,转换速度会变慢。具体来讲,实际采样率和你配置的通过率之间的对应关系如数据手册中的下表所示。

     直接说人话——当你使用网上到处能找到的下面的代码启动每次转换时,你只能获得上表右列所示的转换速度。

    1 ADS1256WREG(ADS1256_MUX,temp);        
    2 SPI_WriteByte(ADS1256_CMD_SYNC);
    3 SPI_WriteByte(ADS1256_CMD_WAKEUP);
    4 SPI_WriteByte(ADS1256_CMD_RDATA);
    5 UN_sum |= (SPI_WriteByte(0xff) << 16);
    6 UN_sum |= (SPI_WriteByte(0xff) << 8);
    7 UN_sum |= SPI_WriteByte(0xff);
    错误的连续转换代码

    因为上面的代码头两句进行同步和唤醒后,ADS1256会以为你切换了通道,需要多用一点时间来时滤波器稳定下来。要获得DRATE寄存器所需的采样率,你必须做到:1)只对一个通道进行采样,不切换输入通道配置;2)在每次读取采样结果时,只使用上面后边四句代码,将通道配置的那句代码放在采集开始之前一次性完成。

    三、ADS1256在使用中广泛出现的问题及其解决办法

    1、ADS1256 在继电器工作的时候自动复位问题的解决

    TI官网问答论坛(https://e2echina.ti.com/support/data-converters/f/data-converters-forum/114019/ads1256)和阿莫电子论坛(https://www.amobbs.com/thread-5484227-1-1.html)中都多次提到ADS1256等多个知名论坛中都出现讨论ADS1256会在电磁继电器等干扰条件下出现自动复位的现象(自动复位后采样率会自动切换到30KSPS),我在使用中也观察到了这个现象,但TI官方及其FAE都未对此问题作出正面回应。仔细阅读手册后发现ADS1256的复位脚RESET的复位时间非常短,仅为4个时钟周期(7.68M晶振下仅0.5us数量级),且没有连接施密特触发器输入滤波。

     我用STM32的GPIO控制RESET管脚亦无法避免自动复位现象,最后我在距离RESET非常近的地方,在RESET和地之间连接了一只低ESR的1uF瓷片电容,解决了干扰条件下自动复位问题

    图4

    2、读写操作时序问题及其实现

    1)读数据指令

    ADS1256有两条度指令:读数据RDATA(01h)和连续读数据指令RDATAC(03h)。读数据指令是在每次数据转换完成后(DRDY信号变低电平),后发送一个RDATA(01h) 在读取本次输出的24bits结果;连续度数据指令是在发送一次RDATAC(03h)后,即可在每次DRDY信号变低后都直接读取24bits结果,但需要在退出连续读取指令时发送退出连续读取指令SDATAC(0Fh)。

    个人觉得ADS1256转换速度较慢,如果使用STM32作为控制器,没必要省去每次发送一个指令字节的时间,因此我倾向于使用读数据指令RDATA,以降低代码的复杂程度。

    2)指令后读取等待时间t6

    不论使用读数据指令RDATA,还是连续读数据指令RDATAC指令都需要在发送指令后等待t6的延迟时间才能够读出转换时间,根据数据手册t6约为50个ADS1256时钟周期(在7.68M时钟下,略小于1us)。若使用51内核的MCU,基本可以不考虑刻意为t6进行延时处理,但对STM32而言,若不专门为t6进行延迟,则有可能造成后续读取的第一个位(MSB)为错误位。因此连续读取固定采样率的代码应如下所示:

    1 SPI_WriteByte(ADS1256_CMD_RDATA);
    2 delay_us(2);//指令后的等待时间
    3 UN_sum |= (SPI_WriteByte(0xff) << 16);
    4 UN_sum |= (SPI_WriteByte(0xff) << 8);
    5 UN_sum |= SPI_WriteByte(0xff);
    6 delay_us(2);//读取后等待DRDY管脚恢复时间

    3)读取后的等待DRDY管脚恢复时间

    每次ADS1256转换完成后,会使DRDY管脚输出低电平,以提示STM32来读取本次转换结果。STM32如果能够在下一次转换完成刷新结果寄存器之前将本次转换结果读走,DRDY管脚将恢复高电平提示STM32等待下一次转换结果。不幸的是,STM32的速度相对于ADS1256太快,以至于读走数据后DRDY管脚还来不及恢复高电平,STM32就有可能再次检测到DRDY管脚为低电平,而认为需要再次读取转换结果,从而造成同一个结果被连续读取两次。而这一现象在ADS1256的数据手册中并未正式提及,也没有用给出DRDY转换为高电平的延迟时间。我尝试性的在读取24bits转化结果后,加入了2us的延迟时间(如上面的代码最后一行所示),解决了同一个结果被STM32连续读取两次的现象。

    4)SPI时钟速度

    ADS1256手册要求的SPI最短时钟周期为4个ADS1256工作时钟,也就是最高为1~2MHz。对于51系列单片机而言,不可能超过这个极限,对STM32而言就需要尤其注意SPI时钟的配置,我是用了APB2总线的64分频作为SPI通信时钟频率。

  • 相关阅读:
    SpringBoot(三)SpringApplication启动类准备阶段
    SpringBoot(四)SpringApplication启动类运行阶段 SpringApplicationRunListener
    201871010104陈园园 《面向对象程序设计(java)》第八周学习总结 陈园园
    201871010104陈园园 《面向对象程序设计(java)》第十周学习总结 陈园园
    201871010104陈园园 《面向对象程序设计(java)》第四周学习总结 陈园园
    201871010104陈园园 《面向对象程序设计(java)》第二周学习总结 陈园园
    《2019面向对象程序设计(java)课程学习进度条》 陈园园
    201871010104陈园园 《面向对象程序设计(java)》第七周学习总结 陈园园
    201871010104陈园园 《面向对象程序设计 (java)》第一周学习总结 陈园园
    201871010104陈园园 《面向对象程序设计(java)》第六——七周学习总结 陈园园
  • 原文地址:https://www.cnblogs.com/helesheng/p/15583047.html
Copyright © 2011-2022 走看看