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

发布者:心灵舞动最新更新时间:2019-08-09 来源: eefocus关键字: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);         //触发转换



关键字:STM32  ADC  DMA方式  传输数据 引用地址:STM32 ADC用DMA方式传输数据出错的解决方法

上一篇:STM32学习之路:I2C的基本读写
下一篇:【STM32CUBEMX】 I2C Slave 实现

推荐阅读最新更新时间:2024-11-14 10:19

STM32接口中FSMC/FMC难点问题理解
一,FSMC简 FSMC,即灵活的静态存储控制器,能够与同步或异步存储器和 16 位 PC 存储器卡连接, STM32 的 FSMC 接口支持包括 SRAM、NAND FLASH、NOR FLASH 和 PSRAM 等存储器。 二,FSMC存储块 STM32F767的FMC将外部存储器划分为6个固定大小的256M的存储区域,如下图 如图: FSMC分为4块,每块256M字节又被划分为4*64,即四个片选 NOR / PSRAM使用块1,共256M NAND闪存使用块2,3,共512M PC卡使用块4,共256M 三,存储块1(Bank1)寄存器 STM32 的 FSMC 存储块 1(Bank1)被
[单片机]
<font color='red'>STM32</font>接口中FSMC/FMC难点问题理解
STM32的串口1发送、接收DMA模式函数配置
/********************************************************************************** **函数名称:void USART1_Config(void) **函数功能:USART1串口引脚初始化 **输入参数:无 **返回参数:无 **函数调用:内部调用 **********************************************************************************/ static void USART1_Config(void) { GPIO_InitTypeDef GPIO_InitStructu
[单片机]
keil+stm32+JTAG利用swd方式进行printf输出
使用ITM机制实现调试stm32单片机,实现printf与scanf。 1. ITM简介 ITM机制是一种调试机制,是新一代调试方式,在这之前,有一种比较出名的调试方式,称为半主机(semihosting)方式。 在pc上编写过C语言的人都知道,printf可以向控制台输出,scanf可以从控制台获取输入,这里的printf/scanf都是标准库函数,利用操作系统的这些函数,我们可以很方便的调试程序。在嵌入式设备上(如stm32单片机平台上)开发工具(如MDK/IAR)也都提供了标准库函,自然也提供了printf/scanf函数,那么这些函数是否可以使用呢? 问题来了,printf向哪里输出呢?并且大部分情况下,也没有键盘,又如何
[单片机]
keil+stm32+JTAG利用swd<font color='red'>方式</font>进行printf输出
stm32_SPI基本函数
void SPI_RCC_config(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE); } void SPI_GPIO_config(void) { GPIO_InitTypeDef GPIO_InitStructure;; GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5;//SCK GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; GPIO_InitStructu
[单片机]
意法半导体(ST)推出最新STM32 ARM Cortex-M0微控制器STM32F091
意法半导体(STMicroelectronics,简称ST)最新的STM32F091 ARM Cortex-M0微控制器,克服了目前定位在经济型应用的同类产品的限制,可提供大容量片上存储器和多达8通用同步/异步串行接收/发送器 (USART, Universal Synchronous/Asynchronous Receiver/Transmitter),为车载音响或三相电表等应用节省多路复用通信端口。 STM32F091微控制器单片集成最高256KB的闪存和32KB的SRAM存储器,足以实现Java堆栈,能够运行通常只有大存储容量或昂贵产品才能运行的复杂应用软件,带来令人满意的用户体验。全系列产品(包括经济型48引脚微控制器
[单片机]
从流式细胞仪看高速高精度信号链如何改变医学技术
流式细胞仪被临床医生和诊断医生广泛用于分析细胞特征。通过一次测量一个细胞,以光学方式评估蛋白质水平、血液健康、粒度和细胞大小以及其他属性。尽管它们是高度敏感的系统,但流式细胞仪的设计人员一直承受着加快分析时间的压力,需要流式细胞仪及其相关电子设备的新方法。 细胞仪对单个细胞进行激光照射,以产生散射和荧光信号。要快速准确地捕获产生的光并将其转换为数字信号,需要雪崩光电二极管 (APD) 和复杂的电子设备。此过程的电路可能需要很长时间来设计和实施,特别是考虑到流式细胞数据采集系统需要高速、低噪声的设备来确保系统准确性。 为了经济高效地支持更快的流式细胞术分析,设计人员可以使用包含内部放大器驱动器和模数转换器 (ADC) 的数据
[医疗电子]
从流式细胞仪看高速高精度信号链如何改变医学技术
STM32通过命令行编译和下载keil和IAR工程的方法
可能很多人都不习惯使用Keil、IAR自带的编辑器,可能代码补全、错误提示、高亮等编辑功能相对来说支持的不是很好。 虽然Keil MDK 从 V5.25版本开始对编辑功能改善了很多,但是很多人还是青睐于第三方的编辑器。 使用第三方的编辑器,如果需要编译和下载,就需要借助通过额外的方式实现,比如本文即将描述的通过命令行编译和下载的方式,可以让我们在使用第三方编辑器编辑的时候,进行代码编译和下载。 下面我们来描述以下内容: 常用代码编辑器 Keil 命令行编译下载 IAR 命令行编译下载 编译下载使用方法 1、常用的代码编辑器 下面介绍几款常用的代码编辑器: 1.VS Code VS Code 是绝大部分软件工程师都在使用
[单片机]
<font color='red'>STM32</font>通过命令行编译和下载keil和IAR工程的方法
ADC0832检测模拟电压值
============================================================================================= `````````````````````````````` 程序思想````````````````````````````` AD0832与AD08004有所不同,AD0804的数据是并行输出,而AD0832是串行输出,其思想略有复杂。 根据ADC0832的时序,首先选通芯片,在第一个脉冲下沿前让addi为高,在第二个下沿前给addi1位数据,在第三个下沿前给addi1位数据, 两位数据为10时选通CH0,为11时选通CH1; 在第三个下沿
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
  • 学习ARM开发(16)
    ARM有很多东西要学习,那么中断,就肯定是需要学习的东西。自从CPU引入中断以来,才真正地进入多任务系统工作,并且大大提高了工作效率。采 ...
  • 学习ARM开发(17)
    因为嵌入式系统里全部要使用中断的,那么我的S3C44B0怎么样中断流程呢?那我就需要了解整个流程了。要深入了解,最好的方法,就是去写程序 ...
  • 学习ARM开发(18)
    上一次已经了解ARM的中断处理过程,并且可以设置中断函数,那么它这样就可以工作了吗?答案是否定的。因为S3C44B0还有好几个寄存器是控制中 ...
  • 嵌入式系统调试仿真工具
    嵌入式硬件系统设计出来后就要进行调试,不管是硬件调试还是软件调试或者程序固化,都需要用到调试仿真工具。 随着处理器新品种、新 ...
  • 最近困扰在心中的一个小疑问终于解惑了~~
    最近在驱动方面一直在概念上不能很好的理解 有时候结合别人写的一点usb的例子能有点感觉,但是因为arm体系里面没有像单片机那样直接讲解引脚 ...
  • 学习ARM开发(1)
  • 学习ARM开发(2)
  • 学习ARM开发(4)
  • 学习ARM开发(6)
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved