/ 电子设计 / 807浏览

【STM32】实现ADC等间隔采样:使用定时器触发ADC转换,并使用DMA进行数据搬运

进行定时采样的方法大致有三种:
1、使用定时器中断每隔一定时间进行ADC转换,这样每次都必须读ADC的数据寄存器,如果采样率很低到时可以用。

2、把ADC设置成连续转换模式,同时对应的DMA通道开启循环模式,这样ADC就一直在进行数据采集然后通过DMA把数据搬运至内存(一个U16变量)。
然后再加一个定时中断,定时读取那个U16变量,存入你的采样数组。

3、使用定时器触发ADC转换的功能,然后使用DMA进行数据的搬运。这样只要设置好定时器的触发间隔,就能实现ADC定时采样转换的功能,
然后可以在程序的死循环中一直检测DMA转换完成标志,然后进行数据的读取,或者使能DMA转换完成中断,这样每次转换完成就会产生中断。

第三种方法较于第二种方法的好处在于它由定时器触发ADC采样,那样ADC的采样间隔会更加均匀,方便闭环控制、数据滤波等操作。
本文示意采用第三种方法的配置过程。


//一次采集多少数据
u16 ADC_BUFFER[BufferSize];
u8 ADC_DMA_FINISHED;

void TIM5_Init(void)
{
    //设置触发ADC的定时器5 通道1
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
    TIM_OCInitTypeDef TIM_OCInitStructure;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE);

    TIM_TimeBaseStructure.TIM_Period=999;//设置1ms一次TIM5比较的周期 = 1 KHz
    TIM_TimeBaseStructure.TIM_Prescaler=83;//系统主频84M,这里分频83,相当于1000K的定时器10时钟
    TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
    TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
    TIM_TimeBaseInit(TIM5,&TIM_TimeBaseStructure);

    TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;//下面详细说明
    TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;//TIM_OutputState_Disable;
    TIM_OCInitStructure.TIM_Pulse=499;
    TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_Low;//如果是PWM1要为Low,PWM2则为High
    TIM_OC1Init(TIM5,&TIM_OCInitStructure); // channel 1

    TIM_SelectOutputTrigger(TIM5, TIM_TRGOSource_OC1Ref);  //选择TIM5的OC1事件更新为触发源
}
//初始化ADC    with DMA                                                           
void  ADC_DMA_Init(void)
{    
  GPIO_InitTypeDef  GPIO_InitStructure;
    ADC_CommonInitTypeDef ADC_CommonInitStructure;
    ADC_InitTypeDef       ADC_InitStructure;
    DMA_InitTypeDef  DMA_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    TIM5_Init();
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);//使能GPIOC时钟
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); //使能ADC1时钟
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);//DMA2时钟使能 

  //先初始化ADC1通道10 IO口
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;//PC0 通道10
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;//模拟输入
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;//不带上下拉
  GPIO_Init(GPIOC, &GPIO_InitStructure);//初始化  

    RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1,ENABLE);   //ADC1复位
    RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1,DISABLE);    //复位结束   

  ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;//独立模式
  ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;//两个采样阶段之间的延迟5个时钟  47.6 ns*5 = 238.1 ns
  ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; //DMA失能
  ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;//预分频4分频。ADCCLK=PCLK2/4=84/4=21Mhz,ADC时钟最好不要超过36Mhz 
  ADC_CommonInit(&ADC_CommonInitStructure);//初始化

  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;//12位模式
  ADC_InitStructure.ADC_ScanConvMode = DISABLE;//非扫描模式  
  ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;//关闭连续转换 ;如果开启,后续的转换就会永不停歇(除非CONT清0)
  ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_Rising;//上升沿触发检测
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T5_CC1;
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//右对齐   
  ADC_InitStructure.ADC_NbrOfConversion = 1;//1个转换在规则序列中 也就是只转换规则序列1 
  ADC_Init(ADC1, &ADC_InitStructure);//ADC初始化

    ADC_RegularChannelConfig(ADC1,ADC_Channel_10,1,ADC_SampleTime_480Cycles); // 不间断连续(最大)采样间隔大约23.5 us -->42KHz

    DMA_DeInit(DMA2_Stream0);
    while (DMA_GetCmdStatus(DMA2_Stream0) != DISABLE){}//等待DMA可配置 

  /* 配置 DMA Stream */
  DMA_InitStructure.DMA_Channel = DMA_Channel_0;  //通道选择
  DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&ADC1->DR;//DMA外设地址
  DMA_InitStructure.DMA_Memory0BaseAddr = (u32)ADC_BUFFER;//DMA 存储器0地址
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;//外设到存储器模式
  DMA_InitStructure.DMA_BufferSize = BufferSize;//数据传输量 
  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_PeripheralDataSize_HalfWord;//存储器数据长度:16位
  DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;// 不使用循环模式 ,普通模式
  DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//中等优先级
  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 Stream

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

    DMA_ITConfig(DMA2_Stream0,DMA_IT_TC,ENABLE);        //使能传输完成中断

}                 

void Start_Sample()
{
        TIM_Cmd(TIM5,ENABLE);
        ADC_Cmd(ADC1, ENABLE);//打开AD转换器 失能ADC_ADON=1
        ADC_DMACmd(ADC1,ENABLE);
        DMA_Cmd(DMA2_Stream0, ENABLE); //使能DMA
        ADC_DMA_FINISHED = 0;
        //ADC_SoftwareStartConv(ADC1);
}
void Stop_Sample()
{
        TIM_Cmd(TIM5,DISABLE);
        ADC_Cmd(ADC1, DISABLE);//关闭AD转换器    失能ADC_ADON=0
        ADC_DMACmd(ADC1,DISABLE);
        DMA_Cmd(DMA2_Stream0, DISABLE); //失能DMA
      ADC_DMA_FINISHED = 1;
}
void DMA2_Stream0_IRQHandler(void)
{
    if(DMA_GetITStatus(DMA2_Stream0,DMA_IT_TCIF0)!=RESET)
    {
        DMA_ClearITPendingBit(DMA2_Stream0,DMA_IT_TCIF0);
        Stop_Sample();
    }

}

void ADC2Voltage(u16* adc,float*vol)
{
    u16 i;

    for(i=0;i
Eysent
【STM32】三相逆变闭环控制代码,输出SVPWM
【VHDL】用VHDL实现Cyclone II EP2C8QR208C8的音乐播放功能

0

  1. This post has no comment yet

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注