基于STM32F103驱动ADS1118 16位 ADC模块采集四单端 两差分信号

一、ADS1118模块简介

  ADS111x是一款精密、低功耗、16位DELTA-SIGMA(∆-Σ)模数转换器(ADC),提供测量采用超小型VSSOP-10封装的传感器最常见信号所需的所有功能。ADS111x集成了可编程增益放大器(PGA)、电压基准、振荡器;其中ADS1115带数字比较器输出;ADS1118带高精度温度传感器。这些功能以及2V至5.5V的宽电源电压范围,使得ADS111x 非常适合功率受限和空间受限的传感器测量应用。
  ADS111x数据转换速率最高可达每秒860次采样(SPS)。PGA的 输入范围为士256MV至±6.144V,能够以高分辨率测量大信号和小信号。该器件通过输入多路复用器(MUX)测量双路差分输入或四路单端输入。ADS1118高精度温度传感器用于系统级温度监控或对热电偶进行冷结点补偿。

特性

  • 模块供电:2-5.5V
  • 通讯接口:SPI串行通讯
  • 静态功耗:<1mA(仅供参考)
  • 输入通道数:4通道单端或2通道差分,分时采样
  • PGA输入范围:±256mV至±6.144V,软件切换量程
  • 分辨率:16位
  • 最大采样率:860 SPS
  • 模块特点:内部集成高精度温度传感器

模块应用

  • 温度测量:热电偶测量、冷结点补偿、热敏电阻测量
  • 便携式仪表
  • 工厂自动化和过程控制

二、模块引脚说明

CS CS片选
SCLK 串行时钟输入
DIN 串行数据输入
DOUT 数据输出与数据就绪

三、功能框图与读写时序分析

  ADS1118 的一次“数据传输周期”有两种常见形式:32-bit 周期(同时写配置并回读配置)和 16-bit 周期(短读,仅读转换结果)。

  32-bit 周期:在一个 32 位数据传输周期中,数据由四个字节组成:两个字节用于转换结果,另外两个字节用于读取配置寄存器。设备始终先读取最高有效位 (MSB)。如图 40 所示,在一个传输周期内,将相同的配置寄存器设置写入两次。如果方便,可以在传输周期的前半段写入一次配置寄存器设置,然后在周期的后半段将 DIN 引脚保持低电平(如图 41 所示)或高电平。如果不需要更新配置寄存器,则在整个传输周期内将 DIN 引脚保持低电平或高电平。在 32 位传输周期的前两个字节中写入的配置寄存器设置,将在同一周期的最后两个字节中读取。

  16-bit 周期:如果不需要读取配置寄存器数据,ADS1118 转换数据也可以通过一个较短的 16 位数据传输周期输出,如图 42 所示。因此,在第 16 个 SCLK 周期之后,必须将 CS 置高。将 CS 置高会复位 SPI 接口。下次将 CS 置低时,数据传输开始,在第一个 SCLK 上升沿读取当前缓存的转换结果。如果在数据读取开始时 DOUT/DRDY 为低,则转换缓冲区已更新为新结果。否则,如果 DOUT/DRDY 为高,则读取上一个数据传输周期的结果。

四、ADS1118的寄存器说明

  ADS1118 有两个可通过 SPI 接口访问的寄存器。转换寄存器存储上次转换的结果。配置寄存器允许用户更改 ADS1118 的工作模式并查询器件状态。
  转换寄存器:16 位转换寄存器以二进制补码格式存储上次转换的结果。上电后,转换寄存器被清零,并保持为 0,直到第一次转换完成。

  配置寄存器:16 位配置寄存器可用于控制 ADS1118 的工作模式、输入选择、数据速率、满量程范围和温度传感器模式。

名字 读写类型 初始值 描述
15 SS 读/写 0h 单次转换启动:此位用于启动单次转换。SS 只能在断电状态下写入,转换进行时无效。写入时:0 = 无影响;1 = 启动单次转换(断电状态下);始终读取为 0(默认值)。
14~12 MUX 读/写 0h 输入多路复用器配置,这些位用于配置输入多路复用器。
11~9 PGA 读/写 2h 可编程增益放大器配置,这些位用于配置可编程增益放大器。
8 MODE 读/写 1h 设备工作模式:此位控制 ADS1118 的工作模式。0 = 连续转换模式 1 = 断电和单次转换模式(默认)。
7~5 DR 读/写 4h 数据速率:这些位控制数据速率设置。000 = 8 SPS;001 = 16 SPS;010 = 32 SPS;011 = 64 SPS;100 = 128 SPS(默认);101 = 250 SPS;110 = 475 SPS;111 = 860 SPS
4 TS_MODE 读/写 0h 温度传感器模式:此位配置 ADC 以转换温度信号或输入信号。0 = ADC 模式(默认);1 = 温度传感器模式
3 PULL_UP_EN 读/写 1h 上拉使能位:仅当 CS 为高电平时,此位才启用 DOUT/DRDY 引脚上的弱上拉电阻。启用后,一个 400 kΩ 的内部电阻将总线连接到电源。禁用时,DOUT/DRDY 引脚悬空。0 = DOUT/DRDY 引脚上的上拉电阻禁用;1 = DOUT/DRDY 引脚上的上拉电阻启用(默认值)。
2~1 NOP 读/写 1h NOP[1:0] 位控制是否将数据写入配置寄存器。要将数据写入配置寄存器,NOP[1:0] 位必须为“01”。任何其他值都会导致 NOP 命令。在 SCLK 脉冲期间,DIN 可以保持高电平或低电平,而不会将数据写入配置寄存器。01=数据有效,其他为数据无效。
0 保留 1h 保留位。向此位写入 0 或 1 均无效。始终读取为 1。

五、数据输出格式与电压换算

  ADS1118 以二进制补码格式提供 16 位数据。正满量程输入产生 7FFFh 的输出码,负满量程输入产生 8000h 的输出码。对于超过满量程的信号,输出将截断至这些码值。表 5 总结了不同输入信号的理想输出码。图 39 显示了码转换与输入电压的关系。

采集数据与电压转换
  ADS1118 输出 16-bit 有符号整数,范围 -32768 .. +32767。MSB 为符号位(负数以二补表示),ADC 的物理量程由 PGA/FSR 设置决定(例如 ±6.144V、±2.048V 等),每个 LSB 对应的电压 = FSR / 32768(注意分母是 32768 = 2^15)。
  即电压 = 16-bit有符号整数 x LSB,LSB大小由设置的量程决定。量程和比例系数如下:

六、STM32F103驱动ADS1118采集信号

准备工作

  STM32F103C8T6最小系统板,ADS1118 ADC模块,OLED显示屏。

引脚接线

STM32F103C8T6 ADS1118
PA0 SCLK
PA1 DIN
PA2 CS
PA3 DOUT
PB8 SCL
PB9 SDA

代码示例

ads1118.c

#include "stm32f10x.h"
#include "ads1118.h"
#include "delay.h"

void ADS1118_Init(void)    //ADS1118初始化
{
    uint16_t config = ADS1118_CONFIG_SS_START_OFF |  // 
                    ADS1118_CONFIG_MODE_CONTIN  |  //连续转换模式 
                    ADS1118_CONFIG_DR_128SPS   |  // 转换 速率 SPS
                    ADS1118_CONFIG_TS_MODE_ADC |  // 读取ADC,而不是温度
                    ADS1118_CONFIG_PULL_UP_ON  |  //上拉电阻启用
                    ADS1118_CONFIG_NOP_VALID   |  // this is valid data (default)
                                        ADS1118_CONFIG_PGA_6_144V  | // FSR is ±6.144 V
                                        ADS1118_CONFIG_MUX_SINGLE_0|  //AINP is AIN0 and AINN is GND//单端
                    ADS1118_CONFIG_RESV;          // reserved bits must be set to 1
    
    GPIO_InitTypeDef  GPIO_InitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);    //使能端口时钟

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2;              
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;         //推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;         //推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    CS_H;
    MISO_H;
    SCLK_L;
    MOSI_L;
    
    Write_ADS1118(config,1);//设置ads1118
}

/*******************************************************************************
//函数名称:ADS_SEL_Read()
//函数功能:读取各路电压,通过两个switch选择读取不同的通道
//输    入:road:增益放大器两端的电压选择,并选择测几路电压
//          Ref: 选择参考电压,有6种选择
//          mode: 是否更新读回数据 0读回 1不读回
//输    出:dat:16位ad转换数据
//备    注:这一次读出的转换数据是上一次的转换数据,不要混淆.这里选择的是单次
            转换电压值,当然,也可以选择多次转换,通过寄存器的第8位可以设置
*******************************************************************************/
int16_t ADS_SEL_Read(uint8_t road,uint8_t Ref,uint8_t mode)         //测几路电压
{
    int dat = 0;
        uint16_t config = ADS1118_CONFIG_SS_START_OFF |  // 
                    ADS1118_CONFIG_MODE_CONTIN  |  //连续转换模式 
                    ADS1118_CONFIG_DR_128SPS   |  // 转换 速率 SPS
                    ADS1118_CONFIG_TS_MODE_ADC |  // 读取ADC,而不是温度
                    ADS1118_CONFIG_PULL_UP_ON  |  //上拉电阻启用
                    ADS1118_CONFIG_NOP_VALID   |  // this is valid data (default)
                    ADS1118_CONFIG_RESV;          // reserved bits must be set to 1
    switch(road)       //选择有效转换的路数
    {
            case 0:  config |= ADS1118_CONFIG_MUX_DIFF_0_1;break;    //AINP = AIN0 and AINN = AIN1 (default)
            case 1:  config |= ADS1118_CONFIG_MUX_DIFF_0_3;break;    //AINP = AIN0 and AINN = AIN3
            case 2:  config |= ADS1118_CONFIG_MUX_DIFF_1_3;break;    //AINP = AIN1 and AINN = AIN3
            case 3:  config |= ADS1118_CONFIG_MUX_DIFF_2_3;break;    //AINP = AIN2 and AINN = AIN3
            case 4:  config |= ADS1118_CONFIG_MUX_SINGLE_0;break;    //AINP = AIN0 and AINN = GND
            case 5:  config |= ADS1118_CONFIG_MUX_SINGLE_1;break;    //AINP = AIN1 and AINN = GND
            case 6:  config |= ADS1118_CONFIG_MUX_SINGLE_2;break;    //AINP = AIN2 and AINN = GND
            case 7:  config |= ADS1118_CONFIG_MUX_SINGLE_3;break;    //AINP = AIN3 and AINN = GND
            default : break;
    }
    switch(Ref)
    {
            case 0:  config |= ADS1118_CONFIG_PGA_6_144V;break;    //000 : FS = ±6.144V(1)
            case 1:  config |= ADS1118_CONFIG_PGA_4_096V;break;    //001 : FS = ±4.096V(1)
            case 2:  config |= ADS1118_CONFIG_PGA_2_048V;break;    //002 : FS = ±2.048V(1)
            case 3:  config |= ADS1118_CONFIG_PGA_1_024V;break;    //003 : FS = ±1.024V(1)
            case 4:  config |= ADS1118_CONFIG_PGA_0_512V;break;    //004 : FS = ±0.512V(1)
            case 5: case 6: case 7: config |= ADS1118_CONFIG_PGA_0_256V;break;    //005 : FS = ±0.256V(1)
            default : break;
    }
    dat = Write_ADS1118(config,mode);
    return dat;
}
/*******************************************************************************
//函数名称:Write_ADS1118()
//函数功能:设置1118寄存器
//输    入:config:寄存器配置
//          discardData: 是否更新读回数据 0读回 1不读回
//返    回: 16位ad转换数据
//备    注: 
*******************************************************************************/
int16_t Write_ADS1118(uint16_t config,uint8_t discardData)
{
    uint8_t i=0;
  static int16_t read=0;
    CS_L;
    if(discardData==0) 
    {
        read=0;
    }
    delay_us(1);
     for(i=0;i<16;i++)     // 循环16次 
    {       
        if(config & 0x8000)MOSI_H;
        else MOSI_L;
        config <<= 1;

        delay_us(1);
        SCLK_H;
        delay_us(1);
        SCLK_L;
        delay_us(1);
        
        if(discardData==0)
        {
            read<<=1;
            if(READ_MISO)read ++;
                
        }else{
            delay_us(2);
        }
    }
    CS_H;
    delay_us(2);
    CS_L;
//  SCLK_L;
//  MOSI_L;
//  MISO_H;
    return read;
}

main.c

#include "delay.h"
#include "sys.h"
#include "usart.h"
#include "stdlib.h"
#include "oled.h"
#include "ads1118.h"

int main(void)
{
    uint8_t i=0;
    char showLcd[30];
    char infoBackPC[64];
    int16_t value[4];
    float Volt_Value;

    SystemInit();
    delay_init(72);      //延时初始化
    uart_init(9600);   //串口初始化
    OLED_Init();
    delay_ms(100);
    
    ADS1118_Init();//ADS1118初始化
    OLED_ShowString(1, 5, "ADS1118");
    delay_ms(1000);
    OLED_Clear();

    while(1)
    {
        delay_ms(100);
        
        //四单端
        if(READ_MISO==0)
        {
            ///循环配置通道并读取
            value[i]=ADS_SEL_Read(i+4,0,0); //读取通道
            if(i==3) ADS_SEL_Read(4,0,1);//配置下一通道
            else ADS_SEL_Read(i+5,0,1);  //配置下一通道
            i++;
        }
        if(i==4)
        {
            i=0;

            Volt_Value = value[0]*ADS1118_CONST_6_144V_LSB_mV/1000; 
            sprintf(showLcd, "AIN0=%f",Volt_Value);
            OLED_ShowString(1, 1, showLcd);

            Volt_Value = value[1]*ADS1118_CONST_6_144V_LSB_mV/1000; 
            sprintf(showLcd, "AIN1=%f",Volt_Value);
            OLED_ShowString(2, 1, showLcd);
            
            Volt_Value = value[2]*ADS1118_CONST_6_144V_LSB_mV/1000; 
            sprintf(showLcd, "AIN2=%f",Volt_Value);
            OLED_ShowString(3, 1, showLcd);
            
            Volt_Value = value[3]*ADS1118_CONST_6_144V_LSB_mV/1000; 
            sprintf(showLcd, "AIN3=%f",Volt_Value);
            OLED_ShowString(4, 1, showLcd);
        
//          sprintf(infoBackPC, "AIN0=%f\r\nAIN1=%f\r\nAIN2=%f\r\nAIN3=%f\r\n\r\n",value[0]*ADS1118_CONST_6_144V_LSB_mV/1000,\
//                                                                                  value[1]*ADS1118_CONST_6_144V_LSB_mV/1000,\
//                                                                                  value[2]*ADS1118_CONST_6_144V_LSB_mV/1000,\
//                                                                                  value[3]*ADS1118_CONST_6_144V_LSB_mV/1000);         
//          printf("%s",infoBackPC);  //串口发送
        }
        
        
        //两差分,采集差分信号时需把ADS1118_Init函数的ADS1118_CONFIG_MUX_SINGLE_0改为ADS1118_CONFIG_MUX_DIFF_0_1
//      if(READ_MISO==0)
//      {
//          ///循环配置通道并读取
//          value[i]=ADS_SEL_Read(i,0,0); //读取通道
//          if(i==1) ADS_SEL_Read(0,0,1);//配置下一通道
//          else ADS_SEL_Read(i+3,0,1);  //配置下一通道
//          i++;
//      }
//      if(i==2)
//      {
//          i=0;
//          Volt_Value = value[0]*ADS1118_CONST_6_144V_LSB_mV/1000; 
//          sprintf(showLcd, "AIN01=%f",Volt_Value);        
//          OLED_ShowString(1,1,showLcd);
//          
//          Volt_Value = value[1]*ADS1118_CONST_6_144V_LSB_mV/1000; 
//          sprintf(showLcd, "AIN23=%f",Volt_Value);
//          OLED_ShowString(2,1,showLcd);
//  
////            sprintf(infoBackPC, "AIN0=%.6f\r\nAIN1=%.6f\r\n\r\n",value[0]*ADS1118_CONST_6_144V_LSB_mV/1000,value[1]*ADS1118_CONST_6_144V_LSB_mV/1000);
////            printf("%s",infoBackPC);  //串口发送
//      }
    }
}

效果展示

四单端输入:AIN0接GND,AIN1接3.30V,AIN2接1.81V,AIN3接1.20V 。
两差分输入:AIN0接3.30V,AIN1接2.47V,AIN2接1.20V,AIN3接1.81V。
注意:通道悬空不为0。

七、注意事项和常见问题

注意事项

(1)模块为低功耗模块,建议供电电源不超过5.5V。
(2)由于模块是高精度器件,为了避免不必要的干扰,建议使用线性电源供电。
(3)输出信号线建议尽量短,过长容易引入噪声信号。接触不良或劣质的线材可能导致信号衰减或者噪声过大。
(4)如需简单测试模块功能,建议搭配本店控制板使用,正确接线后给控制板供电即可实现信号采集显示。

常见问题

Q:ADS1115和ADS1118有什么区别?
A:ADS1118是SPI通信,内部集成了高精度温度传感器;ADS1115 是IIC通信,带数字比较器输出。

Q:最大可以测量多少电压?
A:最大测量电压为供电电压加0.3V。即理论最大测量电压为5.8V。

Q:比如给一个电压:2.1234V的一个电压让它去一直采集,它的结果是怎样的?数值会跳动吗?
A:数据肯定是有跳动的,这个不是单一条件决定的,电源纹波噪声,线材过长等因素都会对其造成影响。

Q:使用ADS111X和配套的主控板,用USB口供电,无法采集到5V的电压?
A:由于普遍的USB口的电压都是低于5V的,则ADS1118芯片的供电电压就会不足5V,这样就采集不了5V的电压,建议使用DC接口,5V 以上的供电,但是不可超过5.5V,这样就可以采集到5V的电压。

Q:ADS111X采集小电压信号不准,是什么情况?
A:可能是芯片内部(PGA)放大倍率配置过大,可根据自己要采集的信号范围合理设置芯片量程范围(PGA)。

Q:模块正常驱动后,没有接电压的管脚显示也有电压,正常吗?
A:模块默认是4通道一直采集的,在没有接入电压的时候也会采集到管脚上的浮空电压。可将管脚直接接地。即为0电压。

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容