硬汉嵌入式论坛

 找回密码
 立即注册
查看: 542|回复: 5
收起左侧

[有问必答] STM32F4 使用定时器1触发ADC1采样频率200Hz+DMA双缓存中断,为什么取了1024个数据,前后两次进入DMA中断的时间间隔只有2秒左右

[复制链接]

2

主题

7

回帖

13

积分

新手上路

积分
13
发表于 2023-9-20 20:44:33 | 显示全部楼层 |阅读模式
STM32F4 使用定时器1触发ADC1采样频率200Hz+DMA双缓存中断,为什么取了1024个数据,前后两次进入DMA中断的时间间隔只有2秒左右
代码如下
#include "bsp.h"


/* define ---------------------------------------------------------------------*/
#define ADC3_DR_ADDRESS    ((uint32_t)0x4001224C)


/* 变量 ----------------------------------------------------------------------*/
uint16_t ADC1ConvertedValue_a[1024] = {0};
uint16_t ADC1ConvertedValue_b[1024] = {0};

uint8_t flag_dma = 0;

/* 供本文件使用 --------------------------------------------------------------*/
static void TIM1_Config(void);
/*
*********************************************************************************************************
*        函 数 名: bsp_InitADC
*        功能说明: ADC初始化
*        形    参: 无
*        返 回 值: 无
*********************************************************************************************************
*/

void bsp_InitADC(void)
{
        /* 配置GPIO. */
        {
                GPIO_InitTypeDef GPIO_InitStructure = {0};
               
                RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
               
                /* 配置ADC引脚为模拟输入模式 ******************************/
               
                GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;                /* 设为输出口 */
                GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;                /* 设为推挽模式 */
                GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;        /* 上下拉电阻不使能 */
                GPIO_InitStructure.GPIO_Speed = GPIO_Speed_25MHz;        /* IO口最大速度 */
               
                GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
                GPIO_Init(GPIOC, &GPIO_InitStructure);

                /* 配置ADC引脚为模拟输入模式 ******************************/
                GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
                GPIO_Init(GPIOC, &GPIO_InitStructure);               
        }
       
       

       
        {
                DMA_InitTypeDef       DMA_InitStructure = {0};
               
                RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
               
                /* DMA2 Stream0 channel0 配置用于ADC1 **************************************/
                DMA_DeInit(DMA2_Stream0);
                DMA_InitStructure.DMA_Channel = DMA_Channel_0;  
                DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;
                DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&ADC1ConvertedValue_a;
                DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
                DMA_InitStructure.DMA_BufferSize = 1024;
                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_PeripheralDataSize_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_Full;
                DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
                DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
                DMA_Init(DMA2_Stream0, &DMA_InitStructure);
               
                //双缓冲模式设置
//                DMA_DoubleBufferModeConfig(DMA2_Stream0,(uint32_t)(u16 *)(ADC1ConvertedValue_b),DMA_Memory_1);    //DMA_Memory_0首先被传输
//                DMA_DoubleBufferModeCmd(DMA2_Stream0,ENABLE);
               
               
                /* DMA2_Stream0 enable */
                DMA_Cmd(DMA2_Stream0, ENABLE);
        }
       
        /*DMA2_Stream0 传输完成中断使能 传输一半中断使能*/
        {
                  NVIC_InitTypeDef NVIC_InitStructure = {0};
                  
                  // 配置DMA中断优先级
                  NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream0_IRQn;
                  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // 可以根据需要设置中断优先级
                  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
                  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
                  NVIC_Init(&NVIC_InitStructure);
                  DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TC | DMA_IT_HT); //清除中断标志
                  DMA_ITConfig(DMA2_Stream0, DMA_IT_TC, ENABLE);                         // 使能DMA传输完成中断
                  DMA_ITConfig(DMA2_Stream0, DMA_IT_HT, ENABLE);                         // 使能DMA半传输完成中断
        }
        /* ADC公共部分初始化**********************************************************/
        {
                /*
                ***************************************************************************
                  PCLK2 = HCLK / 2
                  下面选择的是2分频
                  ADCCLK = PCLK2 /2 = HCLK / 4 = 168 / 4 = 42M  [手册最大时36M,此时有超频]
                  ADC采样频率: Sampling Time + Conversion Time = 3 + 12 cycles = 15cyc
                                                Conversion Time = 42MHz / 15cyc = 2.8Mbps.               
                ****************************************************************************
                */
                ADC_CommonInitTypeDef ADC_CommonInitStructure = {0};

                ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
                ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
                ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
                ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
                ADC_CommonInit(&ADC_CommonInitStructure);
        }
       
        /* 配置 PC0/ADC1_IN10  ******************************************************************/
        {
                ADC_InitTypeDef       ADC_InitStructure = {0};
               
                RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
               
                ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
                ADC_InitStructure.ADC_ScanConvMode = ENABLE;
                ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
                ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising;
                ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
                ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
                ADC_InitStructure.ADC_NbrOfConversion = 2;

                /* ADC1 规则通道配置 -------------------------------------------------------*/
                ADC_Init(ADC1, &ADC_InitStructure);
                ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_3Cycles);
                ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 2, ADC_SampleTime_3Cycles);
               
                /* 使能 ADC1 DMA */
                ADC_DMACmd(ADC1, ENABLE);

                /* 使能DMA请求 最后一个传输结束后继续使能DMA, 对于循环模式必须使能 -------*/
                ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);

                /* Enable ADC1 --------------------------------------------------------------*/
                ADC_Cmd(ADC1, ENABLE);
        }
       
                TIM1_Config();
}

void DMA2_Stream0_IRQHandler(void)
{
       
  // DMA半传输中断标志位
  if(DMA_GetITStatus(DMA2_Stream0, DMA_IT_HTIF0))
  {
                DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_HTIF0); // 清除中断标志
                if(DMA_GetCurrentMemoryTarget(DMA2_Stream0) == DMA_Memory_1)
                {
                        flag_dma = 1;
                }
                else
                {
                        flag_dma = 2;
                }
  }
         
  // DMA传输完成后的处理代码
  if (DMA_GetITStatus(DMA2_Stream0, DMA_IT_TCIF0))
  {
   
    DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0); // 清除中断标志
       
  }
  
  

}
/*
*********************************************************************************************************
*        函 数 名: TIM1_Config
*        功能说明: 配置定时器1,用于触发ADC, 触发频率1Msps
*        形    参: 无
*        返 回 值: 无
*********************************************************************************************************
*/
static void TIM1_Config(void)
{
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure = {0};
    TIM_OCInitTypeDef  TIM_OCInitStructure = {0};
   
        /* 使能定时器1 */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);                                                   //使能定时器1时钟
   
        /* 先禁能再配置 */
    TIM_Cmd(TIM1, DISABLE);       
   
    /*
     ********************************************************************************
    system_stm32f4xx.c 文件中 void SetSysClock(void) 函数对时钟的配置如下:

    HCLK = SYSCLK / 1     (AHB1Periph)
    PCLK2 = HCLK / 2      (APB2Periph)
    PCLK1 = HCLK / 4      (APB1Periph)

    因为APB1 prescaler != 1, 所以 APB1上的TIMxCLK = PCLK1 x 2 = SystemCoreClock / 2;
    因为APB2 prescaler != 1, 所以 APB2上的TIMxCLK = PCLK2 x 2 = SystemCoreClock;

    APB1 定时器有 TIM2, TIM3 ,TIM4, TIM5, TIM6, TIM7, TIM12, TIM13, TIM14
    APB2 定时器有 TIM1, TIM8 ,TIM9, TIM10, TIM11
         
    TIM6 更新周期是 = TIM1CLK / (TIM_Period + 1)/(TIM_Prescaler + 1)
    ********************************************************************************
    */
   
    TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);                                     //初始化定时器1的寄存器为复位值
    TIM_TimeBaseStructure.TIM_Period = 50 - 1;                                        //ARR自动重装载寄存器周期的值(定时时间)到设置频率后产生个更新或者中断(也是说定时时间到)
    TIM_TimeBaseStructure.TIM_Prescaler = 16800 - 1;  //PSC时钟预分频数 例如:时钟频率=TIM1CLK/(时钟预分频+1)
    TIM_TimeBaseStructure.TIM_ClockDivision = 0x0;                                       //CR1->CKD时间分割值
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;             //CR1->CMS[1:0]和DIR定时器模式 向上计数
    TIM_TimeBaseStructure.TIM_RepetitionCounter = 0x0000;                /* TIM1 和 TIM8 必须设置 */       
    TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);

        /**************ADC1的触发***********************************************/
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;                                   
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;     
    TIM_OCInitStructure.TIM_Pulse = TIM_TimeBaseStructure.TIM_Period - 1;
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
    TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;           /* only for TIM1 and TIM8. 此处和正相引脚不同 */       
    TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;                   /* only for TIM1 and TIM8. */                 
    TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;           /* only for TIM1 and TIM8. */
    TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;           /* only for TIM1 and TIM8. */               
    TIM_OC1Init(TIM1, &TIM_OCInitStructure);
    //TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);                                        //CMR2 设置预装载使能  更新事件产生时写入有效
    //TIM_ARRPreloadConfig(TIM1, ENABLE);                                                                    //CR1  设置ARR自动重装 更新事件产生时写入有效
    TIM_Cmd(TIM1, ENABLE);                                                                                          
    TIM_CtrlPWMOutputs(TIM1, ENABLE);                                                                  //使能PWM 输出
}
回复

使用道具 举报

2

主题

7

回帖

13

积分

新手上路

积分
13
 楼主| 发表于 2023-9-21 00:21:28 | 显示全部楼层
我把定时器分频变成
    TIM_TimeBaseStructure.TIM_Period =  100 - 1;    //ARR自动重装载寄存器周期的值(定时时间)到设置频率后产生个更新或者中断(也是说定时时间到)
    TIM_TimeBaseStructure.TIM_Prescaler = 16800 - 1;                      //PSC时钟预分频数 例如:时钟频率=TIM1CLK/(时钟预分频+1)
这样就可以了,但是这么一算timehclk有336000000M主频,我用的8M外部晶振PLL设置如下
#if defined(STM32F40_41xxx) || defined(STM32F427_437xx) || defined(STM32F429_439xx) || defined(STM32F401xx)
/* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N */
#define PLL_M      8
#elif defined (STM32F446xx)
#define PLL_M      8
#elif defined (STM32F411xE)

#if defined(USE_HSE_BYPASS)
#define PLL_M      8   
#else  
#define PLL_M      16
#endif /* USE_HSE_BYPASS */

#endif /* STM32F40_41xxx || STM32F427_437xx || STM32F429_439xx || STM32F401xx */  

/* USB OTG FS, SDIO and RNG Clock =  PLL_VCO / PLLQ */
#define PLL_Q      7

#if defined(STM32F446xx)
/* PLL division factor for I2S, SAI, SYSTEM and SPDIF: Clock =  PLL_VCO / PLLR */
#define PLL_R      7
#endif /* STM32F446xx */

#if defined(STM32F40_41xxx) || defined(STM32F427_437xx) || defined(STM32F429_439xx) || defined(STM32F446xx)
#define PLL_N      336
/* SYSCLK = PLL_VCO / PLL_P */
#define PLL_P      2
#endif /* STM32F40_41xxx || STM32F427_437x || STM32F429_439xx || STM32F446xx */

#if defined(STM32F401xx)
#define PLL_N      336
/* SYSCLK = PLL_VCO / PLL_P */
#define PLL_P      4
#endif /* STM32F401xx */

#if defined(STM32F411xE)
#define PLL_N      400
/* SYSCLK = PLL_VCO / PLL_P */
#define PLL_P      4   
#endif /* STM32F411xx */
晶振设置
#if defined(STM32F40_41xxx) || defined(STM32F427_437xx)  || defined(STM32F429_439xx) || defined(STM32F401xx)  || defined(STM32F411xE)
#if !defined  (HSE_VALUE)
  #define HSE_VALUE    ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */
感觉是时钟没有配置对,但是又不知道那不对
回复

使用道具 举报

2

主题

7

回帖

13

积分

新手上路

积分
13
 楼主| 发表于 2023-9-21 00:26:08 | 显示全部楼层
将定时器设置为

就可以了,但是这样一算定时器主频就有336 000 000Hz了
我用的外部晶振8M的

PLL设置为

感觉是时钟没有配置对,但是又不知道哪里错了


回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106757
QQ
发表于 2023-9-21 08:44:56 | 显示全部楼层
看下ndtr寄存器,dma传输点数对吧,点数对就是定时器触发时间不准
回复

使用道具 举报

2

主题

7

回帖

13

积分

新手上路

积分
13
 楼主| 发表于 2023-9-21 10:04:06 | 显示全部楼层
是我脑子的问题,我开起了两通道,1024个数据就是转换512次,200Hz,512次就是2.56秒
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106757
QQ
发表于 2023-9-23 07:44:12 | 显示全部楼层
zqy 发表于 2023-9-21 10:04
是我脑子的问题,我开起了两通道,1024个数据就是转换512次,200Hz,512次就是2.56秒

有始有终,谢谢分享问题原因。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-4 16:33 , Processed in 0.332982 second(s), 30 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表