STM32H7教程第93章 STM32H7的SPI总线应用之驱动ADS1256(8通道24bit ADC, 增益可编程)

Posted 安富莱电子

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了STM32H7教程第93章 STM32H7的SPI总线应用之驱动ADS1256(8通道24bit ADC, 增益可编程)相关的知识,希望对你有一定的参考价值。

完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980

第93章       STM32H7的SPI总线应用之驱动ADS1256(8通道24bit ADC, 增益可编程)

本章节为大家讲解8通道24bit ADC芯片驱动实现。

93.1 初学者重要提示

93.2 ADC结构分类

93.3 ADS1256硬件设计

93.4 ADS1256关键知识点整理(重要)

93.5 ADS1256驱动设计

93.6 ADS1256板级支持包(bsp_spi_ads1256)

93.7 ADS1256实际测试效果(10uV抖动)

93.8 ADS1256驱动移植和使用

93.9 实验例程设计框架

93.10 实验例程说明(MDK)

93.11 实验例程说明(IAR)

93.12 总结

 

 

93.1 初学者重要提示

  1.   ADS1256的模拟部分供电5V,SPI数字接口电平3.3V。
  2.   ADS1256的PGA可以编程增益支持: 1、2、4、8、16、32、64。
  3.   ADS1256支持自动校准 (当设置了PGA,BUF使能、数据采样率时,会启动自校准)。
  4.   ADS1256支持8通道单端ADC采集或者4通道差分采集。
  5.   ADS1256支持正负5V差分采集,但不支持负压,使用时要注意。
  6.   ADS1256时序操作稍有点特殊,所以本章是采用的模拟SPI控制。
  7.   ADS1256数据手册,模块原理图(通用版)和接线图都已经放到本章教程配置例子的Doc文件里。
  8.   ADC 的专业术语诠释文档,推荐大家看看:http://www.armbbs.cn/forum.php?mod=viewthread&tid=89414
  9.   测试时,务必使用外置电源为开发板供电,因为ADS1256需要5V供电电压。板子上插入ADS1256模块时,注意对齐。

93.2 ADC结构分类

这里将六种DAC结构为大家做个普及。注,这些知识翻译自美信和TI的英文技术手册。

 

 

93.2.1 SAR ADC(逐次逼近型)

逐次逼近型ADC通常是中高分辨率的首选架构,采样速率通常低于5Msps。SAR ADC最常见的分辨率范围是8位到20位,并具有低功耗和小尺寸的特点。这种组合使其非常适合各种应用,例如自动测试设备,电池供电的设备,数据采集系统,医疗仪器,电机和过程控制,工业自动化,电信,测试和测量,便携式系统,高速闭环系统和窄带接收器。

93.2.2 Sigma-Delta ADC

Sigma-delta ADC主要用于低速应用中,该应用需要通过过采样来权衡速度和分辨率,然后进行滤波以降低噪声。24位sigma-delta转换器用于自动化测试设备,高精度便携式传感器,医疗和科学仪器以及地震数据采集等应用中。

93.2.3 Integrating ADC

集成ADC提供高分辨率,并且可以提供良好的线路频率和噪声抑制。集成架构提供了一种新颖且直接的方法,可将低带宽模拟信号转换为数字表示形式。这些类型的转换器通常包括用于LCD或LED显示器的内置驱动器,并且在许多便携式仪器应用中都可以找到,包括数字面板表和数字万用表。

93.2.4 FLASH ADC

Flash ADC是将模拟信号转换为数字信号的最快方法。它们适用于需要非常大带宽的应用。然而,闪存转换器功率高,具有相对较低的分辨率,并且可能非常昂贵。这将它们限制在通常无法以其他任何方式解决的高频应用中。示例包括数据采集,卫星通信,雷达处理,示波器和高密度磁盘驱动器。

93.2.5 Pipelined ADC

流水线ADC已成为最受欢迎的ADC体系结构,其采样率从每秒几兆采样(MS / s)到最高100MS / s +,分辨率为8至16位。它们提供的分辨率和采样率,可覆盖各种应用,包括CCD成像,超声医学成像,数字接收器,基站,数字视频(例如HDTV),xDSL,电缆调制解调器和快速以太网。

93.2.6 Two Step ADC

两步ADC也称为子范围转换器,有时也称为多步或half flash(比Flash架构慢)。这是Flash ADC和流水线ADC的交叉点。与Flash ADC相比,可以实现更高的分辨率或更小的裸片尺寸。

93.3 ADS1256硬件设计

这里将开发板上的ADS1256硬件接口,ADS1256模块为大家做个说明。

ADS1256的原理图论坛下载:

http://www.armbbs.cn/forum.php?mod=viewthread&tid=97547

93.3.1 ADS1256硬件接口

V7板子上ADS1256模块的插座的原理图如下:

 

实际对应开发板的位置如下:

 

为了方便大家更好的理解接线,下面是框图:

 

93.3.2 ADS1256模块

产品规格:

1、 单电源5.0V DC供电,提供正负5V信号采样功能。

2、 MCU接口:SPI。

3、 主ADC芯片:ADS1256  (全新进口原装正品)。

4、 电压基准,之前采用的LM285-2.5,现在采用的REF5025(全新进口原装正品)。

5、 输入电路带分压电阻和R-C滤波,方便客户自己变更增益范围。

6、 芯片内带可编程增益放大器,增益范围:1-64倍。

7、 芯片内部输入带缓冲放大器,可以直接连接传感器。

正面:

 

 

反面:

 

 

接线图:

 

 

93.4 ADS1256关键知识点整理(重要)

驱动ADS1256需要对下面这些知识点有个认识。

93.4.1 ADS1256基础信息

ADS1256是TI公司推出的微功耗、高精度、8通道、 24位△-∑型高性能模数转换器(ADC)。该器件提供高达23比特的无噪声精度、数据速率高达30kSPS(次采样/秒)、0.0010%非线性特性(最大值)以及众多的板上外设(输入模拟多路开关、输入缓冲器、可编程增益放大器和可编程数字滤波器等),可为设计人员带来完整而高分辨率的量测解决方案。

  •   24位无数据丢失;
  •   高达23比特的无噪声精度;
  •   低非线性度: ±0.0010% ;
  •   数据采样率可达30kSPS ;
  •   采用单周期转换模式;
  •   带有模拟多路开关,具有传感器接口(可配置为4路差动输入或8路单极输入) ;
  •   带有输入缓冲器( BUF) ;
  •   带有串行外设接口( SPI) ;
  •   内含低噪声可编程增益放大器( PGA ) ,所有的PGA均具有自校准和系统校准;
    •  PGA= 1时,可提供高达25.3位的有效分辨率;
    •  PGA = 64时,可提供高达22.5位的有效分辨率;
  •   模拟输入电压为5V ,数字电压为1.8~3.6V ;
  •   正常模式下功耗低至38mW ,备用模式下功耗为0.4mW。

93.4.2 ADS1256常用引脚的作用

ADS1256的封装形式:

 

 

这里把常用的几个引脚做个说明:

  •   AVDD

模拟电源供电。

  •   AGND

模拟地。

  •   VREFN

负参考电压输入。

  •   VREFP

正参考电压输入。

  •   AINCOM

模拟公共输入。

  •   AIN0 – AIN7

模拟输入通道0到通道7

  •   SYNC/PDWN

同步,掉电输入。

  •   RESET

复位引脚。

  •   DVDD

数字电源。

  •   DGND

数字地。

  •   XTAL1,XTAL2

晶振输入端。

  •   CS

片选输入端。

  •   DRDY

数据就绪输出信号引脚。

  •   DOUT

数据输出。

  •   DIN

数据输入。

  •   SCLK

时钟引脚。

  •   D0,D1,D2,D3

通用GPIO

93.4.3 ADS1256输出电压计算公式

ADS1256的计算公式如下:

 

 

最小单位值是2 * VREF/(PGA * (2^23 − 1))

采用二进制补码表示(其实就是24bit有符号数,我们将转换结果定义为int32_t即可)。

93.4.4 ADS1256时序图

驱动ADS1256主要是两个时序图需要了解,读写时序:

 

 

  •   t1:SPI时钟周期:

外部晶振频率 = 7.68MHz,

              时钟频率 tCLK = 1/7.68M = 0.13uS

              输出数据周期 tDATA =  1 / 30K = 0.033mS  (按30Ksps计算)

       对SPI的时钟速度要求:

              最快 4个tCLK = 0.52uS

              最慢 10个tDATA = 0.3mS (按 30Ksps 计算)

 

 

 

  •   t2H,t2L :脉冲高低电平:

SCL高电平和低电平持续时间最小 200ns。

 

 

数据读取流程:

 

 

  •   第1步:ADS1256_SetChannal(g_tADS1256.Channel)切换模拟通道。
  •   第2步:发送SYNC同步命令。
  •   第3步:唤醒。
  •   第4步:读取数据。

这个过程中特别注意读取的是上次转换的数据。

93.4.5 ADS1256的增益和测量范围问题

ADS1256的增益和测量范围关系如下:

 

 

比如增益是1时,测量范围是正负5V,增益是64时,测量范围是正负78.125mV。

93.4.6 ADS1256输入缓冲器

开关输入缓冲器时,影响到的几个参数,大家需要做个了解。

开缓冲的情况下,输入参考值噪声。

 

 

关闭缓冲时的输入参考噪声:

 

 

开缓冲的情况下,有效分辨率:

 

 

关闭缓冲时的有效位数:

 

 

打开缓冲器后的输入阻抗:

 

 

 

关闭缓冲器后的输入阻抗:

 

 

 

93.4.7 ADS1256支持的采样率

ADS1256支持的采样率如下,这里特别注意,因为切换通道和读数据耗时 123微秒, 因此扫描中断模式工作时,最大速率 = DRATE_1000SPS。

 

 

93.4.8 ADS1256的多路选择器,单端和多端输入

ADS1256的8路支持是通过多路选择器实现,8路采样时是选择相应通道进行采样:

 

 

实际应用的的8路单端采样和4路差分采样效果如下:

 

 

93.5 ADS1256驱动设计

ADS1256的程序驱动框架设计如下:

 

有了这个框图,程序设计就比较好理解了。

93.5.1 第1步,ADS1256所涉及到的GPIO配置

这里需要把用到的GPIO时钟、GPIO引脚配置好:

/*
    ADS1256模块    STM32-V7开发板(示波器接口)
      +5V   <------  5.0V      5V供电
      GND   -------  GND       地
      DRDY  ------>  PC6       准备就绪
      CS    <------  PC7       SPI_CS
      DIN   <------  PG10      SPI_MOSI
      DOUT  ------>  PA5       SPI_MISO
      SCLK  <------  PA4       SPI时钟
      GND   -------  GND       地
      PDWN  <------  PB7       掉电控制
      RST   <------  PC3       复位信号
      NC   空脚
      NC   空脚
*/

#ifdef SOFT_SPI        /* 软件SPI */
    /* 定义GPIO端口 */    
    #define SCK_CLK_ENABLE()     __HAL_RCC_GPIOA_CLK_ENABLE()
    #define SCK_GPIO            GPIOA
    #define SCK_PIN            GPIO_PIN_4
    #define SCK_1()            SCK_GPIO->BSRR = SCK_PIN
    #define SCK_0()            SCK_GPIO->BSRR = ((uint32_t)SCK_PIN << 16U)    

    #define DIN_CLK_ENABLE()     __HAL_RCC_GPIOG_CLK_ENABLE()
    #define DIN_GPIO            GPIOG
    #define DIN_PIN            GPIO_PIN_10
    #define DIN_1()            DIN_GPIO->BSRR = DIN_PIN
    #define DIN_0()            DIN_GPIO->BSRR = ((uint32_t)DIN_PIN << 16U)    

    #define CS_CLK_ENABLE()     __HAL_RCC_GPIOC_CLK_ENABLE()
    #define CS_GPIO            GPIOC
    #define CS_PIN            GPIO_PIN_7
    #define CS_1()            CS_GPIO->BSRR = CS_PIN
    #define CS_0()            CS_GPIO->BSRR = ((uint32_t)CS_PIN << 16U)    

    #define DOUT_CLK_ENABLE()     __HAL_RCC_GPIOA_CLK_ENABLE()
    #define DOUT_GPIO            GPIOA
    #define DOUT_PIN            GPIO_PIN_5
    #define DOUT_IS_HIGH()        ((DOUT_GPIO->IDR & DOUT_PIN) != 0)

    #define DRDY_CLK_ENABLE()     __HAL_RCC_GPIOC_CLK_ENABLE()
    #define DRDY_GPIO            GPIOC
    #define DRDY_PIN            GPIO_PIN_6
    #define DRDY_IS_LOW()        ((DRDY_GPIO->IDR & DRDY_PIN) == 0)
    #define DRDY_IRQn             EXTI9_5_IRQn
    #define DRDY_IRQHandler        EXTI9_5_IRQHandler    

    /* PDWN  <------  PB7       掉电控制 */
    #define PWDN_CLK_ENABLE()     __HAL_RCC_GPIOB_CLK_ENABLE()
    #define PWDN_GPIO            GPIOB
    #define PWDN_PIN            GPIO_PIN_7
    #define PWDN_1()            PWDN_GPIO->BSRR = PWDN_PIN
    #define PWDN_0()            PWDN_GPIO->BSRR = ((uint32_t)PWDN_PIN << 16U)            
    
    /*  RST   <------  PC3       复位信号     */
    #define RST_CLK_ENABLE()     __HAL_RCC_GPIOC_CLK_ENABLE()
    #define RST_GPIO            GPIOC
    #define RST_PIN            GPIO_PIN_3
    #define RST_1()            RST_GPIO->BSRR = RST_PIN
    #define RST_0()            RST_GPIO->BSRR = ((uint32_t)RST_PIN << 16U)            
#endif

/*
*********************************************************************************************************
*    函 数 名: bsp_InitADS1256
*    功能说明: 配置STM32的GPIO和SPI接口,用于连接 ADS1256
*    形    参: 无
*    返 回 值: 无
*********************************************************************************************************
*/
void bsp_InitADS1256(void)
{
#ifdef SOFT_SPI
    GPIO_InitTypeDef gpio_init;
    
    RST_1();
    PWDN_1();
    CS_1();
    SCK_0();        /* SPI总线空闲时,钟线是低电平 */
    DIN_1();

    /* 打开GPIO时钟 */
    SCK_CLK_ENABLE();
    DIN_CLK_ENABLE();
    CS_CLK_ENABLE();
    DOUT_CLK_ENABLE();
    DRDY_CLK_ENABLE();
    PWDN_CLK_ENABLE();
    RST_CLK_ENABLE();

    /* 配置几个推完输出IO */
    gpio_init.Mode = GPIO_MODE_OUTPUT_PP;        /* 设置推挽输出 */
    gpio_init.Pull = GPIO_NOPULL;                /* 上下拉电阻不使能 */
    gpio_init.Speed = GPIO_SPEED_FREQ_HIGH;      /* GPIO速度等级 */        
    
    gpio_init.Pin = SCK_PIN;    
    HAL_GPIO_Init(SCK_GPIO, &gpio_init);    

    gpio_init.Pin = DIN_PIN;    
    HAL_GPIO_Init(DIN_GPIO, &gpio_init);    
    
    gpio_init.Pin = CS_PIN;    
    HAL_GPIO_Init(CS_GPIO, &gpio_init);    

    gpio_init.Pin = PWDN_PIN;    
    HAL_GPIO_Init(PWDN_GPIO, &gpio_init);    

    /* DRDY 设置为输入 */
    gpio_init.Mode = GPIO_MODE_INPUT;        /* 设置输入 */
    gpio_init.Pull = GPIO_NOPULL;            /* 上下拉电阻不使能 */
    gpio_init.Speed = GPIO_SPEED_FREQ_HIGH;      /* GPIO速度等级 */
    
    gpio_init.Pin = DRDY_PIN;    
    HAL_GPIO_Init(DRDY_GPIO, &gpio_init);    

    gpio_init.Pin = DOUT_PIN;    
    HAL_GPIO_Init(DOUT_GPIO, &gpio_init);    
#endif
}

这里重点注意DRDY转换就绪引脚的配置,DRDY_IRQn和DRDY_IRQHandler不要配置错了。

93.5.2 第2步,ADS1256的8bit读写函数实现

读写函数实现如下:

/*
*********************************************************************************************************
*    函 数 名: ADS1256_Send8Bit
*    功能说明: 向SPI总线发送8个bit数据。 不带CS控制。
*    形    参: _data : 数据
*    返 回 值: 无
*********************************************************************************************************
*/
static void ADS1256_Send8Bit(uint8_t _data)
{
    uint8_t i;

    /* 连续发送多个字节时,需要延迟一下 */
    ADS1256_DelaySCLK();
    ADS1256_DelaySCLK();

    /* ADS1256 要求 SCL高电平和低电平持续时间最小 200ns  */
    for(i = 0; i < 8; i++)
    {
        if (_data & 0x80)
        {
            DIN_1();
        }
        else
        {
            DIN_0();
        }
        SCK_1();                
        ADS1256_DelaySCLK();        
        _data <<= 1;        
        SCK_0();            /* <----  ADS1256 是在SCK下降沿采样DIN数据, 数据必须维持 50nS */
        ADS1256_DelaySCLK();        
    }
}

/*
*********************************************************************************************************
*    函 数 名: ADS1256_Recive8Bit
*    功能说明: 从SPI总线接收8个bit数据。 不带CS控制。
*    形    参: 无
*    返 回 值: 无
*********************************************************************************************************
*/
static uint8_t ADS1256_Recive8Bit(void)
{
    uint8_t i;
    uint8_t read = 0;

    ADS1256_DelaySCLK();
    /* ADS1256 要求 SCL高电平和低电平持续时间最小 200ns  */
    for (i = 0; i < 8; i++)
    {
        SCK_1();
        ADS1256_DelaySCLK();
        read = read<<1;
        SCK_0();
        if (DOUT_IS_HIGH())
        {
            read++;
        }        
        ADS1256_DelaySCLK();
    }
    return read;
}

读写的实现完全按照下面的时序实现:

 

 

这里主要注意时间实现:

t1:SPI时钟周期:

外部晶振频率 = 7.68MHz,

              时钟频率 tCLK = 1/7.68M = 0.13uS

              输出数据周期 tDATA =  1 / 30K = 0.033mS  (按30Ksps计算)

       对SPI的时钟速度要求:

              最快 4个tCLK = 0.52uS

              最慢 10个tDATA = 0.3mS (按 30Ksps 计算)

 

 

t2H,t2L :脉冲高低电平:

SCL高电平和低电平持续时间最小 200ns。

 

 

93.5.3 第3步,ADS1256的24bit ADC数据读取

实现代码如下:

/*
*********************************************************************************************************
*    函 数 名: ADS1256_ReadData
*    功能说明: 读ADC数据
*    形    参: 无
*    返 回 值: 无
*********************************************************************************************************
*/
static int32_t ADS1256_ReadData(void)
{
    uint32_t read = 0;

    CS_0();    /* SPI片选 = 0 */

    ADS1256_Send8Bit(CMD_RDATA);    /* 读数据的命令 */
    
    ADS1256_DelayDATA();    /* 必须延迟才能读取芯片返回数据 */

    /* 读采样结果,3个字节,高字节在前 */
    read = ADS1256_Recive8Bit() << 16;
    read += ADS1256_Recive8Bit() << 8;
    read += ADS1256_Recive8Bit() << 0;

    CS_1();    /* SPI片选 = 1 */
    
    /* 负数进行扩展。24位有符号数扩展为32位有符号数 */
    if (read & 0x800000)
    {
        read += 0xFF000000;
    }
    
    return (int32_t)read;
}

这段代码里面关键是24bit数据的补码处理。对负数进行扩展,24位有符号数扩展为32位有符号数。

93.5.4 第3步,ADS1256增益和采样率配置

代码如下:

/*
*********************************************************************************************************
*    函 数 名: ADS1256_CfgADC
*    功能说明: 配置ADC参数,增益和数据输出速率
*    形    参: _gain : 支持增益参数。
*                    ADS1256_GAIN_1
*                    ADS1256_GAIN_2    
*                    ADS1256_GAIN_4
*                    ADS1256_GAIN_8
*                    ADS1256_GAIN_16
*                    ADS1256_GAIN_32
*                    ADS1256_GAIN_64
*
*             _drate : 数据输出速率,不推荐超过1000SPS
*                    ADS1256_30000SPS
*                    ADS1256_15000SPS
*                    ADS1256_7500SPS
*                    ADS1256_3750SPS
*                    ADS1256_2000SPS
*                    ADS1256_1000SPS
*                    ADS1256_500SPS
*                    ADS1256_100SPS
*                    ADS1256_60SPS
*                    ADS1256_50SPS
*                    ADS1256_30SPS
*                    ADS1256_25SPS
*                    ADS1256_15SPS
*                    ADS1256_10SPS
*                    ADS1256_5SPS
*                    ADS1256_2d5SPS
*    返 回 值: 无
*********************************************************************************************************
*/
void ADS1256_CfgADC(ADS1256_GAIN_E _gain, ADS1256_DRATE_E _drate)
{    
    g_tADS1256.Gain = _gain;
    g_tADS1256.DataRate = _drate;
    
    ADS1256_StopScan();            /* 暂停CPU中断 */
    
    ADS1256_ResetHard();        /* 硬件复位 */

    ADS1256_WaitDRDY();

    {
        uint8_t buf[4];        /* 暂存ADS1256 寄存器配置参数,之后连续写4个寄存器 */
    
        buf[0] = (0 << 3) | (1 << 2) | (1 << 1);
        
        buf[1] = 0x08;    /* 高四位0表示AINP接 AIN0,  低四位8表示 AINN 固定接 AINCOM */

        buf[2] = (0 << 5) | (0 << 2) | (_gain << 1);

        /* 因为切换通道和读数据耗时 123uS, 因此扫描中断模式工作时,最大速率 = DRATE_1000SPS */
        buf[3] = s_tabDataRate[_drate];    // DRATE_10SPS;    /* 选择数据输出速率 */
        
        CS_0();    /* SPI片选 = 0 */
        ADS1256_Send8Bit(CMD_WREG | 0);    /* 写寄存器的命令, 并发送寄存器地址 */
        ADS1256_Send8Bit(0x03);            /* 寄存器个数 - 1, 此处3表示写4个寄存器 */
        
        ADS1256_Send8Bit(buf[0]);    /* 设置状态寄存器 */
        ADS1256_Send8Bit(buf[1]);    /* 设置输入通道参数 */
        ADS1256_Send8Bit(buf[2]);    /* 设置ADCON控制寄存器,增益 */
        ADS1256_Send8Bit(buf[3]);    /* 设置输出数据速率 */
        
        CS_1();    /* SPI片选 = 1 */        
    }

    bsp_DelayUS(50);    
}

这个函数主要配置了4个ADS1256寄存器。

  •   设置状态寄存器:

 

 

程序中的配置为:buf[0] = (0 << 3) | (1 << 2) | (1 << 1) ,意思是LSB传输,自动校准,使能模拟输入缓冲。

  •   设置输入通道参数

 

 

程序中的配置为:buf[1] = 0x08, 高四位0表示AINp接通的 AIN0,  低四位8表示 AINn接通的 AINCOM。AINp和AINn表示当前的多路选择器选通的AIN0:

 

 

  •   设置ADCON控制寄存器,主要用于增益设置

 

 

程序中的配置为:buf[2] = (0 << 5) | (0 << 2) | (_gain << 1), 意思是关闭CLKOUT引脚输出,关闭传感器检测,设置增益为形参_gain。

  •   设置ADC采样率

 

 

程序中的配置为:buf[3] = s_tabDataRate[_drate],用于设置波特率:

static const uint8_t s_tabDataRate[ADS1256_DRATE_MAX] = 
{
    0xF0,        /* 复位时缺省值 */
    0xE0,
    0xD0,
    0xC0,
    0xB0,
    0xA1,
    0x92,
    0x82,
    0x72,
    0x63,
    0x53,
    0x43,
    0x33,
    0x20,
    0x13,
    0x03
};
typedef enum
{
    ADS1256_30000SPS = 0,
    ADS1256_15000SPS,
    ADS1256_7500SPS,
    ADS1256_3750SPS,
    ADS1256_2000SPS,
    ADS1256_1000SPS,
    ADS1256_500SPS,
    ADS1256_100SPS,
    ADS1256_60SPS,
    ADS1256_50SPS,
    ADS1256_30SPS,
    ADS1256_25SPS,
    ADS1256_15SPS,
    ADS1256_10SPS,
    ADS1256_5SPS,
    ADS1256_2d5SPS,
    
    ADS1256_DRATE_MAX
}ADS1256_DRATE_E;

93.5.5 第4步,ADS1256启动采样

代码实现如下

/*
*********************************************************************************************************
*    函 数 名: ADS1256_StartScan
*    功能说明: 将 DRDY引脚 (PC6 )配置成外部中断触发方式, 中断服务程序中扫描8个通道的数据。
*    形    参: 无
*    返 回 值: 无
*********************************************************************************************************
*/
void ADS1256_StartScan(void)
{
    /* PC6 外部中断,BUSY 
        配置 BUSY 作为中断输入口,下降沿触发 */
    {
        GPIO_InitTypeDef   GPIO_InitStructure;
        
        DRDY_CLK_ENABLE();    /* 打开GPIO时钟 */

        GPIO_InitStructure.Mode = GPIO_MODE_IT_FALLING;
        GPIO_InitStructure.Pull = GPIO_NOPULL;
        GPIO_InitStructure.Pin = DRDY_PIN;
        HAL_GPIO_Init(DRDY_GPIO, &GPIO_InitStructure);    

        HAL_NVIC_SetPriority(DRDY_IRQn, 2, 0);
        HAL_NVIC_EnableIRQ(DRDY_IRQn);    
    }
    
    /* 开始扫描前, 清零结果缓冲区 */    
    {
        uint8_t i;
        
        g_tADS1256.Channel = 0;
        
        for (i = 0; i < 8; i++)
        {
            g_tADS1256.AdcNow[i] = 0;
        }    
    }
}

代码比较简单,主要是配置PC6的EXTI外部中断,并初始化变量。

93.5.6 第5步,ADS1256的中断处理(8通道数据读取)

代码如下:

/*
*********************************************************************************************************
*    函 数 名: EXTI9_5_IRQHandler
*    功能说明: 外部中断服务程序.  此程序执行时间约 123uS
*    形    参:无
*    返 回 值: 无
*********************************************************************************************************
*/
#ifdef EXTI9_5_ISR_MOVE_OUT        /* bsp.h 中定义此行,表示本函数移到 stam32f4xx_it.c。 避免重复定义 */
void EXTI9_5_IRQHandler(void)
{
    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_6);
}

/*
*********************************************************************************************************
*    函 数 名: EXTI9_5_IRQHandler
*    功能说明: 外部中断服务程序入口。PI6 / AD7606_BUSY 下降沿中断触发
*    形    参: 无
*    返 回 值: 无
*********************************************************************************************************
*/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    if (GPIO_Pin == GPIO_PIN_6)
    {

        ADS1256_ISR();
    }
}
#endif

/*
*********************************************************************************************************
*    函 数 名: ADS1256_ISR
*    功能说明: 定时采集中断服务程序
*    形    参: 无
*    返 回 值: 无
*********************************************************************************************************
*/
void ADS1256_ISR(void)
{
    /* 读取采集结构,保存在全局变量 */                    
    ADS1256_SetChannal(g_tADS1256.Channel);    /* 切换模拟通道 */    
    bsp_DelayUS(5);
    
    ADS1256_WriteCmd(CMD_SYNC);
    bsp_DelayUS(5);
    
    ADS1256_WriteCmd(CMD_WAKEUP);
    bsp_DelayUS(25);
    
    if (g_tADS1256.Channel == 0)
    {
        g_tADS1256.AdcNow[7] = ADS1256_ReadData();    /* 注意保存的是上一个通道的数据 */
    }
    else
    {
        g_tADS1256.AdcNow[g_tADS1256.Channel-1] = ADS1256_ReadData(); /* 注意保存的是上一个通道的数据 */
    }
                
    if (++g_tADS1256.Channel >= 8)
    {
        g_tADS1256.Channel = 0;
    }
}

中断服务程序的代码完全是按照下面的时序时序:

 

 

  •   第1步:ADS1256_SetChannal(g_tADS1256.Channel)切换模拟通道。
  •   第2步:发送SYNC同步命令。
  •   第3步:唤醒。
  •   第4步:读取数据。

这个过程中特别注意读取的是上次转换的数据。

93.6 ADS1256板级支持包(bsp_spi_ads1256.c)

ADS1256驱动文件bsp_spi_ads1256.c主要实现了如下几个API供用户调用:

  •   bsp_InitADS1256
  •   ADS1256_CfgADC
  •   ADS1256_StartScan
  •   ADS1256_SetChannal
  •   ADS1256_SetDiffChannal

93.6.1 函数bsp_InitADS1256

函数原型:

void bsp_InitADS1256(void)

函数描述:

主要用于ADS1256的初始化。

93.6.2 函数ADS1256_CfgADC

函数原型:

void ADS1256_CfgADC(ADS1256_GAIN_E _gain, ADS1256_DRATE_E _drate)

函数描述:

用于配置ADS1256的增益和采样率。

函数参数:

  •   第1个参数用于设置增益,支持的参数如下:

ADS1256_GAIN_1

ADS1256_GAIN_2     

ADS1256_GAIN_4

ADS1256_GAIN_8

ADS1256_GAIN_16

ADS1256_GAIN_32

ADS1256_GAIN_64

  •   第2个参数用于设置采样率,支持的参数如下:

ADS1256_30000SPS

ADS1256_15000SPS

ADS1256_7500SPS

ADS1256_3750SPS

ADS1256_2000SPS

ADS1256_1000SPS

ADS1256_500SPS

ADS1256_100SPS

ADS1256_60SPS

ADS1256_50SPS

ADS1256_30SPS

ADS1256_25SPS

ADS1256_15SPS

ADS1256_10SPS

ADS1256_5SPS

ADS1256_2d5SPS

93.6.3 函数ADS1256_StartScan

函数原型:

void ADS1256_StartScan(void)

函数描述:

此函数用于启动扫描,采样的中断方式。

93.6.4 函数ADS1256_SetChannal

函数原型:

static void ADS1256_SetChannal(uint8_t _ch)

函数描述:

此函数用于设置单端采样的通道。

函数参数:

  •   第1个参数支持0到7,0表示采样的通道0, 1表示采样的通道1,依次类推,范围0-7,共8个通道。

 

93.7 ADS1256实际测量效果(10uV抖动)

测试LM285-2.5V稳压效果,抖动40uV:

 

 

测试干电池效果,抖动10uV左右,注意,这个级别的抖动容易受环境温度的影响,特别是开关空调,最明显。

 

 

93.8 ADS1256驱动移植和使用

移植步骤如下:

  •   第1步:复制bsp_spi_ads1256.c和bsp_spi_ads1256.h到自己的工程目录,并添加到工程里面。
  •   第2步:根据使用的SPI引脚,DRDY就绪引脚,RST复位引脚,修改bsp_spi_ads1256.c开头的宏定义。
/* 定义GPIO端口 */    
#define SCK_CLK_ENABLE()     __HAL_RCC_GPIOA_CLK_ENABLE()
#define SCK_GPIO            GPIOA
#define SCK_PIN                GPIO_PIN_4
#define SCK_1()                SCK_GPIO->BSRR = SCK_PIN
#define SCK_0()                SCK_GPIO->BSRR = ((uint32_t)SCK_PIN << 16U)    

#define DIN_CLK_ENABLE()     __HAL_RCC_GPIOG_CLK_ENABLE()
#define DIN_GPIO            GPIOG
#define DIN_PIN                GPIO_PIN_10
#define DIN_1()                DIN_GPIO->BSRR = DIN_PIN
#define DIN_0()                DIN_GPIO->BSRR = ((uint32_t)DIN_PIN << 16U)    

#define CS_CLK_ENABLE()     __HAL_RCC_GPIOC_CLK_ENABLE()
#define CS_GPIO                GPIOC
#define CS_PIN                GPIO_PIN_7
#define CS_1()                CS_GPIO->BSRR = CS_PIN
#define CS_0()                CS_GPIO->BSRR = ((uint32_t)CS_PIN << 16U)    

#define DOUT_CLK_ENABLE()     __HAL_RCC_GPIOA_CLK_ENABLE()
#define DOUT_GPIO            GPIOA
#define DOUT_PIN            GPIO_PIN_5
#define DOUT_IS_HIGH()        ((DOUT_GPIO->IDR & DOUT_PIN) != 0)

#define DRDY_CLK_ENABLE()     __HAL_RCC_GPIOC_CLK_ENABLE()
#define DRDY_GPIO            GPIOC
#define DRDY_PIN            GPIO_PIN_6
#define DRDY_IS_LOW()        ((DRDY_GPIO->IDR & DRDY_PIN) == 0)
#define DRDY_IRQn             EXTI9_5_IRQn
#define DRDY_IRQHandler        EXTI9_5_IRQHandler    

/* PDWN  <------  PB7       掉电控制 */
#define PWDN_CLK_ENABLE()     __HAL_RCC_GPIOB_CLK_ENABLE()
#define PWDN_GPIO            GPIOB
#define PWDN_PIN            GPIO_PIN_7
#define PWDN_1()            PWDN_GPIO->BSRR = PWDN_PIN
#define PWDN_0()            PWDN_GPIO->BSRR = ((uint32_t)PWDN_PIN << 16U)            

/*  RST   <------  PC3       复位信号     */
#define RST_CLK_ENABLE()     __HAL_RCC_GPIOC_CLK_ENABLE()
#define RST_GPIO            GPIOC
#define RST_PIN                GPIO_PIN_3
#define RST_1()                RST_GPIO->BSRR = RST_PIN
#define RST_0()                RST_GPIO->BSRR = ((uint32_t)RST_PIN << 16U)    
  •   第3步:特别注意中断服务程序的入口要根据使用的DRDY引脚修改。
/*
*********************************************************************************************************
*    函 数 名: EXTI9_5_IRQHandler
*    功能说明: 外部中断服务程序.  此程序执行时间约 123uS
*    形    参:无
*    返 回 值: 无
*********************************************************************************************************
*/
#ifdef EXTI9_5_ISR_MOVE_OUT        /* bsp.h 中定义此行,表示本函数移到 stam32f4xx_it.c。 避免重复定义 */
void EXTI9_5_IRQHandler(void)
{
    HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_6);
}

/*
*********************************************************************************************************
*    函 数 名: EXTI9_5_IRQHandler
*    功能说明: 外部中断服务程序入口。PI6 / AD7606_BUSY 下降沿中断触发
*    形    参: 无
*    返 回 值: 无
*********************************************************************************************************
*/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    if (GPIO_Pin == GPIO_PIN_6)
    {

        ADS1256_ISR();
    }
}
#endif
  •   第4步:应用方法看本章节配套例子即可。

93.9 实验例程设计框架

通过程序设计框架,让大家先对配套例程有一个全面的认识,然后再理解细节,本次实验例程的设计框架如下:

 

 

  第1阶段,上电启动

以上是关于STM32H7教程第93章 STM32H7的SPI总线应用之驱动ADS1256(8通道24bit ADC, 增益可编程)的主要内容,如果未能解决你的问题,请参考以下文章

STM32H7教程第14章 STM32H7的电源,复位和时钟系统

STM32H7教程第39章 STM32H7的DMAMUX基础知识(重要)

STM32H7教程第49章 STM32H7的FMC总线应用之SDRAM

STM32H7的DSP教程第33章 STM32H7不限制点数FFT实现

STM32H7教程第89章 STM32H7的CAN FD总线基础之前世今生

STM32H7的DSP教程第33章 STM32H7不限制点数FFT实现