STM32H7教程第93章 STM32H7的SPI总线应用之驱动ADS1256(8通道24bit ADC, 增益可编程)

Posted Simon223

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了STM32H7教程第93章 STM32H7的SPI总线应用之驱动ADS1256(8通道24bit ADC, 增益可编程)相关的知识,希望对你有一定的参考价值。

完整教程下载地址:【安富莱】STM32H7用户手册发布,重在BSP驱动包设计方法,HAL库的框架学习,授人以渔,更新至94章(2021-11-29) - STM32H7 - 硬汉嵌入式论坛 - Powered by Discuz!

第93章       STM32H7的SPI总线应用之驱动ADS1256(8通道24bit ADC, 增益可编程)

本章节为大家讲解8通道24bit ADC芯片驱动实现。

目录

93.1 初学者重要提示

93.2 ADC结构分类

93.2.1 SAR ADC(逐次逼近型)

93.2.2 Sigma-Delta ADC

93.2.3 Integrating ADC

93.2.4 FLASH ADC

93.2.5 Pipelined ADC

93.2.6 Two Step ADC

93.3 ADS1256硬件设计

93.3.1 ADS1256硬件接口

93.3.2 ADS1256模块

93.4 ADS1256关键知识点整理(重要)

93.4.1 ADS1256基础信息

93.4.2 ADS1256常用引脚的作用

93.4.3 ADS1256输出电压计算公式

93.4.4 ADS1256时序图

93.4.5 ADS1256的增益和测量范围问题

93.4.6 ADS1256输入缓冲器

93.4.7 ADS1256支持的采样率

93.4.8 ADS1256的多路选择器,单端和多端输入

93.5 ADS1256驱动设计

93.5.1 第1步,ADS1256所涉及到的GPIO配置

93.5.2 第2步,ADS1256的8bit读写函数实现

93.5.3 第3步,ADS1256的24bit ADC数据读取

93.5.4 第3步,ADS1256增益和采样率配置

93.5.5 第4步,ADS1256启动采样

93.5.6 第5步,ADS1256的中断处理(8通道数据读取)

93.6 ADS1256板级支持包(bsp_spi_ads1256.c)

93.6.1 函数bsp_InitADS1256

93.6.2 函数ADS1256_CfgADC

93.6.3 函数ADS1256_StartScan

93.6.4 函数ADS1256_SetChannal

93.7 ADS1256实际测量效果(10uV抖动)

93.8 ADS1256驱动移植和使用

93.9 实验例程设计框架

93.10          实验例程说明(MDK)

93.11          实验例程说明(IAR)

93.12   总结



93.1 初学者重要提示

  1.   ADS1256的模拟部分供电5V,SPI数字接口电平3.3V。
  2.   ADS1256的PGA可以编程增益支持: 1、2、4、8、16、32、64。
  3.   ADS1256支持自动校准 (当设置了PGA,BUF使能、数据采样率时,会启动自校准)。
  4.   ADS1256支持8通道单端ADC采集或者4通道差分采集。
  5.   ADS1256支持正负5V差分采集,但不支持负压,使用时要注意。
  6.   ADS1256时序操作稍有点特殊,所以本章是采用的模拟SPI控制。
  7.   ADS1256数据手册,模块原理图(通用版)和接线图都已经放到本章教程配置例子的Doc文件里。
  8.   ADC 的专业术语诠释文档,推荐大家看看:链接 。
  9.   测试时,务必使用外置电源为开发板供电,因为ADS1256需要5V供电电压。板子上插入ADS1256模块时,注意对齐。

93.2 ADC结构分类

这里将六种DAC结构为大家做个普及。注,这些知识翻译自美信和TI的英文技术手册。

93.2.1 SAR ADC(逐次逼近型)

逐次逼近型ADC通常是中高分辨率的首选架构,采样速率通常低于5Msps。SAR ADC最常见的分辨率范围是8位到20位,并具有低功耗和小尺寸的特点。这种组合使其非常适合各种应用,例如自动测试设备,电池供电的设备,数据采集系统,医疗仪器,电机和过程控制,工业自动化,电信,测试和测量,便携式系统,高速闭环系统和窄带接收器。

93.2.2 Sigma-Delta ADC

Sigma-delta ADC主要用于低速应用中,该应用需要通过过采样来权衡速度和分辨率,然后进行滤波以降低噪声。24位sigma-delta转换器用于自动化测试设备,高精度便携式传感器,医疗和科学仪器以及地震数据采集等应用中。

93.2.3 Integrating ADC

集成ADC提供高分辨率,并且可以提供良好的线路频率和噪声抑制。集成架构提供了一种新颖且直接的方法,可将低带宽模拟信号转换为数字表示形式。这些类型的转换器通常包括用于LCD或LED显示器的内置驱动器,并且在许多便携式仪器应用中都可以找到,包括数字面板表和数字万用表。

93.2.4 FLASH ADC

Flash ADC是将模拟信号转换为数字信号的最快方法。它们适用于需要非常大带宽的应用。然而,闪存转换器功率高,具有相对较低的分辨率,并且可能非常昂贵。这将它们限制在通常无法以其他任何方式解决的高频应用中。示例包括数据采集,卫星通信,雷达处理,示波器和高密度磁盘驱动器。

93.2.5 Pipelined ADC

流水线ADC已成为最受欢迎的ADC体系结构,其采样率从每秒几兆采样(MS / s)到最高100MS / s +,分辨率为8至16位。它们提供的分辨率和采样率,可覆盖各种应用,包括CCD成像,超声医学成像,数字接收器,基站,数字视频(例如HDTV),xDSL,电缆调制解调器和快速以太网。

93.2.6 Two Step ADC

两步ADC也称为子范围转换器,有时也称为多步或half flash(比Flash架构慢)。这是Flash ADC和流水线ADC的交叉点。与Flash ADC相比,可以实现更高的分辨率或更小的裸片尺寸。

93.3 ADS1256硬件设计

这里将开发板上的ADS1256硬件接口,ADS1256模块为大家做个说明。

ADS1256的原理图论坛下载:链接 。

93.3.1 ADS1256硬件接口

V7板子上ADS1256模块的插座的原理图如下:

实际对应开发板的位置如下:

为了方便大家更好的理解接线,下面是框图:

93.3.2 ADS1256模块

产品规格:

1、 单电源5.0V DC供电,提供正负5V信号采样功能。

2、 MCU接口:SPI。

3、 主ADC芯片:ADS1256  (全新进口原装正品)。

4、 电压基准,之前采用的LM285-2.5,现在采用的REF5025(全新进口原装正品)。

5、 输入电路带分压电阻和R-C滤波,方便客户自己变更增益范围。

6、 芯片内带可编程增益放大器,增益范围:1-64倍。

7、 芯片内部输入带缓冲放大器,可以直接连接传感器。

正面:

反面:

接线图:

93.4 ADS1256关键知识点整理(重要)

驱动ADS1256需要对下面这些知识点有个认识。

93.4.1 ADS1256基础信息

ADS1256是TI公司推出的微功耗、高精度、8通道、 24位△-∑型高性能模数转换器(ADC)。该器件提供高达23比特的无噪声精度、数据速率高达30kSPS(次采样/秒)、0.0010%非线性特性(最大值)以及众多的板上外设(输入模拟多路开关、输入缓冲器、可编程增益放大器和可编程数字滤波器等),可为设计人员带来完整而高分辨率的量测解决方案。

  •   24位无数据丢失;
  •   高达23比特的无噪声精度;
  •   低非线性度: ±0.0010% ;
  •   数据采样率可达30kSPS ;
  •   采用单周期转换模式;
  •   带有模拟多路开关,具有传感器接口(可配置为4路差动输入或8路单极输入) ;
  •   带有输入缓冲器( BUF) ;
  •   带有串行外设接口( SPI) ;
  •   内含低噪声可编程增益放大器( PGA ) ,所有的PGA均具有自校准和系统校准;
    •  PGA= 1时,可提供高达25.3位的有效分辨率;
    •  PGA = 64时,可提供高达22.5位的有效分辨率;
  •   模拟输入电压为5V ,数字电压为1.8~3.6V ;
  •   正常模式下功耗低至38mW ,备用模式下功耗为0.4mW。

93.4.2 ADS1256常用引脚的作用

ADS1256的封装形式:

这里把常用的几个引脚做个说明:

  •   AVDD

模拟电源供电。

  •   AGND

模拟地。

  •   VREFN

负参考电压输入。

  •   VREFP

正参考电压输入。

  •   AINCOM

模拟公共输入。

  •   AIN0 – AIN7

模拟输入通道0到通道7

  •   SYNC/PDWN

同步,掉电输入。

  •   RESET

复位引脚。

  •   DVDD

数字电源。

  •   DGND

数字地。

  •   XTAL1,XTAL2

晶振输入端。

  •   CS

片选输入端。

  •   DRDY

数据就绪输出信号引脚。

  •   DOUT

数据输出。

  •   DIN

数据输入。

  •   SCLK

时钟引脚。

  •   D0,D1,D2,D3

通用GPIO

93.4.3 ADS1256输出电压计算公式

ADS1256的计算公式如下:

最小单位值是2 * VREF/(PGA * (2^23 − 1))

采用二进制补码表示(其实就是24bit有符号数,我们将转换结果定义为int32_t即可)。

93.4.4 ADS1256时序图

驱动ADS1256主要是两个时序图需要了解,读写时序:

  •   t1:SPI时钟周期:

外部晶振频率 = 7.68MHz,

              时钟频率 tCLK = 1/7.68M = 0.13uS

              输出数据周期 tDATA =  1 / 30K = 0.033mS  (按30Ksps计算)

       对SPI的时钟速度要求:

              最快 4个tCLK = 0.52uS

              最慢 10个tDATA = 0.3mS (按 30Ksps 计算)

  •   t2H,t2L :脉冲高低电平:

SCL高电平和低电平持续时间最小 200ns。

数据读取流程:

  •   第1步:ADS1256_SetChannal(g_tADS1256.Channel)切换模拟通道。
  •   第2步:发送SYNC同步命令。
  •   第3步:唤醒。
  •   第4步:读取数据。

这个过程中特别注意读取的是上次转换的数据。

93.4.5 ADS1256的增益和测量范围问题

ADS1256的增益和测量范围关系如下:

比如增益是1时,测量范围是正负5V,增益是64时,测量范围是正负78.125mV。

93.4.6 ADS1256输入缓冲器

开关输入缓冲器时,影响到的几个参数,大家需要做个了解。

开缓冲的情况下,输入参考值噪声。

关闭缓冲时的输入参考噪声:

开缓冲的情况下,有效分辨率:

关闭缓冲时的有效位数:

打开缓冲器后的输入阻抗:

关闭缓冲器后的输入阻抗:

93.4.7 ADS1256支持的采样率

ADS1256支持的采样率如下,这里特别注意,因为切换通道和读数据耗时 123微秒, 因此扫描中断模式工作时,最大速率 = DRATE_1000SPS。

93.4.8 ADS1256的多路选择器,单端和多端输入

ADS1256的8路支持是通过多路选择器实现,8路采样时是选择相应通道进行采样:

实际应用的的8路单端采样和4路差分采样效果如下:

93.5 ADS1256驱动设计

ADS1256的程序驱动框架设计如下:

有了这个框图,程序设计就比较好理解了。

93.5.1 第1步,ADS1256所涉及到的GPIO配置

这里需要把用到的GPIO时钟、GPIO引脚配置好:

/*
    ADS1256模块    STM32-V7开发板(示波器接口)
      +5V   <------  5.0V      5V供电
      GND   -------  GND       地
      DRDY  ------>  PC6       准备就绪
      CS    <------  PC7       SPI_CS
      DIN   <------  PG10      SPI_MOSI
      DOUT  ------>  PA5       SPI_MISO
      SCLK  <------  PA4       SPI时钟
      GND   -------  GND       地
      PDWN  <------  PB7       掉电控制
      RST   <------  PC3       复位信号
      NC   空脚
      NC   空脚
*/

#ifdef SOFT_SPI		/* 软件SPI */
	/* 定义GPIO端口 */	
	#define SCK_CLK_ENABLE() 	__HAL_RCC_GPIOA_CLK_ENABLE()
	#define SCK_GPIO			GPIOA
	#define SCK_PIN			GPIO_PIN_4
	#define SCK_1()			SCK_GPIO->BSRR = SCK_PIN
	#define SCK_0()			SCK_GPIO->BSRR = ((uint32_t)SCK_PIN << 16U)	

	#define DIN_CLK_ENABLE() 	__HAL_RCC_GPIOG_CLK_ENABLE()
	#define DIN_GPIO			GPIOG
	#define DIN_PIN			GPIO_PIN_10
	#define DIN_1()			DIN_GPIO->BSRR = DIN_PIN
	#define DIN_0()			DIN_GPIO->BSRR = ((uint32_t)DIN_PIN << 16U)	

	#define CS_CLK_ENABLE() 	__HAL_RCC_GPIOC_CLK_ENABLE()
	#define CS_GPIO			GPIOC
	#define CS_PIN			GPIO_PIN_7
	#define CS_1()			CS_GPIO->BSRR = CS_PIN
	#define CS_0()			CS_GPIO->BSRR = ((uint32_t)CS_PIN << 16U)	

	#define DOUT_CLK_ENABLE() 	__HAL_RCC_GPIOA_CLK_ENABLE()
	#define DOUT_GPIO			GPIOA
	#define DOUT_PIN			GPIO_PIN_5
	#define DOUT_IS_HIGH()		((DOUT_GPIO->IDR & DOUT_PIN) != 0)

	#define DRDY_CLK_ENABLE() 	__HAL_RCC_GPIOC_CLK_ENABLE()
	#define DRDY_GPIO			GPIOC
	#define DRDY_PIN			GPIO_PIN_6
	#define DRDY_IS_LOW()		((DRDY_GPIO->IDR & DRDY_PIN) == 0)
	#define DRDY_IRQn 			EXTI9_5_IRQn
	#define DRDY_IRQHandler		EXTI9_5_IRQHandler	

	/* PDWN  <------  PB7       掉电控制 */
	#define PWDN_CLK_ENABLE() 	__HAL_RCC_GPIOB_CLK_ENABLE()
	#define PWDN_GPIO			GPIOB
	#define PWDN_PIN			GPIO_PIN_7
	#define PWDN_1()			PWDN_GPIO->BSRR = PWDN_PIN
	#define PWDN_0()			PWDN_GPIO->BSRR = ((uint32_t)PWDN_PIN << 16U)			
	
	/*  RST   <------  PC3       复位信号	 */
	#define RST_CLK_ENABLE() 	__HAL_RCC_GPIOC_CLK_ENABLE()
	#define RST_GPIO			GPIOC
	#define RST_PIN			GPIO_PIN_3
	#define RST_1()			RST_GPIO->BSRR = RST_PIN
	#define RST_0()			RST_GPIO->BSRR = ((uint32_t)RST_PIN << 16U)			
#endif

/*
*********************************************************************************************************
*	函 数 名: bsp_InitADS1256
*	功能说明: 配置STM32的GPIO和SPI接口,用于连接 ADS1256
*	形    参: 无
*	返 回 值: 无
*********************************************************************************************************
*/
void bsp_InitADS1256(void)

#ifdef SOFT_SPI
	GPIO_InitTypeDef gpio_init;
	
	RST_1();
	PWDN_1();
	CS_1();
	SCK_0();		/* SPI总线空闲时,钟线是低电平 */
	DIN_1();

	/* 打开GPIO时钟 */
	SCK_CLK_ENABLE();
	DIN_CLK_ENABLE();
	CS_CLK_ENABLE();
	DOUT_CLK_ENABLE();
	DRDY_CLK_ENABLE();
	PWDN_CLK_ENABLE();
	RST_CLK_ENABLE();

	/* 配置几个推完输出IO */
	gpio_init.Mode = GPIO_MODE_OUTPUT_PP;		/* 设置推挽输出 */
	gpio_init.Pull = GPIO_NOPULL;				/* 上下拉电阻不使能 */
	gpio_init.Speed = GPIO_SPEED_FREQ_HIGH;  	/* GPIO速度等级 */		
	
	gpio_init.Pin = SCK_PIN;	
	HAL_GPIO_Init(SCK_GPIO, &gpio_init);	

	gpio_init.Pin = DIN_PIN;	
	HAL_GPIO_Init(DIN_GPIO, &gpio_init);	
	
	gpio_init.Pin = CS_PIN;	
	HAL_GPIO_Init(CS_GPIO, &gpio_init);	

	gpio_init.Pin = PWDN_PIN;	
	HAL_GPIO_Init(PWDN_GPIO, &gpio_init);	

	/* DRDY 设置为输入 */
	gpio_init.Mode = GPIO_MODE_INPUT;		/* 设置输入 */
	gpio_init.Pull = GPIO_NOPULL;			/* 上下拉电阻不使能 */
	gpio_init.Speed = GPIO_SPEED_FREQ_HIGH;  	/* GPIO速度等级 */
	
	gpio_init.Pin = DRDY_PIN;	
	HAL_GPIO_Init(DRDY_GPIO, &gpio_init);	

	gpio_init.Pin = DOUT_PIN;	
	HAL_GPIO_Init(DOUT_GPIO, &gpio_init);	
#endif

这里重点注意DRDY转换就绪引脚的配置,DRDY_IRQn和DRDY_IRQHandler不要配置错了。

93.5.2 第2步,ADS1256的8bit读写函数实现

读写函数实现如下:

/*
*********************************************************************************************************
*	函 数 名: ADS1256_Send8Bit
*	功能说明: 向SPI总线发送8个bit数据。 不带CS控制。
*	形    参: _data : 数据
*	返 回 值: 无
*********************************************************************************************************
*/
static void ADS1256_Send8Bit(uint8_t _data)

	uint8_t i;

	/* 连续发送多个字节时,需要延迟一下 */
	ADS1256_DelaySCLK();
	ADS1256_DelaySCLK();

	/* ADS1256 要求 SCL高电平和低电平持续时间最小 200ns  */
	for(i = 0; i < 8; i++)
	
		if (_data & 0x80)
		
			DIN_1();
		
		else
		
			DIN_0();
		
		SCK_1();				
		ADS1256_DelaySCLK();		
		_data <<= 1;		
		SCK_0();			/* <----  ADS1256 是在SCK下降沿采样DIN数据, 数据必须维持 50nS */
		ADS1256_DelaySCLK();		
	


/*
*********************************************************************************************************
*	函 数 名: ADS1256_Recive8Bit
*	功能说明: 从SPI总线接收8个bit数据。 不带CS控制。
*	形    参: 无
*	返 回 值: 无
*********************************************************************************************************
*/
static uint8_t ADS1256_Recive8Bit(void)

	uint8_t i;
	uint8_t read = 0;

	ADS1256_DelaySCLK();
	/* ADS1256 要求 SCL高电平和低电平持续时间最小 200ns  */
	for (i = 0; i < 8; i++)
	
		SCK_1();
		ADS1256_DelaySCLK();
		read = read<<1;
		SCK_0();
		if (DOUT_IS_HIGH())
		
			read++;
				
		ADS1256_DelaySCLK();
	
	return read;

读写的实现完全按照下面的时序实现:

这里主要注意时间实现:

t1:SPI时钟周期:

外部晶振频率 = 7.68MHz,

              时钟频率 tCLK = 1/7.68M = 0.13uS

              输出数据周期 tDATA =  1 / 30K = 0.033mS  (按30Ksps计算)

       对SPI的时钟速度要求:

              最快 4个tCLK = 0.52uS

              最慢 10个tDATA = 0.3mS (按 30Ksps 计算)

t2H,t2L :脉冲高低电平:

SCL高电平和低电平持续时间最小 200ns。

93.5.3 第3步,ADS1256的24bit ADC数据读取

实现代码如下:

/*
*********************************************************************************************************
*	函 数 名: ADS1256_ReadData
*	功能说明: 读ADC数据
*	形    参: 无
*	返 回 值: 无
*********************************************************************************************************
*/
static int32_t ADS1256_ReadData(void)

	uint32_t read = 0;

	CS_0();	/* SPI片选 = 0 */

	ADS1256_Send8Bit(CMD_RDATA);	/* 读数据的命令 */
	
	ADS1256_DelayDATA();	/* 必须延迟才能读取芯片返回数据 */

	/* 读采样结果,3个字节,高字节在前 */
	read = ADS1256_Recive8Bit() << 16;
	read += ADS1256_Recive8Bit() << 8;
	read += ADS1256_Recive8Bit() << 0;

	CS_1();	/* SPI片选 = 1 */
	
	/* 负数进行扩展。24位有符号数扩展为32位有符号数 */
	if (read & 0x800000)
	
		read += 0xFF000000;
	
	
	return (int32_t)read;

这段代码里面关键是24bit数据的补码处理。对负数进行扩展,24位有符号数扩展为32位有符号数。

93.5.4 第3步,ADS1256增益和采样率配置

代码如下:

/*
*********************************************************************************************************
*	函 数 名: ADS1256_CfgADC
*	功能说明: 配置ADC参数,增益和数据输出速率
*	形    参: _gain : 支持增益参数。
*                    ADS1256_GAIN_1
*                    ADS1256_GAIN_2	
*                    ADS1256_GAIN_4
*                    ADS1256_GAIN_8
*                    ADS1256_GAIN_16
*                    ADS1256_GAIN_32
*                    ADS1256_GAIN_64
*
*			 _drate : 数据输出速率,不推荐超过1000SPS
*			 	   ADS1256_30000SPS
*			 	   ADS1256_15000SPS
*			 	   ADS1256_7500SPS
*			 	   ADS1256_3750SPS
*			 	   ADS1256_2000SPS
*			 	   ADS1256_1000SPS
*			 	   ADS1256_500SPS
*			 	   ADS1256_100SPS
*			 	   ADS1256_60SPS
*			 	   ADS1256_50SPS
*			 	   ADS1256_30SPS
*			 	   ADS1256_25SPS
*			 	   ADS1256_15SPS
*			 	   ADS1256_10SPS
*			 	   ADS1256_5SPS
*			 	   ADS1256_2d5SPS
*	返 回 值: 无
*********************************************************************************************************
*/
void ADS1256_CfgADC(ADS1256_GAIN_E _gain, ADS1256_DRATE_E _drate)
	
	g_tADS1256.Gain = _gain;
	g_tADS1256.DataRate = _drate;
	
	ADS1256_StopScan();			/* 暂停CPU中断 */
	
	ADS1256_ResetHard();		/* 硬件复位 */

	ADS1256_WaitDRDY();

	
		uint8_t buf[4];		/* 暂存ADS1256 寄存器配置参数,之后连续写4个寄存器 */
	
		buf[0] = (0 << 3) | (1 << 2) | (1 << 1);
		
		buf[1] = 0x08;	/* 高四位0表示AINP接 AIN0,  低四位8表示 AINN 固定接 AINCOM */

		buf[2] = (0 << 5) | (0 << 2) | (_gain << 1);

		/* 因为切换通道和读数据耗时 123uS, 因此扫描中断模式工作时,最大速率 = DRATE_1000SPS */
		buf[3] = s_tabDataRate[_drate];	// DRATE_10SPS;	/* 选择数据输出速率 */
		
		CS_0();	/* SPI片选 = 0 */
		ADS1256_Send8Bit(CMD_WREG | 0);	/* 写寄存器的命令, 并发送寄存器地址 */
		ADS1256_Send8Bit(0x03);			/* 寄存器个数 - 1, 此处3表示写4个寄存器 */
		
		ADS1256_Send8Bit(buf[0]);	/* 设置状态寄存器 */
		ADS1256_Send8Bit(buf[1]);	/* 设置输入通道参数 */
		ADS1256_Send8Bit(buf[2]);	/* 设置ADCON控制寄存器,增益 */
		ADS1256_Send8Bit(buf[3]);	/* 设置输出数据速率 */
		
		CS_1();	/* SPI片选 = 1 */		
	

	bsp_DelayUS(50);	

这个函数主要配置了4个ADS1256寄存器。

  •   设置状态寄存器:

程序中的配置为:buf[0] = (0 << 3) | (1 << 2) | (1 << 1) ,意思是LSB传输,自动校准,使能模拟输入缓冲。

  •   设置输入通道参数

程序中的配置为:buf[1] = 0x08, 高四位0表示AINp接通的 AIN0,  低四位8表示 AINn接通的 AINCOM。AINp和AINn表示当前的多路选择器选通的AIN0:

  •   设置ADCON控制寄存器,主要用于增益设置

程序中的配置为:buf[2] = (0 << 5) | (0 << 2) | (_gain << 1), 意思是关闭CLKOUT引脚输出,关闭传感器检测,设置增益为形参_gain。

  •   设置ADC采样率

程序中的配置为:buf[3] = s_tabDataRate[_drate],用于设置波特率:

static const uint8_t s_tabDataRate[ADS1256_DRATE_MAX] = 

	0xF0,		/* 复位时缺省值 */
	0xE0,
	0xD0,
	0xC0,
	0xB0,
	0xA1,
	0x92,
	0x82,
	0x72,
	0x63,
	0x53,
	0x43,
	0x33,
	0x20,
	0x13,
	0x03
;
typedef enum

	ADS1256_30000SPS = 0,
	ADS1256_15000SPS,
	ADS1256_7500SPS,
	ADS1256_3750SPS,
	ADS1256_2000SPS,
	ADS1256_1000SPS,
	ADS1256_500SPS,
	ADS1256_100SPS,
	ADS1256_60SPS,
	ADS1256_50SPS,
	ADS1256_30SPS,
	ADS1256_25SPS,
	ADS1256_15SPS,
	ADS1256_10SPS,
	ADS1256_5SPS,
	ADS1256_2d5SPS,
	
	ADS1256_DRATE_MAX
ADS1256_DRATE_E;

93.5.5 第4步,ADS1256启动采样

代码实现如下:

/*
*********************************************************************************************************
*	函 数 名: ADS1256_StartScan
*	功能说明: 将 DRDY引脚 (PC6 )配置成外部中断触发方式, 中断服务程序中扫描8个通道的数据。
*	形    参: 无
*	返 回 值: 无
*********************************************************************************************************
*/
void ADS1256_StartScan(void)

	/* PC6 外部中断,BUSY 
		配置 BUSY 作为中断输入口,下降沿触发 */
	
		GPIO_InitTypeDef   GPIO_InitStructure;
		
		DRDY_CLK_ENABLE();	/* 打开GPIO时钟 */

		GPIO_InitStructure.Mode = GPIO_MODE_IT_FALLING;
		GPIO_InitStructure.Pull = GPIO_NOPULL;
		GPIO_InitStructure.Pin = DRDY_PIN;
		HAL_GPIO_Init(DRDY_GPIO, &GPIO_InitStructure);	

		HAL_NVIC_SetPriority(DRDY_IRQn, 2, 0);
		HAL_NVIC_EnableIRQ(DRDY_IRQn);	
	
	
	/* 开始扫描前, 清零结果缓冲区 */	
	
		uint8_t i;
		
		g_tADS1256.Channel = 0;
		
		for (i = 0; i < 8; i++)
		
			g_tADS1256.AdcNow[i] = 0;
			
	

代码比较简单,主要是配置PC6的EXTI外部中断,并初始化变量。

93.5.6 第5步,ADS1256的中断处理(8通道数据读取)

代码如下:

/*
*********************************************************************************************************
*	函 数 名: EXTI9_5_IRQHandler
*	功能说明: 外部中断服务程序.  此程序执行时间约 123uS
*	形    参:无
*	返 回 值: 无
*********************************************************************************************************
*/
#ifdef EXTI9_5_ISR_MOVE_OUT		/* bsp.h 中定义此行,表示本函数移到 stam32f4xx_it.c。 避免重复定义 */
void EXTI9_5_IRQHandler(void)

	HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_6);


/*
*********************************************************************************************************
*	函 数 名: EXTI9_5_IRQHandler
*	功能说明: 外部中断服务程序入口。PI6 / AD7606_BUSY 下降沿中断触发
*	形    参: 无
*	返 回 值: 无
*********************************************************************************************************
*/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)

	if (GPIO_Pin == GPIO_PIN_6)
	

		ADS1256_ISR();
	

#endif

/*
*********************************************************************************************************
*	函 数 名: ADS1256_ISR
*	功能说明: 定时采集中断服务程序
*	形    参: 无
*	返 回 值: 无
*********************************************************************************************************
*/
void ADS1256_ISR(void)

	/* 读取采集结构,保存在全局变量 */					
	ADS1256_SetChannal(g_tADS1256.Channel);	/* 切换模拟通道 */	
	bsp_DelayUS(5);
	
	ADS1256_WriteCmd(CMD_SYNC);
	bsp_DelayUS(5);
	
	ADS1256_WriteCmd(CMD_WAKEUP);
	bsp_DelayUS(25);
	
	if (g_tADS1256.Channel == 0)
	
		g_tADS1256.AdcNow[7] = ADS1256_ReadData();	/* 注意保存的是上一个通道的数据 */
	
	else
	
		g_tADS1256.AdcNow[g_tADS1256.Channel-1] = ADS1256_ReadData(); /* 注意保存的是上一个通道的数据 */
	
				
	if (++g_tADS1256.Channel >= 8)
	
		g_tADS1256.Channel = 0;
	

中断服务程序的代码完全是按照下面的时序时序:

  •   第1步:ADS1256_SetChannal(g_tADS1256.Channel)切换模拟通道。
  •   第2步:发送SYNC同步命令。
  •   第3步:唤醒。
  •   第4步:读取数据。

这个过程中特别注意读取的是上次转换的数据。

93.6 ADS1256板级支持包(bsp_spi_ads1256.c)

ADS1256驱动文件bsp_spi_ads1256.c主要实现了如下几个API供用户调用:

  •   bsp_InitADS1256
  •   ADS1256_CfgADC
  •   ADS1256_StartScan
  •   ADS1256_SetChannal
  •   ADS1256_SetDiffChannal

93.6.1 函数bsp_InitADS1256

函数原型:

void bsp_InitADS1256(void)

函数描述:

主要用于ADS1256的初始化。

93.6.2 函数ADS1256_CfgADC

函数原型:

void ADS1256_CfgADC(ADS1256_GAIN_E _gain, ADS1256_DRATE_E _drate)

函数描述:

用于配置ADS1256的增益和采样率。

函数参数:

  •   第1个参数用于设置增益,支持的参数如下:

ADS1256_GAIN_1

ADS1256_GAIN_2     

ADS1256_GAIN_4

ADS1256_GAIN_8

ADS1256_GAIN_16

ADS1256_GAIN_32

ADS1256_GAIN_64

  •   第2个参数用于设置采样率,支持的参数如下:

ADS1256_30000SPS

ADS1256_15000SPS

ADS1256_7500SPS

ADS1256_3750SPS

ADS1256_2000SPS

ADS1256_1000SPS

ADS1256_500SPS

ADS1256_100SPS

ADS1256_60SPS

ADS1256_50SPS

ADS1256_30SPS

ADS1256_25SPS

ADS1256_15SPS

ADS1256_10SPS

ADS1256_5SPS

ADS1256_2d5SPS

93.6.3 函数ADS1256_StartScan

函数原型:

void ADS1256_StartScan(void)

函数描述:

此函数用于启动扫描,采样的中断方式。

93.6.4 函数ADS1256_SetChannal

函数原型:

static void ADS1256_SetChannal(uint8_t _ch)

函数描述:

此函数用于设置单端采样的通道。

函数参数:

  •   第1个参数支持0到7,0表示采样的通道0, 1表示采样的通道1,依次类推,范围0-7,共8个通道。

93.7 ADS1256实际测量效果(10uV抖动)

测试LM285-2.5V稳压效果,抖动40uV:

测试干电池效果,抖动10uV左右,注意,这个级别的抖动容易受环境温度的影响,特别是开关空调,最明显。

93.8 ADS1256驱动移植和使用

移植步骤如下:

  •   第1步:复制bsp_spi_ads1256.c和bsp_spi_ads1256.h到自己的工程目录,并添加到工程里面。
  •   第2步:根据使用的SPI引脚,DRDY就绪引脚,RST复位引脚,修改bsp_spi_ads1256.c开头的宏定义。
/* 定义GPIO端口 */	
#define SCK_CLK_ENABLE() 	__HAL_RCC_GPIOA_CLK_ENABLE()
#define SCK_GPIO			GPIOA
#define SCK_PIN				GPIO_PIN_4
#define SCK_1()				SCK_GPIO->BSRR = SCK_PIN
#define SCK_0()				SCK_GPIO->BSRR = ((uint32_t)SCK_PIN << 16U)	

#define DIN_CLK_ENABLE() 	__HAL_RCC_GPIOG_CLK_ENABLE()
#define DIN_GPIO			GPIOG
#define DIN_PIN				GPIO_PIN_10
#define DIN_1()				DIN_GPIO->BSRR = DIN_PIN
#define DIN_0()				DIN_GPIO->BSRR = ((uint32_t)DIN_PIN << 16U)	

#define CS_CLK_ENABLE() 	__HAL_RCC_GPIOC_CLK_ENABLE()
#define CS_GPIO				GPIOC
#define CS_PIN				GPIO_PIN_7
#define CS_1()				CS_GPIO->BSRR = CS_PIN
#define CS_0()				CS_GPIO->BSRR = ((uint32_t)CS_PIN << 16U)	

#define DOUT_CLK_ENABLE() 	__HAL_RCC_GPIOA_CLK_ENABLE()
#define DOUT_GPIO			GPIOA
#define DOUT_PIN			GPIO_PIN_5
#define DOUT_IS_HIGH()		((DOUT_GPIO->IDR & DOUT_PIN) != 0)

#define DRDY_CLK_ENABLE() 	__HAL_RCC_GPIOC_CLK_ENABLE()
#define DRDY_GPIO			GPIOC
#define DRDY_PIN			GPIO_PIN_6
#define DRDY_IS_LOW()		((DRDY_GPIO->IDR & DRDY_PIN) == 0)
#define DRDY_IRQn 			EXTI9_5_IRQn
#define DRDY_IRQHandler		EXTI9_5_IRQHandler	

/* PDWN  <------  PB7       掉电控制 */
#define PWDN_CLK_ENABLE() 	__HAL_RCC_GPIOB_CLK_ENABLE()
#define PWDN_GPIO			GPIOB
#define PWDN_PIN			GPIO_PIN_7
#define PWDN_1()			PWDN_GPIO->BSRR = PWDN_PIN
#define PWDN_0()			PWDN_GPIO->BSRR = ((uint32_t)PWDN_PIN << 16U)			

/*  RST   <------  PC3       复位信号	 */
#define RST_CLK_ENABLE() 	__HAL_RCC_GPIOC_CLK_ENABLE()
#define RST_GPIO			GPIOC
#define RST_PIN				GPIO_PIN_3
#define RST_1()				RST_GPIO->BSRR = RST_PIN
#define RST_0()				RST_GPIO->BSRR = ((uint32_t)RST_PIN << 16U)	
  •   第3步:特别注意中断服务程序的入口要根据使用的DRDY引脚修改。
/*
*********************************************************************************************************
*	函 数 名: EXTI9_5_IRQHandler
*	功能说明: 外部中断服务程序.  此程序执行时间约 123uS
*	形    参:无
*	返 回 值: 无
*********************************************************************************************************
*/
#ifdef EXTI9_5_ISR_MOVE_OUT		/* bsp.h 中定义此行,表示本函数移到 stam32f4xx_it.c。 避免重复定义 */
void EXTI9_5_IRQHandler(void)

	HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_6);


/*
*********************************************************************************************************
*	函 数 名: EXTI9_5_IRQHandler
*	功能说明: 外部中断服务程序入口。PI6 / AD7606_BUSY 下降沿中断触发
*	形    参: 无
*	返 回 值: 无
*********************************************************************************************************
*/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)

	if (GPIO_Pin == GPIO_PIN_6)
	

		ADS1256_ISR();
	

#endif
  •   第4步:应用方法看本章节配套例子即可。

93.9 实验例程设计框架

通过程序设计框架,让大家先对配套例程有一个全面的认识,然后再理解细节,本次实验例程的设计框架如下:

  第1阶段,上电启动阶段:

  • 这部分在第14章进行了详细说明。

  第2阶段,进入main函数:

  •   第1部分,硬件初始化,主要是MPU,Cache,HAL库,系统时钟,滴答定时器和LED。
  •   第2部分,应用程序设计部分,测试ADS1256。

93.10          实验例程说明(MDK)

配套例子:

V7-068_ADS1256(8通道带PGA的24位ADC)

实验目的:

  1. 学习ADS1256, 8通道带PGA的24bit ADC。

重要提示:

  1. 开发板请使用外置电源供电。

实验内容:

  1. 启动一个自动重装软件定时器,每100ms翻转一次LED2。
  2. 上电后插入ADS1256模块到右上角CN26(2*6P双排母), 程序每1秒打印一次8通道采样数据。

上电后串口打印的信息:

波特率 115200,数据位 8,奇偶校验位无,停止位 1。

模块插入位置:

程序设计:

  系统栈大小分配:

  RAM空间用的DTCM:

  硬件外设初始化

硬件外设的初始化是在 bsp.c 文件实现:

/*
*********************************************************************************************************
*	函 数 名: EXTI9_5_IRQHandler
*	功能说明: 外部中断服务程序.  此程序执行时间约 123uS
*	形    参:无
*	返 回 值: 无
*********************************************************************************************************
*/
#ifdef EXTI9_5_ISR_MOVE_OUT		/* bsp.h 中定义此行,表示本函数移到 stam32f4xx_it.c。 避免重复定义 */
void EXTI9_5_IRQHandler(void)

	HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_6);


/*
*********************************************************************************************************
*	函 数 名: EXTI9_5_IRQHandler
*	功能说明: 外部中断服务程序入口。PI6 / AD7606_BUSY 下降沿中断触发
*	形    参: 无
*	返 回 值: 无
*********************************************************************************************************
*/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)

	if (GPIO_Pin == GPIO_PIN_6)
	

		ADS1256_ISR();
	

#endif

  MPU配置和Cache配置:

数据Cache和指令Cache都开启。配置了AXI SRAM区(本例子未用到AXI SRAM)和FMC的扩展IO区。

/*
*********************************************************************************************************
*	函 数 名: MPU_Config
*	功能说明: 配置MPU
*	形    参: 无
*	返 回 值: 无
*********************************************************************************************************
*/
static void MPU_Config( void )

	MPU_Region_InitTypeDef MPU_InitStruct;

	/* 禁止 MPU */
	HAL_MPU_Disable();

	/* 配置AXI SRAM的MPU属性为Write back, Read allocate,Write allocate */
	MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
	MPU_InitStruct.BaseAddress      = 0x24000000;
	MPU_InitStruct.Size             = MPU_REGION_SIZE_512KB;
	MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
	MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;
	MPU_InitStruct.IsCacheable      = MPU_ACCESS_CACHEABLE;
	MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
	MPU_InitStruct.Number           = MPU_REGION_NUMBER0;
	MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL1;
	MPU_InitStruct.SubRegionDisable = 0x00;
	MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;

	HAL_MPU_ConfigRegion(&MPU_InitStruct);
	
	
	/* 配置FMC扩展IO的MPU属性为Device或者Strongly Ordered */
	MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
	MPU_InitStruct.BaseAddress      = 0x60000000;
	MPU_InitStruct.Size             = ARM_MPU_REGION_SIZE_64KB;	
	MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
	MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;
	MPU_InitStruct.IsCacheable      = MPU_ACCESS_NOT_CACHEABLE;	
	MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
	MPU_InitStruct.Number           = MPU_REGION_NUMBER1;
	MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;
	MPU_InitStruct.SubRegionDisable = 0x00;
	MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;
	
	HAL_MPU_ConfigRegion(&MPU_InitStruct);

	/*使能 MPU */
	HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);


/*
*********************************************************************************************************
*	函 数 名: CPU_CACHE_Enable
*	功能说明: 使能L1 Cache
*	形    参: 无
*	返 回 值: 无
*********************************************************************************************************
*/
static void CPU_CACHE_Enable(void)

	/* 使能 I-Cache */
	SCB_EnableICache();

	/* 使能 D-Cache */
	SCB_EnableDCache();

  每10ms调用一次按键处理:

按键处理是在滴答定时器中断里面实现,每10ms执行一次检测。

/*
*********************************************************************************************************
*	函 数 名: bsp_RunPer10ms
*	功能说明: 该函数每隔10ms被Systick中断调用1次。详见 bsp_timer.c的定时中断服务程序。一些处理时间要求
*              不严格的任务可以放在此函数。比如:按键扫描、蜂鸣器鸣叫控制等。
*	形    参: 无
*	返 回 值: 无
*********************************************************************************************************
*/
void bsp_RunPer10ms(void)

	bsp_KeyScan10ms();

  主功能:

主程序实现如下操作:

  •   启动一个自动重装软件定时器,每100ms翻转一次LED2。
  •   上电后插入ADS1256模块到右上角CN26(2*6P双排母), 程序每1秒打印一次8通道采样数据。
/*
*********************************************************************************************************
*	函 数 名: main
*	功能说明: c程序入口
*	形    参: 无
*	返 回 值: 错误代码(无需处理)
*********************************************************************************************************
*/
int main(void)

	uint8_t i;
	int32_t iTemp;
	float fTemp;

	
	bsp_Init();		/* 硬件初始化 */
	PrintfLogo();	/* 打印例程信息到串口1 */

	PrintfHelp();	/* 打印操作提示信息 */
	
	
	bsp_DelayMS(500);	/* 等待上电稳定,等基准电压电路稳定, bsp_InitADS1256() 内部会进行自校准 */

	bsp_InitADS1256();	/* 初始化配置ADS1256.  PGA=1, DRATE=30KSPS, BUFEN=1, 输入正负5V */
	
	
	/* 打印芯片ID (通过读ID可以判断硬件接口是否正常) , 正常时状态寄存器的高4bit = 3 */
#if 0
	
		uint8_t id;

		id = ADS1256_ReadChipID();

		if (id != 3)
		
			printf("Error, ASD1256 Chip ID = 0x%X\\r\\n", id);
		
		else
		
			printf("Ok, ASD1256 Chip ID = 0x%X\\r\\n", id);
		
	
#endif
	
	ADS1256_CfgADC(ADS1256_GAIN_1, ADS1256_30SPS);	/* 配置ADC参数: 增益1:1, 数据输出速率 30Hz */

/* 启动中断扫描模式, 轮流采集8个通道的ADC数据. 通过 ADS1256_GetAdc() 函数来读取这些数据 */
	ADS1256_StartScan();	
	
	bsp_StartAutoTimer(0, 1000);	/* 启动1个100ms的自动重装的定时器 */

	/* 进入主程序循环体 */
	while (1)
	
		bsp_Idle();		/* 这个函数在bsp.c文件。用户可以修改这个函数实现CPU休眠和喂狗 */
		

		if (bsp_CheckTimer(0))	/* 判断定时器超时时间 */
		
			/* 每隔1000ms 进来一次 */
			bsp_LedToggle(2);	/* 翻转LED的状态 */
			
			/* 打印采集数据 */
			for (i = 0; i < 8; i++)
			

                  /*
                    计算公式:2 * VREF/(PGA * (2^23 - 1)) ,这里VREF是2.5V,PGA = 1
                  */
                   /* 计算实际电压值(近似估算的),如需准确,请进行校准 */
				iTemp = ((int64_t)g_tADS1256.AdcNow[i] * 2500000) / 4194303; 

				
				fTemp = (float)iTemp / 1000000;   

				printf("CH%d=%07d(%fV) ", i, g_tADS1256.AdcNow[i], fTemp);

				if(i == 3)
				
					printf("\\r\\n");
				
			
			
			printf("\\r\\n\\r\\n");
		
	

93.11          实验例程说明(IAR)

配套例子:

V7-068_ADS1256(8通道带PGA的24位ADC)

实验目的:

  1. 学习ADS1256, 8通道带PGA的24bit ADC。

重要提示:

  1. 开发板请使用外置电源供电。

实验内容:

  1. 启动一个自动重装软件定时器,每100ms翻转一次LED2。
  2. 上电后插入ADS1256模块到右上角CN26(2*6P双排母), 程序每1秒打印一次8通道采样数据。

上电后串口打印的信息:

波特率 115200,数据位 8,奇偶校验位无,停止位 1。

模块插入位置:

程序设计:

  系统栈大小分配:

  RAM空间用的DTCM:

STM32H7教程第75章 STM32H7的SPI总线应用之驱动DAC8501(双路输出,16bit分辨率,0-5V)

STM32H7教程第75章 STM32H7的SPI总线应用之驱动DAC8501(双路输出,16bit分辨率,0-5V)

STM32H7教程第14章 STM32H7的电源,复位和时钟系统

STM32H7的SPI总线基础知识和HAL库API

STM32H7教程第39章 STM32H7的DMAMUX基础知识(重要)

STM32H7的SPI总线应用之双机通信(DMA方式)