STM32用定时器输出比较模式来周期定时采集多通道的ADC,并由DMA传输

2019-03-23 19:19发布

1、我使用定时器输出比较模式中的timing模式,进行周期定时,并产生中断,但是时间不准确
2、ADC串口输出通道之间发生错位

望高人指点,下面是我的程序
#include "stm32f10x.h"
#include "stm32f10x_it.h"
#include "UART_INTERFACE.h"
#include "SysTickDelay.h"
#include "EVAL.h"
#include <stdio.h>

volatile bool ShiJianDao=FALSE;


#define N 10         //每通道采10次
#define M  3        //为3个通道

vu16 AD_Value[N][M];
vu16 After_filter[M];
int         i;
int j=0;

uint16_t PrescalerValue = 0;
__IO uint16_t CCR2_Val = 10000;



void GPIO_Configuration(void)
        {
        GPIO_InitTypeDef GPIO_InitStructure;
        /*GPIOA Configuration: TIM3 channel2*/         
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; //TIM_CH2
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

        GPIO_Init(GPIOA, &GPIO_InitStructure);


        /* Configure USART1 Tx (PA.09) as alternate function push-pull */
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(GPIOA, &GPIO_InitStructure);

        /* Configure USART1 Rx (PA.10) as input floating */
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
        GPIO_Init(GPIOA, &GPIO_InitStructure);

        //PA0/1/2 作为模拟通道输入引脚                        
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;                //模拟输入引脚
        GPIO_Init(GPIOA, &GPIO_InitStructure);

       
        }



void NVIC_Configuration(void)
        {
        NVIC_InitTypeDef NVIC_InitStructure;

        /* Configure the NVIC Preemption Priority Bits */  
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);        //设置优先级分组:先占优先级1位,从优先级3位

        #ifdef  VECT_TAB_RAM  
                /* Set the Vector Table base location at 0x20000000 */
                NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);                 //向量表位于RAM
        #else  /* VECT_TAB_FLASH  */
                /* Set the Vector Table base location at 0x08000000 */
                NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);   //向量表位于FLASH
        #endif
        /* Enable the TIM3 gloabal Interrupt */
   NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
   NVIC_Init(&NVIC_InitStructure);

  

        }


//配置系统时钟,使能各外设时钟
void RCC_Configuration(void)
        {
        ErrorStatus  HSEStartUpStatus;

     RCC_DeInit();         //RCC system reset(for debug purpose)
     RCC_HSEConfig(RCC_HSE_ON);      //Enable HSE
     HSEStartUpStatus = RCC_WaitForHSEStartUp();  //Wait till HSE is ready
     if(HSEStartUpStatus == SUCCESS)
     {
       FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable); //Enable Prefetch Buffer
       FLASH_SetLatency(FLASH_Latency_2);      //Set 2 Latency cycles
       RCC_HCLKConfig(RCC_SYSCLK_Div1); //AHB clock  = SYSCLK
       RCC_PCLK2Config(RCC_HCLK_Div1);  //APB2 clock = HCLK
       RCC_PCLK1Config(RCC_HCLK_Div4);  //APB1 clock = HCLK/4
       RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_6); //PLLCLK = 12MHz * 6 = 72 MHz
       RCC_PLLCmd(ENABLE);          //Enable PLL
       while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);  //Wait till PLL is ready  
       RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //Select PLL as system clock source
       while(RCC_GetSYSCLKSource() != 0x08);  //Wait till PLL is used as system clock source



          
           RCC_ADCCLKConfig(RCC_PCLK2_Div6);   //72M/6=12,ADC最大时间不能超过14M
           RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);        //使能DMA传输
           RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
           RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO
                                  | RCC_APB2Periph_USART1 |RCC_APB2Periph_ADC1 , ENABLE);  //使能GPIO外设和AFIO复用功能模块时钟使能
        }
       
}


void TIM3_Configuration(void)
        {

       
   
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    TIM_OCInitTypeDef  TIM_OCInitStructure;

       
       
        PrescalerValue = (uint16_t) (36000000 / 2000) - 1;

        /* ---------------------------------------------------------------
        TIM3CLK 36MHz
        TIM3 Configuration: generate 1 signals :
    TIM3CLK = 36 MHz, Prescaler = 0x0, TIM3 counter clock = 549.3Hz
        --------------------------------------------------------------- */
/* Time base configuration */
   TIM_TimeBaseStructure.TIM_Period = 65535;
   TIM_TimeBaseStructure.TIM_Prescaler =0;
   TIM_TimeBaseStructure.TIM_ClockDivision= 0;
   TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

   TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

  TIM_PrescalerConfig(TIM2, PrescalerValue, TIM_PSCReloadMode_Immediate);


   TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_Timing;
   TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
   TIM_OCInitStructure.TIM_Pulse = CCR2_Val;
   TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;

   TIM_OC2Init(TIM3, &TIM_OCInitStructure);
   
   
     //失能 TIMx 在 CCR1 上的预装载寄存器
   TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Disable);

       
   TIM_ITConfig(TIM3,  TIM_IT_CC2 , ENABLE);

       
        /* TIM3 enable counter */
        TIM_Cmd(TIM3, ENABLE);  //使能TIMx外设
        }



void ADC1_Configuration(void)
    {
         ADC_InitTypeDef ADC_InitStructure;
                /* Resets ADC1 */
        ADC_DeInit(ADC1);  //将外设 ADC1 的全部寄存器重设为缺省值
       
        /* ADC1 configuration ------------------------------------------------------*/
        ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;        //ADC工作模式:ADC1和ADC2工作在独立模式
        ADC_InitStructure.ADC_ScanConvMode =ENABLE;        //模数转换工作在扫描模式
        ADC_InitStructure.ADC_ContinuousConvMode = DISABLE ;        //模数转换工作在连续转换模式
        ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;       
        ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;        //ADC数据右对齐
        ADC_InitStructure.ADC_NbrOfChannel = M;        //顺序进行规则转换的ADC通道的数目
        ADC_Init(ADC1, &ADC_InitStructure);        //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器
       
       
        //设置指定ADC的规则组通道,设置它们的转化顺序和采样时间

        ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5 );        //ADC1,ADC通道2,规则采样顺序值为3,采样时间为55.5周期
        ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_55Cycles5 );
        ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_55Cycles5 );

                /* Enable ADC1 */
         ADC_Cmd(ADC1, ENABLE);        //使能指定的ADC1

       
       
         // 开启ADC的DMA支持(要实现DMA功能,还需独立配置DMA通道参等数)
           
       

         /* Enable ADC1 reset calibaration register */   
        ADC_ResetCalibration(ADC1);        //重置指定的ADC1的校准寄存器
        /* Check the end of ADC1 reset calibration register */
        while(ADC_GetResetCalibrationStatus(ADC1));        //获取ADC1重置校准寄存器的状态,设置状态则等待
       
        /* Start ADC1 calibaration */
        ADC_StartCalibration(ADC1);                //开始指定ADC1的校准状态
        /* Check the end of ADC1 calibration */
        while(ADC_GetCalibrationStatus(ADC1));                //获取指定ADC1的校准程序,设置状态则等待
       

       
        }



void DMA_Configuration(void)
        {
        /* ADC1  DMA1 Channel Config */
        DMA_InitTypeDef DMA_InitStructure;
        DMA_DeInit(DMA1_Channel1);   //将DMA的通道1寄存器重设为缺省值
        DMA_InitStructure.DMA_PeripheralBaseAddr =  (u32)&ADC1->DR;  //DMA外设ADC基地址
        DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&AD_Value;  //DMA内存基地址
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;  //内存作为数据传输的目的地
        DMA_InitStructure.DMA_BufferSize = M*N;  //DMA通道的DMA缓存的大小
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;  //外设地址寄存器不变
        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;  //内存地址寄存器递增
        DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;  //数据宽度为16位
        DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //数据宽度为16位
        DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;  //工作在正常模式
        DMA_InitStructure.DMA_Priority = DMA_Priority_High; //DMA通道 x拥有高优先级
        DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  //DMA通道x没有设置为内存到内存传输
        DMA_Init(DMA1_Channel1, &DMA_InitStructure);  //根据DMA_InitStruct中指定的参数初始化DMA的通道

       
       
        /* DMA IT enable */
     //DMA_ITConfig(DMA_Channel1, DMA_IT_TC, ENABLE); //使能DMA传输完成中断

       


        }











//配置所有外设
void Init_All_Periph(void)
        {
       
        RCC_Configuration();       
       
        NVIC_Configuration();
       
        GPIO_Configuration();

        TIM3_Configuration();

        ADC1_Configuration();

        DMA_Configuration();

  
       
        //USART1_Configuration();
        USART_Configuration(9600);
//        USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
//          USART_ITConfig(USART1, USART_IT_TXE, DISABLE);

         
        }


u16 GetVolt(u16 advalue)   

  {
   
   return (u16)(advalue * 330 / 4096);   

  }

void filter(void)
{
          int  sum = 0;
        u8 count;
          for(i=0;i<M;i++)

      {

         for ( count=0;count<N;count++)

          {

           sum += AD_Value[count];

          }

          After_filter=sum/N;

          sum=0;
      }

}
int main(void)
{
    u16         value[M];
       
          Init_All_Periph();
        SysTick_Initaize();
   

       
        while(1)
        {
       if(ShiJianDao==TRUE)
                  {
                  delay_us(9);
                  
                  ADC_SoftwareStartConvCmd(ADC1, DISABLE);
                  ADC_DMACmd(ADC1, DISABLE);
              DMA_Cmd(DMA1_Channel1, DISABLE);
                  
                  ShiJianDao=FALSE;
                  
                  }
            
                 
           if(j==10)
            {

                  filter();
                  delay_ms(6);
                  
              for(i=0;i<M;i++)
               {
                value=GetVolt(After_filter);
                printf("value[%d]: %d.%dv ",i,value/100,value%100) ;
          
               }
                   j=0;
                }
               
         
         
          
        }                                                                                                  
}



中断函数
uint16_t capture = 0;
extern __IO uint16_t CCR2_Val;
extern volatile bool ShiJianDao;

extern int j;


void TIM3_IRQHandler(void)
{
   
  if (TIM_GetITStatus(TIM3, TIM_IT_CC2) != RESET)
  {
    TIM_ClearITPendingBit(TIM3, TIM_IT_CC2);
    capture = TIM_GetCapture2(TIM3);   //获得 TIM3 输入捕获 2的值
    TIM_SetCompare2(TIM3, capture + CCR2_Val); //设置 TIM3 捕获比较 2寄存器值
       
        ADC_DMACmd(ADC1, ENABLE);
        ADC_SoftwareStartConvCmd(ADC1, ENABLE);
        DMA_Cmd(DMA1_Channel1, ENABLE);         //启动DMA通道
        printf("please wait! ");
       
        ShiJianDao=TRUE;
        j++;
         


  }


} 此帖出自小平头技术问答
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
3条回答
Li_Lei
1楼-- · 2019-03-24 03:15
 精彩回答 2  元偷偷看……
yuanwei_guo
2楼-- · 2019-03-24 07:31
该问题自己已经解决了
bdsjhh
3楼-- · 2019-03-24 08:00
我也遇到相同的问题,求解决。。。谢谢了啊 我QQ:845496118

一周热门 更多>