详细配置说明:TI ADS1248/1247 24位ADC

ADS1248/1247介绍:

ADS1248是TI的一款 24位delta-sigma(ΔΣ) 、2KSPS、8通道(4通道差分)ADC芯片,通讯协议为SPI。可编程数据速率高达2ksps。低噪声PGA:48nVRMS在PGA=128。低漂移内部2.048-V参考值:10ppm/°C(最大值)。模拟电源:单极(2.7V至5.25V)和双极(±2.5V)工作。


ADS1248/1247寄存器讲解

提示:在配置寄存器前,默认已经配置好了硬件SPI,SPI的配置为主模式、全双工、数据位8位、CPOL = 0、CPHA为数据线的第一个变化沿、软件控制NSS、256分频、最高位先发送、TIMODE模式关闭、CRC关闭。作者使用的是STM32L433单片机,使用HAL库来编写,本文将详细阐述ADS1248各个寄存器以及注意事项。

ADS1248/1247一共有15个寄存器,寄存器列表如下:


提示:图上可以看到,寄存器的地址为0x00 - 0x0e,每个寄存器都是一个字节八位分别去配置ADC的功能。

  1. MUX0寄存器:此寄存器的[7:6]位为BSC位,此位用于配置输入电流的限位值,手册上说是烧毁检测电流源的设置,一般设置为00,[5:3]位为MUX_SP位,此位用于设置ADC的输入正通道,000-111分别对应AIN0-AIN7,默认为AIN0。[2:0]位为输入的负通道,此位也是000-111对应AIN0-AIN7通道。
  2. VBIAS寄存器:此寄存器用于配置ADC在通道上施加的偏置电压,偏置电压计算是 (AVDD + AVSS) / 2,默认此位不做配置
  3. MUX1寄存器:7位为CLKSTAT位,此位为只读,用于读取当前ADC使用的是外部还是内部振荡器,0为内部,1为外部。[6:5]此位用于是否打开内部参考,如果使用内部基准,此位需要打开设置为01.[4:3]此位用于选择内部引用还是外部引用,我们用的是内部,所以设置为10.[2:0]此位为一个监视器,用于将输入端在内部直接连接内部基准源或者温度测量单元上,我们没有使用监视器,设置为000.
  4. SYS0寄存器(此位非常重要!):[7]此位必须始终设置为0,手册上这样说,[6:4]此位用于设置内部增益PGA,000-111分别对应放大倍数1、2、4、8、16、32、64、128倍。[3:0]此位用于设置ADC的输出速率,0000-1000分别对应5、10、20、40、80、160、320、640、1000SPS,1001-1111对应2000SPS,一般我们如果要输出速率为2000SPS时设置为1111,当然1001也是可以的。
  5. OFC1/OFC1/OFC2寄存器:三个寄存器组成了ADC24位偏移校准字。24位字是两种补体格式,内部向左移以与ADC24位转换结果对齐。ADC在全比例操作前从转换结果中减去寄存器值。默认此位不做配置
  6. FSC0/FSC1/FSC2寄存器:三个寄存器组成了ADC24位全标度校准字。这个24位的字是直接的二进制字。ADC将寄存器值除以FSC寄存器400000h,得到校准的比例因子。在偏移校准后,ADC将比例因子乘以转换结果。当PGA设置改变时,经过后的FSC重置值自动加载。此位需要配置为0x400000,此位需要注意,要记得配置
  7. IDAC0寄存器:[7:4]此位只读,TI编程的位,用于版本标识。[3]此位用于设置DRDY/DOUT仅作为输出功能或时作为数据准备和数据输出功能。[2:0]此位用于使能两个励磁电流源(IDACs),可用于传感器激励,默认此位不做配置
  8. IDAC1寄存器:[7:4]此位为选择了第一励磁电流源的输出引脚,[3:0]此位为选择了第二励磁电流源的输出引脚,默认此位不做配置
  9. GPIOCFG/GPIODIR/GPIODAT寄存器:用于IO口扩展,因为此器件时SPI传输,可以通过单片机配置寄存器直接操作ADC上的IO口,用作IO口的扩展,默认此位不做配置

ADS1248/1247程序编写

ADS1248命令清单

写寄存器:


提示:手册说的很清楚,第一个命令字节:0100 rrrr,其中rrrr是要写入的第一个寄存器的地址。第二个命令字节:0000 nnnn,其中nnnn是要写入的字节数-1。字节(s):要写入寄存器的数据。
所以我们按照手册的方法来写:

static void ADS1248_WriteReg(uint8_t RegAddr,uint8_t *Buffer,uint8_t Length)
{   
    uint8_t Cmd[2];  
    ADS1248_CLR_CS;
    ADS1248_SET_START;
    HAL_Delay(20);
    /*ADS1248芯片手册规定的发送数据格式*/
    /*First Command Byte: 0100 rrrr
      where rrrr is the address of the first register to be written.*/
    Cmd[0] = ADS1248_CMD_WREG | (RegAddr & 0x0F);  
    /*Second Command Byte: 0000 nnnn, 
      where nnnn is the number of bytes to be written – 1*/
    Cmd[1] = (Length - 1) & 0x0F;
    /*指定向指定寄存器写入指定字节数据*/
    HAL_SPI_Transmit(&hspi3, Cmd, 2,HAL_MAX_DELAY);
    /*Byte(s): data to be written to the registers.*/
    HAL_SPI_Transmit(&hspi3, Buffer, Length,HAL_MAX_DELAY);
    HAL_Delay(20);
    ADS1248_SET_CS;
    ADS1248_CLR_START;
}

我们先定义一个cmd的数组,然后将CS片选拉低,START置高,然后进行数据的拼接,在第一个字节里发送0x04然后将要写的寄存器进行或操作,这样就完成了手册中说的前四个位是写命令,后四个位是要写的寄存器,后面跟着要给这个寄存器写的数据。

读寄存器:


提示:还是按照手册来,先进行数据拼接然后读出要的数据,这里TI给出的是:在读取寄存器数据时,不可能使用串行接口的全双工特性。例如,在读取VBIAS和MUX1数据时,不能发出SYNC命令,如图84所示。在读出寄存器数据期间发送的任何命令都将被忽略。因此,TI建议在读出寄存器数据时通过DIN发送nop。

void ADS1248_ReadReg(uint8_t RegAddr,uint8_t *Buffer,uint8_t Length)
{
    uint8_t Cmd[2];
    ADS1248_CLR_CS;
    ADS1248_SET_START;
    /*ADS1248芯片手册规定的发送数据格式*/
    /*First Command Byte: 0010 rrrr, 
      where rrrr is the address of the first register to read.*/
    Cmd[0] = ADS1248_CMD_RREG | (RegAddr & 0x0f);  
    /*Second Command Byte: 0000 nnnn, 
      where nnnn is the number of bytes to read –1*/
    Cmd[1] = (Length - 1) & 0x0f;
    /*发送读取指令*/
    HAL_SPI_Transmit(&hspi3,Cmd,2,HAL_MAX_DELAY);	
    /*接收数据*/	
    HAL_SPI_Receive(&hspi3, Buffer, Length, HAL_MAX_DELAY);		
    Cmd[0] = ADS1248_CMD_NOP;  
    /*接受数据时不能使用SPI的全双工,要发送nop,此为手册原句*/
    /*It is not possible to use the full-duplex nature of the 
      serial interface when reading out the register data. For
      example, a SYNC command cannot be issued when reading out the 
      VBIAS and MUX1 data, as shown in
      Figure 84. Any command sent during the readout of the register
      data is ignored. Thus, TI recommends sending
      NOPs through DIN when reading out the register data.*/
    HAL_SPI_Transmit(&hspi3, Cmd,1,HAL_MAX_DELAY); 
    HAL_Delay(20);
    ADS1248_SET_CS;
}

还是和写寄存器一样,先进行指令的拼接,然后通过SPI直接将数据读出来,读数据的时候持续发送nop,因为TI说了在读数据的时候不能进行写操作,否则命令将会被忽略。

配置ADS1248/1247寄存器:

    uint8_t Cmd = 0; 
    /*对ADC进行复位*/
    ADS1248_Reset();  																	     
    HAL_Delay(20);	      
    /*配置MUX0寄存器AIN0为正输入,AIN1为负输入*/
    Cmd = 0x08;/*0000 0001*/					
    ADS1248_WriteReg(ADS1248_MUX0,&Cmd,1);      
    /*配置MUX1使用内部2.048基准、打开内部基准源*/
    Cmd=0x30 ;/*0 01 00 000*/
    ADS1248_WriteReg(ADS1248_MUX1,&Cmd,1);            																								
    /*配置SYS0寄存器PGA为放大64倍,输出速率为20SPS*/
    Cmd=0x62;/*0 110 0010*/
    ADS1248_WriteReg(ADS1248_SYS0,&Cmd,1); 
    /*配置IDAC0不使能DRDY、关闭激励*/
    Cmd=0x00 ;/*0000 0000*/
    ADS1248_WriteReg(ADS1248_IDAC0,&Cmd,1);   				
    /*配置IDAC1寄存器不选择励磁电流源引脚、不使能引脚*/
    Cmd=0xFF;/*1111 1111*/	
    ADS1248_WriteReg(ADS1248_IDAC1,&Cmd,1);   		
    /*配置FSC0为00*/
    Cmd=0x00;/*0010 0000*/		
    ADS1248_WriteReg(ADS1248_FSC0,&Cmd,1); 
    /*配置FSC1为00*/
    Cmd=0x00;/*0000 0000*/		
    ADS1248_WriteReg(ADS1248_FSC1,&Cmd,1); 
    /*配置FSC2为40,在公式中需要除以常数0x400000*/
    Cmd=0x40;/*0000 0100*/		
    ADS1248_WriteReg(ADS1248_FSC2,&Cmd,1);     
    HAL_Delay(20);	 
    /*拉高START准备ADC转换*/ 
    ADS1248_CLR_START;

上面的代码是上电对ADS1248/1247进行一个寄存器的配置,配置完之后选择持续转换,这样就可以一直获取到数据了。

读数据:

提示:因为此ADC是24位的ADC,最高位是符号位,所以有23位的分辨率,最大值是8388608,24位的数据我们用数据进行移位拼接,将最高位左移16位,第二位左移8位,最后一个直接获取,之后将数据相加即可得到我们要的最终数据,手册上写了内置滤波器,所以我们不需要在用软件滤波,直接读取数字量即可。

int32_t ADS1248_Read(void)
{
    /*定义发送的读取指令,后面三个是空操作等待ADC相应*/
	uint8_t  Cmd[4]={ADS1248_CMD_RDATAC,ADS1248_CMD_NOP,ADS1248_CMD_NOP,ADS1248_CMD_NOP};
	int32_t  i32Data = 0;
    int32_t  i32Data0 = 0;
    int32_t  i32Data1 = 0;
    int32_t  i32Data2 = 0;
    uint8_t  Buf[4] = {0};
    /*开启转换*/	
	ADS1248_SET_START;
    /*等待转换结束*/
	if(ADS1248_Wait() == 0)
    {
        ADS1248_CLR_CS;
        /*读取ADC数据保存在BUF中*/
		HAL_SPI_TransmitReceive(&hspi3,Cmd,Buf,4,HAL_MAX_DELAY);	 	
		ADS1248_SET_CS;		
	    ADS1248_CLR_START;	
		/*24位ADC数据进行拼接*/
        i32Data0 = Buf[0];
        i32Data0 = i32Data0 << 16;
        i32Data1 = Buf[1];
        i32Data1 = i32Data1 << 8;        
        i32Data2 = Buf[2];     
		i32Data = i32Data0 + i32Data1 + i32Data2;
		return i32Data;		
    }
    else
    {
        return 0;
    }
}

这样的写法我也知道很蠢,但是比较直观,也可以将buf0直接左移,将buf1直接左移之后直接进行或操作也可以实现数据获取,也不用定义这么多变量,即下面这样写。

i32Data=Buf[0]<<16|Buf[1]<<8|Buf[2];

开启转换

开启转换很简单,只需要将START引脚拉高即可,关闭转换也只需要把START引脚拉低即可。

GPIO初始化

这部分不用说了,凡是看这篇文章的肯定都会,只是配置IO推挽输出和输入,DRDY为输入,CS和START为推挽输出,可以根据需要修改IO的宏定义。

void Ads1248Init(void)
{
    /*初始化各个引脚*/
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    __HAL_RCC_GPIOA_CLK_ENABLE();
    GPIO_InitStruct.Pin = ADS1248_CS_PIN | ADS1248_START_PIN | ADS1248_RST_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);    

    __HAL_RCC_GPIOA_CLK_ENABLE();
    GPIO_InitStruct.Pin = ADS1248_DRDY_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    
    __HAL_RCC_GPIOB_CLK_ENABLE();
    GPIO_InitStruct.Pin = GPIO_PIN_9;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); 
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_9, GPIO_PIN_SET);
}
	}

H文件的定义如下:

/*RST复位引脚*/
#define ADS1248_RST_PIN         GPIO_PIN_9
#define ADS1248_RST_GPIO        GPIOA
#define ADS1248_SET_RESET		HAL_GPIO_WritePin(ADS1248_RST_GPIO, ADS1248_RST_PIN, GPIO_PIN_SET)
#define ADS1248_CLR_RESET		HAL_GPIO_WritePin(ADS1248_RST_GPIO, ADS1248_RST_PIN, GPIO_PIN_RESET)
/*开始使能引脚*/
#define ADS1248_START_PIN       GPIO_PIN_10
#define ADS1248_START_GPIO      GPIOA
#define ADS1248_SET_START		HAL_GPIO_WritePin(ADS1248_START_GPIO, ADS1248_START_PIN, GPIO_PIN_SET)
#define ADS1248_CLR_START		HAL_GPIO_WritePin(ADS1248_START_GPIO, ADS1248_START_PIN, GPIO_PIN_RESET)
/*DRDY引脚*/
#define ADS1248_DRDY_PIN        GPIO_PIN_11
#define ADS1248_DRDY_GPIO       GPIOA
#define ADS1248_DRDY_READY		HAL_GPIO_ReadPin(ADS1248_DRDY_GPIO,ADS1248_DRDY_PIN) 
/*CS片选引脚*/
#define ADS1248_CS_PIN          GPIO_PIN_15
#define ADS1248_CS_GPIO         GPIOA
#define ADS1248_SET_CS			HAL_GPIO_WritePin(ADS1248_CS_GPIO, ADS1248_CS_PIN, GPIO_PIN_SET)
#define ADS1248_CLR_CS			HAL_GPIO_WritePin(ADS1248_CS_GPIO, ADS1248_CS_PIN, GPIO_PIN_RESET)

注意事项


手册写的很清楚,差分输入的电压正负都需要计算,差模输入,意味着负输入端不可直接接地,接地会引发不可预知的错误。我遇到的错误是AD值不准,PGA = 16以上会引发线性度畸变。

下面贴出实测的线性度和数据

应用电路

物联沃分享整理
物联沃-IOTWORD物联网 » 详细配置说明:TI ADS1248/1247 24位ADC

发表评论