TI公司16位ADC芯片 --- ADS1158 单端模式使用心得


【本文发布于https://blog.csdn.net/Stack_/article/details/116331897,未经许可不得转载,转载须注明出处】




以下为个人理解,如有不对的地方欢迎指正。



一、电路

TI公司16位ADC芯片 --- ADS1158 单端模式使用心得_第1张图片

单端模式采集16路模拟量电路



二、SPI

TI公司16位ADC芯片 --- ADS1158 单端模式使用心得_第2张图片

使用外接16M晶振时,SPI最高波特率为8M



根据时序配置SPI

@ CSDN Tyrion.Mon
/**
  * @brief  初始化SPI0
  * @note   SPI0_NSS -- PA4
  *         SPI0_SCK -- PA5
  *         SPI0_MI  -- PA6
  *         SPI0_MO  -- PA7
  * @param  None
  * @retval None
  * @author PWH
  * @date   2021/3
  */
void SPI0_Init(void)
{
	RCU->RCU_APB2EN.Bits.SPI0EN = 1;			//
	
	/* SCK复用输出 */
	Gd32f30x_Gpio_Init(GPIO_PA5, GPIO_MODE_OUT_50MHZ, GPIO_CTL_AF_PP);
	/* MI上拉输入 */
	Gd32f30x_Gpio_Init(GPIO_PA6, GPIO_MODE_IN, GPIO_CTL_IPU);
	/* MO复用输出 */
	Gd32f30x_Gpio_Init(GPIO_PA7, GPIO_MODE_OUT_50MHZ, GPIO_CTL_AF_PP);
	/* SPI0 */
	//1:主机模式
	SPI0->SPI_CTL0.Bits.MSTMOD = 1;
	//0: 2 线单向传输模式
	SPI0->SPI_CTL0.Bits.BDEN = 0;
	//0:全双工模式(当 BDEN 清零时)
	SPI0->SPI_CTL0.Bits.RO = 0;
	//0: 8 位数据帧格式
	SPI0->SPI_CTL0.Bits.FF16 = 0;
	//1: NSS 软件模式, NSS 电平取决于 SWNSS 位
	SPI0->SPI_CTL0.Bits.SWNSSEN = 1;
	SPI0->SPI_CTL0.Bits.SWNSS = 1;
	//SPI0时钟来源:APB2   psc=011 : 16分频  
	//120M/16=7.5<(ADS1158 16M外部晶振时,SPI最高速度8M)
	SPI0->SPI_CTL0.Bits.PSC = 3;
	//0:先发送最高有效位
	SPI0->SPI_CTL0.Bits.LF = 0;
	//0: SPI 为空闲状态时, CLK 引脚拉低
	SPI0->SPI_CTL0.Bits.CKPL = 0;
	//0:在第1个时钟跳变沿采集第一个数据
	SPI0->SPI_CTL0.Bits.CKPH = 0;
	//1: RBNE 中断使能。当 RBNE 置位时,产生中断。
//	SPI0->SPI_CTL1.Bits.RBNEIE = 1;
	//1: SPI 设备使能
	SPI0->SPI_CTL0.Bits.SPIEN = 1;
}



三、命令字节

TI公司16位ADC芯片 --- ADS1158 单端模式使用心得_第3张图片

@ CSDN Tyrion.Mon
/* 命令字节的bits[7:5] 表示命令类型 */
#define COMMAND_CH_DATA_DIRECT					0x00	//直接读取通道数据
#define COMMAND_CH_DATA_COMMAND					0x20	//命令读取通道数据
#define COMMAND_READ_REGISTER					0x40	//读寄存器
#define COMMAND_WRITE_REGISTER					0x60	//写寄存器
#define COMMAND_PULSE_CONVERT					0x80	//开始转换,此命令bit[4:0]无效
#define COMMAND_RESEVED							0xA0	//保留
#define COMMAND_RESET							0xC0	//reset,此命令bit[4:0]无效
//#define COMMAND_CH_DATA_DIRECT					0xE0	//和0x00↑一样

/* 命令字节的bits[4] */
#define ENABLE_MULTIPLE_REG_ACCESS				0x10	//启用多寄存器访问
#define DISABLE_MULTIPLE_REG_ACCESS				0x00	//禁用多寄存器访问

/* 命令字节的bits[3:0] 表示访问的寄存器地址 */
#define REG_ADDR_CONFIG0						0x00	//配置寄存器0
#define REG_ADDR_CONFIG1						0x01	//配置寄存器1
#define REG_ADDR_MUXSCH							0x02	//多路复用固定通道寄存器
#define REG_ADDR_MUXDIF							0x03	//多路复用器差分输入选择寄存器
#define REG_ADDR_MUXSG0							0x04	//多路复用单端输入选择寄存器0
#define REG_ADDR_MUXSG1							0x05	//多路复用单端输入选择寄存器1
#define REG_ADDR_SYSRED							0x06	//系统读取选择寄存器
#define REG_ADDR_GPIO_CONFIG					0x07	//GPIO配置寄存器(输入输出配置)
#define REG_ADDR_GPIO_DATA						0x08	//GPIO数据寄存器(置位、清零、读状态)
#define REG_ADDR_ID								0x09	//出厂ID

/* 软/命令复位 bit[4:0]无效 */
#define COMMAND_SOFE_RESET						COMMAND_RESET
/* 软 脉冲触发单次转换 bit[4:0]无效 */
#define COMMAND_SOFE_PULSE_CONVERT				COMMAND_PULSE_CONVERT
/* 命令读通道数据 bit[3:0]无效 */
#define COMMAND_CH_DATA_READ					(COMMAND_CH_DATA_COMMAND | ENABLE_MULTIPLE_REG_ACCESS)

读单个寄存器时,发送COMMAND_READ_REGISTER | DISABLE_MULTIPLE_REG_ACCESS | 寄存器地址,再发送任意一个字节,即可获得该寄存器值;

写单个寄存器时,发送COMMAND_WRITE_REGISTER | DISABLE_MULTIPLE_REG_ACCESS | 寄存器地址,再发送配置值,即可更改该寄存器的值。



四、寄存器

TI公司16位ADC芯片 --- ADS1158 单端模式使用心得_第4张图片

CONFIG0 @ CSDN Tyrion.Mon
BIT5 0:自动扫描模式;1:固定通道模式。在这里配为自动扫描
BIT4 0:AD转换器直接从16个通道采样;1:如下图,16个通道模拟量从MUXOUTP和MUXOUTN输出,经外部电路(如果设计有)处理过后,输入到ADCINP和ADCINN再到AD转换器。适用于需要放大输入信号或者对信号作其它处理的情况,可以节省硬件电路。
BIT3 0:使用外部晶振;1:晶振引脚输出时钟
BIT2 未明白,可维持默认值
BIT1 0:转换完成后读取AD值时伴随表示数据状态的一个字节
CONFIG1 @ CSDN Tyrion.Mon
BIT7 如果对耗电没有要求,选择待机模式,理论上从待机模式下启动转换会快些
BIT[6:4] 不是很明白,保持默认即可
BIT[3:2] 不是很明白,保持默认即可
BIT[1:0] 对转换速度没有要求就选最大值,转换速度选择越慢的越精确
MUXSCH @ CSDN Tyrion.Mon
BIT[7:0] 在固定通道模式下使用,测量有正有负的电压,参考电源须由5V - 0V改为+2.5V - -2.5V。AINPx指定电压对的正压通道,AINNx指定电压对的负压通道。(懵逼,不知道怎么用)
MUXDIF
BIT[7:0] AIN0置位时,AIN0和AIN1组成一对差分信号对,电压为两者差值; AIN1置位时,AIN2和AIN3组成一对差分信号对;…在自动扫描模式下有效,未选中的在一轮扫描中会被跳过。
MUXSG0 @ CSDN Tyrion.Mon
BIT[7:0] AIN0置位时,通道AIN0被选中为单端模式,电压为AIN0和AINCOM的差值;AIN1置位时,通道AIN1被选中为单端模式,电压为AIN1和AINCOM的差值。…在自动扫描模式下有效,,未选中的在一轮扫描中会被跳过。
MUXSG1 @ CSDN Tyrion.Mon
BIT[7:0] AIN0置位时,通道AIN8被选中为单端模式,电压为AIN8和AINCOM的差值。…在自动扫描模式下有效,未选中的在一轮扫描中会被跳过。
SYSRED @ CSDN Tyrion.Mon
BIT[7:0] 未明

TI公司16位ADC芯片 --- ADS1158 单端模式使用心得_第5张图片

看懂这个图就最好



五、开启转换

在上电不进行配置时,ADS1158会自动扫描所有通道,用示波器能看到DRDY引脚有波形输出。

TI公司16位ADC芯片 --- ADS1158 单端模式使用心得_第6张图片

1.持续转换: 配置好ADS1158后,把START脚一直拉高,会自动扫描选中的所有通道。扫描完一个通道并准备好从SPI输出数据时,会拉低DRDY引脚一段时间,然后拉高继续转换下一通道,转换完成再次拉低DRDY。如果没能及时将数据读出来,将会导致数据被覆盖;
2. 脉冲转换:配置好ADS1158后,把START拉高立刻又拉低,ADS1158将只转换当前通道,转换完成后拉低DRDY,并指向下一通道。而后进入待机或睡眠模式。



六、数据读取

将转换模式配置为脉冲转换:START脚触发转换,DRDY引脚变低后读取三字节通道数据。不断循环此操作

TI公司16位ADC芯片 --- ADS1158 单端模式使用心得_第7张图片

以第一个字节的bit7判断数据是否有效:为1时为新/已更新数据。
以第一个字节的bit[4:0]判断当前数据为哪个通道的数据。

TI公司16位ADC芯片 --- ADS1158 单端模式使用心得_第8张图片



七、数据解析

第二、第三个字节的数据需要根据公式进行转换为电压。
.. ..

TI公司16位ADC芯片 --- ADS1158 单端模式使用心得_第9张图片






@ CSDN Tyrion.Mon
/**
  * @brief  向一个寄存器写一个字节
  * @note   
  * @param  None
  * @retval None
  * @author PWH
  * @date   2021/3
  */
static uint16_t Ads1158_WriteOneReg(uint8_t Reg, uint8_t Byte)
{	
	Ads1158_Select(CS_ENABLE);
	
	SPIx_SendData(SPI0, COMMAND_WRITE_REGISTER | DISABLE_MULTIPLE_REG_ACCESS | Reg);
	SPIx_SendData(SPI0, Byte);
	
	Ads1158_Select(CS_DISABLE);
	
	return 0;
}
/**
  * @brief  ADS 读寄存器
  * @note   
  * @param  None
  * @retval 
  * @author PWH
  * @date   2021/3
  */
static uint16_t Ads1158_ReadOneReg(uint8_t Reg)
{
	uint16_t rec = 0;
	
	Ads1158_Select(CS_ENABLE);
	
	rec = SPIx_SendData(SPI0, COMMAND_READ_REGISTER | DISABLE_MULTIPLE_REG_ACCESS | Reg);
	rec = SPIx_SendData(SPI0, 0x00);
	
	Ads1158_Select(CS_DISABLE);
//	printf("Reg = %#x\r\n", rec);
	return rec;
}
/**
  * @brief  ADS软件复位
  * @note   
  * @param  None
  * @retval None
  * @author PWH
  * @date   2021/3
  */
static void Ads1158_Reset(void)
{
	Ads1158_Select(CS_ENABLE);
	
	SPIx_SendData(SPI0, COMMAND_SOFE_RESET);
	
	Ads1158_Select(CS_DISABLE);
}

/**
  * @brief  ADS 读ID寄存器进行通讯测试
  * @note   
  * @param  None
  * @retval 
  * @author PWH
  * @date   2021/3
  */
static int8_t Ads1158_CommTest(void)
{
	if ((uint8_t)(Ads1158_ReadOneReg(REG_ADDR_ID)) == DEVICE_ID)
		return 1;
	return -1;
}

/**
  * @brief  初始化ADS1158
  * @note       SPI  -- SPI0
  *             CS   -- PA4
  *             START-- PB2
  *             DRDY -- PF11
  *             RST  -- PF12
  * @param  None
  * @retval None
  * @author PWH
  * @date   2021/3
  */
void Ads1158_Init(void)
{
	/* CS推挽输出 */
	Gd32f30x_Gpio_Init(ADS1158_CS_PIN, GPIO_MODE_OUT_50MHZ, GPIO_CTL_OUT_PP);
	Gd32f30x_Gpio_Write(ADS1158_CS_PIN, GPIO_SET);
	/* START 推挽输出 */
	Gd32f30x_Gpio_Init(ADS1158_START_PIN, GPIO_MODE_OUT_50MHZ, GPIO_CTL_OUT_PP);
	Gd32f30x_Gpio_Write(ADS1158_START_PIN, GPIO_RESET);
	/* DRDY(ADS1158数据准备好输出)上拉输入 */
	Gd32f30x_Gpio_Init(ADS1158_DRDY_PIN, GPIO_MODE_IN, GPIO_CTL_IPU);
	/* RST 推挽输出 */
	Gd32f30x_Gpio_Init(ADS1158_RST_PIN, GPIO_MODE_OUT_50MHZ, GPIO_CTL_OUT_PP);
	Gd32f30x_Gpio_Write(ADS1158_RST_PIN, GPIO_RESET);
	
	SPI0_Init();

	Gd32f30x_Gpio_Write(ADS1158_RST_PIN, GPIO_SET);

	Ads1158_Reset();
	
	while (Ads1158_CommTest() != 1);
	
	//CONFIG0 
	Ads1158_WriteOneReg(REG_ADDR_CONFIG0, DATA_CONFIG0);
	//CONFIG1
	Ads1158_WriteOneReg(REG_ADDR_CONFIG1, DATA_CONFIG1);
	//MUXSG0
	Ads1158_WriteOneReg(REG_ADDR_MUXSG0, DATA_MUXSG0);
	//MUXSG1
	Ads1158_WriteOneReg(REG_ADDR_MUXSG1, DATA_MUXSG1);
	//GPIO
	Ads1158_WriteOneReg(REG_ADDR_GPIO_CONFIG, DATA_GPIO_CONFIG);
	
	if (Ads1158_ReadOneReg(REG_ADDR_CONFIG0) != DATA_CONFIG0)
	{
		while (1);
	}
	if (Ads1158_ReadOneReg(REG_ADDR_CONFIG1) != DATA_CONFIG1)
	{
		while (1);
	}
	if (Ads1158_ReadOneReg(REG_ADDR_MUXSG0) != DATA_MUXSG0)
	{
		while (1);
	}
	if (Ads1158_ReadOneReg(REG_ADDR_MUXSG1) != DATA_MUXSG1)
	{
		while (1);
	}
	if (Ads1158_ReadOneReg(REG_ADDR_GPIO_CONFIG) != DATA_GPIO_CONFIG)
	{
		while (1);
	}
}
/**
  * @brief  检测到DRDY引脚下降沿后读取通道数据
  * @note   
  * @param  None
  * @retval None
  * @author PWH
  * @date   2021/3
  */
void Ads1158_ReadChannelDataWithoutCmd(uint8_t *pBuff, uint8_t len)
{
	uint8_t i = 0;
	
	Ads1158_Select(CS_ENABLE);
	for (i = 0; i < len; i++)
	{
		*pBuff++ = SPIx_SendData(SPI0, 0x00);
	}
	Ads1158_Select(CS_DISABLE);
}
/**
  * @brief  ADS开始转换
  * @note   
  * @param  None
  * @retval None
  * @author PWH
  * @date   2021/3
  */
void Ads1158_StartStopConvert(uint8_t StartStop)
{
	if (StartStop == CONVERT_START)
	{
		Gd32f30x_Gpio_Write(ADS1158_START_PIN, GPIO_SET);
	}
	else
	{
		Gd32f30x_Gpio_Write(ADS1158_START_PIN, GPIO_RESET);
	}
}

/**
  * @brief  ADS数据是否准备输出
  * @note   
  * @param  None
  * @retval 0 -- ready
  * @author PWH
  * @date   2021/3
  */
int8_t Ads1158_DataReady(void)
{
	if (Gd32f30x_Gpio_Read(ADS1158_DRDY_PIN) == DATA_READY)
		return DATA_READY;
	return -1;
}

@ CSDN Tyrion.Mon
static uint8_t Ads1158_ReadComplete = true;		// 1 表示已读取通道
uint16_t Ads1158_ChConvertData[16] = {0x00};	// 通道转换的原始数据
uint32_t Ads1158_ChRealVoltage[16] = {0x00};	// 通道电压(根据原始数据转换)
uint32_t Ads1158_AD[16] = {0x00};				// 通道AD(根据电压数据转换)

/**
  * @brief  
  * @note   
  * @param  None
  * @retval None
  * @author PWH
  * @date   2021/4
  */
void Ads1158_Proc(void)
{
	uint8_t i;
	static uint32_t ads_time = 0;
	uint8_t array[3];
	
	/* 启动转换 */
	if ((Ads1158_ReadComplete == true) && (Ads1158_DataReady() != DATA_READY))
	{
		Ads1158_ReadComplete = false;
		Ads1158_StartStopConvert(CONVERT_START);	// 脉冲触发转换,只转换一个通道
		Ads1158_StartStopConvert(CONVERT_STOP);		// 
	}

	if (UserTimer_Read(&ads_time) > 5000)	//超时
	{
		printf("                            ADS ERROR RESET\r\n ");
		UserTimer_Reset(&ads_time);
		Ads1158_ReadComplete = true;
	}
	
	/* 读取数据 */
	if ((Ads1158_ReadComplete == false) && (Ads1158_DataReady() == DATA_READY))
	{
		/* 读取转换数据 */
		Ads1158_ReadChannelDataWithoutCmd(array, 3);
		if (array[0] & 0x80)	//数据已刷新
		{
			array[0] &= 0x1f;	//bit4-bit0表示当前读回的数据所属通道
			if ( (array[0] >= DATA_AIN0) && (array[0] <= DATA_AIN15) )
			{
				Ads1158_ChConvertData[array[0] - DATA_AIN0] = ((uint16_t)array[1]) << 8 | array[2];
				Ads1158_ChRealVoltage[array[0] - DATA_AIN0] = (uint32_t)(Ads1158_ChConvertData[array[0] - DATA_AIN0] * REFERENCE_VOLTAGE / 30720.0);
				Ads1158_AD[array[0] - DATA_AIN0] = Ads1158_ChRealVoltage[array[0] - DATA_AIN0] * 65536.0 / REFERENCE_VOLTAGE;
			}
			if (array[0] == DATA_AIN15)
			{
				UserTimer_Reset(&ads_time);
			}
			Ads1158_ReadComplete = true;	//表示已读取通道
		}
	}
}


你可能感兴趣的:(MCU,笔记,单片机,stm32,嵌入式硬件)