单片机学习小组
直播中

孔朱磊

7年用户 906经验值
私信 关注

如何实现定时器TIM3输出PWM波触发ADC采样呢


STM32F4定时器系统包括哪些部分?
如何实现定时器tiM3输出PWM波触发ADC采样呢?

回帖(1)

李飞凤

2022-1-25 13:36:49
STM32F4xx 通用定时器相关知识

STM32F4定时器系统包括,高级控制定时器 TIM1和 TIM8、通用定时器TIM2~TIM5、通用定时器TIM9 ~TIM14、基本定时器TIM6和TIM7。我们重点关注通用定时器的相关配置。
通用定时器TIM2~TIM5包含一个 16 位或 32 位自动重载计数器,该计数器由可编程预分频器驱动。它们可用于多种用途,包括测量输入信号的脉冲宽度(输入捕获)或生成输出波形(输出比较和 PWM)。使用定时器预分频器和 RCC 时钟控制器预分频器,可将脉冲宽度和波形周期从几微秒调制 到几毫秒。这些定时器彼此完全独立,不共享任何资源。
TIM3配置函数如下,注意GPIO复用,自动重装载值和分频系数的设置。定时器溢出时间Tout和重装载值arr以及预分频系数psc的关系如下:



  • Tout=((arr+1)*(psc+1))/TCLK


//初始化定时器
void ADC12_TIM3_Mode_Config(void)
{
          GPIO_InitTypeDef     GPIO_InitStructure;
          TIM_TimeBaseInitTypeDef   TIM_TimeBaseStructure;
                TIM_OCInitTypeDef         TIM_OCInitStructure;


          RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);          //TIM3时钟使能   
         // RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);         //使能PORTC时钟       
       
          GPIO_PinAFConfig(GPIOC,GPIO_PinSource6,GPIO_AF_TIM3); //GPIOC6(USART)复用为定时器3
       
         
          GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;           //GPIOC6
          GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;        //复用功能
          GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;        //速度100MHz
          GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;      //推挽复用输出
          GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;        //下拉
          GPIO_Init(GPIOC,&GPIO_InitStructure);              //初始化PC6
         
                TIM_TimeBaseStructure.TIM_Prescaler = 83;//psc=83
                TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
                TIM_TimeBaseStructure.TIM_Period =49;//arr=49
                TIM_TimeBaseStructure.TIM_ClockDivision =TIM_CKD_DIV1;
                TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);


                 
                TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
                TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
                TIM_OCInitStructure.TIM_Pulse=25;//自动重装载值为49,占空比设置为50%,则这里应赋值25
                TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;      


                TIM_OC1Init(TIM3, &TIM_OCInitStructure);
          TIM_OC1PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能TIM3在CCR1上的预装载寄存器
    TIM_ARRPreloadConfig(TIM3,ENABLE);//ARPE使能


                TIM_Cmd(TIM3, ENABLE);




}


DMA相关配置

在配置DMA时要注意以下几点


  • 由于我们采用双重ADC模式采样,必须使用ADC1和ADC2,ADC1为主,ADC2为从,因此根据STM32F4xx中文参考手册中的DMA请求映射表

    我们应选择ADC1对应的DMA2的通道0和数据流0。
  • 由于我们采用的是双重ADC规则同步模式,ADC采集的数据并没有存储在ADC1的数据寄存器中,而是在ADC->CDR寄存器中,所以DMA传输的源地址要改写成ADC->CDR
  • DMA目的地址为自己设定的数组ADC_ConvertedValue[]
  • 另外,双重ADC 模式下,ADC1和2的数据都存储在同一个32位的寄存器中,低半字为ADC1的数据,高半字为ADC2的数据,所以要设置源和目的数据大小为一个字。
    DMA相关配置函数如下:


//初始化DMA2
void ADC12_DMA2_Mode_Config(void)
{
        DMA_InitTypeDef DMA_InitStructure;
        RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);    //使能DMA2时钟
       
        //DMA是一种快速的数据传送方式
        while(DMA_GetCmdStatus(DMA2_Stream0)!=DISABLE);
        DMA_InitStructure.DMA_BufferSize=NUM;
        DMA_InitStructure.DMA_Channel=DMA_Channel_0;
        DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralToMemory;
        DMA_InitStructure.DMA_Memory0BaseAddr=(u32)ADC_ConvertedValue;
        DMA_InitStructure.DMA_MemoryBurst=DMA_MemoryBurst_Single;
        DMA_InitStructure.DMA_MemoryDataSize=DMA_PeripheralDataSize_Word;
        DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable;
        DMA_InitStructure.DMA_Mode=DMA_Mode_Circular;
        DMA_InitStructure.DMA_PeripheralBaseAddr=(u32)&(ADC->CDR);
        DMA_InitStructure.DMA_PeripheralBurst=DMA_PeripheralBurst_Single;
        DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Word;
        DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;
        DMA_InitStructure.DMA_Priority=DMA_Priority_High;
        DMA_InitStructure.DMA_FIFOMode=DMA_FIFOMode_Disable;
  DMA_Init(DMA2_Stream0, &DMA_InitStructure);
  
       
  //使能DMA通道2
  DMA_Cmd(DMA2_Stream0, ENABLE);
}
ADC1和ADC2的配置



  • ADC通用设置中要将模式设置为双重模式ADC_DualMode_RegSimult
  • 注意ADC的时钟最好不要超过36Mhz,否则ADC采集的数据将会不理想。
  • 要设置ADC1为定时器触发,ADC2要设置为软件触发,使用ADC_SoftwareStartConv(ADC2)函数实现。
  • DMA设置为多重模式 ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE)
    配置函数如下:


/********************************
配置ADC1,ADC2和DMA,利用DMA来读取ADC采
集到的数据  
********************************/
void ADC12_Mode_Config(void)
{
  
  ADC_InitTypeDef ADC_InitStructure;       
        ADC_CommonInitTypeDef ADC_CommonInitStructure;
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);        //使能ADC1时钟
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2, ENABLE);        //使能ADC2时钟   
       
        ADC12_GPIO_Config();
        ADC12_DMA2_Mode_Config();
        ADC12_TIM3_Mode_Config();
       
  //ADC通用配置
        ADC_CommonInitStructure.ADC_Mode = ADC_DualMode_RegSimult;//双重模式
  ADC_CommonInitStructure.ADC_TwoSamplingDelay =ADC_TwoSamplingDelay_5Cycles;//两个采样阶段之间的延迟 5 个时钟,影响不大
  ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_2; //DMA 模式选择
  ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;//预分频 4 分频。
   //ADCCLK=PCLK2/4=84/4=21Mhz,ADC 时钟最好不要超过 36Mhz
  ADC_CommonInit(&ADC_CommonInitStructure);//初始化
       
  //配置ADC1
  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;               //使用12 位分辨率
  ADC_InitStructure.ADC_ScanConvMode =DISABLE;                         //非扫描模式
  ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;                  //只采集一次,等待下次触发
        ADC_InitStructure.ADC_ExternalTrigConvEdge=ADC_ExternalTrigConvEdge_Rising;//上升沿触发
        ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_T3_CC1;         //定时器触发
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;              //ADC数据右对齐方式
  ADC_InitStructure.ADC_NbrOfConversion = 1;                  // 用来设置规则序列的长度,我们只对一个ADC通道进行转换
  ADC_Init(ADC1, &ADC_InitStructure);
        ADC_Cmd(ADC1, ENABLE);                     //使能ADC1         
         
        ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_84Cycles); //
// ADC_DMARequestAfterLastTransferCmd(ADC1,ENABLE);


  //ADC_DMACmd(ADC1, ENABLE);                         //使能ADC1的DMA
       
    //配置ADC2
  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;               //使用12 位分辨率
  ADC_InitStructure.ADC_ScanConvMode =DISABLE;                         //非扫描模式
  ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;                  //只采集一次,等待下次触发
        //ADC_InitStructure.ADC_ExternalTrigConvEdge=ADC_ExternalTrigConvEdge_Rising;//上升沿触发
        ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConvEdge_None;         //从ADC不设置外部触发
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;              //ADC数据右对齐方式
  ADC_InitStructure.ADC_NbrOfConversion = 1;                  // 用来设置规则序列的长度,我们只对一个ADC通道进行转换
  ADC_Init(ADC2, &ADC_InitStructure);
        ADC_Cmd(ADC2, ENABLE);                     //使能ADC2


        ADC_RegularChannelConfig(ADC2, ADC_Channel_11, 1, ADC_SampleTime_84Cycles); //
         // ADC_DMARequestAfterLastTransferCmd(ADC2,ENABLE);
  //ADC_DMACmd(ADC2, ENABLE);                         //使能ADC1的DMA
                ADC_SoftwareStartConv(ADC2);
        ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE);


}
数据转换

将采集到的数据转化为两组数据,输入波形数据和输出波形数据

/******************************************************************
将采集到的数据转化为两组数据,输入数据和输出数据
*******************************************************************/
void zhuanhua(void)
{int i=0;
        for(i=0;i<2000;i++)
        { ADC2_ConvertedValue=(u16)((ADC_ConvertedValue&0xFFFF0000)>>16);
                ADC1_ConvertedValue=(u16)(ADC_ConvertedValue&0xFFFF);
        }


}       
举报

更多回帖

发帖
×
20
完善资料,
赚取积分