关于STM32 ADC DMA 使用心得(2)

发布者:vettykatty最新更新时间:2018-05-20 来源: eefocus关键字:STM32  ADC  DMA  使用心得 手机看文章 扫描二维码
随时随地手机看文章

(二)ADC循环采集六路电压,使用DMA.
     这次实验真的很郁闷,对DMA的不了解让我深陷误区,明白之后,让我更加佩服DMA的强大。
     误区就是:从实验的目标我们知道这次是用DMA把ADC转换的数据传送到内存中的一个数组里存起来,因为是采集6个通道,这里使能了ADC的扫描模式。一旦启动ADC,就会按顺序转换SQRX里选中的通道,问题就是我一开始以为ADC与DMA并不会协调工做,也就是ADC自己转自己的,DMA自己传自己的,这样的话内存里的数组就不是我想要的了,后来着实的研究了很长时间,在群里的一位兄弟的提醒下,我才知道,可能我想的复杂了,也许就可以在ADC转一次,然后DMA把数据传一次,Ok,经过实验得知,这个想法是正确的。
    好了,说了这么多废话,开始进入正题。
    这里使用了ADC1的六个规则通道分别是:CH0、CH1、CH2、CH3、CH14、CH15,
                    分别对应的引脚为PA0、PA1、PA2、PA3、PC4、PC5。
    关于ADC的配置:
    启动了ADC1的扫描模式,还有连续转换模式,独立工作模式(只用1个ADC),因为用的了DMA,所以也要使能DMA位,使用外部触发(SWSTART),数据为右对齐。还有SQRX等等就不说了,这里不需要ADC中断的。中断在DMA里。
    关于DMA的配置:
    因为ADC请求规定在DMA1的第一个通道,所以这里使用DMA_CH1,外设地址为ADC唯一的数据寄存器(u32)&ADC1->DR,存储器地址为(u32)SendBuff数组,这个数组可以存放6个元素。这里还有使能传输完中断(TCIF),选择从外设读取,循环模式,外设地址非增量模式,存储器地址增量模式,外设数据宽度16位,存储器地址16位,非存储器到存储器模式。
    关于DMA中断函数:
   当DMA传输完6次数据时,TCIF位自动置位,程序进入中断服务函数,首先先关闭ADC的连续转换,我们把数组的处理都放在了这里,处理完发送到串口,通过电脑的超级终端可以看到不停变化的6个引脚电压的数据。别忘了一定要清楚中断标志位并置位ADC的连续转换,然后再次启动转换。
    主程序中只要初始化系统函数,还有串口,然后配置好DMA,启动规则转换通道,并启动DMA,然后等在死循环即可。
    下面附上部分代码
------------------------------------------------------------------------------------------- 
 void  Adc_Init(void)
{    
 //先初始化IO口
  RCC->APB2ENR|=1<<2;     //使能PORTA口时钟 
  RCC->APB2ENR|=1<<4;     //使能PORTC口时钟 
 GPIOA->CRL&=0XFFFF0000; //PA0 1 2 3 anolog输入
 GPIOC->CRL&=0XFF00FFFF; //PC4,5 anolog输入

 //通道10/11设置    
 RCC->APB2ENR|=1<<9;     //ADC1时钟使能   
 RCC->APB2RSTR|=1<<9;    //ADC1复位
 RCC->APB2RSTR&=~(1<<9); //复位结束     
 RCC->CFGR&=~(3<<14);    //分频因子清零 
 //SYSCLK/DIV2=12M ADC时钟设置为12M,ADC最大时钟不能超过14M!
 //否则将导致ADC准确度下降! 
 RCC->CFGR|=2<<14;        
 ADC1->CR1&=0XF0FFFF;    //工作模式清零
 ADC1->CR1|=0<<16;       //独立工作模式  
 ADC1->CR1|=1<<8;     //扫描模式
 ADC1->CR2|=1<<1;        //启用连续转换            
 ADC1->CR2|=1<<8;        //启用DMA      
// ADC1->CR2&=~(1<<1);     //单次转换模式
 ADC1->CR2&=~(7<<17);    
 ADC1->CR2|=7<<17;     //软件控制转换  
 ADC1->CR2|=1<<20;       //使用用外部触发(SWSTART)!!! 必须使用一个事件来触发
 ADC1->CR2&=~(1<<11);    //右对齐

 ADC1->SQR1&=~(0XF<<20);
 ADC1->SQR1|=5<<20;      //6个转换在规则序列
 ADC1->SQR3 = 0X00000000;
 ADC1->SQR3|= 0X1EE18820;       
 //设置通道0~3,14,15的采样时间
 ADC1->SMPR1&=0XFFFC0FFF;//通道14,15采样时间清空
 ADC1->SMPR2&=0XFFFFF000;//通道0,1,2,3采样时间清空  

 ADC1->SMPR1|=7<<15;     //通道15  239.5周期,提高采样时间可以提高精确度  
 ADC1->SMPR1|=7<<12;     //通道14  239.5周期,提高采样时间可以提高精确度   
 ADC1->SMPR2|=7<<9;      //通道3  239.5周期,提高采样时间可以提高精确度  
 ADC1->SMPR2|=7<<6;      //通道2  239.5周期,提高采样时间可以提高精确度  
 ADC1->SMPR2|=7<<3;      //通道1  239.5周期,提高采样时间可以提高精确度  
 ADC1->SMPR2|=7<<0;      //通道0  239.5周期,提高采样时间可以提高精确度 

 ADC1->CR2|=1<<0;     //开启AD转换器  
 ADC1->CR2|=1<<3;        //使能复位校准  
 while(ADC1->CR2&1<<3);  //等待校准结束     
    //该位由软件设置并由硬件清除。在校准寄存器被初始化后该位将被清除。    
 ADC1->CR2|=1<<2;        //开启AD校准    
 while(ADC1->CR2&1<<2);  //等待校准结束
 //该位由软件设置以开始校准,并在校准结束时由硬件清除  
}     

 void MYDMA_Config(DMA_Channel_TypeDef*DMA_CHx,u32 cpar,u32 cmar,u16 cndtr)
{
 u32 DR_Base;      //做缓冲用,不知道为什么.非要不可
 RCC->AHBENR|=1<<0;   //开启DMA1时钟
 DR_Base=cpar;
 DMA_CHx->CPAR=DR_Base;    //DMA1 外设地址 
 DMA_CHx->CMAR=(u32)cmar;  //DMA1,存储器地址
 DMA1_MEM_LEN=cndtr;       //保存DMA传输数据量
 DMA_CHx->CNDTR=cndtr;     //DMA1,传输数据量
 DMA_CHx->CCR=0X00000000; //复位
 DMA_CHx->CCR|=1<<1;    //允许传输完中断
 DMA_CHx->CCR|=0<<4;    //从外设读
 DMA_CHx->CCR|=1<<5;    //循环模式
 DMA_CHx->CCR|=0<<6;    //外设地址非增量模式
 DMA_CHx->CCR|=1<<7;    //存储器增量模式
 DMA_CHx->CCR|=1<<8;    //外设数据宽度为16位
 DMA_CHx->CCR|=1<<10;   //存储器数据宽度16位
 DMA_CHx->CCR|=1<<12;   //中等优先级
 DMA_CHx->CCR|=0<<14;   //非存储器到存储器模式
 MY_NVIC_Init(1,3,DMA1_Channel1_IRQChannel ,2);     

//开启一次DMA传输
void MYDMA_Enable(DMA_Channel_TypeDef*DMA_CHx)
{
 DMA_CHx->CCR&=~(1<<0);       //关闭DMA传输 
 DMA_CHx->CNDTR=DMA1_MEM_LEN; //DMA1,传输数据量 
 DMA_CHx->CCR|=1<<0;          //开启DMA传输
}
u16 ADC1_DR, adcx;

void DMAChannel1_IRQHandler(void)
{       
 u16 i;
 u32 sum[6]={0},val=0;  
 LED0 =!LED0;
 ADC1->CR2&=~(1<<1);        //关闭连续转换            
 for( i = 0; i<768 ;i+= 6)
 {
  sum[0] += SendBuff[i];
  sum[1] += SendBuff[i+1];
  sum[2] += SendBuff[i+2];
  sum[3] += SendBuff[i+3];
  sum[4] += SendBuff[i+4];
  sum[5] += SendBuff[i+5];
 }
 for(i = 0;i <6 ;i++)
 {
  val = sum[i]/DMA_COUNT;
  ADC1_DR = sum[i]/DMA_COUNT;
  TEMP=(float)ADC1_DR*(3.3/4096); 
  adcx=TEMP;
  LCD_ShowNum(149,70+i*20,adcx,1,16);//显示电压值
  TEMP-=adcx;
  TEMP*=1000;
  LCD_ShowNum(165,70+i*20,TEMP,3,16);
 }
 delay_ms(200); 
   DMA1->IFCR |= 1<<1;        //清零通道完成中断标志位
 ADC1->CR2|=1<<1;           //启用连续转换            
 ADC1->CR2|=1<<22;          //启动规则转换通道          

--------------------------------------------------------------------------------------


关键字:STM32  ADC  DMA  使用心得 引用地址:关于STM32 ADC DMA 使用心得(2)

上一篇:ARM处理器启动流程———S3C2440、S3C6410、S5PV210
下一篇:STM32 在 KEIL 下使用 SWV 输出调试信息

推荐阅读最新更新时间:2024-03-16 16:03

STM32开发笔记84: SX1268驱动程序设计(SPI总线)
单片机型号:STM32L053R8T6 本系列开发日志,将详述SX1268驱动程序的整个设计过程,本篇介绍SPI总线驱动程序。 一、数据手册 1、关键点: 全双工SPI CPOL=0,CPHA=0 从器件 写操作:地址字节+数据字节 读操作:直接发送地址字节,就可返回一个数据字节 NSS在整个帧传输过程保持低电平 MISO在NSS为高时为高阻态 SCK最大时钟16M 2、几个时序图,t10是指从睡眠状态唤醒,NSS下降沿到SCK上升沿的时间,数据手册表明最短时间为100us。 3、芯片离开sleep模式的方法 可以通过NSS的下降沿使得芯片从sleep模式唤醒。下降沿发生后,芯片内部的稳压器都将打开。芯片
[单片机]
<font color='red'>STM32</font>开发笔记84: SX1268驱动程序设计(SPI总线)
STM32基于固件库学习笔记(13)ADC读取电压值
ADC简介 STM32f103 系列有 3 个 ADC(STM32F101/102 系列只有 1 个 ADC),精度为 12 位,每个 ADC 最多有 16 个外部通道。其中ADC1和 ADC2 都有 16个外部通道,ADC3根据 CPU 引脚的不同通道数也不同,一般都有8 个外部通道。 ADC 可以独立使用,也可以使用双重模式(提高采样率)。STM32 的 ADC 是 12 位逐次逼近型的模拟数字转换器。它有 18 个通道,可测量 16 个外部和 2 个内部信号源。各通道的 A/D 转换可以单次、连续、扫描或间断模式执行。ADC 的结果可以左对齐或右对齐方式存储在 16 位数据寄存器中。 模拟看门狗特性允许应用程序检测输入电压是
[单片机]
驱动单极性精密ADC的单/双通道放大器配置(第1部分)
简介 传感器输出与ADC接口的最常见问题之一是:如何让X V到Y V的信号范围适应ADC的输入范围。 本文介绍多种不同的配置,其利用单通道或双通道运算放大器来缩放信号并进行电平转换,以使单极性ADC的范围最大。 通常,无论单端还是差分,单极性ADC的输入范围都是从地到VREF电压。 本文还会介绍常见全差分放大器(FDA)配置。 对于给定功率水平,FDA可实现最佳性能,但合适的FDA并不是总能找到。不过,单通道和双通道运算放大器的选择范围更广,可用来构建定制前端。 本文旨在介绍不同的配置,讨论各种配置的用法和利弊,但并不涉及选择适当的放大器及周边无源元件等细节,因为后者须视具体情况而定。 单端/伪差分
[模拟电子]
驱动单极性精密<font color='red'>ADC</font>的单/双通道放大器配置(第1部分)
STM32入门之滴答定时器
Cortex-M3处理器内部包含了一个简单的定时器。因为所有的CM3芯片都带有这个定时器,软件在不同 CM3器件间的移植工作就得以化简。该定时器的时钟源可以是内部时钟(FCLK,CM3上的自由运行时钟),或者是外部时钟( CM3处理器上的STCLK信号)。不过,STCLK的具体来源则由芯片设计者决定,因此不同产品之间的时钟频率可能会大不相同。因此,需要检视芯片的器件手册来决定选择什么作为时钟源。 SysTick定时器被捆绑在NVIC中,用于产生systick异常。在以前,操作系统还有所有使用了时基的系统,都必须一个硬件定时器来产生需要的“滴答”中断,作为整个系统的时基。滴答中断对操作系统尤其重要。例如,操作系统可以为多个任务许以不
[单片机]
PIC16F15323单片机 (ADC+温度传感器)--汇编+C语言
1 基本原理 1.1 AD原理 见前面的文章 1.2 温度储传感器原理 1.3 FVR原理 2 实现代码 /*---------------------------------函数功能:------------------------------------- 采集MCU的温度,并且用RC0口(LED)来判断是否采集完成,如果温度采集AD完成,则 * AD对应的标志位ADIF=1,如果使能有效,则会产生一个中断,此时LED灯亮。 编程思路:参考手册的P131 To do an A/D Conversion, follow these steps --------------------------
[单片机]
PIC16F15323单片机 (<font color='red'>ADC</font>+温度传感器)--汇编+C语言
STM32学习记录11:启动配置
当前的嵌入式应用程序开发过程里,C语言已成为了绝大部分场合的最佳选择。如此一来main函数似乎成为了理所当然的起点 因为C程序往往从main函数开始执行。但一个经常会被忽略的问题是:微控制器(单片机)上电后,是如何寻找到并执行main函数的呢?很显然微控制器无法从硬件上定位main函数的入口地址,因为使用C语言作为开发语言后,变量/函数的地址便由编译器在编译时自行分配,这样一来main函数的入口地址在微控制器的内部存储空间中不再是绝对不变的。相信读者都可以回答这个问题,答案也许大同小异,但肯定都有个关键词,叫 启动文件 ,用英文单词来描述是 Bootloader 。 无论性能高下,结构简繁,价格贵贱,每一种微控制器(处理器)
[单片机]
关于STM32的计数与延时
Ⅰ关于STM32的计数和延时 在STM32中,具有计数(或计时)功能的模块基本都能实现延时功能。如:系统滴答SysTick、定时器TIM、实时时钟RTC、看门狗WDG。 精确延时一般使用定时器TIM即可实现。当然,是否精确,取决于你的主频(也就是晶振)是否准确,如果主频精确,那么实现的延时也一定精确。 一般来说,常温下实现us微秒级的延时,误差还是挺小的(应该说挺精确)。拿F407,主频168M来说,可以实现几十ns纳秒的延时,如果选用高精度的晶振,误差还是很小的。 总结:想要TIM定时器实现高精确的延时,就需要高精度的晶振。主频精确,那么延时就精确。 ⅡSTM32的TIM定时器 STM32的定时器有3类: 高级定
[单片机]
关于<font color='red'>STM32</font>的计数与延时
理解热插拔技术:热插拔保护电路设计过程实例
   引言   服务器、网络交换机、冗余存储磁盘阵列(RAID),以及其它形式的通信基础设施等高可用性系统,需要在整个使用生命周期内具有接近零的停机率。如果这种系统的一个部件发生了故障或是需要升级,它必须在不中断系统其余部分的情况下进行替换,在系统维持运转的情况下,发生故障的电路板或模块将被移除,同时替换部件被插入。这个过程被称为热插拔(hot swapping)(当模块与系统软件有相互作用时,也被称为hot plugging1)。为了实现安全的热插拔,通常使用带交错引脚的连接器来保证地与电源的建立先于其它连接,另外,为了能够容易的从带电背板上安全的移除和插入模块,每块印制板(PCB)或热插拔模块都带有热插拔控制器2。在工作状
[模拟电子]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

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

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

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