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)工作。
提示:在配置寄存器前,默认已经配置好了硬件SPI,SPI的配置为主模式、全双工、数据位8位、CPOL = 0、CPHA为数据线的第一个变化沿、软件控制NSS、256分频、最高位先发送、TIMODE模式关闭、CRC关闭。作者使用的是STM32L433单片机,使用HAL库来编写,本文将详细阐述ADS1248各个寄存器以及注意事项。
ADS1248/1247一共有15个寄存器,寄存器列表如下:
提示:图上可以看到,寄存器的地址为0x00 - 0x0e,每个寄存器都是一个字节八位分别去配置ADC的功能。
提示:手册说的很清楚,第一个命令字节: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说了在读数据的时候不能进行写操作,否则命令将会被忽略。
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引脚拉低即可。
这部分不用说了,凡是看这篇文章的肯定都会,只是配置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以上会引发线性度畸变。