stm32之adc多路采集+dma传输

STM32 ADC简介
  12位ADC是一种逐次逼近型模拟数字转换器。它有多达18个通道,可测量16个外部和2个内部信号源。各通道的A/D转换可以单次、连续、扫描或间断模式执行。ADC的结果可以左对齐或右对齐方式存储在16位数据寄存器中。 模拟看门狗特性允许应用程序检测输入电压是否超出用户定义的高/低阀值。 ADC的输入时钟不得超过14MHz,它是由PCLK2经分频产生。对于小容量、中容量和大容量产品.
ADC主要特征:
  ● 12位分辨率 ● 转换结束、注入转换结束和发生模拟看门狗事件时产生中断
  ● 单次和连续转换模式
  ● 从通道0到通道n的自动扫描模式
  ● 自校准
  ● 带内嵌数据一致性的数据对齐
  ● 采样间隔可以按通道分别编程
  ● 规则转换和注入转换均有外部触发选项
  ● 间断模式
  ● 双重模式(带2个或以上ADC的器件)
  ● ADC转换时间: ─ STM32F103xx增强型产品:时钟为56MHz时为1μs(时钟为72MHz为1.17μs) ─ STM32F101xx基本型产品:时钟为28MHz时为1μs(时钟为36MHz为1.55μs) ─ STM32F102xxUSB型产品:时钟为48MHz时为1.2μs ─ STM32F105xx和STM32F107xx产品:时钟为56MHz时为1μs(时钟为72MHz为1.17μs)
  ● ADC供电要求:2.4V到3.6V
  ● ADC输入范围:VREF- ≤ VIN ≤ VREF+
  ● 规则通道转换期间有DMA请求产生。

DMA简介:
  直接存储器存取(DMA)用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。无须CPU干预,数据可以通过DMA快速地移动,这就节省了CPU的资源来做其他操作。 两个DMA控制器有12个通道(DMA1有7个通道,DMA2有5个通道),每个通道专门用来管理来自于一个或多个外设对存储器访问的请求。还有一个仲裁器来协调各个DMA请求的优先权。

以上为adc和dma的基本知识,具体细节如何配置?我们在分析代码的时候详解。

本例程代码:使用ADC1多通道循环连续采集,并通过dma传输数据。 实测有效。
本文用到的宏定义:

#define    ADC1_DR_Address ((u32)0x40012400+0x4c)

#define    N    31                             //采样次数
#define    M    2                              //采样通道个数
vu16       ADC_ConvertedValue[N][M];           //采集数据的存储地址

1:使能adc和dma的时钟

    //CONFIG DMA1 AND ADC1   CLOCK
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);							//DMA1挂载到AHP总线上
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);

查看手册上的时钟树可知:
在这里插入图片描述
2:配置DMA参数

    //配置DMA的参数
    DMA_DeInit(DMA1_Channel1);  								//复位
    DMA_InitStructure.DMA_PeripheralBaseAddr=ADC1_DR_Address;	//外设地址,这里就是adc1的地址
    DMA_InitStructure.DMA_MemoryBaseAddr=(u32)&ADC_ConvertedValue;//存储器地址
    DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralSRC;//传输方向,外设-->内存

    DMA_InitStructure.DMA_BufferSize=M*N;	//存储数据大小
    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; //外设与内存数据宽度应为一样
    DMA_InitStructure.DMA_Mode=DMA_Mode_Circular;//DMA传输模式为循环传输

    DMA_InitStructure.DMA_Priority=DMA_Priority_High;	//通道优先级为高
    DMA_InitStructure.DMA_M2M=DMA_M2M_Disable;	//关闭从存储器到存储器模式
    DMA_Init(DMA1_Channel1,&DMA_InitStructure);	

  第一个参数 DMA_PeripheralBaseAddr 用来设置 DMA 传输的外设基地址
  第二个参数DMA_MemoryBaseAddr 为内存基地址,也就是我们存放DMA传输数据的内存地址,为自定义的存储buf。
   第三个参数 DMA_DIR 设置数据传输方向,决定是从外设读取数据到内存还送从内存读取数据发送到外设,也就是外设是源地还是目的地。
  第四个参数 DMA_BufferSize 设置一次传输数据量的大小,可以理解成buf的大小
  第五个参数 DMA_PeripheralInc 设置传输数据的时候外设地址是不变还是递增。我们这里设置成不变,都是从adc中搬运。
  第六个参数 DMA_MemoryInc 设置传输数据时候内存地址是否递增。这个参数和DMA_PeripheralInc 意思接近,只不过针对的是内存。
  第七个参数 DMA_PeripheralDataSize 用来设置外设的数据长度是为字节传输(8bits),半字传输 (16bits) 还是字传输 (32bits) ,
  第八个参数 DMA_MemoryDataSize 是用来设置内存的数据长度,外设与内存数据宽度应为一样
  第九个参数 DMA_Mode 用来设置 DMA 模式是否循环采集,DMA传输模式为循环传输,因为adc配置的是连续循环模式,所以dma也得是循环模式。
  第十个参数是设置 DMA 通道的优先级,有低,中,高,超高三种模式,这个在前面讲解过,这里我们设置优先级别为中级,所以值为 DMA_Priority_Medium。如果要开启多个通道,那么这个值就非常有意义,由于我们这里只使用一个通道,优先级就不关心了,随便设置一个即可。
  第十一个参数 DMA_M2M 设置是否是存储器到存储器模式传输,这里我们选择DMA_M2M_Disable。

常见问题:
  为什么是 DMA1_Channel1 看下图既可知,dma1使用通道1用于搬运adc1的采集数据。
在这里插入图片描述
宏定义:#define ADC1_DR_Address ((u32)0x40012400+0x4c) 很多人不理解 ,为什么是这个地址?查看参考手册可知:adc1的基地址为0x40012400, 数据寄存器偏移0x4c。
在这里插入图片描述
在这里插入图片描述
3:配置adc参数

    ADC_DeInit(ADC1);
    ADC_InitStructure.ADC_Mode=ADC_Mode_Independent; 			//配置成独立工作模
    ADC_InitStructure.ADC_ScanConvMode=ENABLE;      			//多通道循环扫描
    ADC_InitStructure.ADC_ContinuousConvMode=ENABLE;  			//使能自动连续转换

    ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//转换由软件触发启动
    ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right;		//数据选择右对其
    ADC_InitStructure.ADC_NbrOfChannel=	M;						//转换通道数目
    ADC_Init(ADC1,&ADC_InitStructure);							//初始化adc
  

  第一个参数 ADC_Mode 故名是以是用来设置 ADC 的模式。ADC 的模式非常多,包括独立模式,注入同步模式等等,这里我们选择独立模式,所以参数为 ADC_Mode_Independent。
  第二个参数 ADC_ScanConvMode 用来设置是否开启扫描模式,因为是多通道采集,采集完一个通道后自动转换到下一个通道采集。
  第三个参数 ADC_ContinuousConvMode 用来设置是否开启连续转换模式,说的简单点就是是否开启循环模式,采完最后一个通道后自动又从第一个通道开始采集。
  第四个参数 ADC_ExternalTrigConv 是用来设置启动规则转换组转换的外部事件,这里我们选择软件触发,选择值为 ADC_ExternalTrigConv_None 即可。
  第五个参数 DataAlign 用来设置 ADC 数据对齐方式是左对齐还是右对齐,这里我们选择右对齐方式ADC_DataAlign_Right。 因为adc是12位的,所以有效数据最大只有12位,这时候就需要查看对齐方式,避免处理数据时出错。
  第六个参数 ADC_NbrOfChannel 用来设置规则序列的长度,就是你使能了几个采集通道就写几个。我这里M是宏定义2个.

    RCC_ADCCLKConfig(RCC_PCLK2_Div6);     	//配置adc的时钟72/8
    //配置adc通道转换顺序和采样周期,(55.5+12.5)/12M=5.6us
    ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5); //PA0
    ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_55Cycles5); //PA1
    
    ADC_DMACmd(ADC1, ENABLE);								//adc传输选用dma1工作模式,
    ADC_Cmd(ADC1,ENABLE);									//使能ADC1
  
    //复位校准寄存器
    ADC_ResetCalibration(ADC1);
    //等待校准寄存器复位完成
    while(ADC_GetResetCalibrationStatus(ADC1));			//ADC校准
    ADC_StartCalibration(ADC1);							// 等待校准完成
    while(ADC_GetCalibrationStatus(ADC1));
     DMA_Cmd(DMA1_Channel1,ENABLE);	 					//使能DMA																				// 由于没有采用外部触发,所以使用软件触发ADC转换
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);

  前面我们只是打开挂载adc1 的总线时钟,这里需要设置adc的输入时钟。分频因子要确保 ADC1 的时钟(ADCCLK)不要超过 14Mhz。 这个我们设置分频因子位 6,时钟为 72/6=12MHz,原则上不超过14Mhz即可。
  ADC_RegularChannelConfig()这个函数是用于设置采样顺序和采样周期的。对于关于adc的采样时钟,采样率,采样周期,很多人不是很清楚,迷糊。我会再新开一片文章来详细讲解和计算,这里不赘述。
  ADC_DMACmd(ADC1, ENABLE); 使能adc使用dma传输的功能,不能忘了,否则你前面配置正确,你不打开这个开关也是白忙活一场。
  adc的校准,这个是必须的,否则有可能会导致数据不准确。
   软件使能,因为我们在前面设置了软件触发

至此,配置结束,项目模块,功能实测有效。

  • 41
    点赞
  • 277
    收藏
    觉得还不错? 一键收藏
  • 22
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值