当前位置: 首页 > article >正文

基于STM32F103驱动AD7606串行采集数据信号

文章目录

  • 一、AD7606 模块简介
  • 二、模块接口说明
  • 三、时序图的理解
  • 四、AD7606的传递特性
  • 五、STM32F103驱动AD7606采集数据
    • 1、引脚接线
    • 2、参考示例
    • 3、效果展示
  • 六、应用建议

一、AD7606 模块简介

AD7606是一款16位、8通道同步采样的高性能模数转换器(ADC),具有以下核心特性:

  1. 集成功能丰富
      内置 2.5V 基准电压源 和 基准电压缓冲器(可自行配置外部基准电压)。
      支持高速串行和并行接口,适应不同系统需求。
  2. 供电与输入支持
      工作电压为 5V 单电源,无需外部双极性电源。
      支持 ±10V 和 ±5V 双极性输入信号,适应广泛的信号范围。
  3. 高采样性能
      所有通道均支持高达 200kSPS 的同步采样吞吐速率。
      在任意采样频率下,模拟输入阻抗固定为 1MΩ,无需外部驱动运算放大器。
  4. 模拟输入箝位保护:±16.5V
  5. 模拟输入滤波器带宽:23KHz(-3dB,±10V 范围)
              15KHz(-3dB,±5V 范围)
  6. 信噪比:90dB(典型值,无过采样,±10V)
        89dB(典型值,无过采样,±5V)

二、模块接口说明

  1. 芯片部分管脚焊接在一起。
  2. 模块默认串行。
  3. CA(CONVST_A)与 CB(CONVST_B)默认短接
  4. SCK 为芯片 12 脚,在模块数据口丝印标注为 RD
  5. AD_SPI_MISO_PIN为模块上D7(其余D0-D6,D8-D15均接地)

三、时序图的理解

  • CONVST A/B:CONVST 信号的上升沿触发模数转换(ADC 的采样操作),即启动采样转换。
  • BUSY:在 CONVST A/B均达到上升沿之后,BUSY拉高,表示 ADC 正在进行数据转换。BUSY输出保持高电平,直到所有通道转换完成。BUSY下降沿表示转换数据正被所存至数据寄存器。经过时间t4之后便可读取,BUSY为高电平时,执行的数据读取操作要在BUSY下降沿之前完成。当BUSY高电平时,CONVST A/B的上升沿不起作用。
  • CS:CS片选低电平有效,使能CS串行数据传输,逐个输出串行数据的最高有效位(MSB)。


  读取一个通道的数据的时序图。SCLK为输入串行读取操作提供的时钟源,AD7606转换完成后CS片选信号拉低,开始读取数据。由于是16位8通道ADC,一次读取一个字节,所以一个通道需要读取两次数据。因为是高位在前低位在后所以就是先读取的是MSB,后读取的LSB,数据需要SCLK下降沿有效。经过16*8 = 128个SCLK读取后已经全部将ADC转换的数据全部读取完了,之后就可以将CS片选信号拉高了(由于串行通讯FRSTDATA数据线可以不接,所以并没有用到这个脚)。

  对一个字节的读取,将时钟线拉高后拉低然后读取一下当前的值然后拉高,重复八次就是一个字节的读取。(MSB的最高位为符号位,若为1则数据为负数,若为0则数据为正数)
  通过以上三个时序图就可以利用SPI总线来驱动AD7606,值得注意的是转换期间的上升沿,下降沿会受到时间的影响,所以延迟函数不能随意使用。

四、AD7606的传递特性

、

AD7606输出编码方式采用的是二进制补码方式(其实就是16bit有符号数,将转换结果定义为int16_t即可),因为AD7606支持正负压采集。

五、STM32F103驱动AD7606采集数据

1、引脚接线

AD7606STM32F103
5V / GND5V / GND
RDPC11
D7PC9
CSPC12
RESETPC10
CAPC13
RANGEPC8
OS0PC4
OS1PC5
OS2PC6

2、参考示例

AD7606.c

#include "stm32f10x.h"
#include <stdio.h>
#include "ad7606.h"

FIFO_T	g_tAD;	/* 定义一个交换缓冲区,用于存储AD采集数据,并用于写入SD卡 */

void bsp_TIM4_Configuration(void);

/*
*********************************************************************************************************
*	函 数 名: bsp_InitAD7606
*	功能说明: 初始化AD7606 SPI口线
*	形    参:无
*	返 回 值: 无
*********************************************************************************************************
*/
void bsp_InitAD7606(void)
{
	GPIO_InitTypeDef  GPIO_InitStructure;
	SPI_InitTypeDef   SPI_InitStructure;
	
	/* AD_SPI_CS_GPIO, AD_SPI_MOSI_GPIO, AD_SPI_MISO_GPIO, AD_SPI_DETECT_GPIO 
	   and AD_SPI_SCK_GPIO Periph clock enable */
	RCC_APB2PeriphClockCmd(AD_CS_GPIO_CLK | AD_SPI_MISO_GPIO_CLK | AD_SPI_SCK_GPIO_CLK
			, ENABLE);
	
	GPIO_InitStructure.GPIO_Pin = AD_SPI_SCK_PIN;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_Init(AD_SPI_SCK_GPIO_PORT, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin = AD_CS_PIN;
	GPIO_Init(AD_CS_GPIO_PORT, &GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Pin = AD_SPI_MISO_PIN;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
	GPIO_Init(AD_SPI_MISO_GPIO_PORT, &GPIO_InitStructure);
	/* 配置其它的GPIO */

	/* 使能GPIO时钟 */
	RCC_APB2PeriphClockCmd(AD_RESET_GPIO_CLK | AD_CONVST_GPIO_CLK | AD_RANGE_GPIO_CLK | AD_OS0_GPIO_CLK 
		| AD_OS1_GPIO_CLK | AD_OS2_GPIO_CLK, ENABLE);

	/* 配置RESET GPIO */
	GPIO_InitStructure.GPIO_Pin = AD_RESET_PIN;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_Init(AD_RESET_GPIO_PORT, &GPIO_InitStructure);
	
	/* 配置CONVST GPIO */
	GPIO_InitStructure.GPIO_Pin = AD_CONVST_PIN;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_Init(AD_CONVST_GPIO_PORT, &GPIO_InitStructure);

	/* 配置RANGE GPIO */
	GPIO_InitStructure.GPIO_Pin = AD_RANGE_PIN;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_Init(AD_RANGE_GPIO_PORT, &GPIO_InitStructure);
	
	/* 配置OS0-2 GPIO */
	GPIO_InitStructure.GPIO_Pin = AD_OS0_PIN;
	GPIO_Init(AD_OS0_GPIO_PORT, &GPIO_InitStructure);

	GPIO_InitStructure.GPIO_Pin = AD_OS1_PIN;
	GPIO_Init(AD_OS1_GPIO_PORT, &GPIO_InitStructure);

	GPIO_InitStructure.GPIO_Pin = AD_OS2_PIN;
	GPIO_Init(AD_OS2_GPIO_PORT, &GPIO_InitStructure);

	/* 设置过采样模式 */
	ad7606_SetOS(0);

	/* 设置GPIO的初始状态 */
	ad7606_Reset();				/* 硬件复位复AD7606 */
	
	AD_CONVST_HIGH();			/* CONVST脚设置为高电平 */	

	bsp_TIM4_Configuration();	/* 配置TIM2定时中断 */		
}

/*
*********************************************************************************************************
*	函 数 名: ad7606_Reset
*	功能说明: 硬件复位AD7606
*	形    参:无
*	返 回 值: 无
*********************************************************************************************************
*/
void ad7606_Reset(void)
{
	/* AD7606是高电平复位,要求最小脉宽50ns */
	
	AD_RESET_LOW();
	
	AD_RESET_HIGH();
	AD_RESET_HIGH();
	AD_RESET_HIGH();
	AD_RESET_HIGH();
	
	AD_RESET_LOW();
}

/*
*********************************************************************************************************
*	函 数 名: ad7606_SetOS
*	功能说明: 设置过采样模式(数字滤波,硬件求平均值)
*	形    参:_ucMode : 0-6  0表示无过采样,1表示2倍,2表示4倍,3表示8倍,4表示16倍
*				5表示32倍,6表示64倍
*	返 回 值: 无
*********************************************************************************************************
*/
void ad7606_SetOS(uint8_t _ucMode)
{
	if (_ucMode == 1)
	{
		AD_OS2_0();
		AD_OS1_0();
		AD_OS0_1();
	}
	else if (_ucMode == 2)
	{
		AD_OS2_0();
		AD_OS1_1();
		AD_OS0_0();
	}
	else if (_ucMode == 3)
	{
		AD_OS2_0();
		AD_OS1_1();
		AD_OS0_1();
	}
	else if (_ucMode == 4)
	{
		AD_OS2_1();
		AD_OS1_0();
		AD_OS0_0();
	}
	else if (_ucMode == 5)
	{
		AD_OS2_1();
		AD_OS1_0();
		AD_OS0_1();
	}
	else if (_ucMode == 6)
	{
		AD_OS2_1();
		AD_OS1_1();
		AD_OS0_0();
	}
	else	/* 按0处理 */
	{
		AD_OS2_0();
		AD_OS1_0();
		AD_OS0_0();
	}
}

/*
*********************************************************************************************************
*	函 数 名: ad7606_StartConv
*	功能说明: 启动AD7606的ADC转换
*	形    参:无
*	返 回 值: 无
*********************************************************************************************************
*/
void ad7606_StartConv(void)
{
	/* 上升沿开始转换,低电平持续时间至少25ns  */
	AD_CONVST_LOW();
	AD_CONVST_LOW();
	AD_CONVST_LOW();	/* 连续执行2次,低电平约50ns */
	AD_CONVST_LOW();
	AD_CONVST_LOW();
	AD_CONVST_LOW();
	AD_CONVST_LOW();
	AD_CONVST_LOW();
	AD_CONVST_LOW();
	
	AD_CONVST_HIGH();
}

/*
*********************************************************************************************************
*	函 数 名: bsp_TIM4_Configuration
*	功能说明: 配置TIM4定时器
*	形    参:无
*	返 回 值: 无
*********************************************************************************************************
*/
void bsp_TIM4_Configuration(void)
{
	NVIC_InitTypeDef NVIC_InitStructure;
	
	/* TIM2 clock enable */
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);  

	/* Configure the NVIC Preemption Priority Bits[配置优先级组] */  
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);

	/* Enable the TIM2 gloabal Interrupt [允许TIM2全局中断]*/
	NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;  
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
}
	
/*
*********************************************************************************************************
*	函 数 名: bsp_SET_TIM4_FREQ
*	功能说明: 设置TIM4定时器频率
*	形    参:_ulFreq : 采样频率,单位Hz,
*	返 回 值: 无
*********************************************************************************************************
*/
void bsp_SET_TIM4_FREQ(uint32_t _ulFreq)
{
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	uint16_t usPrescaler;
	uint16_t usPeriod;

	TIM_DeInit(TIM4);	/* 复位TIM2定时器 */

	/* TIM2 configuration 
		TIM2CLK = 36 MHz	
	*/
	if (_ulFreq == 0)
	{
		return;		/* 采样频率为0,停止采样 */
	}
	else if (_ulFreq <= 100)   /* 采样频率小于100Hz */
	{
		usPrescaler = 36000;		/* TM2CLK = 72 000 000/36000 = 2000 */
		usPeriod = 2000 / _ulFreq;			 	
	}
	else if (_ulFreq <= 200000)	/* 采样频率 :100Hz - 200kHz */
	{
		usPrescaler = 36 - 1;		/* TM2CLK = 36 000 000/36 = 2 000 000 */
		usPeriod = 2000000 / _ulFreq;
	}	
	else	/* 采样频率大于 200kHz */
	{
		return;
	}
	
	TIM_TimeBaseStructure.TIM_Period = usPeriod - 1; 		/* 计数周期 */
	TIM_TimeBaseStructure.TIM_Prescaler = usPrescaler;	/* 分频系数 */
	TIM_TimeBaseStructure.TIM_ClockDivision = 0x0; 		/* */
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //计数方向向上计数
	TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure);

	/* Clear TIM2 update pending flag[清除TIM2溢出中断标志] */
	TIM_ClearFlag(TIM4, TIM_FLAG_Update);

	TIM_SetCounter(TIM4, 0);

	/* Enable TIM2 Update interrupt [TIM2溢出中断允许]*/
	TIM_ITConfig(TIM4, TIM_IT_Update, ENABLE);  

	/* TIM2 enable counter [允许tim2计数]*/
	TIM_Cmd(TIM4, ENABLE);
}  

//SPI写数据
//向触摸屏IC写入1byte数据    
//num:要写入的数据
void SPI_SendData(u16 data)    
{  
	u8 count=0;   
	AD_SCK_LOW();	//下降沿有效
	for(count=0;count<16;count++)  
	{ 	  
		if(data&0x8000)
			AD_MISO_LOW();  
		else 
			AD_MISO_HIGH();   
		data<<=1;    
		AD_SCK_LOW(); 	 
		AD_CSK_HIGH();		//上升沿有效	        
	}		 			    
} 

//SPI读数据 
//从触摸屏IC读取adc值
//CMD:指令
//返回值:读到的数据	   
//u16 SPI_ReceiveData(void)	  
//{ 	 
//	u8 count=0; 	  
//	u16 Num=0; 
//	AD_SCK_LOW();		//先拉低时钟 	 	     	    
//	for(count=0;count<16;count++)//读出16位数据,只有高12位有效 
//	{ 				  
//		Num<<=1; 	 
//		AD_SCK_LOW();	//下降沿有效  	    	   
//		AD_CSK_HIGH();
//		
//		if(AD_MISO_IN)Num++;
//	}
//	return(Num);
//}

u16 SPI_ReceiveData(void)	  
{ 	 
	u8 count=0; 	  
	u16 Num=0; 
	AD_CSK_HIGH();	
	for(count=0;count<16;count++)//读出16位数据
	{
		Num<<=1;
		AD_SCK_LOW();	//下降沿有效
		if(AD_MISO_IN)Num++;
		AD_CSK_HIGH();
	}
	return(Num);
}
/*
*********************************************************************************************************
*	函 数 名: ad7606_ReadBytes
*	功能说明: 读取AD7606的采样结果
*	形    参:
*	返 回 值: 无
*********************************************************************************************************
*/
uint16_t ad7606_ReadBytes(void)
{
  uint16_t usData = 0;
  
  /* Wait until the transmit buffer is empty */
  while (SPI_I2S_GetFlagStatus(AD_SPI, SPI_I2S_FLAG_TXE) == RESET)
  {
  }
  
//  /* Send the byte */
//  SPI_I2S_SendData(AD_SPI, 0xFFFF);
	SPI_SendData(0xFFFF);

  /* Wait until a data is received */
  while (SPI_I2S_GetFlagStatus(AD_SPI, SPI_I2S_FLAG_RXNE) == RESET)
  {
  }
  
  /* Get the received data */
  usData = SPI_I2S_ReceiveData(AD_SPI);
	usData = SPI_ReceiveData();

  /* Return the shifted data */
  return usData;
}

/*
*********************************************************************************************************
*	函 数 名: ad7606_IRQSrc
*	功能说明: 定时调用本函数,用于读取AD转换器数据
*	形    参:无
*	返 回 值: 无
*********************************************************************************************************
*/
void ad7606_IRQSrc(void)
{
	uint8_t i;
	uint16_t usReadValue;

	TIM_ClearFlag(TIM4, TIM_FLAG_Update);

	/* 读取数据 
	示波器监测,CS低电平持续时间 35us 
	*/
	AD_CS_LOW();
	for (i = 0; i < CH_NUM; i++)
	{
		usReadValue = ad7606_ReadBytes();	
		if (g_tAD.usWrite < FIFO_SIZE)
		{
			g_tAD.usBuf[g_tAD.usWrite] = usReadValue;
			++g_tAD.usWrite;
		}
	}		
	
	AD_CS_HIGH();
//	g_tAD.usWrite = 0;
	ad7606_StartConv();
}

/*
*********************************************************************************************************
*	函 数 名: GetAdcFormFifo
*	功能说明: 从FIFO中读取一个ADC值
*	形    参:_usReadAdc : 存放ADC结果的变量指针
*	返 回 值: 1 表示OK,0表示暂无数据
*********************************************************************************************************
*/
uint8_t GetAdcFormFifo(uint16_t *_usReadAdc)
{
	uint16_t usWrite;
	
	DISABLE_INT();	
	usWrite = g_tAD.usWrite;
	ENABLE_INT();
	
	if (usWrite != g_tAD.usRead)
	{
		*_usReadAdc = g_tAD.usBuf[g_tAD.usRead];

		DISABLE_INT();
		if (++g_tAD.usRead >= FIFO_SIZE)
		{
			g_tAD.usRead = 0;
		}		
		ENABLE_INT();
		return 1;		
	}
	return 0;
}

/*
*********************************************************************************************************
*	函 数 名: ad7606_StartRecord
*	功能说明: 开始采集
*	形    参:_ulFreq : 采样频率, 单位 HZ
*	返 回 值: 无
*********************************************************************************************************
*/
void ad7606_StartRecord(uint32_t _ulFreq)
{
	//ad7606_Reset();	/* 复位硬件 */

	ad7606_StartConv();				/* 启动采样,避免第1组数据全0的问题 */

	g_tAD.usRead = 0;				/* 必须在开启TIM2之前清0 */
	g_tAD.usWrite = 0;

	bsp_TIM4_Configuration();		/* 配置TIM2定时中断 */		

	bsp_SET_TIM4_FREQ(_ulFreq);		/* 设置采样频率, 并使能TIM2定时采样中断 */
}

/*
*********************************************************************************************************
*	函 数 名: ad7606_StopRecord
*	功能说明: 停止采集
*	形    参:无
*	返 回 值: 无
*********************************************************************************************************
*/
void ad7606_StopRecord(void)
{
	/* TIM2 enable counter [允许tim2计数]*/
	TIM_Cmd(TIM4, DISABLE);
}

void TIM4_IRQHandler(void)
{
	ad7606_IRQSrc();
}

main.c

#include "sys.h"
#include "ad7606.h"
#include "delay.h"
#include "usart.h"

int main(void)
{
	uint16_t sampleVol[8];
	int32_t int_sampleVol[8];
	char transStr[30];
	char showLcd[30];
	 
	int i;
	SystemInit();
	delay_init();	     //延时初始化
	usart_Init(115200);   //串口初始化
	delay_ms(100);
	
	bsp_InitAD7606();	/* 配置AD7606所用的GPIO */
	AD_RANGE_10V();
	ad7606_StartRecord(200);
	sprintf(transStr, "Range = %d, OS = %d, \r\n", g_tAD.usBuf[0], g_tAD.usBuf[1]);
	
	while(1)
	{
		delay_ms(100);
		for(i = 0; i < 8; i++)
		{
			int_sampleVol[i] = ((int32_t)10000)*((float)((short)g_tAD.usBuf[i])/32768);	//单位1mv
			sprintf(transStr, "Range%d = %d\t", i, int_sampleVol[i]);
			
			usart_SendString(transStr);
		}
		usart_SendString("\r\n");
		
		g_tAD.usWrite = 0;
	}
}

3、效果展示

信号输入通道1-6:GND,1.2V,1.5V,1.8V,2.5V,3.3V,通道7-8悬空。

六、应用建议

  1. 当模块不正常工作时,首先检测供电是否正常,接线是否正确,同时最好使用和模块接口匹配的标准接线。必要时,可多测几组数据,以便分析问题原因。
  2. 模块采集口浮空时,有数据输出且数据随机,建议输入信号测试。
  3. 模块只能采集单端信号,如需采集差分信号,可在本店搜索 ADS1256。

http://www.kler.cn/a/514818.html

相关文章:

  • STranslate 中文绿色版即时翻译/ OCR 工具 v1.3.1.120
  • 缓存之美:万文详解 Caffeine 实现原理(下)
  • 备赛蓝桥杯之第十五届职业院校组省赛第二题:分享点滴
  • WPF2-在xaml为对象的属性赋值
  • 【数据分享】1929-2024年全球站点的逐年最低气温数据(Shp\Excel\免费获取)
  • 如何使用 Pytest 断言测试 Python 异常处理
  • C++之初识模版
  • 安卓APP如何适配不同的手机分辨率
  • 【动态规划】--- 斐波那契数模型
  • 短剧系统开发功能需求/APP开发/源码指南
  • 计算在不规则形状内不同结构的占比
  • winfrom项目,引用EPPlus.dll实现将DataTable 中的数据保存到Excel文件
  • 鸿蒙开发入门之Hello World
  • 炸场硅谷,大模型“蒸汽机”迎来“瓦特时刻”
  • 论文速读|Multi-Modal Disordered Representation Learning Network for TBPS.AAAI24
  • 错误记录(二)virtualbox连共享文件夹
  • 09_异步加载_单例模式_常量类配置_不可销毁
  • Spring MVC(二)
  • Unreal Engine 5 C++ Advanced Action RPG 十一章笔记
  • CSS语言的学习路线
  • 【蓝桥杯】43693.日期问题
  • 【Unity3D实现雨下在窗户上的效果】
  • OpenEuler学习笔记(九):安装 OpenEuler后配置和优化
  • 【Leetcode 每日一题】1561. 你可以获得的最大硬币数目
  • 数据库事务详解
  • 分支与循环(下)