历史上的今天
返回首页

历史上的今天

今天是:2025年08月09日(星期六)

2019年08月09日 | STM32 ADC用DMA方式传输数据出错的解决方法

2019-08-09 来源:eefocus

在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);         //触发转换



推荐阅读

史海拾趣

安国国际(ALCOR)公司的发展小趣事

安国国际在创立初期便展现出强大的研发实力。1997年,公司成功推出了世界第一颗单一整合的USB键盘集线器控制IC,这一创新成果奠定了安国在IC专业设计领域的领导地位。随后,在1998年,安国将总部迁往台湾,以便为全球客户提供更及时的技术支持和服务,同时与晶圆代工厂紧密配合,确保产品质量和技术水平。

Hengstler GmbH公司的发展小趣事

随着公司规模的扩大和业绩的增长,安国国际的产品线逐渐从计算机外设产品拓展至消费型电子产品和手持便携装置。为满足市场需求,公司不断推出创新产品,如输出入装置暨多媒体图像处理装置应用控制芯片、网桥控制芯片、网络安全保护装置等。同时,为提升运营效率和灵活性,安国在2015年进行了组织调整和专业分工,将不同业务线分割为多家子公司,使得各业务领域能够更加专注和高效地发展。

Filtran Ltd公司的发展小趣事

近年来,随着5G、物联网等技术的快速发展,电子行业面临着前所未有的挑战和机遇。Filtran Ltd深知唯有不断创新才能保持竞争力。公司加大了在研发方面的投入,建立了多个专项研究小组,专注于新技术、新材料和新工艺的探索。通过持续创新,Filtran Ltd成功推出了多款符合市场需求的新产品,进一步巩固了其在电子行业中的地位。同时,公司还积极拥抱数字化转型,利用大数据、人工智能等先进技术提升运营效率和服务水平。

台湾奇力(Chip)公司的发展小趣事

在市场拓展方面,奇力公司采取了多元化的销售策略。除了与大型知名企业合作外,奇力公司还积极开拓国内外市场,参加各类展会和论坛,提升品牌知名度和影响力。同时,奇力公司还注重品牌建设,通过提升产品质量和服务水平,树立了良好的企业形象。

Curtis Electromusic Specialties Inc公司的发展小趣事

CUI公司在发展过程中,始终注重市场拓展和品牌建设。公司通过与国内外知名企业的合作,不断拓宽产品应用领域,提升品牌影响力。同时,公司还积极参加各类行业展会和交流活动,与同行和客户建立紧密的合作关系,为公司的长期发展奠定了坚实的基础。

芯源半导体(CW)公司的发展小趣事

随着公司产品的逐步成熟,芯源半导体(CW)公司开始寻求与行业内其他企业的合作。经过深入的市场调研和谈判,公司成功与多家知名电子企业建立了战略合作伙伴关系。这些合作伙伴为芯源半导体(CW)公司提供了更多的市场机会和技术支持,使公司得以迅速扩大市场份额,提升品牌影响力。

问答坊 | AI 解惑

用电阻做功率模拟

请教各位,我现在测一块散热板的散热效率,打算用铜壳线绕电阻做一个30W的发热源,电阻型号有以下几款 220Ω/5W;500Ω/8W;输入电压在60V左右,请问应该怎样排列电阻效果才好?谢谢!…

查看全部问答>

闪电击中世界最高建筑哈利法塔

上面这张令人震惊的照片展示了世界最高建筑哈利法塔遭闪电击中时的场面。 照片的拍摄者是一位23岁名叫穆罕默德·哈姆丹的学生,来自巴基斯坦,目前在阿联酋攻读建筑工程学。当时,迪拜正遭受暴风雨的袭击。雷电中,高达828米的哈利法塔在紫色的 ...…

查看全部问答>

今天参加mcu day赠送的一款开发板

参加TI mcu Day时,送的开发板,据说可以当做jtag仿真器使用,双重功能!!!…

查看全部问答>

U盘多盘符的问题

我在一个嵌入式系统中,主机在GET MAX LUN我已经返回01,但是主机并未显示2个盘符.仅仅出现了一个盘符 还需要做哪方面的工作…

查看全部问答>

关于桥式整流

这是在空闲之际模拟的几张桥式整流和接电容的图片,希望能对大家有点用处。    大家注意看波形随着电容的变化而变化。…

查看全部问答>

hmc5883的程序有人做过么?我的程序哪里出问题了?本人菜鸟,见笑了。

调了好几个小时了,就是不知道问题在哪里,请高手们指点。 测量先不说,就是怎么读寄存器都没弄清。 看了中文的pdf了,但是还是没搞懂,先看看我的程序吧。 程序部分(已近将无关部分删除): uchar code table[]=\"0123456789\"; //////////// ...…

查看全部问答>

有谁用了ADS8332,求程序!

最近用到团购买回来的ADS8332,但是调试了两天没成功,求助各位!谢谢!…

查看全部问答>

debug正常,51运算错误

已经用其他程序试验过了,不是xdata的问题,xdata里的数据能正常使用。我在用51做一个32点的fft。 部分代码如下: #include #include #define  uchar  unsigned  char #define  uint unsigned int ...…

查看全部问答>

谁用单片机驱动过PS2的数字小键盘?

我在网上买了一块PS2的数字小键盘,就是传统台式机键盘最右边的数字键部分。 学习了一下PS2及扫描编码相关内容,看懂了程序,但是,由于小键盘只有部分按键,有的键还是不能读取。 0—9数字键是可以输入的,小键盘的enter也能读取,但+、-、*、/ ...…

查看全部问答>