STM32 ADC用DMA方式传输数据出错的解决方法

在ADC高速采集数据时,通过DMA一次性获取大量的转换数据。比如5个通道,一次获取1000组数据。获得1000组数据后再统一处理,然后触发下一次转换。在调试过程中发现获取的通道数据序号出错。经过一番折腾终于调通,程序如下


定义

#define  adNum   10000
u16 adsample[adNum];
//#define DMA1_Channel4_IRQn_EN  1//DMA 电压采集中断
#ifdef DMA1_Channel4_IRQn_EN
    #define DMA1_Channel4_IRQn_PreemptionPriority 1
    #define DMA1_Channel4_IRQn_SubPriority        1
    u16 Flag,FlagTemp;
    void DMA1_Channel1_IRQHandler(void)
    {
           if(DMA_GetITStatus(DMA1_IT_TC1)!=RESET)
           {
               DMA_ClearITPendingBit(DMA1_IT_TC1);
               Flag++;
            }
    }   
#endif

ADC&DMA初始化

    void ADCDMAInit(void)
    {
        u8 ADC_SampleTime;
        ADC_InitTypeDef         ADC_InitStructure;
        GPIO_InitTypeDef        GPIO_InitStructure;
        DMA_InitTypeDef         DMA_InitStructure;
        NVIC_InitTypeDef NVIC_InitStructure;

    RCC_ADCCLKConfig(RCC_PCLK2_Div8);//RCC_PCLK2_Div6//12M
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1|RCC_APB2Periph_GPIOC,ENABLE);
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); 
    GPIO_InitStructure.GPIO_Mode =GPIO_Mode_AIN;
    GPIO_InitStructure.GPIO_Pin  =(GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3);
    GPIO_Init(GPIOC,&GPIO_InitStructure);
         /* DMA channel1 configuration ---------------------------*/
    DMA_DeInit(DMA1_Channel1);   //将DMA的通道1寄存器重设为缺省值
    DMA_InitStructure.DMA_PeripheralBaseAddr =  (u32)&ADC1->DR;//DMA外设ADC基地址
    DMA_InitStructure.DMA_MemoryBaseAddr =(u32)&adsample[0]; //DMA内存基地址
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;  //内存作为数据传输的目的地
    DMA_InitStructure.DMA_BufferSize =adNum;  //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_Normal;//正常模式!!!!
    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的通道
 #ifdef DMA1_Channel4_IRQn_EN
        NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=DMA1_Channel4_IRQn_PreemptionPriority ;//抢占优先级
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = DMA1_Channel4_IRQn_SubPriority;     //子优先级
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;         //IRQ通道使能
        NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
  DMA_ITConfig(DMA1_Channel1,DMA_IT_TC,ENABLE);      
  #endif  
    ADC_InitStructure.ADC_Mode=ADC_Mode_RegSimult;
    ADC_InitStructure.ADC_ContinuousConvMode=ENABLE;
    ADC_InitStructure.ADC_ScanConvMode=ENABLE;
    ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right;
    ADC_InitStructure.ADC_NbrOfChannel=5;
    ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;
    ADC_Init(ADC1,&ADC_InitStructure);
       ADC_SampleTime=ADC_SampleTime_71Cycles5;//ADC_SampleTime_71Cycles5;//ADC_SampleTime_55Cycles5;//ADC_SampleTime_239Cycles5;//ADC_SampleTime_1Cycles5;//ADC_SampleTime_13Cycles5;//
    ADC_RegularChannelConfig(ADC1, ADC_Channel_10,1, ADC_SampleTime);//L1
    ADC_RegularChannelConfig(ADC1, ADC_Channel_11,2, ADC_SampleTime);//L2
    ADC_RegularChannelConfig(ADC1, ADC_Channel_12,3, ADC_SampleTime);//L3
    ADC_RegularChannelConfig(ADC1, ADC_Channel_13,4, ADC_SampleTime);//V
    ADC_RegularChannelConfig(ADC1, ADC_Channel_17,5, ADC_SampleTime);//内部参考电压   
    ADC_DMACmd(ADC1, ENABLE);
    ADC_Cmd(ADC1,ENABLE);
    DMA_Cmd(DMA1_Channel1, ENABLE);
    ADC_ResetCalibration(ADC1);
    while(ADC_GetResetCalibrationStatus(ADC1));
    ADC_StartCalibration(ADC1);
    while(ADC_GetCalibrationStatus(ADC1));
    ADC_SoftwareStartConvCmd(ADC1, ENABLE); 
}

主函数中

#ifdef DMA1_Channel4_IRQn_EN
    if(Flag!=Flagtemp)
    {
        Flagtemp=Flag;
        DMA_Cmd(DMA1_Channel1, DISABLE);            //关闭DMA
        ADC_Cmd(ADC1,DISABLE);                      //关闭ADC
        ProcessUData();//数据处理
        DMA_SetCurrDataCounter(DMA1_Channel1,adNum); //传输数据变成0,必须重新设置
        DMA_Cmd(DMA1_Channel1,ENABLE);                //开DMA1   
        ADC_Cmd(ADC1,ENABLE);                           //开ADC
        ADC_SoftwareStartConvCmd(ADC1, ENABLE);         //触发转换
    }
 #endif      
   if(DMA_GetFlagStatus(DMA1_IT_TC1)!=RESET)
   {
    DMA_ClearFlag(DMA1_IT_TC1);
    DMA_Cmd(DMA1_Channel1, DISABLE);            //关闭DMA
    ADC_Cmd(ADC1,DISABLE);                      //关闭ADC
    ProcessUData();//数据处理
    DMA_SetCurrDataCounter(DMA1_Channel1,adNum); //传输数据变成0,必须重新设置
    DMA_Cmd(DMA1_Channel1,ENABLE);                //开DMA1   
    ADC_Cmd(ADC1,ENABLE);                           //开ADC
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);         //触发转换
   }

注意

1、DMA工作在DMA_Mode_Normal模式下传输完成后需要重新设定DMA_MemoryDataSize。设定该参数就需要先关闭DMA,然后再开启。
没有这一步操作,DMA只能传输一次。
2、DMA传输完成后要先关闭ADC,再开启ADC,然后再ADC_SoftwareStartConvCmd-ENABLE。没有这个过程,通道数据将会打乱
3、DMA1_Channel4_IRQn_EN 配置DMA中断或查询

    DMA_Cmd(DMA1_Channel1, DISABLE);            //关闭DMA
    ADC_Cmd(ADC1,DISABLE);                      //关闭ADC
    DMA_SetCurrDataCounter(DMA1_Channel1,adNum); 
    DMA_Cmd(DMA1_Channel1,ENABLE);                
    ADC_Cmd(ADC1,ENABLE);                          
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);         //触发转换
  • 7
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值