ADS1220 STM32硬件SPI驱动程序

发布于:2024-05-21 ⋅ 阅读:(407) ⋅ 点赞:(0)

前一段时间温故了下标准库,使用的是F1系列芯片,测试程序。

1 硬件部分

1.1 电路

注:该电路只是参考,是我另一个板卡上使用。和本文所使用标准库代码不是一组引脚。

1.2 接线

SCK:ADS1220的串行时钟输入。

DRDY:数据准备就绪,低电平有效。

DOUT:串行数据输出。

DIN:串行数据输入。

CS:片选,低电平有效。

IN0~IN3:电压输入引脚。

VREF:REFP0是正电压输入引脚,REFN0是负电压输入引进。这里只引入了正电压,REFN0接地。

2 程序

2.1 SPI模式

        该器件的SPI兼容串行接口适用于读取转换数据、读写器件配置寄存器以及控制器件工作状态。仅支持SPI1(CPOL=0,CPHA=1)。见官方手册Page34,8.5.1 Serial Interface。

       ADS1220_IOInit()函数包含了IO初始化,SPI初始化以及外部中断引脚初始化。其中SPI1使用的是PB3PB4PB5,需要进行重映射。

IO重映射:GPIO_PinRemapConfig(GPIO_Remap_SPI1,ENABLE);   

2.2 多路复用器

      可以测量四路单端信号、双路差分信号、双路单端信号与单路差分信号组合。

       该多路复用器通过配置寄存器的四个位(MUX[3:0])进行配置。见官方手册Page40。

       测量单端信号时,ADC输入(AINN)通过多路复用器内的开关在内部与AVSS相连。

       该多路复用器还可以将两个可编程电流源任意一路引至任意模拟输入或任意基准引脚(REFP0,REFN0)。

       ADC并不能同时采样,切换通道时需要进行切换,重新配置。一个时间只能采样一个输入通道。        

2.3 配置寄存器

SPI是全双工通信,读和写可以使用同一个函数。ADS1220寄存器配置都是8位,在初始化SPI1时,设置数据大小为8bit。在读16位ADC的值时,需要读2次。        

具体配置内容在ads1220_Config.c文件中。

       ADS1220一共有4个配置寄存器。先用SPI写函数进行写寄存器指令,根据官方手册Page36,Table 14,WREG一共8位,高4位固定为0100,低四位rrnn根据使用情况改写。rr=配置寄存器(00~11),nn=配置寄存器数量-1。

       写完写寄存器指令后,再用SPI写函数对寄存器进行配置。

       配置寄存器函数在ads1220.c中的void ADS1220WriteReg(uint8_t RegAddr,uint8_t Num,uint8_t* pData)。

       ads1220_Config.h定义了4个寄存器一些配置参数。

       4个寄存器配置参数用数组存储。用ADS1220WriteReg函数写到芯片中。

注:ADS1120和ADS1220寄存器完全一样,一个是16位ADC芯片,一个是24位。

2.4数据格式

           ADS1220为24位ADC,但是根据手册内容,需要使用223(8388608)作为最大量程。单端输入和差分输入采集到的电压值在误差范围内正确。

        该器件以二进制补码格式提供24位数据。单一代码通过Page35,公式16进行计算。满量程为223。

2.4.1 单端

在测试读取电压过程中,暂时使用的是STM32F103C8T6芯片,没有DAC输出,单端输入时候使用的3.3V和GND进行测试。

公式:输入电压=(数字量*基准电压/ADC分辨率)/增益

其中:

  基准电压=3.3V,ADC分辨率=223,增益=1。

       在不同输入IN切换电压,采集的值正确。

注:单端输入时,PGA必须禁用,并且只可使用增益1,2,4。在使用增益4之后,结果正确。例如DAC输出0.22V,ADC采集0.95094V/8=0.237735V。

2.4.2 差分

差分输入和单端输入公式相同。选择IN0和IN3为差分输入口,IN1和IN2为单端输入口,互不影响。

     

2.5 外部中断

       DRDY引脚用于指示新转换结果,降为低电平表示新转换数据准备就绪。DRDY将在下一个SCLK上升沿时转换回高电平。如果在连续转换模式下未读取任何数据,则DRDY保持低电平。

       外部中断使用下降沿触发,每进一次中断读取一次值,读取完之后配置下一个要读取的通道值。当全部通道读取完毕之后,使DataReady=1,调用Printf_Data()成功输出串口信息。

       ads1220.c中的宏定义是修改测试方式,如下:

#define SINGLE 0  //4路单端

#define DIFFER 0  //1对差分2路单端

#define Flag_Send 1 //用外部中断进行调试

修改其中一行为1,其余为0切换相关测试代码。

2.6代码

     

#include "ads1220.h" 

//测试采集电压用
#define SINGLE 0  //4路单端
#define DIFFER 0  //1对差分2路单端
#define Flag_Send 1 //用外部中断进行调试

static  enum {INIT, CH1,CH2,CH0_3} ADS1220State; 

uint8_t SPI1_ReadWriteByte(uint8_t TxData);

 /******************************************************************************
	* @brief  ADS1220引脚初始化
	* @Note   IO,SPI初始化和NVIC配置
  * @param  None
  * @retval None
  *****************************************************************************/
void ADS1220_IOInit()
{
		GPIO_InitTypeDef  GPIO_InitStructure;
	 	EXTI_InitTypeDef EXTI_InitStructure;
		SPI_InitTypeDef  SPI_InitStructure;
		NVIC_InitTypeDef NVIC_InitStructure;

		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO|RCC_APB2Periph_SPI1,ENABLE);	
		GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);
		GPIO_PinRemapConfig(GPIO_Remap_SPI1,ENABLE);
	
	//配置片选引脚
		GPIO_InitStructure.GPIO_Pin = ADS1220_CS_Pin;  
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_Init(GPIOB, &GPIO_InitStructure);
		GPIO_SetBits(GPIOB,ADS1220_CS_Pin);
	
	//SPI1
		GPIO_InitStructure.GPIO_Pin = SCLK_Pin | MISO_Pin | MOSI_Pin;
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_Init(GPIOB, &GPIO_InitStructure);

		GPIO_SetBits(GPIOB,SCLK_Pin | MISO_Pin | MOSI_Pin);
		
		SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工
		SPI_InitStructure.SPI_Mode = SPI_Mode_Master;		//设置SPI工作模式:设置为主SPI
		SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;		//设置SPI的数据大小:SPI发送接收8位帧结构
		SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;		//选择了串行时钟的稳态:时钟0
		SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;	//数据捕获于第二个时钟沿
		SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;		//NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制
		SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_32;		//定义波特率预分频的值:波特率预分频值为32 72M/32=2.25M
		SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;	//指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
		SPI_InitStructure.SPI_CRCPolynomial = 7;	
		SPI_Init(SPI1, &SPI_InitStructure);  //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器
	 
		SPI_Cmd(SPI1, ENABLE); //使能SPI外设

	//外部中断测试
	#if Flag_Send
		//外部中断
		GPIO_InitStructure.GPIO_Pin = NDRDY_Pin;
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
		GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	  //GPIO 中断线以及中断初始化配置   下降沿触发
  	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource7);
		
	  EXTI_InitStructure.EXTI_Line=EXTI_Line7;	
  	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;	
  	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
  	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  	EXTI_Init(&EXTI_InitStructure);	 
		
	  NVIC_InitStructure.NVIC_IRQChannel = NDRDY_EXTI_IRQn;		
  	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;	
  	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;				
  	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;								
  	NVIC_Init(&NVIC_InitStructure); 
		#endif
}


 /******************************************************************************
	* @brief  SPI1读写一个字节
	* @Note   None
  * @param  要写入的字节
  * @retval 读取到的字节
  *****************************************************************************/
uint8_t SPI1_ReadWriteByte(uint8_t TxData)
{		
	uint8_t retry=0;				 	
	while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET) //检查指定的SPI标志位设置与否:发送缓存空标志位
		{
		retry++;
		if(retry>200)return 0;
		}			  
	SPI_I2S_SendData(SPI1, TxData); //通过外设SPIx发送一个数据
	retry=0;

	while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET)//检查指定的SPI标志位设置与否:接受缓存非空标志位
		{
		retry++;
		if(retry>200)return 0;
		}	  						    
	return SPI_I2S_ReceiveData(SPI1); //返回通过SPIx最近接收的数据					    
}

 /******************************************************************************
	* @brief  SPI1读一个字节
	* @Note   None
  * @param  None
  * @retval 读取到的字节
  *****************************************************************************/
uint8_t SPI1_ReadByte()
{		
	uint8_t retry=0;				 	
	while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET)//检查指定的SPI标志位设置与否:接受缓存非空标志位
		{
		retry++;
		if(retry>200)return 0;
		}	  						    
	return SPI_I2S_ReceiveData(SPI1); //返回通过SPIx最近接收的数据					    
}

 /******************************************************************************
	* @brief  ADS1220写寄存器
	* @Note   None
  * @param  RegAddr:ADS1220的4个寄存器
						Num:配置数量
						pData:配置数据
  * @retval None
  *****************************************************************************/
void ADS1220WriteReg(uint8_t RegAddr,uint8_t Num,uint8_t* pData)
{
	uint8_t i;
	CS_0();
	SPI1_ReadWriteByte(ADS1220_CMD_WREG | ((( RegAddr<<2 )& 0x0c )|(( Num-1 ) & 0x03)));
	for(i=0;i<Num;i++)
	{
		SPI1_ReadWriteByte(*pData++);
	}
	CS_1();
}

 /******************************************************************************
	* @brief  ADS1220查看寄存器
	* @Note   None
  * @param  RegAddr:ADS1220四页寄存器
						Num:配置数量
						pData:返回值
  * @retval None
  *****************************************************************************/
void ADS1220_ReadReg(uint8_t RegAddr,uint8_t Num,uint8_t* pData)
{
	uint8_t i;
	CS_0();
	SPI1_ReadWriteByte(ADS1220_CMD_RREG | ((( RegAddr<<2 )& 0x0c )|(( Num-1 ) & 0x03)));
	for(i=0;i<Num;i++)
	{
		*pData++=SPI1_ReadByte();
	}
	CS_1();
}

 /******************************************************************************
	* @brief  ADS1220复位指令
	* @Note   None
  * @param  None
  * @retval None
  *****************************************************************************/
void ADS1220_RESET()
{
	CS_0();
	SPI1_ReadWriteByte(ADS1220_CMD_RESET);
	CS_1();
}

 /******************************************************************************
	* @brief  ADS1220启动连续转换指令
	* @Note   在单次模式下是启动一次转换,连续只需要开启一次
  * @param  None
  * @retval None
  *****************************************************************************/
void ADS1220_SYNC_START()
{
	CS_0();
	SPI1_ReadWriteByte(ADS1220_CMD_SYNC);
	CS_1();
}

 /******************************************************************************
	* @brief  ADS1220配置
	* @Note   None
  * @param  寄存器配置数组 寄存器共4页
  * @retval None
  *****************************************************************************/
void ADS1220_Config(uint8_t c[])
{
	uint8_t cfg[4];
	cfg[0]=c[0];
	cfg[1]=c[1];
	cfg[2]=c[2];
	cfg[3]=c[3];
	
	ADS1220_RESET();
	delay_ms(5);
	//ADS1220WriteReg(ADS1220_REG_0,4,cfg);//写寄存器指令,配置寄存器
	ADS1220WriteReg(ADS1220_REG_0,1,&cfg[0]);
	ADS1220WriteReg(ADS1220_REG_1,1,&cfg[1]);
	ADS1220WriteReg(ADS1220_REG_2,1,&cfg[2]);
	ADS1220WriteReg(ADS1220_REG_3,1,&cfg[3]);
	delay_ms(5);
	ADS1220_SYNC_START();  //在连续转换模式下发送sync命令开始转换
}


 /******************************************************************************
	* @brief  ADS1220读取数据
	* @Note   None
  * @param  None
  * @retval 24位数据
  *****************************************************************************/
long ADS1220_ReadData()
{
	long dat;
	CS_0();
	SPI1_ReadWriteByte(ADS1220_CMD_RDATA);
	
	dat=SPI1_ReadWriteByte(0xff);
	dat=(dat<<8)|SPI1_ReadWriteByte(0xff);
	dat=(dat<<8)|SPI1_ReadWriteByte(0xff);
	CS_1();
	
	//判断最高位是否为 负数,芯片传来是补码格式
	if(dat&0x800000)
		dat|=0xff000000;  //满量程前面根据变量类型最高几位加ff
	
	//这里的0x0080000(8388608) 需要转换成负数 0xff80000(-8388608) 和取反加1计算方式相同
	//正数000001h~7FFFFFh,负数FFFFFh~800000
	return dat;
}
uint8_t reg_test;
 /******************************************************************************
	* @brief  ADS1220初始化程序
	* @Note   函数放在主循环前
  * @param  None
  * @retval None
  *****************************************************************************/
void ADS1220_INIT()
{
		//初始化IO及SPI
		ADS1220_IOInit();
		//配置ADS1220
		ADS1220_Config(Set_IN1);
		//读寄存器
		ADS1220_ReadReg(ADS1220_REG_0,1,&reg_test);
		ADS1220State = INIT;	
}


//存储通道的数字量,测试用
volatile long IN1_Val,IN2_Val,IN0_3_Val;
ADS1220外部中断中的数据转换标志位
uint8_t DataReady;

 /******************************************************************************
	* @brief  AD1220中断功能函数
  * @Note   放入中断回调函数运行
  * @param  None
  * @retval None
  *****************************************************************************/
void AD1220Irq()
{
……
}

uint8_t ext=0; //看是否进入中断
 /******************************************************************************
	* @brief  外部中断
  * @Note   SDATA引脚
  * @param  None
  * @retval None
  *****************************************************************************/
void EXTI9_5_IRQHandler(void)
{
	if(EXTI_GetITStatus(EXTI_Line7)!=RESET)
	{
		AD1220Irq();
		ext=!ext;
		EXTI_ClearITPendingBit(EXTI_Line7); 
	}
}



#ifndef ADS1220_H
#define ADS1220_H

#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
#include "usart.h"
#include "stm32f10x_exti.h"
#include "stm32f10x_spi.h"
#include "delay.h"
#include "dac.h"
#include "ads1220_Config.h" 

#define SCLK_Pin GPIO_Pin_3
#define MISO_Pin GPIO_Pin_4
#define MOSI_Pin GPIO_Pin_5
#define ADS1220_CS_Pin GPIO_Pin_6
#define NDRDY_Pin GPIO_Pin_7
#define NDRDY_EXTI_IRQn EXTI9_5_IRQn

#define CS_0() do{GPIO_WriteBit(GPIOB,ADS1220_CS_Pin,Bit_RESET);}while(0)
#define CS_1() do{GPIO_WriteBit(GPIOB,ADS1220_CS_Pin,Bit_SET);}while(0)

#define NDRDY_IN PBin(7)



void ADS1220_INIT(void);
long ADS1220_ReadData(void);
void Printf_Data(void);




#endif 

寄存器配置相关参考了官方手册和其他人的写法:

​​​​​​​

代码自取:https://download.csdn.net/download/zy19981110/89319670


网站公告

今日签到

点亮在社区的每一天
去签到