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

206 阅读14分钟

一、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
  • 模块特点:内部集成高精度温度传感器

模块应用

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

二、模块引脚说明

CSCS片选
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 的工作模式、输入选择、数据速率、满量程范围和温度传感器模式。

名字读写类型初始值描述
15SS读/写0h单次转换启动:此位用于启动单次转换。SS 只能在断电状态下写入,转换进行时无效。写入时:0 = 无影响;1 = 启动单次转换(断电状态下);始终读取为 0(默认值)。
14~12MUX读/写0h输入多路复用器配置,这些位用于配置输入多路复用器。
11~9PGA读/写2h可编程增益放大器配置,这些位用于配置可编程增益放大器。
8MODE读/写1h设备工作模式:此位控制 ADS1118 的工作模式。0 = 连续转换模式 1 = 断电和单次转换模式(默认)。
7~5DR读/写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
4TS_MODE读/写0h温度传感器模式:此位配置 ADC 以转换温度信号或输入信号。0 = ADC 模式(默认);1 = 温度传感器模式
3PULL_UP_EN读/写1h上拉使能位:仅当 CS 为高电平时,此位才启用 DOUT/DRDY 引脚上的弱上拉电阻。启用后,一个 400 kΩ 的内部电阻将总线连接到电源。禁用时,DOUT/DRDY 引脚悬空。0 = DOUT/DRDY 引脚上的上拉电阻禁用;1 = DOUT/DRDY 引脚上的上拉电阻启用(默认值)。
2~1NOP读/写1hNOP[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显示屏。

引脚接线

STM32F103C8T6ADS1118
PA0SCLK
PA1DIN
PA2CS
PA3DOUT
PB8SCL
PB9SDA

代码示例

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电压。