ARM技术论坛
直播中

Warden

12年用户 13经验值
擅长:模拟技术
私信 关注
[问答]

关于STM32F030K6T6用DMA传输ADC采样值问题,请大神指导。

    3.jpg


        最近在学STM32F0芯片,在网上看到一个网友用DMA传输ADC采样值,并用tiM15间隔触发ADC的思路,觉得不错想把他的代码移植一下,由于我用的是STM32F030K6T6,与网友的芯片不一样,网友做的是三路连续采样,而我的硬件电路采样点只有一个,就是采样外部锂电池电压,锂电池电压约4.1v,用两个10K电阻串联分压,PA3采样分压电压(,图片上是两个100K,由于ADC采样电流的问题后将100K调整成10K),于是准备将通道17(Vref)加进来,也就是用DMA传输2路,后串口打印仿真发现采样值不正确,看规格书发现这句代码配置ADC_InitStructure.ADC_ScanDirection = ADC_ScanDirection_Upward 的解释是:向前扫描 ( 从 CHSEL0 到 CHSEL16)  ,那这样可能采样不到通道17上面,将采样2路的想法放弃,于是又只单采样一路再打印值为97,为简单验证是否正确,用芯片供电电压3.3V加到采样通道PA3上,打印值为255,这样肯定采样不对,因我配置的是12位采样(DC_InitStructure.ADC_Resolution =   ADC_Resolution_12b),理论值应该在4095左右,反复查询代码找不到问题,后来发现255这个参数好是配置8位采样的理论值,于是又将采样配置成8位,串口打印150,在PA3上加3.3v也是255,这样3.3V*150/255的结果是1.92V,至此排除误差,感觉ADC采样正确。
做这个实验我已经花了很多时间和精力,我不知道是不是因为只有一个ADC通道还配置DMA传输的问题,如果多几个通道(0-16)可能不会这样,能成功配置成12位采样,能力有限,请大神们帮忙指导一下,谢谢!

代码如下:

//u16 ADC_Array[SAMPLE_NUM];
//u16 sample0[10],sample1[10];
u16 adc1,adc2;
u8 ADC_Updata=0;//DMA传输完成标志
void Adc_Battery_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    ADC_InitTypeDef ADC_InitStructure;
    DMA_InitTypeDef DMA_InitStructure;
    NVIC_InitTypeDef NVIC_InitStruct;
   
    /*配置DMA中断*/
    NVIC_InitStruct.NVIC_IRQChannel = DMA1_Channel1_IRQn;
    NVIC_InitStruct.NVIC_IRQChannelPriority = 0;
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStruct);


                       
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1 , ENABLE);
    RCC_ADCCLKConfig(RCC_ADCCLK_PCLK_Div4);//12M  


    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN ;
    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_3 ; //用PA3采样一个电压
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    ADC_DeInit(ADC1);
   
     DMA_DeInit(DMA1_Channel1);//channel1
     DMA_StructInit(&DMA_InitStructure);
    DMA_InitStructure.DMA_BufferSize = 1;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC ;
    DMA_InitStructure.DMA_M2M  =  DMA_M2M_Disable ;//
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&adc1;
    DMA_InitStructure.DMA_MemoryDataSize  =  DMA_MemoryDataSize_HalfWord;DMA_MemoryDataSize_HalfWord;
    DMA_InitStructure.DMA_MemoryInc=  DMA_MemoryInc_Disable ;
    DMA_InitStructure.DMA_Mode  = DMA_Mode_Circular ;
    DMA_InitStructure.DMA_PeripheralBaseAddr =(uint32_t)(ADC1_BASE+0x40);//(uint32_t)(&ADC1->DR);//网友配置 的 是(uint32_t)ADC1_DR_Address,因为MDK没有这个定义,我修改了下,不知道是否正确,看有数据出来,猜想应该没问题。
    DMA_InitStructure.DMA_PeripheralDataSize=  DMA_MemoryDataSize_HalfWord;
    DMA_InitStructure.DMA_PeripheralInc =DMA_PeripheralInc_Disable  ;
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
     
    DMA_Init(DMA1_Channel1, &DMA_InitStructure);
  
   
   ADC_DeInit(ADC1);      
    ADC_StructInit(&ADC_InitStructure);


    ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;// 关闭连续模式,用定时器触发采样
    ADC_InitStructure.ADC_DataAlign =  ADC_DataAlign_Right;
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConvEdge_Rising;//上升沿触发  ;
    ADC_InitStructure.ADC_Resolution =   ADC_Resolution_8b ;
    ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConv_T3_TRGO; //网友配置的是TIM15,我的芯片没有TIM15,用TIM3替代


    ADC_InitStructure.ADC_ScanDirection = ADC_ScanDirection_Upward ;  //向前扫描 ( 从 CHSEL0 到 CHSEL16)
    ADC_JitterCmd(ADC1, ADC_JitterOff_PCLKDiv4, ENABLE);//12M滤波采样
    ADC_OverrunModeCmd(ADC1, ENABLE);  
    ADC_ChannelConfig(ADC1, ADC_Channel_3, ADC_SampleTime_55_5Cycles);
    ADC_Init(ADC1,&ADC_InitStructure);
   // ADC_VrefintCmd(ENABLE);
    ADC_GetCalibrationFactor(ADC1);  
   //  ADC_ContinuousModeCmd(ADC1, ENABLE);
    ADC_Cmd(ADC1,ENABLE);          
    while(ADC_GetFlagStatus(ADC1, ADC_FLAG_ADRDY ) == RESET);        
     DMA_ITConfig(DMA1_Channel1,DMA_IT_TC,ENABLE);
     DMA_ClearFlag(DMA1_FLAG_TC1);
      
    ADC_DMACmd(ADC1, ENABLE);
     ADC_DMARequestModeConfig(ADC1, ADC_DMAMode_Circular);
     DMA_Cmd(DMA1_Channel1,ENABLE);
    ADC_StartOfConversion(ADC1);
    // while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC)==RESET);     
}


void Adc_TimerInit(void)  
{  
    TIM_TimeBaseInitTypeDef timer_init_structure;  
    NVIC_InitTypeDef nvic_init_structure;  
  
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3 , ENABLE);            //打开TIM3时钟
  
    nvic_init_structure.NVIC_IRQChannel = TIM3_IRQn;                //TIM3中断
    nvic_init_structure.NVIC_IRQChannelCmd = ENABLE;                //  
    nvic_init_structure.NVIC_IRQChannelPriority = 2;                //
    NVIC_Init(&nvic_init_structure);  
  
    TIM_DeInit(TIM3);                                               //
    TIM_TimeBaseStructInit(&timer_init_structure);                  //
  
    timer_init_structure.TIM_ClockDivision = TIM_CKD_DIV1;          //TIM3时钟48M  
    timer_init_structure.TIM_CounterMode = TIM_CounterMode_Up;      //
    timer_init_structure.TIM_Period = 999;                          //怕时间不够ADC采样,配置1S采样1次
    timer_init_structure.TIM_Prescaler = 48000-1;                     
    timer_init_structure.TIM_RepetitionCounter = 0x00;              
    TIM_TimeBaseInit(TIM3,&timer_init_structure);  
  
    TIM_ITConfig(TIM3, TIM_IT_Update, ENABLE);                      //??TIM15??  
    TIM_SelectOutputTrigger(TIM3, TIM_TRGOSource_Update);           //配置TIM3更新触发中断
  
    TIM_Cmd(TIM3, ENABLE);                                          //??TIM15  
}  

void TIM3_IRQHandler()  
{  
    if(TIM_GetITStatus(TIM3, TIM_IT_Update))            //????update????  
    {  
      //加一LED指示TIM3是否有工作
         if(GPIO_ReadOutputDataBit(LED_PORT, LED3_PIN)==RESET)

         GPIO_SetBits(LED_PORT, LED3_PIN);
         else
         GPIO_ResetBits(LED_PORT, LED3_PIN);
        TIM_ClearITPendingBit(TIM3, TIM_IT_Update);     //
    }  
}  




void DMA1_Channel1_IRQHandler()  
{  
   /* u8 SampleIndex=0;
    if(DMA_GetITStatus(DMA1_IT_TC1))   
    {  
      
               
             while(SampleIndex !=10)  
                {  
                    sample0[SampleIndex] = ADC_Array[0+SampleIndex*2]&0x00000fff;  
                    sample1[SampleIndex] =ADC_Array[1+SampleIndex*2]&0x00000fff;               
                    SampleIndex++;  
                }  
                ADC_Updata=1;
         
      
    }      
    DMA_ClearFlag(DMA1_FLAG_TC1);*/


    if(DMA_GetITStatus(DMA1_IT_TC1))   
    {        
      ADC_Updata=1;
    }      
    DMA_ClearFlag(DMA1_FLAG_TC1);
}



主程序
int main(void)
{        
    u16 Adc_Value;
    RCC_ClocksTypeDef RCC_CLOCK;
    SystemInit();//用的内部时钟,配置最大时钟48MHZ
    Delay_Init(); //systicK时钟配置
        ALL_Config();
        RCC_MCOConfig(RCC_MCOSource_HSI);
     RCC_GetClocksFreq(&RCC_CLOCK);
   
   
    while(1)
    {
        
         if(ADC_Updata==1)
         {
              ADC_Updata=0;
           // Adc_Value = ADC_Get_Average(sample0);
             printf("ADC_Valeue:%dn",adc1);
              printf("ADC_Voltage:%fn",3.3*adc1/255);
           //  printf("ADC_Valeue:%fn",3.3*Adc_Value/4095);
         }
         delay_ms(1000);
         delay_ms(1000);
    }

  • 1.png
已退回10积分

回帖(2)

hih

2021-11-19 14:26:05
dma多通道 采集的数据存储 一般是 建立个 二维数组  存储方式 是按顺序存储 类似{1, 2}  {1, 2}   {1, 2}    每个数组 第一个数据 才是 第一通道的数据      
举报

jinyi7016

2021-11-26 08:50:14
最好是用cubemx进行配置一下再试
举报

更多回帖

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