基于STM32F103驱动AD7606串行采集数据信号
文章目录
- 一、AD7606 模块简介
- 二、模块接口说明
- 三、时序图的理解
- 四、AD7606的传递特性
- 五、STM32F103驱动AD7606采集数据
- 1、引脚接线
- 2、参考示例
- 3、效果展示
- 六、应用建议
一、AD7606 模块简介
AD7606是一款16位、8通道同步采样的高性能模数转换器(ADC),具有以下核心特性:
- 集成功能丰富
内置 2.5V 基准电压源 和 基准电压缓冲器(可自行配置外部基准电压)。
支持高速串行和并行接口,适应不同系统需求。 - 供电与输入支持
工作电压为 5V 单电源,无需外部双极性电源。
支持 ±10V 和 ±5V 双极性输入信号,适应广泛的信号范围。 - 高采样性能
所有通道均支持高达 200kSPS 的同步采样吞吐速率。
在任意采样频率下,模拟输入阻抗固定为 1MΩ,无需外部驱动运算放大器。 - 模拟输入箝位保护:±16.5V
- 模拟输入滤波器带宽:23KHz(-3dB,±10V 范围)
15KHz(-3dB,±5V 范围) - 信噪比:90dB(典型值,无过采样,±10V)
89dB(典型值,无过采样,±5V)
二、模块接口说明
- 芯片部分管脚焊接在一起。
- 模块默认串行。
- CA(CONVST_A)与 CB(CONVST_B)默认短接
- SCK 为芯片 12 脚,在模块数据口丝印标注为 RD
- 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、引脚接线
AD7606 | STM32F103 |
---|---|
5V / GND | 5V / GND |
RD | PC11 |
D7 | PC9 |
CS | PC12 |
RESET | PC10 |
CA | PC13 |
RANGE | PC8 |
OS0 | PC4 |
OS1 | PC5 |
OS2 | PC6 |
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悬空。
六、应用建议
- 当模块不正常工作时,首先检测供电是否正常,接线是否正确,同时最好使用和模块接口匹配的标准接线。必要时,可多测几组数据,以便分析问题原因。
- 模块采集口浮空时,有数据输出且数据随机,建议输入信号测试。
- 模块只能采集单端信号,如需采集差分信号,可在本店搜索 ADS1256。