1. ADC+DMA+Timer的实现原理

stm32F407/405的ADC为12位逐次逼近型ADC,有着高达2.4MHz的采样率,分辨率 1LSB。这样参数的ADC放在市面上单卖,也起码是¥10+起步。而 stm32F407/405不仅内置了,还内置了2/3个,会用的话血赚。

不过平时使用ADC,都是转换,等待结束,转换...。不能按照固定的频率来进行采样,而且在转换过程中,还需要CPU去控制流程,不能处理其他事情,非常的不实用。

stm32F4的ADC允许将转换后的值,通过DMA进行传输存储,而且可以通过Timer进行触发。这样不仅可以按照固定的频率进行ADC采样,还不占用CPU,可谓一举两得。

分辨率 1LSB的方法见最后,电源电路设计的原因。稍加注意都是可以达到 1LSB的。不要再喷stm32的ADC不好了!!!

2.代码

这个代码在 stm32F407/405上通用,使用的 ADC1,DMA2-Stream0-Channel0,Timer3用来产生2MHz采样触发信号。

adc_dma_timer.c

#include "adc_dma_timer.h"//ADC的GPIO配置:PB1 - ADC1_IN9 | PB0 - ADC1_IN8
void ADC_GPIO_Init(void)
{GPIO_InitTypeDef GPIO_InitStructure;RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB , ENABLE ); //PB0 - ADC1_IN8   //PB1 - ADC1_IN9   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;GPIO_Init( GPIOB , &GPIO_InitStructure );
}//TIM3初始化,作为ADC的采样触发源
//Fre:ADC采样频率
void TIM3_Config( u32 Fre )
{TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;u32 MaxData;u16 div=1;  while( (SystemCoreClock/2/Fre/div)>65535 ){div++;}MaxData =  SystemCoreClock/2/Fre/div - 1;   RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM3 , ENABLE );            //开启时钟//TIM3时间基准配置TIM_TimeBaseStructure.TIM_Period = MaxData ;TIM_TimeBaseStructure.TIM_Prescaler = div-1;TIM_TimeBaseStructure.TIM_ClockDivision = 0;TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM_TimeBaseInit( TIM3 , &TIM_TimeBaseStructure );TIM_SelectOutputTrigger( TIM3 , TIM_TRGOSource_Update );TIM_ARRPreloadConfig( TIM3 , ENABLE );TIM_Cmd( TIM3 , ENABLE );                                                   //使能TIM3
}#define ADC1_DR_ADDRESS  ((uint32_t)0x4001204C)          //ADC1 DR
u16 ADC1_ConvertedValue[ ADC1_DMA_Size ];
//ADC-DMA触发使能
//Size:单次传输的数据量
void ADC_DMA_Trig( u16 Size )
{DMA2_Stream0->CR &= ~((uint32_t)DMA_SxCR_EN);DMA2_Stream0->NDTR = Size;                             //设置数量DMA_ClearITPendingBit( DMA2_Stream0 ,DMA_IT_TCIF0|DMA_IT_DMEIF0|DMA_IT_TEIF0|DMA_IT_HTIF0|DMA_IT_TCIF0 );ADC1->SR = 0;DMA2_Stream0->CR |= (uint32_t)DMA_SxCR_EN;
}   //ADC与DMA关联性配置
//注:2000K采样频率,采集6000个数据,需要花费3ms
void ADC_Config(void)
{ADC_InitTypeDef       ADC_InitStructure;ADC_CommonInitTypeDef ADC_CommonInitStructure;DMA_InitTypeDef       DMA_InitStructure;NVIC_InitTypeDef       NVIC_InitStructure;ADC_DeInit( );DMA_DeInit( DMA2_Stream0 );/* Enable ADCx, DMA and GPIO clocks ****************************************/ RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_DMA2 , ENABLE ); RCC_APB2PeriphClockCmd( RCC_APB2Periph_ADC1 , ENABLE );//RCC_APB2PeriphClockCmd( RCC_APB2Periph_ADC2 , ENABLE );/* Enable the DMA Stream IRQ Channel */NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream0_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);     /* DMA2 Stream0 channel0 configuration **************************************/DMA_InitStructure.DMA_Channel = DMA_Channel_0;  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC1_DR_ADDRESS;DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)ADC1_ConvertedValue;       DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;DMA_InitStructure.DMA_BufferSize = ADC1_DMA_Size;                              //DMA 传输数量DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;DMA_InitStructure.DMA_Priority = DMA_Priority_High;DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;         DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;DMA_Init( DMA2_Stream0 , &DMA_InitStructure );DMA_Cmd( DMA2_Stream0 , DISABLE );DMA_ClearITPendingBit( DMA2_Stream0 ,DMA_IT_TCIF0 );DMA_ITConfig( DMA2_Stream0 , DMA_IT_TC , ENABLE );/* ADC Common Init **********************************************************/ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;ADC_CommonInit( &ADC_CommonInitStructure );/* ADC1 Init ****************************************************************/ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;ADC_InitStructure.ADC_ScanConvMode = DISABLE;ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising;ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T3_TRGO;       //TIM3作为ADC的触发源ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;ADC_InitStructure.ADC_NbrOfConversion = 1;                                   //规则通道序列长度,这里只有一个通道9(下面一条语句进行配置)ADC_Init( ADC1, &ADC_InitStructure );//PB0 - ADC1_IN8 - AD_UT_OP_BW   //PB1 - ADC1_IN9 - AD_UT_OP
//  ADC_RegularChannelConfig( ADC1 , ADC_Channel_8 , 1, ADC_SampleTime_3Cycles);     //PB0 - ADC1_IN8 - AD_UT_OP_BWADC_RegularChannelConfig( ADC1 , ADC_Channel_9 , 1, ADC_SampleTime_3Cycles);     //PB1 - ADC1_IN9 - AD_UT_OPADC_DMARequestAfterLastTransferCmd( ADC1 , ENABLE );ADC_DMACmd(ADC1, ENABLE);ADC_Cmd(ADC1, ENABLE);ADC_SoftwareStartConv(ADC1);
}//DMA中断服务程序,暂不进行数据处理,就是清除一些中断标志位
void DMA2_Stream0_IRQHandler( void )
{   DMA_ClearITPendingBit( DMA2_Stream0 ,DMA_IT_TCIF0|DMA_IT_DMEIF0|DMA_IT_TEIF0|DMA_IT_HTIF0|DMA_IT_TCIF0 );DMA2->HIFCR = 0xffff;DMA2->LIFCR = 0xffff;
}

adc_dma_timer.c

#ifndef _ADC_DMA_Timer_H
#define _ADC_DMA_Timer_H//#define SAM_FRE        200000//采样频率
#define SAM_FRE        2000000//采样频率
//#define ADC1_DMA_Size  25000 //采样点数
#define ADC1_DMA_Size  6000 //采样点数void ADC_GPIO_Init(void);
void TIM3_Config( u32 Fre );
void ADC_Config( void );
void ADC_DMA_Trig( u16 Size );#endif

main.c

int main(void)
{ADC_GPIO_Init();                           // ADC引脚初始化。TIM3_Config( SAM_FRE );                     // 触发ADC采样频率,采样频率2MHzADC_Config();                               // ADC 2000K采样频率,采集6000个数据,需要花费3mswhile(1){ADC_DMA_Trig( ADC1_DMA_Size );          // 开始AD采集,设置采样点数delay_ms(3);                            // 延时3ms,等待ADC数据全部转换到 ADC1_ConvertedValue数组中//用户处理代码delay_ms(100);}
}

3. 代码说明:

代码中,使用了 ADC1,DMA2-Stream0-Channel0,Timer3。

ADC1 为使用到的ADC。

DMA2-Stream0-Channel0 为ADC1 与DMA2通信,所使用到的数据流和通道。不知道为什么要用这个的,可以看:https://blog.csdn.net/Mark_md/article/details/107243054

Timer3用来产生2MHz采样触发信号。

main中,每次触发 6000点连续采样 使用函数 ADC_DMA_Trig( ADC1_DMA_Size );  // ADC1_DMA_Size为单次转换的数量

A/D转换的结果值,都存放在 ADC1_ConvertedValue 数组中,uint16类型。

4. 分辨率 1LSB的实现

有人说stm32的ADC分辨率达不到 1LSB,因为日常使用时,ADC的转换结果都几十几十的跳,根本没有稳定在一个值的时候。

其实都是模拟电源设计不好,重新设计下电源:

1.数字DVCC、模拟AVCC 单独稳压芯片供电,不要使用同一路电源。LDO选择低噪声的,例如SPX3819、MIC5205、LP2985。

(MCU运行时,会对自身的DVCC产生噪声干扰。如果DVCC和AVCC同用一路电源的话,容易将噪声耦合到AVCC)

2.数字DGND、模拟AGND 分割,单点0Ω电阻连接。

不是很推荐磁珠,因为磁珠的滤波特性要根据电路的干扰频率来选择型号。而且电感有感抗,电流通过,滤除噪声的同时也会在此点带来电位差。而且这个电位差跟此时的噪声频段、电流大小都有关,磁珠选择不好反倒容易增大干扰)

stm32F4的ADC+DMA+Timer,实现2MHz连续采样。1LSB分辨率,极低噪声。相关推荐

  1. [STM32F4]STM32F407 ADC采集+DMA传输

    前言        有的项目中需要对多个通道的电压进行一定频率的AD采样. 第一种:是使用定时器去读取,通过检查转换完成标志位来读取,但这样就会加重整个系统的负担,占用CPU资源. 第二种:是采用定时 ...

  2. STM32F407 ADC+DMA+定时器 定时采样模拟量

    STM32F407 ADC+DMA+定时器 定时采样模拟量 文章目录 STM32F407 ADC+DMA+定时器 定时采样模拟量 前言 一.硬件原理 1.1 ADC 1.2 定时器 3. DMA 二. ...

  3. STM32F4系列探究1——三重ADC扫描连续采样+DMA双缓冲区存储

    文章目录 前言 一.STM32F4的ADC理论知识学习 1.基础知识 2.扫描模式与连续模式 3.单ADC模式下双缓存机制的实现 4.三重同步采样模式 二.由定时器触发的单缓冲区模式 1.时钟树配置 ...

  4. STM32F4 ADC+DMA单通道采集

    背景:对锂电池电压进行采集,由于电池电压为12V,已经提前对12V进行分压,保证ADC采集电压的范围为0~3.3V.对电池电压的采集不用太过频繁,循环模式下的ADC+DMA对一直采集电压浪费资源.于是 ...

  5. STM32f4系列ADC解析

    12位ADC简介 12位ADC是一种逐次逼近型模拟数字转换器.它有多达19个通道,可测量16个外部和2个内部信号源和Vbat通道.各通道的A/D转换可以单次.连续.扫描或间断模式执行.ADC的结果可以 ...

  6. STM32F4之ADC介绍

    1. STM32F4 ADC 简介     STM32F4xx 系列一般都有 3 个 ADC,这些 ADC 可以独立使用,也可以使用双重/三重模式(提高采样率). STM32F4 的 ADC 是 12 ...

  7. STM32 HAL库ADC+DMA(非定时器)代码和遇到的问题

    目录 一.整体说明 二.部分知识点预览 三.代码部分 四.遇到的问题及现象 (1)仿真进入错误 (2)非连续模式软件触发时adcbuf里面的数据不对 (3)HAL库的ADC DMA相关中断的嵌套实现 ...

  8. STM32 基础系列教程 13 – ADC DMA

    前言 学习stm32 adc模数转换接口使用,学会用STM32对模拟信号时行采样,通过DMA方式得到ADC结果. 示例详解 基于硬件平台: STM32F10C8T6最小系统板, MCU 的型号是 ST ...

  9. STM32 CubeMX配置ADC+DMA进行FFT(1)

    STM32 CubeMX配置ADC+DMA,计算采样率和ADC电压 原创:睿智嵌入式 最近,因为项目需要处理音频信号,对AD采集的音频信号进行FFT运算,记录一下学习过程. 主要内容: 1.ADC和D ...

最新文章

  1. x264代码剖析(一):图文详解x264在Windows平台上的搭建
  2. yield的用法详解
  3. Apache Kylin的核心概念
  4. python画图表的库_「Python」python绘制图表
  5. 【软件设计师】2020-08-07
  6. OGRE 入门 二、Basic Tutorial 1 : An introduction to the most basic Ogre constructs
  7. 微服务、容器和Kubernetes的2020你怎么看?
  8. P1600 天天爱跑步
  9. MySQL的图形化安装
  10. java map格式化_字符串模板格式化输出map 值
  11. 计算机教学能力大赛实施报告模板,“现代信息技术在课堂教学中的运用”实施情况总结...
  12. matlab转子动力学视频分析,基于ANSYS经典界面的光盘轴的转子动力学分析(谐响应分析)...
  13. 乐视路由器刷机后修改固件成art信息
  14. 微信小程序,实现一个简易的新闻网
  15. Unity与Android权限设置
  16. 如何用matlab编写分段函数_matlab 如何写分段函数
  17. fluentd收集K8S日志并以K8S的container_name作为索引名存入Elasticsearch中
  18. Android手机下载的缓存视频如何找到?
  19. twisted中的延迟(deferred)(一)
  20. esp8266网络自动对时 串口字符连接 病显示 12864i2c u8g2库

热门文章

  1. HTTP协议···(一)
  2. 关于kv的jch分片存储
  3. java对redis的基本操作(初识)
  4. SQL Server创建视图
  5. volatile简记
  6. drupal ajax json异步调用
  7. JZ32变形~剑指 Offer 32 - II. 从上到下打印二叉树 II
  8. mysql数据库自动关闭
  9. 校招刷题---java选择题笔记04
  10. 新鲜出炉!腾讯大数据分析的真实面经,这几个问题把我问懵了