其他分享
首页 > 其他分享> > ADS1158单端模式使用心得

ADS1158单端模式使用心得

作者:互联网

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



一、电路

在这里插入图片描述

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



二、SPI

在这里插入图片描述

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



根据时序配置SPI

/**
  * @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;
}



三、命令字节

在这里插入图片描述

/* 命令字节的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 | 寄存器地址,再发送配置值,即可更改该寄存器的值。



四、寄存器

在这里插入图片描述

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

在这里插入图片描述

看懂这个图就最好



五、开启转换

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

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



六、数据读取

配置连接DRDY引脚的MCU引脚为下降沿触发中断。在中断中读取三字节通道数据。在这里插入图片描述
以第一个字节的bit7判断数据是否有效:为1时为新/已更新数据。
以第一个字节的bit[4:0]判断当前数据为哪个通道的数据。
在这里插入图片描述



七、数据解析

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

在这里插入图片描述






/**
  * @brief  向一个寄存器写一个字节
  * @note   
  * @param  None
  * @retval None
  * @author PWH
  * @date   2021/3
  */
static uint16_t Ads1158_1_WriteOneReg(uint8_t Reg, uint8_t Byte)
{	
	Ads1158_1_Select(CS_ENABLE);
	
	SPIx_SendData(SPI0, COMMAND_WRITE_REGISTER | DISABLE_MULTIPLE_REG_ACCESS | Reg);
	SPIx_SendData(SPI0, Byte);
	
	Ads1158_1_Select(CS_DISABLE);
	
	return 0;
}
/**
  * @brief  ADS 读寄存器
  * @note   
  * @param  None
  * @retval 
  * @author PWH
  * @date   2021/3
  */
static uint16_t Ads1158_1_ReadOneReg(uint8_t Reg)
{
	uint16_t rec = 0;
	
	Ads1158_1_Select(CS_ENABLE);
	
	rec = SPIx_SendData(SPI0, COMMAND_READ_REGISTER | DISABLE_MULTIPLE_REG_ACCESS | Reg);
	rec = SPIx_SendData(SPI0, 0x00);
	
	Ads1158_1_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_1_Reset(void)
{
	Ads1158_1_Select(CS_ENABLE);
	
	SPIx_SendData(SPI0, COMMAND_SOFE_RESET);
	
	Ads1158_1_Select(CS_DISABLE);
}

/**
  * @brief  ADS 读ID寄存器进行通讯测试
  * @note   
  * @param  None
  * @retval 
  * @author PWH
  * @date   2021/3
  */
static int8_t Ads1158_1_CommTest(void)
{
	if ((uint8_t)(Ads1158_1_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_1_Init(void)
{
	/* CS推挽输出 */
	Gd32f30x_Gpio_Init(ADS1158_1_CS_PIN, GPIO_MODE_OUT_50MHZ, GPIO_CTL_OUT_PP);
	Gd32f30x_Gpio_Write(ADS1158_1_CS_PIN, GPIO_SET);
	/* START 推挽输出 */
	Gd32f30x_Gpio_Init(ADS1158_1_START_PIN, GPIO_MODE_OUT_50MHZ, GPIO_CTL_OUT_PP);
	Gd32f30x_Gpio_Write(ADS1158_1_START_PIN, GPIO_RESET);
	/* DRDY(ADS1158数据准备好输出)上拉输入 */
	Gd32f30x_Gpio_Init(ADS1158_1_DRDY_PIN, GPIO_MODE_IN, GPIO_CTL_IPU);
#if (ADS1158_TEST == 0)
	Gd32f30x_Gpio_Interrupt_Init(ADS1158_1_DRDY_PIN, EXTI_TRIG_FALLING);
	NVIC_Init(ADS1158_1_DRDY_PIN_IRQn, 1, 1);
#endif
	/* RST 推挽输出 */
	Gd32f30x_Gpio_Init(ADS1158_1_RST_PIN, GPIO_MODE_OUT_50MHZ, GPIO_CTL_OUT_PP);
	Gd32f30x_Gpio_Write(ADS1158_1_RST_PIN, GPIO_RESET);
	
	SPI0_Init();

	Gd32f30x_Gpio_Write(ADS1158_1_RST_PIN, GPIO_SET);

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

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

/**
  * @brief  
  * @note   
  * @param  None
  * @retval None
  * @author PWH
  * @date   2021/4
  */
void Ads1158_GetVoltage(void)
{
	uint8_t i;
	if ((Ads1158_Which == 0) && (Ads1158_1_FinishFlag == 1) && (Ads1158_1_DataReady() != DATA_READY))
	{
		Ads1158_1_FinishFlag = 0;
		Ads1158_1_StartStopConvert(CONVERT_START);
		Ads1158_1_StartStopConvert(CONVERT_STOP);
		Gd32f30x_Gpio_Interrupt_Enable(ADS1158_1_DRDY_PIN, ENABLE);
	}
	if ((Ads1158_Which == 1) && (Ads1158_2_FinishFlag == 1) && (Ads1158_2_DataReady() != DATA_READY))
	{
		Ads1158_2_FinishFlag = 0;
		Ads1158_2_StartStopConvert(CONVERT_START);
		Ads1158_2_StartStopConvert(CONVERT_STOP);
		Gd32f30x_Gpio_Interrupt_Enable(ADS1158_2_DRDY_PIN, ENABLE);
	}
	if (Ads1158_Which == 2)
	{
		for (i = 0; i < 16; i++)
		{
//			printf("ADS_1_CH%d = %dmv, ", i, Ads1158_1_ChRealVoltage[i]);
//			printf("ADS_2_CH%d = %dmv\r\n", i, Ads1158_2_ChRealVoltage[i]);
		}
		Ads1158_Which = 0;
	}
}

/**
  * @brief  中断服务函数
  * @note   
  * @param  None
  * @retval None
  * @author PWH
  * @date   2021/4
  */
void EXTI10_15_IRQHandler(void)
{
	uint8_t array[3];
	if (ADS1158_1_DRDY_PIN_EXTI_PD)
	{
		ADS1158_1_DRDY_PIN_EXTI_PD = 1;		//清中断标志
		ADS1158_1_DRDY_EXTI_INTEN = 0;		//关中断
		Ads1158_1_ReadChannelDataWithoutCmd(array, 3);
		if (array[0] & 0x80)
		{
			array[0] &= 0x1f;
			if ( (array[0] >= DATA_AIN0) && (array[0] <= DATA_AIN15) )
			{
				Ads1158_1_ChConvertData[array[0] - DATA_AIN0] = ((uint16_t)array[1]) << 8 | array[2];
				Ads1158_1_ChRealVoltage[array[0] - DATA_AIN0] = (uint32_t)(Ads1158_1_ChConvertData[array[0] - DATA_AIN0] * 5000.0 / 30720.0);
			}
			if (array[0] == DATA_AIN15)
			{
				Ads1158_Which = 1;
			}
			Ads1158_1_FinishFlag = 1;
		}
	}
	if (ADS1158_2_DRDY_PIN_EXTI_PD)
	{
		ADS1158_2_DRDY_PIN_EXTI_PD = 1;		//清中断标志
		ADS1158_2_DRDY_EXTI_INTEN = 0;		//关中断
		Ads1158_2_ReadChannelDataWithoutCmd(array, 3);
		if (array[0] & 0x80)
		{
			array[0] &= 0x1f;
			if ( (array[0] >= DATA_AIN0) && (array[0] <= DATA_AIN15) )
			{
				Ads1158_2_ChConvertData[array[0] - DATA_AIN0] = ((uint16_t)array[1]) << 8 | array[2];
				Ads1158_2_ChRealVoltage[array[0] - DATA_AIN0] = (uint32_t)(Ads1158_2_ChConvertData[array[0] - DATA_AIN0] * 5000.0 / 30720.0);
			}
			if (array[0] == DATA_AIN15)
			{
				Ads1158_Which = 2;
			}
			Ads1158_2_FinishFlag = 1;
		}
	}
}

标签:SPI0,ADS1158,DATA,Ads1158,单端,GPIO,心得,REG
来源: https://blog.csdn.net/Stack_/article/details/116331897