【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:

  硬件外设初始化

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

/*
*********************************************************************************************************
*	函 数 名: bsp_Init
*	功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
*	形    参:无
*	返 回 值: 无
*********************************************************************************************************
*/
void bsp_Init(void)
{
    /* 配置MPU */
	MPU_Config();
	
	/* 使能L1 Cache */
	CPU_CACHE_Enable();

	/* 
       STM32H7xx HAL 库初始化,此时系统用的还是H7自带的64MHz,HSI时钟:
	   - 调用函数HAL_InitTick,初始化滴答时钟中断1ms。
	   - 设置NVIV优先级分组为4。
	 */
	HAL_Init();

	/* 
       配置系统时钟到400MHz
       - 切换使用HSE。
       - 此函数会更新全局变量SystemCoreClock,并重新配置HAL_InitTick。
    */
	SystemClock_Config();

	/* 
	   Event Recorder:
	   - 可用于代码执行时间测量,MDK5.25及其以上版本才支持,IAR不支持。
	   - 默认不开启,如果要使能此选项,务必看V7开发板用户手册第xx章
	*/	
#if Enable_EventRecorder == 1  
	/* 初始化EventRecorder并开启 */
	EventRecorderInitialize(EventRecordAll, 1U);
	EventRecorderStart();
#endif
	
bsp_InitDWT();      /* 初始化DWT时钟周期计数器 */       
	bsp_InitKey();    	 /* 按键初始化,要放在滴答定时器之前,因为按钮检测是通过滴答定时器扫描 */
	bsp_InitTimer();  	 /* 初始化滴答定时器 */
	bsp_InitLPUart();	 /* 初始化串口 */
	bsp_InitExtIO();	 /* 初始化FMC总线74HC574扩展IO. 必须在 bsp_InitLed()前执行 */	
	bsp_InitLed();    	 /* 初始化LED */	
bsp_InitExtSDRAM(); /* 初始化SDRAM */

	/* 针对不同的应用程序,添加需要的底层驱动模块初始化函数 */	
	bsp_InitAD7606();	/* 配置AD7606所用的GPIO */
}

  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.12   总结

本章节涉及到的知识点非常多,主要为大家讲解了ADS1256的常用玩法,如果实际项目中用到此芯片需要熟练运用。

  • 15
    点赞
  • 126
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
STM32单片机(STM32F429)读写(8通道带PGA的24ADCADS1256软件例程源码,可以做为你的学习设计参考。 int main(void) { uint8_t i; bsp_Init(); PrintfLogo(); /* 打印例程Logo到串口1 */ bsp_DelayMS(100); /* 等待上电稳定,等基准电压电路稳定, 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, 数据输出速率 1KHz */ ADS1256_StartScan(); /* 启动中断扫描模式, 轮流采集8个通道ADC数据. 通过 ADS1256_GetAdc() 函数来读取这些数据 */ while (1) { bsp_Idle(); /* 空闲时执行的函数,比如喂狗. 在bsp.c中 */ /* 打印采集数据 */ for (i = 0; i < 8; i++) { int32_t iTemp; iTemp = ((int64_t)g_tADS1256.AdcNow[i] * 2500000) / 4194303; /* 计算实际电压值(近似估算的),如需准确,请进行校准 */ if (iTemp < 0) { iTemp = -iTemp; printf("%d=%6d,(-%d.%03d %03d V) ", i, g_tADS1256.AdcNow[i], iTemp /1000000, (iTemp%1000000)/1000, iTemp%1000); } else { printf("%d=%6d,( %d.%03d %03d V) ", i, g_tADS1256.AdcNow[i], iTemp/1000000, (iTemp%1000000)/1000, iTemp%1000); } } printf("\r\n"); bsp_DelayMS(500); /* 每隔500ms 输出一次数据 */ } }
流水线ADC是一种高效的模数转换器,它可以在较短的时间内将模拟信号转换为数字信号。在MATLAB中,我们可以通过建立流水线ADC的模型来模拟其工作原理和性能。 为了熟悉流水线ADC的工作原理,我们可以参考中提供的MATLAB模型。该模型可能包括各种组成部分,如前端采样电路、数字处理单元和数据总线等。通过对模型进行分析,我们可以了解各个阶段的工作原理以及信号在流水线中的传递过程。 在流水线ADC的设计中,余量增益曲线是一个重要的性能指标。它描述了在不同输入信号下,流水线ADC输出的数字码的准确性。理想情况下,余量增益曲线应该是线性的,并且输出的数字码应该与输入信号直接相关。通过分析余量增益曲线,我们可以评估流水线ADC的精度和动态范围。 除了余量增益曲线,流水线ADC还可以通过错位相加输出来获得10位数字码。这意味着每个阶段的数字码被错位相加,最终得到一个10位的数字码。这种方法可以提高流水线ADC的效率和性能。 此外,关于流水线ADC性能的评估,还可以使用THD(总谐波失真)来计算。根据中提到的,THD是从第二到第五阶谐波计算得出的。通过计算不同阶次的谐波成分,我们可以评估流水线ADC的非线性失真程度。 另外,根据中提到的,计算SINAD(信噪比与失真比)和ENOB(等效位数)也是评估流水线ADC性能的一种方法。这种方法通过分析信号与噪声和失真之间的关系来评估流水线ADC的性能。 总结起来,MATLAB可以用来建立流水线ADC的模型,并通过分析余量增益曲线、错位相加输出、THD、SINAD和ENOB等指标来评估其性能。这些指标可以帮助我们了解流水线ADC的工作原理和性能特点。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值