一、简介
*ADC(Analog-Digital Converter)模拟-数字转换器
*ADC可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量,建立模拟电路到数字电路的桥梁
*12位逐次逼近型ADC,1us转换时间
*输入电压范围:0~3.3V,转换结果范围:0~4095(12位转换分辨率)
*18个输入通道,可测量16个外部和2个内部信号源(在任意多个通道上以任意顺序进行的一系列转换构成成组转换(规则通道)。例如,可以如下顺序完成转换:通道3、通道8、通道2、通道0、通道2、通道2、通道15)
*规则组和注入组两个转换单元(规则通道:我们平时用的一般通道,按顺序进行转换),(注入通道:可以理解为插入。它是一种在规则通道转换的时候强行插入要转换的一种。注入通道只有在规则通道存在的时候才会出现)
*模拟看门狗自动监测输入电压范围
*转换时间:最短的转化时间--Tconv = 采样时间 + 12.5个周期
PCLK2 = 72M,ADC_CLK = 72/6 = 12M
Tconv = 1.5+12.4 = 14周期 = 14/12us = 1.17us
*AD转换的步骤:采样,保持,量化,编码
*STM32F103C8T6 ADC资源:ADC1、ADC2,10个外部输入通道(F4有三个ADC)
1、电压输入范围
*输入电压: VREF- <= VIN <= VREF+
*决定输入电压的引脚:VREF-,VREF+,VDDA,VSSA
*VSSA和VREF- 接地,VREF+ 和VDDA 接3.3V
*得到ADC的电压输入范围为: 0-3.3V
电压怎么测?
电压输入范围:ADC可以测量-10V ~ +10V
根据基尔霍夫定理:(Vin - Vout)/R2 + (3v3-Vout)/R1=Vout/R3
Vout=(Vint + 10)/6
二、ADC的基本结构
ps:STM32f103c8t6有ADC1和ADC2,有两个转换单元(规则组、注入组),规则组有16个通道,注入组有4个通道。
规则通道有数据覆盖的问题(用DMA来解决 只能用于ADC1,只有一个数据寄存器),注入通道没有数据覆盖的问题(四个通道有四个存放寄存器)
三、转换模式
1、单次转换,非扫描模式
2、连续转换,非扫描模式
3、单次转换,扫描模式
4、连续转换,扫描模式
四、转换顺序
规则通道:
注入通道:
1、ADC单通道DMA读取
#include "adc.h"
uint16_t ADC_conversionValue;//单ADC模式时,数据寄存器只用到低16位(用来存放 ADC发过来的数据)
static void ACDx_GPIO_Config(void)
{
GPIO_InitTypeDef ADC_GPIO_StructInit;
ADCx_PIN_RCC_Clock_Cmd(ADCx_PIN_Periph,ENABLE);
ADC_GPIO_StructInit.GPIO_Mode = GPIO_Mode_AIN; //必须是模拟输入
ADC_GPIO_StructInit.GPIO_Pin = ADCx_PIN;
GPIO_Init(ADCx_PIN_PORT, &ADC_GPIO_StructInit);
}
static void Config_ADC_Init(void)
{
ADC_InitTypeDef ADC_StructInit;
DMA_InitTypeDef DMA_StructInit;
/*--------------------------DMA-----------------------------------------*/
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //打开时钟
DMA_DeInit(DMA1_Channel1); //将DMA寄存器复位成刚上电的样子
DMA_StructInit.DMA_MemoryBaseAddr = (uint32_t)&ADC_conversionValue; //存储器地址
DMA_StructInit.DMA_PeripheralBaseAddr = (uint32_t)(&(ADC_x->DR)); //外设地址
DMA_StructInit.DMA_DIR = DMA_DIR_PeripheralSRC; //传输方向
DMA_StructInit.DMA_BufferSize = 1; //传输数目
DMA_StructInit.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//外设数据宽度,数据寄存器只用到低16位
DMA_StructInit.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //存储器数据宽度,数据寄存器只用到低16位
DMA_StructInit.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址是否递增
DMA_StructInit.DMA_MemoryInc = DMA_MemoryInc_Disable; //存储器地址是否递增
DMA_StructInit.DMA_Mode = DMA_Mode_Circular; //模式选择(现在时循环模式)
DMA_StructInit.DMA_Priority = DMA_Priority_High; //通道优先级
DMA_StructInit.DMA_M2M = DMA_M2M_Disable; //存储器到存储器模式
DMA_Init( DMA1_Channel1, &DMA_StructInit);
DMA_Cmd(DMA1_Channel1, ENABLE);
/*---------------------ADC------------------------------------*/
ADCx_RCC_Clock_Cmd(ADCx_Periph, ENABLE);
ADC_StructInit.ADC_Mode = ADC_Mode_Independent; //设置独立模式(因为只有一个ADC通道)
ADC_StructInit.ADC_ScanConvMode = DISABLE; //配置是否扫描(用在多通道)
ADC_StructInit.ADC_ContinuousConvMode = ENABLE; //配置是否要连续转换
ADC_StructInit.ADC_DataAlign = ADC_DataAlign_Right; //配置数据的对齐模式
ADC_StructInit.ADC_NbrOfChannel = 1; //配置要转换通道的数目
ADC_StructInit.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//配置触发模式(这里是软件触发,外部触发是有定时器或者GPIO才会使用)
ADC_Init(ADC_x, &ADC_StructInit);
RCC_ADCCLKConfig(RCC_PCLK2_Div8); //时钟配置72/8=9M
ADC_RegularChannelConfig(ADC_x, ADCx_Channel, 1, ADC_SampleTime_55Cycles5); //规则通道的配置,第三个参数是配置第几次转换,第四个参数是配置采样周期
ADC_Cmd(ADC_x, ENABLE); //使能ADC中断
ADC_StartCalibration(ADC_x); //开始校准ADC
while(ADC_GetCalibrationStatus(ADC_x)); //等待校准完成
ADC_SoftwareStartConvCmd(ADC_x, ENABLE); //软件触发使能(开始工作)
//使能DMA ADC
ADC_DMACmd(ADC_x, ENABLE);
}
void ADCx_Init(void)
{
ACDx_GPIO_Config();
Config_ADC_Init();
}
extern uint16_t ADC_conversionValue;
int main()
{
float conversionValue = 0;
initSysTick();
usart_init();
ADCx_Init();
while(1)
{
conversionValue = (float)ADC_conversionValue/4096*3.3;
printf("hex %04x\r\n",ADC_conversionValue);
printf("conversionValue %f\r\n",conversionValue);
ms_delay(2000);
}
}
2、ADC单通道中断读取
#ifndef ADC_H
#define ADC_H
#include "stm32f10x.h"
static void ACDx_GPIO_Config(void);
static void Config_ADC_Init(void);
static void ADCx_NVIC_Config(void);
void ADCx_Init(void);
//ADC引脚配置的宏
#define ADCx_PIN GPIO_Pin_1
#define ADCx_PIN_PORT GPIOA
#define ADCx_PIN_Periph RCC_APB2Periph_GPIOA
#define ADCx_PIN_RCC_Clock_Cmd RCC_APB2PeriphClockCmd
//ADC配置的宏
#define ADCx_Periph RCC_APB2Periph_ADC2
#define ADCx_RCC_Clock_Cmd RCC_APB2PeriphClockCmd
#define ADC_x ADC2
#define ADCx_Channel ADC_Channel_1
#define ADCx_IRQHandler ADC1_2_IRQHandler
#endif
#include "adc.h"
static void ACDx_GPIO_Config(void)
{
GPIO_InitTypeDef ADC_GPIO_StructInit;
ADCx_PIN_RCC_Clock_Cmd(ADCx_PIN_Periph,ENABLE);
ADC_GPIO_StructInit.GPIO_Mode = GPIO_Mode_AIN; //必须是模拟输入
ADC_GPIO_StructInit.GPIO_Pin = ADCx_PIN;
GPIO_Init(ADCx_PIN_PORT, &ADC_GPIO_StructInit);
}
static void Config_ADC_Init(void)
{
ADC_InitTypeDef ADC_StructInit;
ADCx_RCC_Clock_Cmd(ADCx_Periph, ENABLE);
ADC_StructInit.ADC_Mode = ADC_Mode_Independent; //设置独立模式(因为只有一个ADC通道)
ADC_StructInit.ADC_ScanConvMode = DISABLE; //配置是否扫描(用在多通道)
ADC_StructInit.ADC_ContinuousConvMode = ENABLE; //配置是否要连续转换
ADC_StructInit.ADC_DataAlign = ADC_DataAlign_Right; //配置数据的对齐模式
ADC_StructInit.ADC_NbrOfChannel = 1; //配置要转换通道的数目
ADC_StructInit.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//配置触发模式(这里是软件触发,外部触发是有定时器或者输入引脚触发才会使用)
ADC_Init(ADC_x, &ADC_StructInit);
RCC_ADCCLKConfig(RCC_PCLK2_Div8); //时钟配置72/8=9M
ADC_RegularChannelConfig(ADC_x, ADCx_Channel, 1, ADC_SampleTime_55Cycles5); //规则通道的配置,第三个参数是配置第几个转换换通道,第四个参数是配置采样周期,第二个参数是第几个通道(例:A0是通道1)
ADC_ITConfig(ADC_x, ADC_IT_EOC, ENABLE); //配置成规则通道中断
ADC_Cmd(ADC_x, ENABLE); //使能ADC中断
ADC_StartCalibration(ADC_x); //开始校准ADC
while(ADC_GetCalibrationStatus(ADC_x)); //等待校准完成
ADC_SoftwareStartConvCmd(ADC_x, ENABLE); //软件触发使能(开始工作)
}
static void ADCx_NVIC_Config(void)
{
NVIC_InitTypeDef ADCx_NVIC_StructInit;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
ADCx_NVIC_StructInit.NVIC_IRQChannel = ADC1_2_IRQn;
ADCx_NVIC_StructInit.NVIC_IRQChannelCmd = ENABLE;
ADCx_NVIC_StructInit.NVIC_IRQChannelPreemptionPriority = 1;
ADCx_NVIC_StructInit.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&ADCx_NVIC_StructInit);
}
void ADCx_Init(void)
{
ACDx_GPIO_Config();
Config_ADC_Init();
ADCx_NVIC_Config();
}
extern uint32_t ADC_Conversion_value;
int main()
{
float ADC_Value = 0;
initSysTick();
usart_init();
ADCx_Init();
while(1)
{
ADC_Value = (float)ADC_Conversion_value/4096*3.3;
printf("adc_float=%fv\r\n",ADC_Value);
printf("adc_Hex=%04x\r\n",ADC_Conversion_value);
ms_delay(2000);
}
}
void ADCx_IRQHandler(void)
{
if(ADC_GetITStatus(ADC_x, ADC_IT_EOC) == SET)
{
ADC_Conversion_value = ADC_GetConversionValue(ADC_x);//读取转换的数值
}
ADC_ClearITPendingBit(ADC_x, ADC_IT_EOC);
}
3、ADC多通道DMA读取
#ifndef ADC_H
#define ADC_H
#include "stm32f10x.h"
static void ACDx_GPIO_Config(void);
static void Config_ADC_Init(void);
void ADCx_Init(void);
//ADC引脚配置的宏
#define ADCx_PIN GPIO_Pin_1
#define ADCx_PIN_PORT GPIOA
#define ADCx_PIN_Periph RCC_APB2Periph_GPIOA
#define ADCx_PIN_RCC_Clock_Cmd RCC_APB2PeriphClockCmd
//ADC配置的宏
#define ADCx_Periph RCC_APB2Periph_ADC1
#define ADCx_RCC_Clock_Cmd RCC_APB2PeriphClockCmd
#define ADC_x ADC1
#define ADCx_Channel ADC_Channel_1
#define len 3
#endif
#include "adc.h"
uint16_t ADC_conversionValue[len];//单ADC模式时,数据寄存器只用到低16位(用来存放 ADC发过来的数据)
static void ACDx_GPIO_Config(void)
{
GPIO_InitTypeDef ADC_GPIO_StructInit;
ADCx_PIN_RCC_Clock_Cmd(ADCx_PIN_Periph,ENABLE);
ADC_GPIO_StructInit.GPIO_Mode = GPIO_Mode_AIN; //必须是模拟输入
ADC_GPIO_StructInit.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
GPIO_Init(ADCx_PIN_PORT, &ADC_GPIO_StructInit);
}
static void Config_ADC_Init(void)
{
ADC_InitTypeDef ADC_StructInit;
DMA_InitTypeDef DMA_StructInit;
/*--------------------------DMA-----------------------------------------*/
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //打开时钟
DMA_DeInit(DMA1_Channel1); //将DMA寄存器复位成刚上电的样子
DMA_StructInit.DMA_MemoryBaseAddr = (uint32_t)ADC_conversionValue; //存储器地址
DMA_StructInit.DMA_PeripheralBaseAddr = (uint32_t)(&(ADC_x->DR)); //外设地址
DMA_StructInit.DMA_DIR = DMA_DIR_PeripheralSRC; //传输方向
DMA_StructInit.DMA_BufferSize = len; //传输数目(缓冲区大小,应该等于数据目的地的大小)
// 外设数据大小为半字,即两个字节
DMA_StructInit.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//外设数据宽度,数据寄存器只用到低16位
// 内存数据大小也为半字,跟外设数据大小相同
DMA_StructInit.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //存储器数据宽度,数据寄存器只用到低16位
DMA_StructInit.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址是否递增
DMA_StructInit.DMA_MemoryInc = DMA_MemoryInc_Enable; //存储器地址是否递增
DMA_StructInit.DMA_Mode = DMA_Mode_Circular; //模式选择(现在时循环模式)
DMA_StructInit.DMA_Priority = DMA_Priority_High; //通道优先级
DMA_StructInit.DMA_M2M = DMA_M2M_Disable; //存储器到存储器模式
DMA_Init( DMA1_Channel1, &DMA_StructInit);
DMA_Cmd(DMA1_Channel1, ENABLE);
/*---------------------ADC------------------------------------*/
ADCx_RCC_Clock_Cmd(ADCx_Periph, ENABLE);
ADC_StructInit.ADC_Mode = ADC_Mode_Independent; //设置独立模式(因为只有一个ADC)
ADC_StructInit.ADC_ScanConvMode = ENABLE; //配置是否扫描(用在多通道)
ADC_StructInit.ADC_ContinuousConvMode = ENABLE; //配置是否要连续转换
ADC_StructInit.ADC_DataAlign = ADC_DataAlign_Right; //配置数据的对齐模式
ADC_StructInit.ADC_NbrOfChannel = len; //配置要转换通道的数目
ADC_StructInit.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//配置触发模式(这里是软件触发,外部触发是有定时器或者输入引脚触发才会使用)
ADC_Init(ADC_x, &ADC_StructInit);
RCC_ADCCLKConfig(RCC_PCLK2_Div8); //时钟配置72/8=9M
ADC_RegularChannelConfig(ADC_x, ADC_Channel_1, 1, ADC_SampleTime_55Cycles5); //规则通道的配置,第三个参数是配置第几次转换,第四个参数是配置采样周期
ADC_RegularChannelConfig(ADC_x, ADC_Channel_2, 2, ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC_x, ADC_Channel_3, 3, ADC_SampleTime_55Cycles5);
ADC_Cmd(ADC_x, ENABLE); //使能ADC中断
// 初始化ADC 校准寄存器
ADC_ResetCalibration(ADC_x);
// 等待校准寄存器初始化完成
while(ADC_GetResetCalibrationStatus(ADC_x));
ADC_StartCalibration(ADC_x); //开始校准ADC
while(ADC_GetCalibrationStatus(ADC_x)); //等待校准完成
ADC_SoftwareStartConvCmd(ADC_x, ENABLE); //软件触发使能(开始工作)
//使能DMA ADC请求
ADC_DMACmd(ADC_x, ENABLE);
}
void ADCx_Init(void)
{
ACDx_GPIO_Config();
Config_ADC_Init();
}
// 局部变量,用于保存转换计算后的电压值
float ADC_ConvertedValueLocal[len];
int main()
{
float conversionValue = 0;
initSysTick();
usart_init();
ADCx_Init();
printf("\r\n ----这是一个ADC多通道采集实验----\r\n");
while(1)
{
ADC_ConvertedValueLocal[0] =(float) ADC_conversionValue[0]/4096*3.3;
ADC_ConvertedValueLocal[1] =(float) ADC_conversionValue[1]/4096*3.3;
ADC_ConvertedValueLocal[2] =(float) ADC_conversionValue[2]/4096*3.3;
printf("\r\n CH0 value = %f V \r\n",ADC_ConvertedValueLocal[0]);
printf("\r\n CH1 value = %f V \r\n",ADC_ConvertedValueLocal[1]);
printf("\r\n CH2 value = %f V \r\n",ADC_ConvertedValueLocal[2]);
ms_delay(2000);
}
}
4、双ADC_DMA读取_同步规则
#ifndef ADC_H
#define ADC_H
#include "stm32f10x.h"
static void ACDx_GPIO_Config(void);
static void Config_ADC_Init(void);
void ADCx_Init(void);
//ADC引脚配置的宏
#define ADCx_PIN GPIO_Pin_1
#define ADCx_PIN_PORT GPIOA
#define ADCx_PIN_Periph RCC_APB2Periph_GPIOA
#define ADCx_PIN_RCC_Clock_Cmd RCC_APB2PeriphClockCmd
//ADC配置的宏
#define ADCx_Periph RCC_APB2Periph_ADC1
#define ADCx_RCC_Clock_Cmd RCC_APB2PeriphClockCmd
#define ADC_x ADC1
#define ADCx_Channel ADC_Channel_1
#define len 1
#endif
#include "adc.h"
uint32_t ADC_conversionValue[len];//单ADC模式时,数据寄存器只用到低16位(用来存放 ADC发过来的数据)
static void ACDx_GPIO_Config(void)
{
GPIO_InitTypeDef ADC_GPIO_StructInit;
ADCx_PIN_RCC_Clock_Cmd(ADCx_PIN_Periph,ENABLE);
ADC_GPIO_StructInit.GPIO_Mode = GPIO_Mode_AIN; //必须是模拟输入
ADC_GPIO_StructInit.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2 ;
GPIO_Init(ADCx_PIN_PORT, &ADC_GPIO_StructInit);
}
static void Config_ADC_Init(void)
{
ADC_InitTypeDef ADC_StructInit;
DMA_InitTypeDef DMA_StructInit;
/*--------------------------DMA-----------------------------------------*/
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //打开时钟
DMA_DeInit(DMA1_Channel1); //将DMA寄存器复位成刚上电的样子
DMA_StructInit.DMA_MemoryBaseAddr = (uint32_t)ADC_conversionValue; //存储器地址
DMA_StructInit.DMA_PeripheralBaseAddr = (uint32_t)(&(ADC_x->DR)); //外设地址
DMA_StructInit.DMA_DIR = DMA_DIR_PeripheralSRC; //传输方向
DMA_StructInit.DMA_BufferSize = len; //传输数目(缓冲区大小,应该等于数据目的地的大小)
// 外设数据大小为半字,即两个字节
DMA_StructInit.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word; //外设数据宽度(32位)
// 内存数据大小也为半字,跟外设数据大小相同
DMA_StructInit.DMA_MemoryDataSize = DMA_MemoryDataSize_Word; //存储器数据宽度(32位)
DMA_StructInit.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址是否递增
DMA_StructInit.DMA_MemoryInc = DMA_MemoryInc_Enable; //存储器地址是否递增
DMA_StructInit.DMA_Mode = DMA_Mode_Circular; //模式选择(现在时循环模式)
DMA_StructInit.DMA_Priority = DMA_Priority_High; //通道优先级
DMA_StructInit.DMA_M2M = DMA_M2M_Disable; //存储器到存储器模式
DMA_Init( DMA1_Channel1, &DMA_StructInit);
DMA_Cmd(DMA1_Channel1, ENABLE);
/*---------------------ADC1------------------------------------*/
ADCx_RCC_Clock_Cmd(ADCx_Periph, ENABLE);
ADC_StructInit.ADC_Mode = ADC_Mode_RegSimult; //设置成规则同步模式(因为有两个ADC)
ADC_StructInit.ADC_ScanConvMode = ENABLE; //配置是否扫描(用在多通道)
ADC_StructInit.ADC_ContinuousConvMode = ENABLE; //配置是否要连续转换
ADC_StructInit.ADC_DataAlign = ADC_DataAlign_Right; //配置数据的对齐模式
ADC_StructInit.ADC_NbrOfChannel = len; //配置要转换通道的数目
ADC_StructInit.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//配置触发模式(这里是软件触发,外部触发是有定时器或者输入引脚触发才会使用)
ADC_Init(ADC_x, &ADC_StructInit);
RCC_ADCCLKConfig(RCC_PCLK2_Div8); //时钟配置72/8=9M
ADC_Cmd(ADC_x, ENABLE); //使能ADC中断
ADC_RegularChannelConfig(ADC_x, ADC_Channel_1, 1, ADC_SampleTime_55Cycles5);//设置通道1(PA1)
//使能DMA ADC请求
ADC_DMACmd(ADC_x, ENABLE);
/*--------------------ADC2-------------------------------------*/
ADCx_RCC_Clock_Cmd(RCC_APB2Periph_ADC2, ENABLE);
ADC_StructInit.ADC_Mode = ADC_Mode_RegSimult; //设置成规则同步模式(因为有两个ADC)
ADC_StructInit.ADC_ScanConvMode = ENABLE; //配置是否扫描(用在多通道)
ADC_StructInit.ADC_ContinuousConvMode = ENABLE; //配置是否要连续转换
ADC_StructInit.ADC_DataAlign = ADC_DataAlign_Right; //配置数据的对齐模式
ADC_StructInit.ADC_NbrOfChannel = len; //配置要转换通道的数目
ADC_StructInit.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//配置触发模式(这里是软件触发,外部触发是有定时器或者GPIO才会使用)
// RCC_ADCCLKConfig(RCC_PCLK2_Div8); //时钟配置72/8=9M
ADC_Init(ADC2, &ADC_StructInit);
ADC_Cmd(ADC2, ENABLE); //使能ADC中断
ADC_RegularChannelConfig(ADC2, ADC_Channel_2, 1, ADC_SampleTime_55Cycles5);//设置通道2(PA2)
/* 使能ADCx_2的外部触发转换 */
ADC_ExternalTrigConvCmd(ADC2, ENABLE);
// 初始化ADC1 校准寄存器
ADC_ResetCalibration(ADC_x);
// 等待校准寄存器初始化完成
while(ADC_GetResetCalibrationStatus(ADC_x));
ADC_StartCalibration(ADC_x); //开始校准ADC
while(ADC_GetCalibrationStatus(ADC_x)); //等待校准完成
// 初始化ADC2 校准寄存器
ADC_ResetCalibration(ADC2);
// 等待校准寄存器初始化完成
while(ADC_GetResetCalibrationStatus(ADC2));
ADC_StartCalibration(ADC2); //开始校准ADC
while(ADC_GetCalibrationStatus(ADC2)); //等待校准完成
ADC_SoftwareStartConvCmd(ADC_x, ENABLE); //软件触发使能(开始工作)
}
void ADCx_Init(void)
{
ACDx_GPIO_Config();
Config_ADC_Init();
}
extern uint32_t ADC_conversionValue[len];//单ADC模式时,数据寄存器只用到低16位(用来存放 ADC发过来的数据)
// 局部变量,用于保存转换计算后的电压值
float ADC_ConvertedValueLocal[len*2];
int main()
{
uint16_t temp0=0 ,temp1=0;
initSysTick();
usart_init();
ADCx_Init();
printf("\r\n ----这是一个双ADC规则同步采集实验----\r\n");
while(1)
{
// 取出ADC1数据寄存器的高16位,这个是ADC2的转换数据
temp0 = (ADC_conversionValue[0]&0XFFFF0000) >> 16;//取高16位(ADC2的数据)
// 取出ADC1数据寄存器的低16位,这个是ADC1的转换数据
temp1 = (ADC_conversionValue[0]&0XFFFF); //取低16位(ADC1的数据)
ADC_ConvertedValueLocal[0] =(float) temp0/4096*3.3;
ADC_ConvertedValueLocal[1] =(float) temp1/4096*3.3;
printf("\r\n ADC1 value = %f V \r\n",
ADC_ConvertedValueLocal[1]);
printf("\r\n ADC2 value = %f V \r\n",
ADC_ConvertedValueLocal[0]);
ms_delay(2000);
}
}
PS:
*多路ADC模式的时候 ,要配置外部触发转换,单路ADC只需要配置软件触发转换
*多路ADC模式的时候,ADC1,ADC2一起使用,例如设置规则同步的时候,通道的数目要一致,ADC1有两个通道,ADC2也需要有两个通道
*
五、触发源
*ADC 的触发转换有两种方法:分别是通过软件或外部事件(也就是硬件)触发转换。
*软件触发转换的方法。方法是:通过写 ADC_CR2 寄存器的 ADON 这个位来控制,写 1 就开始转换,写 0 就停止转换,这个控制 ADC 转换的方式非常简单。
*外部事件触发转换的方法,有定时器和输入引脚触发等等
六、校准
*ADC有一个内置自校准模式。校准可大幅减小因内部电容器组的变化而造成的准精度误差。校准期间,在每个电容器上都会计算出一个误差修正码(数字值),这个码用于消除在随后的转换中每个电容器上产生的误差
*建议在每次上电后执行一次校准
*启动校准前, ADC必须处于关电状态超过至少两个ADC时钟周期
七、DMA请求
*因为规则通道转换的值储存在一个仅有的数据寄存器中,所以当转换多个规则通道时需要使用 DMA,这可以避免丢失已经存储在ADC_DR寄存器中的数据。
*只有在规则通道的转换结束时才产生DMA请求,并将转换的数据从ADC_DR寄存器传输到用户 指定的目的地址。
*只有ADC1和ADC3拥有DMA功能。由ADC2转化的数据可以通过双ADC模式,利用ADC1的DMA功能传输。(ADC2转换的数据要用DMA传输的时候,就可以用双ADC模式)。
八、中断
*ADC1和ADC2的中断映射在同一个中断向量上,而ADC3的中断有自己的中断向量。