【GD32篇】驱动AD7616完成数据采集

1.AD7616介绍

1.1 概述:

         AD7616 是一款 16 DAS(数据采集系统) ,支持对 16 个通道进行双路同步采样。 AD7616 采用 5 V 单电源供电,可以处理 ±10 V ±5 V 和±2.5 V 真双极性输入信号 ,同时每对通道均能以高达 1 MSPS的吞吐速率和 90.5 dB SNR 采样。利用片内过采样模式可实现更高的SNR 性能(过采样率 (OSR) 2 时, SNR 为92 dB)。输入箝位保护电路可以耐受高达±21 V 的电压。无论以何种采样频率工作 AD7616 的模拟输入阻抗均为 1 MΩ 。它采用单电源工作方式,具有片内滤波和高输入阻抗,因此无需驱动运算放大器和外部双极性电源。该器件均内置模拟输入箝位保护、一个双路 16 位电荷再分配 SAR 模数转换器 (ADC) 、一个灵活的数字滤波器、 2.5 V基准电压源和基准电压缓冲器以及高速串行和并行接口。 AD7616 兼容串行外设接口 (SPI)/QSPI/DSP/MICROWIRE

1.2 产品特性:

16 通道 双路 同步采样输入
可独立选择的通道输入范围
        真双极性 ±10 V ±5 V ±2.5 V
5 V 单模拟电源 V DRIVE 电源电压 2.3 V 3.6 V
完全集成的数据采集解决方案
        模拟输入箝位保护
        具有 1 MΩ 模拟输入阻抗的输入缓冲器
        一阶抗混叠模拟滤波器
        片内精密基准电压及基准电压缓冲器
        双通道 16 位逐次逼近型寄存器 (SAR)ADC
        吞吐速率 2×1 MSPS
        通过数字滤波器提供过采样功能
        灵活的序列器 支持突发模式
灵活的并行 / 串行接口
        SPI/QSPI/MICROWIRE/DSP 兼容
        可选循环冗余校验 (CRC) 错误检查
硬件 / 软件配置
性能
        信噪比 (SNR) 92 dB 500 kSPS 2 倍过采样
        信噪比 (SNR) 90.5 dB (1 MSPS)
        总谐波失真 (THD) −103 dB
        ±1 LSB INL( 典型值 ), ±0.99 LSB DNL 最大值
        模拟输入通道提供 8 kV ESD 额定值
片内自检测功能
80 引脚 LQFP 封装

1.3 引脚配置:

注: 引脚的功能配置详情需查看AD7616数据手册

1.4 时序图

图1.所有接口的通用时序图
图2.复位时序图
参数表1
图3.并行读取时序图
参数表2

        本次学习只使用了AD7616硬件模式下并行接口读取数据,而对于AD7616软件模式、串行接口、并行接口写操作未作介绍。

2.解析数据手册

2.1 引脚连接

35 REFSELGNDDI使用外部基准电压
36 RESETPB11DI复位输入,低有效
37 SEQEN+3.3VDI通道序列器使能
38 HW_RNGSEL1GNDDI硬件模式模拟输入范围±2.5V
39 HW_RNGSEL0+3.3VDI
40 SER/PARGNDDI并行接口选择输入
41-48 DB0-7PD0-PD7O/I并行输出
53-60 DB8-15PD8-PD15
61 WR/BURST+3.3VDI突发模式使能
62 SCLK/RDPE9DI并行数据读取控制输入如果CS,RD均为逻辑低电平,则使能输出总线
63 CSPE10DI片选
64-66 CHSEL0-2+3.3VDI
67 BUSY
PE12DO输出繁忙CONVST 上升沿之后,此引脚变为逻辑高电平,表示转换过程已开始。 
BUSY 输出保持高电平,直到当前选定通道的转换过程完成为止。BUSY 下降沿表示转换数据正被锁存至输出数据寄存器,稍后便可供读取。数据必须在 BUSY 变为低电平之后读取。当 BUSY 信号为高电平时,CONVST 的上升沿不起作用。
68 CONVSTPE11DI通道组A/B的转换开始输入在序列器模式下,当突发模式或过采样模式使能时,为了执行所需数量的转换,只需 CONVST 从低电平变为高电平一次。

注意:未与GPIO连接的引脚,已经与开发板焊死,写代码时不需要为其配置。

2.2工作模式

工作模式(硬件模式或软件模式) 在AD7616退出完全复位时配置 当 RESET 引脚从低电平变为高电平时,HW_RNGSELx 引脚的逻辑电平决定工作模式。HW_RNGSELx引脚具有双重功能。如果 HW_RNGSELx = 0b00,则 AD7616 进入软件模式。 HW_RNGSELx 的任何其它 组合都会将 AD7616 配置为硬件模式 。配置软件模式后,便会忽略 HW_RNGSELx 信号的逻辑电平。配置一种工作模式后,要退出该工作模式并设置另一种工作模式,需要通过RESET 引脚执行完全复位。若选择硬件模式,则所有后续器件配置都是通过引脚控制进行。硬件模式下禁止访问片内寄存器。在软件模式下,接口和基准电压配置必须通过引脚控制进行,但所有后续器件配置只能通过寄存器进行。

2.3数字接口

数字接口选择(并行或串行) 在AD7616退出完全复位时配置 。当RESET 引脚从低电平变为高电平时, SER/PAR 信号的逻辑电平配置该接口。若SER/PAR 信号设为 0 ,则使能并行接口。若SER/PAR 信号设为 1 ,则选择串行接口。

2.4复位功能

AD7616 有两种复位模式:完全或部分。复位模式选择取决于复位低电平脉冲的长度。部分复位要求RESET 引脚保持低电平40 ns到 500 ns 。释放 RESET 50 ns 之后,器件即完全可用,可以启动转换。完全复位要求RESET 引脚保持低电平至少 1.2 μs 。释放RESET 15 ms 之后,器件完成重新配置,可以启动转换。部分复位会重新初始化下列模块
序列器
数字滤波器
SPI
两个 SAR ADC
部分复位完成时,会丢弃当前转换结果。部分复位不会影响软件模式下设置的寄存器值,或硬件和软件模式下存储用户配置的锁存器。部分复位之后,软件模式下需要执行一次伪转换。完全复位会将器件复位至默认上电状态。 AD7616 退出完全复位时 会配置如下内容
硬件模式 或软件模式
内部 / 外部基准电压源
接口类型   (本文为并行接口)
上电时,一旦 V CC V DRIVE 电源均稳定下来,便可释放 RESET信号。完全复位后释放RESET 引脚时, HW_RNGSELx 、REFSEL、 SER/PAR DB4/SER1W 引脚的逻辑电平决定器件配置。
若选择硬件模式,则当RESET 引脚在完全复位模式下从低电平变为高电平时,CRC BURSTEN SEQEN OSx 信号所决定的功能也会被锁存。完成功能配置后,便会忽略这些信号 的变化。在硬件模式下,模拟输入范围(HW_RNGSELx 信号)可在完全或部分复位期间或正常工作期间配置,但硬件/软件模式选择需要完全复位才能重新配置,同时此设置会被锁存。在硬件模式下,退出完全和部分复位时均会查询CHSELx 和HW_RNGSELx引脚,以便执行如下操作
确定要获取哪一个初始模拟输入通道对进行转换。
配置序列器的初始设置。
选择模拟输入电压范围。

2.5 *序列器

AD7616 有一个高度可配置的片内序列器。序列器的功能和配置取决于 AD7616 的工作模式。 在硬件模式下,序列器只能按顺序工作,总是从通道V0A和V0B开始转换,然后依次转换后续各通道,直至配置的最后一个通道。
在硬件模式下,序列器由 SEQEN 引脚和 CHSELx 引脚配置。当 AD7616 退出完全复位时,序列器要么使能,要么禁用。
图4
当序列器使能时, CHSELx 引脚的逻辑电平决定选择哪些通 道在序列中进行转换。
图5

 2.6 *突发序列器

        突发模式下不需要为转换序列中的每个步骤产生一个CONVST脉冲。一个CONVST 脉冲就能转换序列中的每个步 骤。
        突发序列器是一个配合序列器工作的额外特性。若使能突发功能,则一个CONVST脉冲就能启动序列器中配置的所有通道的转换。使用突发功能时,无需为转换序列中的每个步骤产生一个CONVST 脉冲,若禁用突发功能则不然。
硬件突发序列器:
        将BURST 引脚置 1 ,就会在硬件模式下使能突发模式。还要将SEQEN 引脚置 1 以使能序列器。
        在硬件模式下,突发序列器由BURST SEQEN CHSELx 引脚配置。 AD7616 退出完全复位时,突发序列器要么使能,要么禁用。当释放RESET 引脚时, SEQEN 引脚和 BURST 引脚的逻辑电平决定突发序列器是使能还是禁用。释放RESET 引脚后,该功能便固定下来,要退出该功能并设置另一种配置,需要通过RESET 引脚执行完全复位。
        当突发序列器使能时,CHSELx 引脚的逻辑电平决定选择哪些通道在突发序列中进行转换。释放RESET 引脚时的 CHSELx 引脚状态决定要在序列中转换的通道初始设置。要在复位后重新
配置选定进行转换的通道,请将 CHSELx 引脚设为所需的设置并保持下一个BUSY 脉冲时间。
图6.BURST序列器硬件模式

 3. 驱动代码编写

 3.1 配置引脚功能

        配置AD7616引脚功能时需要注意,BUSY引脚类型为DO(只具备输出功能),而对于主芯片(GD32)来说,只需要配置为输入模式即可。而AD7616数据总线DB0-DB15为数字输出,对于主芯片而言并非模拟输入,而是数字输入(因为AD7616通过模拟输入引脚采集模拟数据,芯片内部已经将模拟量转换为数字量)。

//GPIO引脚初始化
void AD7616_PinInit(void)
{
	gpio_init(GPIOE,GPIO_MODE_OUT_PP,GPIO_OSPEED_50MHZ,GPIO_PIN_9|\
						GPIO_PIN_10|GPIO_PIN_11);//通用推挽输出
	gpio_init(GPIOE,GPIO_MODE_IN_FLOATING,GPIO_OSPEED_50MHZ,GPIO_PIN_12);//浮空输入
	gpio_init(GPIOB,GPIO_MODE_OUT_PP,GPIO_OSPEED_50MHZ,GPIO_PIN_11);//通用推挽输出
	
	gpio_init(GPIOD,GPIO_MODE_IPU|GPIO_MODE_IPD,GPIO_OSPEED_50MHZ,GPIO_PIN_ALL);//PD所有引脚为上下拉输入
}
//配置BUSY引脚外部中断
void AD7616_BUSY_ExtiConfig(void)
{
	gpio_exti_source_select(GPIO_PORT_SOURCE_GPIOE,GPIO_PIN_SOURCE_12);//选择gpio引脚中断源
	exti_init(EXTI_12,EXTI_INTERRUPT,EXTI_TRIG_FALLING);//下降沿触发
	exti_interrupt_flag_clear(EXTI_12);//清除中断标志位
	exti_interrupt_enable(EXTI_12);//启用中断线
}

3.2 AD7616初始化配置

  本文使用的主芯片(GD32F10x)时钟频率为108MHZ,

而延时函数AD7616_Delay_9ns(uint32_t ns)只是通过while循环做空操作。

/*
	\brief:	AD7616复位功能配置
	\param:	mode : 复位模式
				AD7616_ALL_RESER :完全复位
				AD7616_PART_RESER :部分复位
	\retval:	none
*/
void AD7616_Reser(uint8_t mode)
{
	switch(mode)
	{
		case AD7616_ALL_RESER: //完全复位
			 AD7616_RESET_0;
			 AD7616_Delay_9ns(140);
			 AD7616_RESET_1;
			 delay_1ms(15);
			 break;
		case AD7616_PART_RESER: //部分复位
			 AD7616_RESET_0;
			 delay_1us(40);
			 AD7616_RESET_1;
			 AD7616_Delay_9ns(5);
			 break;
		default:
			 break;
	}
}

//AD7616初始化
void AD7616_Init(void)
{
	AD7616_PinInit();//引脚初始化
	AD7616_BUSY_ExtiConfig();//配置BUSY引脚外部中断
	//AD7616_RESET_1;
	//AD7616_Reser(AD7616_PART_RESER);//部分复位
	AD7616_Reser(AD7616_ALL_RESER);//完全复位
    //未使能输出总线
	AD7616_RD_1;
	AD7616_CS_1;
    AD7616_CONVST_0;//拉低CONVST电平
}

3.3启动一次转换

//AD值转换为实际温度值
float AD7616_ad_TO_temp(uint16_t i,const uint16_t ad)
{
	return (float)(AD7616_CH_member[i].A*ad*ad + AD7616_CH_member[i].B*ad + AD7616_CH_member[i].C);
}
/*
	AD7616转换函数
*/
void EXTI10_15_IRQHandler(void)
{
	if(RESET!=exti_interrupt_flag_get(EXTI_12))
	{
		exti_interrupt_flag_clear(EXTI_12);//清除中断标志位
		uint16_t i;
        AD7616_CONVST_0;
		for(i=0;i<AD7616_CHANNEL_VAL;i++)
		{
			//printf("BUSY=%d\n",gpio_input_bit_get(GPIOE,GPIO_PIN_12));//启动转换后BUSY为低电平
            AD7616_CS_0;
			AD7616_RD_0;				//低电平时间>30ns
			AD7616_Data[i]=AD7616_GET_DATA();//读取数据
			AD7616_RD_1;				//高电平时间>10ns
			AD7616_CS_1;
			AD7616_Delay_9ns(3);
		}
		AD7616_READ_STATE=AD7616_STATE_READABLE;//可读
		//AD7616_CONVST_0;
	}
}
//启动转换
void AD7616_StartConvst(void)
{
	memset(AD7616_Data,0,AD7616_CHANNEL_VAL);//清空缓存
	//AD7616_CONVST_0;
	//AD7616_Delay_9ns(1);
	AD7616_CONVST_1;
	//printf("BUSY=%d\n",gpio_input_bit_get(GPIOE,GPIO_PIN_12));//未启动转换时BUSY为高电平
}
/*
	\brief:	启动多次转换,并求取各通道AD平均值
	\param:	*ad 接收AD值的地址
				count 启动次数
	\retval:	ERROR 超时    SUCCESS 成功转换
*/

ErrStatus AD7616_Convst_Average(const uint32_t count)
{
	uint32_t i,j;
	uint32_t sum[AD7616_CHANNEL_VAL]={0};
	for(i=0;i<count;i++)
	{
		AD7616_READ_STATE=AD7616_STATE_UNREADABLE;//不可读
		AD7616_StartConvst();//开始转换
		j=0;
		while(AD7616_READ_STATE!=AD7616_STATE_READABLE)//等待转换完成
		{
			AD7616_Delay_9ns(1);
			j++;
			if(j==500000) return ERROR;//超时
		}
		for(j=0;j<AD7616_CHANNEL_VAL;j++)
		{
			sum[j]+=AD7616_Data[j];
		}
	}
	//取平均值
	for(i=0;i<AD7616_CHANNEL_VAL;i++)
	{
		AD7616_AD[i]=sum[i]/count;
		AD7616_Temp[i]=AD7616_ad_TO_temp(i,AD7616_AD[i]);//转换温度
	}
	return SUCCESS;
}

3.4 头文件

#ifndef _AD7616_H_
#define _AD7616_H_

#include "gd32f10x.h"
#include "flash.h"
#include <string.h>
#include <stdlib.h>
/*
	Pin:
	RD 	-- PE9		
	CS   	-- PE10		片选
	CONVST 	-- PE11		
	BUSY 	-- PE12     
	RESET	-- PB11     
	DB0~DB15 -- PD0~PD15
*/
/* Pin define */
#define AD7616_RESET_0 	gpio_bit_reset(GPIOB,GPIO_PIN_11)
#define AD7616_RESET_1 	gpio_bit_set(GPIOB,GPIO_PIN_11)
#define AD7616_RD_0 	gpio_bit_reset(GPIOE,GPIO_PIN_9)
#define AD7616_RD_1 	gpio_bit_set(GPIOE,GPIO_PIN_9)
#define AD7616_CS_0		gpio_bit_reset(GPIOE,GPIO_PIN_10)
#define AD7616_CS_1		gpio_bit_set(GPIOE,GPIO_PIN_10)
#define AD7616_CONVST_0 gpio_bit_reset(GPIOE,GPIO_PIN_11)
#define AD7616_CONVST_1 gpio_bit_set(GPIOE,GPIO_PIN_11)
#define AD7616_BUSY_1	gpio_bit_set(GPIOE,GPIO_PIN_12)
#define AD7616_BUSY_LEVEL() gpio_input_bit_get(GPIOE,GPIO_PIN_12)
#define AD7616_INPUT_DB(x) 	gpio_input_bit_get(GPIOD,BIT(x))//数据引脚0-15
#define AD7616_GET_DATA() gpio_input_port_get(GPIOD)			//获取PE端口值

#define AD7616_CHANNEL_VAL 16

#define AD7616_ALL_CH 16
#define AD7616_V0A 0
#define AD7616_V0B 1
#define AD7616_V1A 2
#define AD7616_V1B 3
#define AD7616_V2A 4
#define AD7616_V2B 5
#define AD7616_V3A 6
#define AD7616_V3B 7
#define AD7616_V4A 8
#define AD7616_V4B 9
#define AD7616_V5A 10
#define AD7616_V5B 11
#define AD7616_V6A 12
#define AD7616_V6B 13
#define AD7616_V7A 14
#define AD7616_V7B 15

#define AD7616_ALL_RESER 0   //完全复位
#define AD7616_PART_RESER 1  //部分复位
#define AD7616_AD_GET_COUNT 6//转换次数
#define AD7616_STATE_UNREADABLE 0  //转换开始
#define AD7616_STATE_READABLE 1 //可读
/*     parameter     */

/*
	AD7616结构体参数
	temp=A*x*x + B*x + C
*/
typedef struct 
{
	uint32_t number;//通道编号
	float A;        
	float B;
	float C;
}AD7616_parameter;
extern AD7616_parameter AD7616_CH_member[AD7616_CHANNEL_VAL];
extern uint16_t AD7616_Data[AD7616_CHANNEL_VAL];//AD值
extern uint16_t AD7616_AD[AD7616_CHANNEL_VAL];//AD平均值
extern float AD7616_Temp[AD7616_CHANNEL_VAL];//温度值


/* function */
void AD7616_Init(void);
void AD7616_StartConvst(void);//启动转换
ErrStatus AD7616_Convst_Average(const uint32_t count);//启动多次转换并取平均值

#endif

3.5实验结果

         未接温度传感器时,所有通道输出最大值0x7FFF(第15位为符号位)。

图6.16通道AD值

         接入一个热敏电阻时,采集到的AD值便随温度改变,可通过校准,把AD值转换为实际温度。

图7

 4.总结

        本文为学习AD7616采集数据所做,数据手册很长,并不是单看时序图就能完成驱动编写,但看懂了数据手册之后,就会发现代码挺简单的。需要注意的便是BUSY引脚,它只有输出状态,不要被(手动模式)干扰。在CONVST引脚上升沿时,BUSY便会自动变为高电平,数据转换完成时,BUSY变为低电平。

 本文中没有提供主函数代码,需要读取数据时,直接调用

ErrStatus AD7616_Convst_Average(const uint32_t count);启动多次转换函数,然后直接从数组中依次读取数据(AD值或温度值)即可。校准值需要自己实际测量写入。

最后,文章中可能存在着问题,欢迎各位大佬不吝赐教。

                                                                                                                                2022年11月29日

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值