ADC的介绍
什么是ADC?
全称:Analog-to-Digital Converter,指模拟/数字转换器。
ADC可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量,建立模拟电路到数字电路的桥梁。
- 12 位 ADC 是一种 逐次逼近型模拟数字转换器(0~4095)。它有多达 18 个通道,可测量 16 个外部和 2 个内部信号源。
- 各通道的 A/D 转换可以单次、连续、扫描或间断模式执行。
- ADC 的结果 可以 左对齐 或 右对齐 方式存储在 16 位数据寄存器中。
-
模拟看门狗特性允许应用程序检测输入电压是否超出用户定义的高 / 低阀值。
-
ADC 的输入时钟不得超过 14MHz,它是由 PCLK2 经分频产生。
- STM32F103C8T6 ADC资源:ADC1、ADC2,10 个外部输入通道(这个芯片中引出的引脚个数,最大有18个)。
ADC的工作原理(逐次逼近型)
说明:
- 当输入模拟量时,控制与定时器会给逐次逼近寄存器发出指令,逐次逼近寄存器会产生数字信号,经过D/A转化器生成模拟信号,与输入的模拟量经过比较器进行比较。
- 当产生的模拟量相比于输入的模拟量过大过小时,会反馈给逐次逼近寄存器,重新修正,当产生的模拟量与输入的模拟量近似相同时,逐次逼近寄存器中的数字量会转运到输出缓冲器中D0~D7的位置。
ADC的性能指标:(量程、分辨率、转化时间)
- 量程:能测量的 电压范围 。
- 分辨率:ADC能辨别的最小模拟量,通常以输出二进制数的位数表示,比如:8、10、12、16位等;位数越多,分辨率越高,一般来说分辨率越高,转化时间越长。
- 转化时间(采样时间):从转换开始到获得稳定的数字量输出所需要的时间称为转换时间。转换时间越长,转换结果相对越准确,但是转换速度就越慢。
ADC特性:(供电电压、ADC输入范围、转化速度)
- 12 位精度下转换速度可高达1MHZ。
- 供电电压:VSSA :0V,VDDA :2.4V~3.6V。
- ADC输入范围:VREF- ≤ VIN ≤ VREF+,0~3.3V。
- ADC 的结果可以 左对齐 或 右对齐 方式存储在 16 位数据寄存器(低16位是ADC1的数据位,高16位是ADC2的数据位)中。
ADC的框图
- 简图:
- 参考手册上的框图:
ADC的输入通道
(16个外部通道和2个内部通道(温度传感器和内部参考电压))
其中16个通道在转化时又分成规则组通道(最多有16路)和注入组通道(最多有4路)
外部的16个通道在转换时又分为规则通道和注入通道,其中规则通道最多有16路,注入通道最多有4路。
转化部分
规则组/注入组
解释:规则组和注入组-----(利用厂里员工检测零部件进行对比)
- 规则组好比是待检测的零部件,最多有16个,工人进行依次按顺序进行检测;
- 注入组好比是老板临时加入的紧急待测件,最多有4个,工人放下手中的规则组零部件,开始按顺序依次检测注入组的零部件,检测完成后,开始检测规则组的零部件。
转化顺序
- 规则组的转化顺序
原因:每个 ADC 规则通道只有一个数据寄存器,16个通道一起共用这个寄存器,所以需要指定规则转换通道的转换顺序。
控制转化顺序的3个寄存器:SQR1、SQR2、SQR3(都是32位寄存器)
SQR 寄存器控制着转换通道的数目和转换顺序,只要在对应的寄存器位SQx 中写入相应的通道,这个通道就是第 x 个转换。
- 注入组的转化顺序
和规则通道转换顺序的控制一样,注入通道的转换也是通过注入寄存器来控制,只不过只有1个JSQR寄存器来控制,控制关系如下:
注入序列的转换顺序是从JSQx[ 4 : 0 ] (x= 4- JL[1:0] ) 开始。例:只有当 JL=4 的时候,注入通道的转换顺序才会按照 JSQ1 、 JSQ2 、 JSQ3 、 JSQ4 的顺序执行。
触发转化的方式
方式1:软件触发
通过向 控制寄存器 ADC-CR2 的 ADON 位写 1 来开启 ADC ,再将 SWSTART 位置 1 ,启动规则通道转换
方式2:外部事件(如定时器)触发
由寄存器 EXTSEL 中的 3位进行控制,所以,总共有2^3=8中触发方式。
转化时间
转换时间 = 采样时间 + 12.5 个周期补充:周期为ADC经PCLK2分频后得到的频率的倒数
周期: ADC 是挂载在 APB2 总线(PCLK2)上的,经过分频器得到 ADC 时钟(ADCCLK),最高 14 MHz。但是,在STM32F103C8T6芯片上的只能进行2/4/6/8分频,因此,最高 12 MHz。
采样时间(可以自己手动设置):共8种
举例:
- 在STM32F103C8T6开发板中,最少的转化时间: 采样周期设置为 1.5 个周期,算出最短的转换时间为 1.17us。
- 若其他芯片中,周期为14MHz的倒数,最低采样时间是1us。
单次转换和连续转换
- 单次转换:只转换一次。
- 连续转换:转换一次之后,立马进行下一次转换。
扫描模式
- 关闭扫描模式:只转换 ADC_SQRx 或 ADC_JSQR 选中的第一个通道。
- 打开扫描模式:扫描所有被 ADC_SQRx 或 ADC_JSQR 选中的所有通道。
输出部分 (中断及事件)
- DMA请求(只适用于规则组:只有一个数据寄存器,防止数据进行覆盖)
规则组每个通道转换结束后,除了可以产生中断外,还可以产生DMA请求,我们利用DMA及时把转换好的数据传输到指定的内存里,防止数据被覆盖。
校准
- ADC有一个内置自校准模式。校准可大幅减小因内部电容器组的变化而造成的准精度误差。在校准期间,在每个电容器上都会计算出一个误差修正码(数字值),这个码用于消除在随后的转换中每个电容器上产生的误差。
- 通过设置ADC_CR2寄存器的CAL位启动校准。一旦校准结束, CAL位被硬件复位,可以开始正常转换。建议在上电时执行一次ADC校准。校准阶段结束后,校准码储存在ADC_DR中。
- 建议在每次上电后执行一次校准。
ADC的寄存器
ADC状态寄存器(ADC_SR)
ADC控制寄存器 1(ADC_CR1)
ADC控制寄存器 2(ADC_CR2)
ADC采样时间寄存器 1(ADC_SMPR1)
ADC采样时间寄存器 2(ADC_SMPR2)
ADC看门狗高阀值寄存器(ADC_HTR)
ADC看门狗低阀值寄存器(ADC_LRT)
ADC规则序列寄存器 1(ADC_SQR1)
ADC规则序列寄存器 2(ADC_SQR2)
ADC规则序列寄存器 3(ADC_SQR3)
ADC注入序列寄存器(ADC_JSQR)
ADC 注入数据寄存器x (ADC_JDRx) (x= 1..4)
ADC规则数据寄存器(ADC_DR)
ADC的库函数
- stm32f1xx_hal_adc.c
- stm32f1xx_hal_adc_ex.c
小实验1:ADC单通道采集实验
实验目的
使用ADC1采集单通道1的电压值,通道1接光敏电阻传感器。
硬件清单
开发板、光敏传感器、ST-Link、USB转TTL
配置代码流程
文件代码
- adc.c文件代码
#include "adc.h"
ADC_HandleTypeDef adc_handle = {0};
void adc_init(void){
adc_handle.Instance = ADC1;
adc_handle.Init.DataAlign = ADC_DATAALIGN_RIGHT; /* 数据对齐:常用右对齐 */
adc_handle.Init.ScanConvMode = ADC_SCAN_DISABLE; /* 需不需扫描:这里只有一个通道,不扫描 */
adc_handle.Init.ContinuousConvMode = DISABLE; /* 连续转化 */
adc_handle.Init.NbrOfConversion = 1; /* 转化的个数 */
adc_handle.Init.DiscontinuousConvMode = DISABLE; /* 间断模式 */
adc_handle.Init.NbrOfDiscConversion = 0; /* 间断的个数 */
adc_handle.Init.ExternalTrigConv = ADC_SOFTWARE_START; /* 触发模式的选择:软件触发 */
HAL_ADC_Init(&adc_handle);
HAL_ADCEx_Calibration_Start(&adc_handle); /* ADC的校准 */
}
void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc){
if(hadc->Instance == ADC1){
RCC_PeriphCLKInitTypeDef adc_clk_init = {0};
__HAL_RCC_ADC1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
adc_clk_init.PeriphClockSelection = RCC_PERIPHCLK_ADC; /* 外设时钟的选择 */
adc_clk_init.AdcClockSelection = RCC_ADCPCLK2_DIV6; /* ADC的预分频:这里6分频,12MHz */
HAL_RCCEx_PeriphCLKConfig(&adc_clk_init); /* 由于ADC转化的时钟是12MHz,要进行改变,进行预分频 */
GPIO_InitTypeDef gpio_initstruct;
gpio_initstruct.Pin = GPIO_PIN_1;
gpio_initstruct.Mode = GPIO_MODE_ANALOG;
gpio_initstruct.Pull = GPIO_PULLUP;
gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA,&gpio_initstruct);
}
}
/**
* @breif 封装一个配置ADC通道的函数。
* @param 配置的ADC1,通道,通道序列,采样时间
* @retval 无
*/
void adc_channel_config(ADC_HandleTypeDef* hadc,uint32_t ch,uint32_t rank,uint32_t stime){
ADC_ChannelConfTypeDef adc_ch_config = {0};
adc_ch_config.Channel = ch; /* 选择配置的通道 */
adc_ch_config.Rank = rank; /* 通道的优先级,序列 */
adc_ch_config.SamplingTime = stime; /* 通道的采样时间 */
HAL_ADC_ConfigChannel(&adc_handle,&adc_ch_config);
}
/**
* @breif 封装一个获取DR寄存器值得函数
* @note 配置的流程:配置通道,打开ADC,阻塞函数等待转化完成,获取DR寄存器数据的值,(uint16_t)将数据强转为十进制数。
* @param 通道,uint32_t ch
* @retval 获取的DR寄存器中的数值
*/
uint32_t adc_get_result(uint32_t ch){
adc_channel_config(&adc_handle,ch,ADC_REGULAR_RANK_1,ADC_SAMPLETIME_239CYCLES_5); /* 通道的配置 */
HAL_ADC_Start(&adc_handle); /* 打开ADC */
HAL_ADC_PollForConversion(&adc_handle,10); /* 等待转化完成,超时时间:10ms*/
return (uint16_t)HAL_ADC_GetValue(&adc_handle);
/* ADC1转化的结果放在DR寄存器的低16位,这里强转为uint16_t就可以直接获取。
DR寄存器的高16位存放的是ADC2转化的结果。 */
}
- adc.h文件代码
#ifndef __ADC_H__
#define __ADC_H__
#include "stm32f1xx.h"
void adc_init(void);
uint32_t adc_get_result(uint32_t ch);
#endif
- mian.c文件代码
#include "sys.h"
#include "led.h"
#include "delay.h"
#include "uart1.h"
#include "adc.h"
int main(void)
{
HAL_Init(); /* 初始化HAL库 */
stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
led_init(); /* LED初始化 */
uart1_init(115200);
printf("hello,world");
adc_init();
while(1)
{
printf("adc:result:%f v\r\n",(float)adc_get_result(ADC_CHANNEL_1) / 4096 * 3.3);
delay_ms(500);
}
}
总结: (代码流程图)
- 初始化ADC的函数;
- 初始化Msp的函数;
- 配置ADC的通道;
- 封装一个函数,取出DR寄存器中的数值。
注意:在HAL_DMA_MspInit( )函数中,要对ADC的时钟进行分频,一般采用的分频系数是6分频。调用的函数如下:
小实验2:ADC单通道采集实验+DMA读取
实验目的
使用ADC1采集通道1的电压值+DMA读取,通道1连接光敏传感器。
硬件清单
开发板、ST-Link、光敏电阻传感器、USB转TTL
配置流程
文件代码
- adc.c文件代码
#include "adc.h"
ADC_HandleTypeDef adc_handle = {0};
void adc_config(void){
adc_handle.Instance = ADC1;
adc_handle.Init.DataAlign = ADC_DATAALIGN_RIGHT; /* 数据对齐:常用右对齐 */
adc_handle.Init.ScanConvMode = ADC_SCAN_DISABLE; /* 需不需扫描:这里只有一个通道,不扫描 */
adc_handle.Init.ContinuousConvMode = ENABLE; /* 连续转化 */
adc_handle.Init.NbrOfConversion = 1; /* 转化的个数 */
adc_handle.Init.DiscontinuousConvMode = DISABLE; /* 间断模式 */
adc_handle.Init.NbrOfDiscConversion = 0; /* 间断的个数 */
adc_handle.Init.ExternalTrigConv = ADC_SOFTWARE_START; /* 触发模式的选择:软件触发 */
HAL_ADC_Init(&adc_handle);
HAL_ADCEx_Calibration_Start(&adc_handle); /* ADC的校准 */
}
DMA_HandleTypeDef dma_handle = {0};
void dma_config(void){
__HAL_RCC_DMA1_CLK_ENABLE();
dma_handle.Instance = DMA1_Channel1;
dma_handle.Init.Direction = DMA_PERIPH_TO_MEMORY;
dma_handle.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; /*ADC的DR寄存器是16,传输的数据是半字符。*/
dma_handle.Init.MemInc = DMA_MINC_ENABLE;
dma_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
dma_handle.Init.PeriphInc = DMA_PINC_ENABLE;
dma_handle.Init.Priority = DMA_PRIORITY_MEDIUM;
dma_handle.Init.Mode = DMA_CIRCULAR;
__HAL_LINKDMA(&adc_handle,DMA_Handle,dma_handle);
HAL_DMA_Init(&dma_handle);
}
void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc){
if(hadc->Instance == ADC1){
RCC_PeriphCLKInitTypeDef adc_clk_init = {0};
__HAL_RCC_ADC1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
adc_clk_init.PeriphClockSelection = RCC_PERIPHCLK_ADC; /* 外设时钟的选择 */
adc_clk_init.AdcClockSelection = RCC_ADCPCLK2_DIV6; /* ADC的预分频:这里6分频,12MHz */
HAL_RCCEx_PeriphCLKConfig(&adc_clk_init); /* 由于ADC转化的时钟是12MHz,要进行改变,进行预分频 */
GPIO_InitTypeDef gpio_initstruct;
gpio_initstruct.Pin = GPIO_PIN_1;
gpio_initstruct.Mode = GPIO_MODE_ANALOG;
gpio_initstruct.Pull = GPIO_PULLUP;
gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA,&gpio_initstruct);
}
}
/**
* @breif 封装一个配置ADC通道的函数。
* @param 配置的ADC1,通道,通道序列,采样时间
* @retval 无
*/
void adc_channel_config(ADC_HandleTypeDef* hadc,uint32_t ch,uint32_t rank,uint32_t stime){
ADC_ChannelConfTypeDef adc_ch_config = {0};
adc_ch_config.Channel = ch; /* 选择配置的通道 */
adc_ch_config.Rank = rank; /* 通道的优先级,序列 */
adc_ch_config.SamplingTime = stime; /* 通道的采样时间 */
HAL_ADC_ConfigChannel(&adc_handle,&adc_ch_config);
}
/**
* @breif 封装一个获取DR寄存器值得函数
* @note 配置的流程:配置通道,打开ADC,阻塞函数等待转化完成,获取DR寄存器数据的值,(uint16_t)将数据强转为十进制数。
* @param 通道,uint32_t ch
* @retval 获取的DR寄存器中的数值
*/
uint32_t adc_get_result(uint32_t ch){
adc_channel_config(&adc_handle,ch,ADC_REGULAR_RANK_1,ADC_SAMPLETIME_239CYCLES_5); /* 通道的配置 */
HAL_ADC_Start(&adc_handle); /* 打开ADC */
HAL_ADC_PollForConversion(&adc_handle,10); /* 等待转化完成,超时时间:10ms*/
return (uint16_t)HAL_ADC_GetValue(&adc_handle);
/* ADC1转化的结果放在DR寄存器的低16位,这里强转为uint16_t就可以直接获取。
DR寄存器的高16位存放的是ADC2转化的结果。 */
}
void adc_dma_init(uint32_t *mar){
adc_config();
adc_channel_config(&adc_handle,ADC_CHANNEL_1,ADC_REGULAR_RANK_1,ADC_SAMPLETIME_239CYCLES_5);
dma_config();
HAL_ADC_Start_DMA(&adc_handle,mar,1);
/* Length: The length of data to be transferred from ADC peripheral to memory. 转运一个数据 */
}
- adc.h文件代码
#ifndef __ADC_H__
#define __ADC_H__
#include "stm32f1xx.h"
void adc_dma_init(uint32_t *mar);
#endif
- mian.c文件代码
#include "sys.h"
#include "led.h"
#include "delay.h"
#include "uart1.h"
#include "adc.h"
uint32_t adc_result = 0;
int main(void)
{
HAL_Init(); /* 初始化HAL库 */
stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
led_init(); /* LED初始化 */
uart1_init(115200);
printf("hello,world");
adc_dma_init(&adc_result);
while(1)
{
printf("adc:result:%f v\r\n",(float)adc_result / 4096 * 3.3);
delay_ms(500);
}
}
注意事项:
- 在初始化ADC的函数中,开启连续模式;
- 在初始化DMA的函数中,数据位是半字符,模式是循环模式;
- 一定要注意使用__HAL_LINKDMA( )函数中的参数。第一个外设的据饼,第二个外设句柄的参数,第三个,DMA的句柄;
adc.c中的文件的书写流程:
- 初始化ADC;
- 初始化ADC相关的外设,MSP函数;
- 初始化DMA,并用函数将ADC外设与内存进行连接;
- 配置ADC的通道(ADCx,channelx,rank,sampleTime);
- 书写一个封装函数:ADC初始化函数->ADC通道的配置->初始化DMA的函数->调用打开ADC和DMA的函数。
小实验3:ADC多通道采集实验+DMA读取
实验目的
使用ADC1采集通道0~3的电压值+DMA读取,通道1连接光敏电阻传感器。
硬件清单
开发板、光敏电阻传感器、ST-Link、USB转TTL
配置流程
和单通道+DMA转运的流程基本相同
文件代码
- adc.c文件代码
#include "adc.h"
ADC_HandleTypeDef adc_handle = {0};
void adc_config(void){
adc_handle.Instance = ADC1;
adc_handle.Init.DataAlign = ADC_DATAALIGN_RIGHT; /* 数据对齐:常用右对齐 */
adc_handle.Init.ScanConvMode = ADC_SCAN_ENABLE; /* 需不需扫描:这里只有一个通道,不扫描 */
adc_handle.Init.ContinuousConvMode = ENABLE; /* 连续转化 */
adc_handle.Init.NbrOfConversion = 3; /* 转化的个数 */
adc_handle.Init.DiscontinuousConvMode = DISABLE; /* 间断模式 */
adc_handle.Init.NbrOfDiscConversion = 0; /* 间断的个数 */
adc_handle.Init.ExternalTrigConv = ADC_SOFTWARE_START; /* 触发模式的选择:软件触发 */
HAL_ADC_Init(&adc_handle);
HAL_ADCEx_Calibration_Start(&adc_handle); /* ADC的校准 */
}
DMA_HandleTypeDef dma_handle = {0};
void dma_config(void){
__HAL_RCC_DMA1_CLK_ENABLE();
dma_handle.Instance = DMA1_Channel1;
dma_handle.Init.Direction = DMA_PERIPH_TO_MEMORY;
dma_handle.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD; /*ADC的DR寄存器是16,传输的数据是半字符。*/
dma_handle.Init.MemInc = DMA_MINC_ENABLE;
dma_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
dma_handle.Init.PeriphInc = DMA_PINC_DISABLE;
dma_handle.Init.Priority = DMA_PRIORITY_MEDIUM;
dma_handle.Init.Mode = DMA_CIRCULAR;
__HAL_LINKDMA(&adc_handle,DMA_Handle,dma_handle);
HAL_DMA_Init(&dma_handle);
}
void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc){
if(hadc->Instance == ADC1){
RCC_PeriphCLKInitTypeDef adc_clk_init = {0};
__HAL_RCC_ADC1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
adc_clk_init.PeriphClockSelection = RCC_PERIPHCLK_ADC; /* 外设时钟的选择 */
adc_clk_init.AdcClockSelection = RCC_ADCPCLK2_DIV6; /* ADC的预分频:这里6分频,12MHz */
HAL_RCCEx_PeriphCLKConfig(&adc_clk_init); /* 由于ADC转化的时钟是12MHz,要进行改变,进行预分频 */
GPIO_InitTypeDef gpio_initstruct;
gpio_initstruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2;
gpio_initstruct.Mode = GPIO_MODE_ANALOG;
gpio_initstruct.Pull = GPIO_PULLUP;
gpio_initstruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA,&gpio_initstruct);
}
}
/**
* @breif 封装一个配置ADC通道的函数。
* @param 配置的ADC1,通道,通道序列,采样时间
* @retval 无
*/
void adc_channel_config(ADC_HandleTypeDef* hadc,uint32_t ch,uint32_t rank,uint32_t stime){
ADC_ChannelConfTypeDef adc_ch_config = {0};
adc_ch_config.Channel = ch; /* 选择配置的通道 */
adc_ch_config.Rank = rank; /* 通道的优先级,序列 */
adc_ch_config.SamplingTime = stime; /* 通道的采样时间 */
HAL_ADC_ConfigChannel(&adc_handle,&adc_ch_config);
}
void adc_dma_init(uint32_t *mar){
adc_config();
adc_channel_config(&adc_handle,ADC_CHANNEL_0,ADC_REGULAR_RANK_1,ADC_SAMPLETIME_239CYCLES_5);
adc_channel_config(&adc_handle,ADC_CHANNEL_1,ADC_REGULAR_RANK_2,ADC_SAMPLETIME_239CYCLES_5);
adc_channel_config(&adc_handle,ADC_CHANNEL_2,ADC_REGULAR_RANK_3,ADC_SAMPLETIME_239CYCLES_5);
dma_config();
HAL_ADC_Start_DMA(&adc_handle,mar,3);
/* Length: The length of data to be transferred from ADC peripheral to memory. 转运3个数据 */
}
遇到的问题:
在DMA初始化函数中,关于外设指针递增,要采取不递增,如下代码所示:
如果采用指针递增的模式的话,通道2和通道3没有数据显示,因为外设只有一个数据,递增的话第一个数据后面没有数据,是空数据。
- adc.h文件代码
#ifndef __ADC_H__
#define __ADC_H__
#include "stm32f1xx.h"
void adc_dma_init(uint32_t *mar);
#endif
- main.c文件代码
#include "sys.h"
#include "led.h"
#include "delay.h"
#include "uart1.h"
#include "adc.h"
uint32_t adc_result[3] = {0};
int main(void)
{
HAL_Init(); /* 初始化HAL库 */
stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
led_init(); /* LED初始化 */
uart1_init(115200);
printf("hello,world");
adc_dma_init(adc_result);
while(1)
{
printf("通道1电压:%f v\r\n",(float)adc_result[0] / 4096 * 3.3);
printf("通道2电压:%f v\r\n",(float)adc_result[1] / 4096 * 3.3);
printf("通道3电压:%f v\r\n\r\n",(float)adc_result[2] / 4096 * 3.3);
delay_ms(500);
}
}
相比于单通道+DMA转运,多通道+DMA转运的区别和一些注意事项:
- 利用多通道配置的话,在初始化ADC的函数中,要开启扫描模式。
- DMA初始化函数中,外设指针不递增。
- 封装一个配置通道的函数,方便在后面函数中配置不同的通道。
- 在主函数中创建一个数组接收不同通道传来的数据。