【STM32】- 定时器+DMA+ADC 双重模式

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

目录

 文章来源地址https://www.toymoban.com/news/detail-692724.html

1 前言

2 ADC介绍

2.1 多重工作模式

2.2 多重ADC框图

2.3 规则同时模式

3 程序设计

3.1 时序图

3.2 初始化流程图

3.3 初始化代码

4 结论


 

1 前言

     关于ADC,相信大家都比较了解,关于STM32的学习教程都会有所讲解,但以查询方式、单通道讲解的较多,主要告诉大家基本的原理。关于ADC多重模式讲解的较少。本文主要通过讲解ADC转换器的双重工作模式,让大家更好的理解ADC的多重模式。

参考资料《STM32F4参考手册》。

2 ADC介绍

    STM32单片机内部集成了12位ADC转换器,是逐次趋近型模数转换器。具有多达19个复用通道,可测量来自16个外部源、两个内部源和VBAT通道的信号。这些通道的AD转换可在单次、连续、扫描和不连续采样模式下进行。

2.1 多重工作模式

    在具有两个或多个ADC的器件中,可以使用两重(具有2个ADC)或三重(具有3个)ADC模式。在多重 ADC 模式下,通过 ADC1 主器件到 ADC2 和 ADC3 从器件的交替触发或同时触发来启动转换,具体取决于 ADC_CCR 寄存器中的 MULTI[4:0] 位所选的模式。在多重 ADC 模式下,配置外部事件触发转换时,应用必须设置为仅主器件触发而禁止从器件触发,以防止出现意外触发而启动不需要的从转换。

    可实现以下四种模式:
    ● 注入同时模式
    ● 规则同时模式
    ● 交替模式
    ● 交替触发模式
     也可按以下方式组合使用上述模式:
    ● 注入同时模式 + 规则同时模式
    ● 规则同时模式 + 交替触发模式

2.2 多重ADC框图

stm32f4双重adc,STM32,stm32,嵌入式硬件,单片机

 

图 1 多重ADC框图

    从图中可以看出:

  1. 尽管 ADC2 和 ADC3 上存在外部触发,但它们并未显示在此图中。
  2. 在双重 ADC 模式下,不存在 ADC3 从器件部分。
  3. 在三重 ADC 模式下, ADC 通用数据寄存器 (ADC_CDR) 包含 ADC1、 ADC2 和 ADC3 的规则转换数据。按照所选的存储顺序使用全部 32 个寄存器位。在双重 ADC 模式下, ADC 通用数据寄存器 (ADC_CDR) 包含 ADC1 和 ADC2 的规则转换数据。使用全部32 个寄存器位。

2.3 规则同时模式

    此模式可用于规则通道组。外部触发源来自 ADC1 的规则组多路复用器。在规则同时模式下,必须使用同一长度来转换序列,或必须确保触发之间的间隔长于 2 个序列(双重 ADC 模式)中的较长转换时间。否则,当序列较长的ADC 完成上一次转换时,序列较短的 ADC 可能重新开始转换。必须禁止注入转换。

     双重 ADC 模式,在 ADC1 或 ADC2 转换事件结束时: 会生成一个 32 位 DMA 传输请求(如果 ADC_CCR 寄存器中的 DMA[1:0] 位等于0b10)。此请求会将存储在 ADC_CDR 32 位寄存器高位半字中的 ADC2 转换数据传输到 SRAM,然后将存储在 ADC_CCR 低位半字中的 ADC1 转换数据传输到 SRAM。

     当 ADC1/ADC2 的规则通道全部完成转换后,会生成一个 EOC 中断(如果已在两个 ADC接口中的一个接口上使能)。

    16通道规则同时模式如下图所示。

stm32f4双重adc,STM32,stm32,嵌入式硬件,单片机

 

图 2 双重ADC模式

3 程序设计

3.1 时序图

stm32f4双重adc,STM32,stm32,嵌入式硬件,单片机

 

图 3定时器+DMA+ADC工作时序图

        如图 3所示,完成DMA、定时器、ADC初始化后,先使能DMA,再使能ADC,最后启动定时器Timer。当定时器发生更新事件时,触发ADC开始采样、转换,转换结束后触发DMA保存数据到缓冲区,完成一次变换。定时器的周期设定要确保完成ADC转换及DMA数据存储,否则将溢出错误。当DMA检测到转换次数达到其预设值时,触发DMA接收完成中断,关闭定时器。一个大的AD采集循环完成。

3.2 初始化流程图

        初始化过程包括ADC初始化、DMA初始化、定时器初始化。ADC初始化和大部分MCU外设初始化流程一样,先使能时钟,包括GPIO时钟、ADC时钟、ADC配置,这里的ADC配置包含ADC1和ADC2两个外设的配置。DMA初始化包含DMA时钟(本文用DMA将ADC转换结果拷贝到RAM中)使能、DMA配置,在后面的实现代码中,将DMA初始化合并在ADC_MspInit函数中完成。因为要用定时器实现定期触发ADC转化,所以在初始化时要对定时器初始化,完成时钟使能、定时器配置。

stm32f4双重adc,STM32,stm32,嵌入式硬件,单片机

 

图 4 初始化流程图

3.3 初始化代码

        ADC初始化相关函数如表 1所示

表 1 ADC初始化相关函数

序号

函数名称

函数功能说明

1

HAL_ADC_MspInit ()

时钟使能、IO、DMA初始化

2

MX_ADC1_Init()

配置ADC1

3

MX_ADC2_Init()

配置ADC2

4

ADC_Trigger_Timer_Start()

启动定时器

5

ADC_Trigger_Timer_Stop()

停止定时器

6

DMA2_Stream0_IRQHandler()

DMA中断处理函数

7

HAL_ADC_ConvCpltCallback()

ADC转换完成回调函数

8

MX_Timer2_Init()

配置Timer2配置为TIM_TRGO_UPDATE输出触发模式

        1)HAL_ADC_MspInit ()代码

        在ADC1底层初始化时,使能了ADC、DMA、GPIO时钟,引脚配置为模拟输入模式。对DMA2初始化,使能DMA中断。具体如下:

void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    
    if(adcHandle->Instance==ADC1)
    {
        __HAL_RCC_ADC1_CLK_ENABLE();    //使能ADC0时钟 
        
        __HAL_RCC_DMA2_CLK_ENABLE();
        
        __HAL_RCC_GPIOA_CLK_ENABLE();
        __HAL_RCC_GPIOC_CLK_ENABLE(); 
        GPIO_InitStruct.Pin = GPIO_PIN_3;
        GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
        HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
        
        GPIO_InitStruct.Pin = GPIO_PIN_0;
        GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
        HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); 

        hdma_adc1.Instance = DMA2_Stream0;
        hdma_adc1.Init.Channel = DMA_CHANNEL_0;
        hdma_adc1.Init.Direction = DMA_PERIPH_TO_MEMORY;
        hdma_adc1.Init.PeriphInc = DMA_PINC_DISABLE;
        hdma_adc1.Init.MemInc = DMA_MINC_ENABLE;
        hdma_adc1.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
        hdma_adc1.Init.MemDataAlignment = DMA_PDATAALIGN_WORD;
        hdma_adc1.Init.Mode = DMA_NORMAL;                           
        hdma_adc1.Init.Priority = DMA_PRIORITY_HIGH;
        hdma_adc1.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
        HAL_DMA_Init(&hdma_adc1);
        
        __HAL_LINKDMA(adcHandle,DMA_Handle,hdma_adc1);
        
        HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 1, 1);  //DMA中断配置
        HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);        
    }
    else if(adcHandle->Instance==ADC2)
    {
        __HAL_RCC_ADC2_CLK_ENABLE();
    }   
}

        2)MX_ADC1_Init()代码

void MX_ADC1_Init(void)
{
    ADC_MultiModeTypeDef multimode;
    ADC_ChannelConfTypeDef sConfig;

    /**配置 ADC通用参数*/
    hadc1.Instance = ADC1;
    hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
    hadc1.Init.Resolution = ADC_RESOLUTION_12B;                 //设置分辨率
    hadc1.Init.ScanConvMode = ENABLE;                                 //扫描方式
    hadc1.Init.ContinuousConvMode = DISABLE;                      //关闭连续扫描
    hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_RISING; //触发模式
    hadc1.Init.ExternalTrigConv = ADC_EXTERNALTRIGCONV_T2_TRGO;  //触发源
    hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;               //对齐方式
    hadc1.Init.NbrOfConversion = 1;
    hadc1.Init.DMAContinuousRequests = ENABLE;
    hadc1.Init.EOCSelection = ADC_EOC_SEQ_CONV;
    HAL_ADC_Init(&hadc1);

    /**配置 ADC工作模式 */
    multimode.Mode = ADC_DUALMODE_REGSIMULT;                    //规则同时模式
    multimode.DMAAccessMode =ADC_DMAACCESSMODE_2;        //ADC同步DMA模式2
    multimode.TwoSamplingDelay = ADC_TWOSAMPLINGDELAY_5CYCLES;    //
    HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode);

    /**配置 ADC采集通道*/
    sConfig.Channel = ADC_CHANNEL_VREFINT;
    sConfig.Rank = 1;
    sConfig.SamplingTime = ADC_SAMPLETIME_56CYCLES;
    HAL_ADC_ConfigChannel(&hadc1, &sConfig);
}

        3)MX_ADC2_Init()代码

void MX_ADC2_Init(void)
{
    ADC_ChannelConfTypeDef sConfig;

    /**配置 ADC通用参数*/
    hadc2.Instance = ADC2;
    hadc2.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;
    hadc2.Init.Resolution = ADC_RESOLUTION_12B;
    hadc2.Init.ScanConvMode = ENABLE;
    hadc2.Init.ContinuousConvMode = DISABLE;
    hadc2.Init.DiscontinuousConvMode = DISABLE;
    hadc2.Init.DataAlign = ADC_DATAALIGN_RIGHT;
    hadc2.Init.NbrOfConversion = 1;
    hadc2.Init.DMAContinuousRequests = DISABLE;  
    hadc2.Init.EOCSelection = ADC_EOC_SEQ_CONV;
    HAL_ADC_Init(&hadc2);  

    /**配置 ADC采集通道*/
    sConfig.Channel = ADC_CHANNEL_13;
    sConfig.Rank = 1;
    sConfig.SamplingTime = ADC_SAMPLETIME_56CYCLES;
    HAL_ADC_ConfigChannel(&hadc2, &sConfig);
    
    HAL_ADC_Start(&hadc2);
}

        4)ADC_Trigger_Timer_Start()代码

static void ADC_Trigger_Timer_Start(void)
{
    __HAL_TIM_ENABLE(&htim2);
}

        5)ADC_Trigger_Timer_Stop()代码

static void ADC_Trigger_Timer_Stop(void)
{
    __HAL_TIM_DISABLE(&htim2);
}

 

6)HAL_ADC_ConvCpltCallback()代码

void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
    ADC_Trigger_Timer_Stop();
    HAL_ADCEx_MultiModeStop_DMA(&hadc1);
    ADC_ConvCpltCallback();
}
  1. MX_Timer2_Init()代码
void MX_Timer2_Init(void)
{    
    TIM_MasterConfigTypeDef sMasterConfig;
    uint32_t uwPrescalerValue = 0;
    
    uwPrescalerValue = (uint32_t) (SystemCoreClock /2/1000000) - 1;       //timer2挂在APB2上,倍频后最大时钟为系统时钟/2,

    htim2.Instance = TIM2;
    htim2.Init.Prescaler = uwPrescalerValue;               //定时器时钟频率为1M
    htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
    htim2.Init.Period = 200-1;  //定时器溢出时间,1uS*100 = 200uS
    htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
    HAL_TIM_Base_Init(&htim2);
    
    sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
    sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
    HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig);
}

4 结论

        本文介绍了定时器+DMA+ADC双重工作模式下ADC驱动设计思路,介绍了ADC初始化、配置的主要函数。文中代码截取自实际工程中部分代码,旨在为读者提供设计思路,可根据自己的程序做简单修改即可。

 

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

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

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

相关文章

  • 【STM32】定时器1触发ADC多(规则)通道采样+DMA(CUBEMX配置)

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

    2024年02月01日
    浏览(46)
  • STM32定时器DMA连续传送功能示例

    在STM32定时器应用中,定时器事件配合DMA连续传输可对定时器的多个寄存器进行读写访问。 定时器事件可以请求DMA,分为以下几种;并不是所有定时器都支持以下事件, 高级定时器是支持的。其他定时器按功能部分支持,例如基础定时器因为没有输出输入通道,所以只有更新

    2024年02月11日
    浏览(40)
  • STM32 HAL库定时器触发DMA并口数据传输

    STM32与FPGA通讯,通过8位并口线进行通讯,16byte的数据在10us之内通过8位并口数据线传给FPGA,FPGA读取该数据。 时钟采用80MHz,由于16byte的数据要在10us之内传完,那么10/(16*2)=0.3125us/次,也就是传输频率得≥3.2MHz。 定时器设置:为了方便起见,先选用了4MHz的传输频率。80MHz

    2024年02月02日
    浏览(69)
  • STM32 HAL库 Timer(定时器)+DMA输出PWM底层配置过程学习

    本文使用的芯片型号是STM32G030,写本文的目前是想记录学习下Timer借助DMA生成可变占空比PWM时的底层配置过程。 使用TIM1,配置就只改了图上的配置,系统时钟用的16M,分频选择15(16-1),自动重装载寄存器ARR选择999(1000-1),那么生成的就是1kHz的PWM,这里为什么要减1,因为这俩是

    2024年04月09日
    浏览(59)
  • STM32 DMA1和DMA2通道一览表、STM32F103C8T6定时器通道对应的引脚

    TIM1_BRK_IRQn               = 24,      TIM1_UP_IRQn                = 25,      TIM1_TRG_COM_IRQn           = 26,     TIM1_CC_IRQn                = 27,     TIM2_IRQn                   = 28,     TIM3_IRQn                   = 29,    这个函数TIM_SetCompare1,这个函数有四个,分别是TIM_SetC

    2024年02月05日
    浏览(47)
  • STM32G0 定时器PWM DMA输出驱动WS2812配置 LL库

    优点:不消耗CPU资源 缺点:占用内存较大 定时器配置 定时器通道:TIM3 CH2 分频:0 重装值:79,芯片主频64Mhz,因此PWM输出频率:64Mhz/79 ≈ 800Khz,满足芯片要求。 auto-reload preload 要关闭 output compare preload 要打开 DMA配置 外设一定要选择TIM3_UP,不要选TIM_CHx 方向是内存到外设,

    2024年02月10日
    浏览(44)
  • 【STM32】定时器PWM模式详解

    PWM模式: PWM模式1,向上计数时,PWM信号从 有效电平 变为 无效电平 PWM模式2,向上计数时,PWM信号从 无效电平 变为 有效电平 PWM极性: 极性为高时, 高电平为有效电平 ,低电平为无效电平 极性为低时, 低电平为有效电平 ,高电平为无效电平 中心对齐模式(先向上再向下

    2024年02月09日
    浏览(38)
  • STM32——高级定时器输出比较模式实验

    1,配置定时器基础工作参数 HAL_TIM_OC_Init() 2,定时器PWM输出MSP初始化 HAL_TIM_OC_MspInit() 配置NVIC、CLOCK、GPIO等 3,配置PWM模式/比较值等 HAL_TIM_OC_ConfigChannel() 4,使能通道预装载 __HAL_TIM_ENABLE_OCxPRELOAD() 5,使能输出、主输出、计数器 HAL_TIM_OC_Start() 6,修改捕获/比较寄存器的值 _HAL

    2024年02月02日
    浏览(50)
  • STM32定时器的编码器接口模式

    MCU为STM32L431,通用定时器框图: 编码器接口模式一共有三种,通过TIMx_SMCR寄存器的SMS[3:0]位来选择。模式1计数器仅在TI1FP1的边沿根据TI2FP2的电平来判断向上/下计数;模式2计数器仅在TI2FP2的边沿根据TI1FP1的电平来判断向上/下计数;模式3计数器同时在TI1FP1和TI2FP2的边沿根据另

    2023年04月15日
    浏览(49)
  • STM32 CubeMX 定时器(普通模式和PWM模式)

    定时器打开与关闭 开启PWM通道 设置PWM,占空比 方式1 方式2 值越大灯越亮

    2024年02月15日
    浏览(35)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包