当前位置:   article > 正文

STM32F4探索者,基于SPI实现AD7606信号串行采集_ad7606 spi

ad7606 spi

目录

1 基本特性

2.模块

3.接线

3.转换时序

4.读取时序

5.转换期间读取

6.读取的16位二进制与电压值的转换

7.spi读取

8.对采样率有要求时


工程压缩包:https://download.csdn.net/download/binocthrx/88222511?spm=1001.2014.3001.5503

  1. 1 基本特性

模块名称:AD7606 多通道AD 数据采集模块

模块尺寸:50mm * 48mm

模块供电:5V

模块输入电压范围:±5V,±10V(由RANGE 引脚的逻辑电平决定,该引脚与逻辑高

电平连接时,所有通道模拟输入范围为±10V。该引脚与逻辑低

电平连接时,所有通道模拟输入范围为±5V。程序默认±5V)

输入阻抗:1MΩ

内部基准电压源:2.5V(可自行配置外部基准电压)

模拟输入箝位保护:±16.5V

模块采样率:200KSPS(所有8 个通道)

模块分辨率:16 bit

模块接口:SPI 接口或16 位并口(模块默认SPI 串口)

模拟输入滤波器带宽:23KHz(-3dB,±10V 范围)

15KHz(-3dB,±5V 范围)

信噪比:90dB(典型值,无过采样,±10V)

89dB(典型值,无过采样,±5V)

2.模块

3.接线

AD_CS-----PC12

AD_RESET-----PC10

AD_CONVST-----PC13  (板子上的CA/CB)

AD_RANGE------PC8 

AD_OS0-----PC4

AD_OS1-----PC5

AD_OS2-----PC6

AD_BUSY-----PA5(不用可以不接)

SPI接线

具体为

SCK-----PB3       (板子上的RD口)

MISO----PB4  (板子上的D7口)

MOSI没用上不接

 3.转换时序

 

CONVST A和CONVST B连在一起,t5接近于0,此时为串行8路采样,CONVST A和CONVST B平时为高电平,转换时拉低至少50ns。转换时BUSY被拉高,转换结束被拉低,转换时间tconv在无过采样时典型值为4ns。

4.读取时序

串行模式转换之后读取是,待BUSY被拉低后,可以将CS拉低控制SCLK时钟信号进行数据的读取,先读出的为高位。读出一个完整通道需要16位,读出8个通道依次16次读取循环8次即可,对于DA口,读取的顺序为通道1、2、3、4、5、6、7、8,对于DB口读取的顺序为通道5、6、7、8、1、2、3、4,两个端口同步输出。若只需一个通道,那么仅读取一次即可。根据DA\DB读取顺序的不同,我们可以两个端口同时读取,一次读取两个通道值,只需读4次即可读完8个通道值。

转换及读取代码如下

  1. uint16_t ADRED_AD7606(){
  2. uint16_t data;
  3. AD_CS_LOW();
  4. data=SPI1_ReadWriteByte(0xff);
  5. AD_CS_HIGH();
  6. ad7606_StartConv();
  7. return data;
  8. }

5.转换期间读取

当BUSY为高电平,转换正在进行时,也可以从AD7606/AD7606-6/AD7606-4读取数据。这几乎不会影响转换器的性能,而且可以实现更快的吞吐速率。转换期间可以执行并行、并行字节或串行读取,可以使用或不用过采样。图3显示并行或串行模式下BUSY为高电平时读取操作的时序图。转换期间执行读取使得使用串行接口且VDRIVE高于4.75V时也可以达到最高吞吐速率。DRIVE在BUSY下降沿时,输出数据寄存器会被新转换数据更新,除外之外的任何时候都可以从AD7606读取数据。对于t6,最后CS上升沿与BUSY下降沿之间的最长时间为25ns。

6.读取的16位二进制与电压值的转换

 

此模块REF为2.5V,范围为10V时,对于正电压,输入电压VIN=CODE*10/32678。

对于负电压,可以看出输出的CODE为补码,负数补码的源码是符号位不变,其余位取反后加一,原码的首位仍为符号位,在此案例中获得其绝对值可以对其全部取反后加一即可,最后将转换的CODE手动加上负号。代码如下:

  1. sampdata=ADRED_AD7606();
  2. if(sampdata<32768){
  3. dataVol=((sampdata)*10.0 * 1000 ) / 32768;
  4. }
  5. else {
  6. sampdata = (~sampdata)+1;
  7. dataVol=((sampdata)*10.0 * -1000 ) / 32768;
  8. }

转换后的电压值负号为mV。

7.spi读取

使用STM32F4自带的spi通信,参考正点原子的spi通信实验的代码,因为是146位ADC,我们直接配置16位的spi,配置如下:

  1. void SPI1_Init(void)
  2. {    
  3.   GPIO_InitTypeDef  GPIO_InitStructure;
  4.   SPI_InitTypeDef  SPI_InitStructure;
  5.       
  6.   RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//使能GPIOB时钟
  7.   RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE);//使能SPI1时钟
  8.   //GPIOFB3,4,5初始化设置
  9.   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5;//PB3~5复用功能输出
  10.   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
  11.   GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
  12.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
  13.   GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
  14.   GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化
  15.       
  16.        GPIO_PinAFConfig(GPIOB,GPIO_PinSource3,GPIO_AF_SPI1); //PB3复用为 SPI1
  17.        GPIO_PinAFConfig(GPIOB,GPIO_PinSource4,GPIO_AF_SPI1); //PB4复用为 SPI1
  18.        GPIO_PinAFConfig(GPIOB,GPIO_PinSource5,GPIO_AF_SPI1); //PB5复用为 SPI1
  19.        //这里只针对SPI口初始化
  20.        RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI1,ENABLE);//复位SPI1
  21.        RCC_APB2PeriphResetCmd(RCC_APB2Periph_SPI1,DISABLE);//停止复位SPI1
  22.        SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;  //设置SPI单向或者双向的数据模式:SPI设置为双线双向全双工
  23.        SPI_InitStructure.SPI_Mode = SPI_Mode_Master;          //设置SPI工作模式:设置为主SPI
  24.        SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b;            //设置SPI的数据大小:SPI发送接收8位帧结构
  25.        SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;           //串行同步时钟的空闲状态为高电平
  26.        SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; //串行同步时钟的第一个跳变沿(上升或下降)数据被采样
  27.        SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;           //NSS信号由硬件(NSS管脚)还是软件(使用SSI位)管理:内部NSS信号有SSI位控制
  28.        SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64;          //定义波特率预分频的值:波特率预分频值为64
  29.        SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;       //指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
  30.        SPI_InitStructure.SPI_CRCPolynomial = 7;       //CRC值计算的多项式
  31.        SPI_Init(SPI1, &SPI_InitStructure);  //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器
  32.        SPI_Cmd(SPI1, ENABLE); //使能SPI外设
  33.        SPI1_ReadWriteByte(0xff);//启动传输              
  34. }  

然后利用此函数进行数据通信:

  1. u16 SPI1_ReadWriteByte(u16 TxData)
  2. {                                
  3.   while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET){}//等待发送区空 
  4.       
  5.        SPI_I2S_SendData(SPI1, TxData); //通过外设SPIx发送一个byte  数据
  6.              
  7.   while (SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_RXNE) == RESET){} //等待接收完一个byte 
  8.        return SPI_I2S_ReceiveData(SPI1); //返回通过SPIx最近接收的数据   
  9.                 
  10. }

最后这是利用信号发生器发出的1HZ正弦波交流信号采集后利用excel画出的波形

8.对采样率有要求时

利用定时器,可控制采样率,此处利用TME3定时器,设置时长为0.5ms,也就是2K左右的采样率(2K实际值为2048),若设置为1ms那也就是大概1K

TIM3_Int_Init(500-1,84-1);    //定时器时钟84M,分频系数84,所以84M/84=1000Khz的计数频率,计数500次为0.5ms  

 对于定时器初始化代码

  1. void TIM3_Int_Init(u16 arr,u16 psc)
  2. {
  3. TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;
  4. NVIC_InitTypeDef NVIC_InitStructure;
  5. RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE); ///使能TIM3时钟
  6. TIM_TimeBaseInitStructure.TIM_Period = arr; //自动重装载值
  7. TIM_TimeBaseInitStructure.TIM_Prescaler=psc; //定时器分频
  8. TIM_TimeBaseInitStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式
  9. TIM_TimeBaseInitStructure.TIM_ClockDivision=TIM_CKD_DIV1;
  10. TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);//初始化TIM3
  11. TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE); //允许定时器3更新中断
  12. TIM_Cmd(TIM3,ENABLE); //使能定时器3
  13. NVIC_InitStructure.NVIC_IRQChannel=TIM3_IRQn; //定时器3中断
  14. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x01; //抢占优先级1
  15. NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x03; //子优先级3
  16. NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
  17. NVIC_Init(&NVIC_InitStructure);
  18. }

在中断函数中调用转换函数,注意此处不要有过多操作,仅读取即可,否则影响采样率精度,个人的操作方式是,采集够数据量时临时暂停一下定时器,在主函数中对数据操作完成后继续定时采集。

  1. //定时器3中断服务函数
  2. void TIM3_IRQHandler(void)
  3. {
  4. if(TIM_GetITStatus(TIM3,TIM_IT_Update)==SET) //溢出中断
  5. {
  6. // LED1=!LED1;//DS1翻转
  7. ad_sampdata[ad_times++]=ADRED_AD7606();
  8. if(ad_times>=CA_SIZE){
  9. ad_times=0;
  10. AD_FULL=1;
  11. ad7606_StopRecord();
  12. }
  13. }
  14. TIM_ClearITPendingBit(TIM3,TIM_IT_Update); //清除中断标志位
  15. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/码创造者/article/detail/829440
推荐阅读
相关标签
  

闽ICP备14008679号