嵌入式系统开发经常会遇到采集模拟量的功能需求,这时就会用到ADC,STM32系列MCU提供了强大的ADC功能,其提供的多通道采集和DMA方式极大的方便了ADC相关的开发流程,本文主要记录一下,如何使用ADC实现基于DMA的多通道模拟量采集功能。
关于ADC的配置,同样可以通过STM32CubeMX来实现,下面是STM32型号和STM32CubeMX的版本信息:
- MCU:STM32F103C8T6
- STM32CubeMX:5.5.0
下面是具体的配置步骤
系统基本配置
时钟配置
首先,配置系统时钟,本文基于STM32F103C8T6的一款开发板进行开发,其提供的外部晶振频率为8MHz,所以,对于时钟我们的配置为:
下面进行ClockConfiguration相关的配置,第一步选择时钟源为HSE:8MHZ,第二步选择APB2的时钟源为32MHz,最后一步选择ADC1的时钟频率为8MHz,最终的配置结果如下:
打开ST-Link调试
对于MCU的程序下载和调试,我们选用的是ST-Link,所以选择系统的调试模式为Serial Wire,配置如下:
注:对于通过ST-Link或JTAG下载、调试程序时,需要配置该选项,否则无法下载程序以及在线调试MCU。
配置ADC
功能需求是:
- 使用ADC1实现模拟量的采集;
- 两路模拟量采集;
- 基于DMA实现外设到内存的数据传输;
基本配置
首先是,基本配置选择将要使用的ADC,这里我们使用的是ADC1,其次是选择用于模拟量采集的ADC通道,这里我们选择是ADC1的通道6和通道7,具体配置如下:
下面是关于ADC的参数配置,主要分为两部分:第一部分为ADC_Setting,第二部分为ADC_Regular_ConversionMode,下面分别解决一下:
- ADC_Setting:
- Data Alignment:Right alignment。表示ADC的regular data register寄存器16bit数据的对齐方式为向右对齐。
- Scan Conversion Mode:Enable。当使用DMA采集多路模拟量时,使能该选项可以自动扫描ADC的模拟量数据通道,采集模拟量数据。
- Continuous Conversion Mode:Enable。使能该项时,可以对各个模拟量通道进行循环、连续的数据采集。
- ADC_Regular_ConversionMode:
- Enable Regular Conversions: Enable。打开Regular数据转换模式。对于Regular Conversion和Injected Conversion两种模式的区别可以简单的理解为:Regular Conversion为轮询采集的工作模式,Injected Conversion为中断采集工作模式,并且Injected Conversion比Regular Conversion的优先级高。
- Nunber of Conversion:2。表示采集的通道数量。
- Rank 1:表示第一个采集通道,即通道Channel 7,Sample Time为1.5 Cycles,1个Cycle为ADC驱动时钟频率的倒数,本文为 1 Cycle = 1/8M s。
- Rank 2:表示第二个采集通道,即通道Channel 6,Sample Time为1.5 Cycles,同上。
DMA配置
进入ADC的DMA配置选项,关于ADC的DMA配置方式如下:
- 添加DMA Request:添加ADC1为DMA Reuest,Channel为DMA1 Channel 1,DMA的数据传输方向为:peripheral To Memory(外设到内存),Priori为Low。
- 配置DMA Requeset Settings:
- Mode:Circular。表示DMA循环、连续采集各个ADC通道的模拟量。
- Data Width为Word。表示DMA传输的数据的基本大小为Word,即四字节。
好了,配置基本完成了,下面是MCU的PinView,大家可以参考一下。点击Generate Code生成工程代码。
功能实现
基于STM32CubeMX生成的代码,完善ADC采集代码,主要就是调用HAL_ADC_Start_DMA启动ADC采集,实现HAL_ADC_ConvCpltCallback接口,当DMA采集完一轮数据之后,会调用该接口通知APP,APP可以在这里完成模拟量的转换功能。
/*其中,pData表示DMA的目标内存地址,Length表示外设向内存传输的数据项的个数。*/ HAL_StatusTypeDef HAL_ADC_Start_DMA(ADC_HandleTypeDef* hadc, uint32_t* pData, uint32_t Length); /*处理DMA数据*/ uint32_t val[2];//保存外设通过DMA传输的过来的数据 float v[2];//保存当前采集到的模拟量 void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc) { for(int8_t i = 0; i < 2; i++) { v[i] = (val[i] / 4095.0) * 3.274; //参考电压为:3.274V }
好了,至此基本完成了基于DMA的ADC采集方式的功能需求。
测试
编译程序,通过ST-Link下载到MCU,搭建好电路,在线监测实时采集到的模拟量数据,模拟量数据源为两路电压模拟量。