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

这篇具有很好参考价值的文章主要介绍了STM32F407 ADC+DMA+定时器 定时采样模拟量。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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


前言

项目中需要对多个通道的电压进行一定频率的AD采样,由于采样过程贯穿整个任务,为了使采样过程尽可能不占用CPU资源,采用定时器触发的多通道ADC扫描采样,且采样数据由DMA传到RAM中的缓存。
这样做有以下几个好处:1、由定时器触发ADC采样,这样采样的频率可控,且定时器触发不会占用任何CPU资源;2、DMA进一步降低了任务对CPU的占有率。


提示:以下是本篇文章正文内容,下面案例可供参考

一、硬件原理

1.1 ADC

STM32F 407的ADC的规则通道扫描采样,配置好规则通道后,可以采用软件触发的方式开启AD转换,也可通过外部触发,如下图所示。可以通过定时器以及外部中断方式触发:
如下图为ADC 内部使用框图:

stm32f407单通道dmaadc定时器中断采样,stm32,单片机,arm

1.2 定时器

stm32f407单通道dmaadc定时器中断采样,stm32,单片机,arm
如上图所示是定时器的内部硬件原理框图,在此使用定时器的TIMER3 的TRGO信号作为ADC转换的触发信号,当接收到一次中断信号后,ADC通道进行转换一次.

3. DMA

stm32f407单通道dmaadc定时器中断采样,stm32,单片机,arm
如上图所示,ADC1 使用的是DMA 的stream0 数据流,ADC2使用DMA2 的Stream2数据流.

二、代码实现

2.1初始化

global 数据

__IO uint16_t g_Adc2ConvertedValues[10][6];//6 个通道每个通道采样10次

2.1.1 PIN initial

	static void BspGpioConfig(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;

    GPIO_InitStructure.GPIO_Pin  =  GPIO_Pin_0    
                                   | GPIO_Pin_4   
                                   | GPIO_Pin_7;  
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_0  
                                 | GPIO_Pin_1;  
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_0    
                                 | GPIO_Pin_1 ; 

    GPIO_Init(GPIOC, &GPIO_InitStructure);

    return;
}

2.2 ADC 初始化 代码

static void BspAdcConfig(void)
{
    ADC_CommonInitTypeDef ADC_CommonInitStructure;
    ADC_InitTypeDef       ADC_InitStructure;

    ADC_CommonInitStructure.ADC_Mode             = ADC_Mode_Independent;
    ADC_CommonInitStructure.ADC_Prescaler        = ADC_Prescaler_Div8;
    ADC_CommonInitStructure.ADC_DMAAccessMode    = ADC_DMAAccessMode_Disabled;
    ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles;
    ADC_CommonInit(&ADC_CommonInitStructure);

    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_T2_TRGO;
    ADC_InitStructure.ADC_DataAlign            = ADC_DataAlign_Right;
    ADC_InitStructure.ADC_NbrOfConversion      = 1;
    ADC_Init(ADC1, &ADC_InitStructure);

    ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_480Cycles);     // PA0_AD0_AC

    ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);
    ADC_DMACmd(ADC1, ENABLE);
    ADC_Cmd(ADC1, ENABLE);

    ADC_InitStructure.ADC_ScanConvMode         = ENABLE;
    ADC_InitStructure.ADC_ExternalTrigConv     = ADC_ExternalTrigConv_T3_TRGO;
    ADC_InitStructure.ADC_NbrOfConversion      = ADC2_NbrofChannel;
    ADC_Init(ADC2, &ADC_InitStructure);


    ADC_RegularChannelConfig(ADC2, ADC_Channel_4, 1, ADC_SampleTime_480Cycles);     // PA4_AD4_24V_2
    ADC_RegularChannelConfig(ADC2, ADC_Channel_7, 2, ADC_SampleTime_480Cycles);     // PA7_AD7_GNDF
    ADC_RegularChannelConfig(ADC2, ADC_Channel_8, 3, ADC_SampleTime_480Cycles);     // PB0_AD8_24V_OCP_C1
    ADC_RegularChannelConfig(ADC2, ADC_Channel_9, 4, ADC_SampleTime_480Cycles);     // PB1_AD9_24V_OCP_C2
    ADC_RegularChannelConfig(ADC2, ADC_Channel_10,5, ADC_SampleTime_480Cycles);     // PC0_AD10_HOUSING
    ADC_RegularChannelConfig(ADC2, ADC_Channel_11,6, ADC_SampleTime_480Cycles);     // PC1_AD11_24V_1

    ADC_DMARequestAfterLastTransferCmd(ADC2, ENABLE);
    ADC_DMACmd(ADC2, ENABLE);
    ADC_Cmd(ADC2, ENABLE);

    return;
}

2.3 DMA 初始化 代码


static void BspDmaConfig(void)
{
    DMA_InitTypeDef DMA_InitStructure;

    DMA_InitStructure.DMA_Channel            = DMA_Channel_0;
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
    DMA_InitStructure.DMA_Memory0BaseAddr    = (uint32_t)&g_Adc1ConvertedValues;
    DMA_InitStructure.DMA_DIR                = DMA_DIR_PeripheralToMemory;
    DMA_InitStructure.DMA_BufferSize         = 1024 * 2;
    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_Circular;
    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_ITConfig(DMA2_Stream0, DMA_IT_HT | DMA_IT_TC, ENABLE);
    DMA_Cmd(DMA2_Stream0, ENABLE);

    DMA_InitStructure.DMA_Channel            = DMA_Channel_1;
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC2->DR;
    DMA_InitStructure.DMA_Memory0BaseAddr    = (uint32_t)&g_Adc2ConvertedValues;
    DMA_InitStructure.DMA_BufferSize         = ADC2_NbrofChannel * SamplingNumber;//N*M N: channel number M:sampling number
    DMA_Init(DMA2_Stream2, &DMA_InitStructure);

    DMA_Cmd(DMA2_Stream2, ENABLE);

    return;
}

static void BspNvicConfig(void)
{
    NVIC_InitTypeDef NVIC_InitStructure;

    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);

    return;
}

在调用这几个函数之前必须设置RCC时钟如下代码设置RCC时钟:

static void BspRccConfig(void)
{
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA
                         | RCC_AHB1Periph_GPIOB
                         | RCC_AHB1Periph_GPIOC
                         | RCC_AHB1Periph_DMA2, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2
                         | RCC_APB1Periph_TIM3, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1
                         | RCC_APB2Periph_ADC2, ENABLE);

    return;
}

3.1 定时器初始化

static void BspTimConfig(void)
{
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

    // TIM2设置ADC1  1024Hz
    TIM_TimeBaseStructure.TIM_Prescaler     = 0;
    TIM_TimeBaseStructure.TIM_CounterMode   = TIM_CounterMode_Up;
    TIM_TimeBaseStructure.TIM_Period        = 84000000 / 1024 - 1;
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

    TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update);

    // TIM3设置ADC2 1000Hz
    TIM_TimeBaseStructure.TIM_Prescaler     = 84000000 / 1000000 - 1;
    TIM_TimeBaseStructure.TIM_Period        = 1000000 / 1000 - 1;
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

    TIM_SelectOutputTrigger(TIM3, TIM_TRGOSource_Update);

    TIM_Cmd(TIM2, ENABLE);
    TIM_Cmd(TIM3, ENABLE);

    return;
}

3.2 函数调用

void BspAdcInit(void)
{
    BspRccConfig();
    BspGpioConfig();
    BspAdcConfig();
    BspDmaConfig();
    BspNvicConfig();
    BspTimConfig();
    return;
}

在调用BspAdcInit()函数后,就配置完成了ADC+DMA+TIMER的配置.会定时完成采集,且不占用CPU资源.采集的数据将会自动存储在定义的g_Adc2ConvertedValues 全局变量中.

总结

以上流程就是使用STM32的ADC+DMA+timer实现自动定时采样模拟电压的配置使用流程,若读者发先任何疑问,妄指出问题…文章来源地址https://www.toymoban.com/news/detail-625349.html

到了这里,关于STM32F407 ADC+DMA+定时器 定时采样模拟量的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • stm32f407单一定时器输出四路PWM波

    最近在玩遥控器多路pwm捕获,顺带着写了一下pwm波输出的代码,下面我来说一下407板子输出pwm波的具体配置及函数说明。 输出效果如下。PS:因为我的分析仪只能接一个,就只看一路的输出 1、开启时钟及定时器引脚复用 在输出PWM波时要开启定时器时钟及GPIO时钟,本例以TI

    2024年02月12日
    浏览(45)
  • stm32f407关于通用定时器各种函数——PWM(二)

            定时器产生PWM:在计数器频率固定时,PWM 频率由 自动重载寄存器(TIMx_ARR) 的值决定,其占空比由 捕获/比较寄存器(TIMx_CCRx) 的值决定         定时器工作在递增计数模式,纵轴是计数器的计数值 CNT,横轴表示时。当 CNT=CCRx 时,IO 输出高电平(逻辑 1);

    2024年02月08日
    浏览(81)
  • 定时器(PWM输出)触发ADC采样(DMA)——STM32CubeMX

    我用的单片机是STM32F103CBTX 定时器:使用PWM输出的模式 ADC:使用DMA的模式 (在不使用DMA的情况下,定时器控制ADC进行数据采集只能是单通道!如果开启了多通道,读取到的ADC采集值只会是最后一个通道的值!所以,要想使用定时器控制ADC采集 多通道 , 必须使用DMA !)  看

    2024年04月10日
    浏览(49)
  • stm32f407探索者开发板(二十二)——通用定时器基本原理讲解

    STM32F40x系列总共最多有14个定时器 三种(4)STM32定时器区别 STM3 F4 的通用 TIMx (TIM2、TIM3、TIM4 和 TIM5)定时器功能特点包括: 16 /32 位向上、向下、向上/向下(中心对齐)计数模式,自动装载计数器(TIMx_CNT)。 16 位可编程(可以实时修改)预分频器(TIMx_PSC),计数器时钟频率的分频系

    2024年02月12日
    浏览(40)
  • 【STM32】定时器1触发ADC多(规则)通道采样+DMA(CUBEMX配置)

    在用单片机做电源控制时不得不提ADC采集,离散系统是有固定的执行周期的,所以我们采样也是要固定时间去采样。然后就是我希望pwm波(定时器1产出)的频率与采样频率一致。 我下面演示的是G431CBU6,当然其他芯片也大差不差了。 说一下大致流程,TIM1触发ADC采样,然后

    2024年02月01日
    浏览(46)
  • 基于STM32CubeMX和keil采用STM32F407的基本定时器中断实现LED闪烁

    定时器有三种,基本定时器,通用定时器,以及高级定时器。 这篇博客以最简单的基本定时器为例,实现LED的闪烁。 后面两种定时器的用法后面再写。 实现功能: TIM6控制LED每隔0.5s变一次状态。 TIM7控制LED1常量2s后熄灭。 因为都是用到LED,所以和上一篇基于STM32CubeMX与keil采

    2024年02月04日
    浏览(58)
  • STM32F407单一定时器输出4路不同频率及占空比的PWM波

    程序效果演示 STM32单一定时器输出四路不同频率及占空比的PWM波 一、程序思路 因为定时器只有一个CNT计数器所以只能有一个输出频率,若要实现多路不同频率波形,只能通过在当前CNT计数器的基础上不断累加自身CCR寄存器的值来触发中断在中断中翻转波形的方式,此时中断

    2024年02月05日
    浏览(54)
  • 【正点原子STM32连载】第二十三章 高级定时器互补输出带死区控制实验 摘自【正点原子】APM32F407最小系统板使用指南

    本章将介绍使用APM32F407输出带死区和刹车控制的两路互补PWM。通过本章的学习,读者将学习到高级定时器的互补输出、死区插入和刹车的功能的使用。 本章分为如下几个小节: 23.1 硬件设计 23.2 程序设计 23.3下载验证 23.1 硬件设计 23.1.1 例程功能 定时器8通道1及其互补通道输

    2024年02月09日
    浏览(61)
  • 【STM32F407 ADC+DMA采集压力变送器数据(HAL库)】

    之前项目中需要对麦克传感器的mpm480隔爆压力变送器(4-20ma输出)的数据进行实时采集,使用STM32F407作为控制器,使用信号转换模块将压力变送器4-20ma的输出转换为0-3.3v的信号量,输入到STM32F407板子的ADC1的通道10,并使用DMA2通道0数据流0将采集的多个值从外设直接存入存储器

    2024年02月16日
    浏览(63)
  • 【STM32】- 定时器+DMA+ADC 双重模式

    目录   1 前言 2 ADC介绍 2.1 多重工作模式 2.2 多重ADC框图 2.3 规则同时模式 3 程序设计 3.1 时序图 3.2 初始化流程图 3.3 初始化代码 4 结论        关于ADC,相信大家都比较了解,关于STM32的学习教程都会有所讲解,但以查询方式、单通道讲解的较多,主要告诉大家基本的原理。

    2024年02月10日
    浏览(53)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包