一、ADC简介
ADC全称是模拟-数字转换器,主要作用是将引脚上连续变化的模拟电压转换为内存中存储的数字变量,建立模拟电路到数字电路的桥梁。其分辨率有12位,输入电压为0~3.3V,转换结果范围在0~4095.拥有18个输入通道,可测量16个外部和2个内部信号源。
二、ADC框图简介
2.1 第一部分:电压输入范围
ADC 输入范围为: VREF- ≤ VIN ≤ VREF+。由 VREF-、 VREF+ 、 VDDA 、 VSSA、这四个外部引脚决定。我们在设计原理图的时候一般把 VSSA 和 VREF- 接地,把 VREF+ 和 VDDA 接 3V3,得到 ADC 的输入电压范围为: 0~3.3V。
2.2 第二部分:输入通道
STM32ADC的通道有18个,其中有16个外部通道,2个内部通道。外部的 16 个通道在转换的时候又分为规则通道和注入通道,其中规则通道最多有 16 路,注入通道最多有 4 路。
规则通道:规则通道就是这16个外部通道,一般使用规则通道比较多。
注入通道:它是一种在规则通道转换的时候强行插入要转换的一种通道。如果在规则通道转换过程中,有注入通道插队,那么就要先转换完注入通道,等注入通道转换完成后,再回到规则通道的转换流程。只有规则通道存在时才会有注入通道。
2.3 第三部分:转换顺序
多个规则通道采集数据转换时需要进行转换顺序,SQR3,SQR2,SQR1这2个寄存器决定了这16个通道的转换顺序。
注入通道转换顺序由JSQR寄存器控制,他最多只支持4个通道,和规则转换的顺序是不一样的,如果有4个通道,第一个转换通道为JSQ1设置。
如果有3个通道,第一个转换通道为JSQ2设置。
如果有2个通道,第一个转换通道为JSQ3设置。
如果有1个通道,第一个转换通道为JSQ4设置。
2.4 第四部分:触发源
ADC的触发源可以是定时器中断触发、外部引脚中断触发,也可以由内部软件触发。
2.5 第五部分:转换时间
ADC的输入时钟ADC_CLK由ABP2(72M)经过分频提供,分频系数为2、4、6、8分频。其ADC_CLK最大时钟频率是14M,所以一般只能进行6分频(72/6=12)或8分频(72/8=9)。
ADC 使用若干个 ADC_CLK 周期对输入的电压进行采样,采样的周期数可通过 ADC 采样时间来控制,其中最快采样时间为1.5周期。
2.6 第六部分:数据寄存器
规则通道的数据寄存器
所有规则通道数据转换后的结果存放在ADC_DR数据寄存器中,ADC_DR数据寄存器是一个32位的寄存器,在单通道情况下,数据存储在ADC_DR数据寄存器的低16位,由于ADC的精度只有12位,所有可以现在左对齐存放和右对齐存放。右对齐存放数据高位补0,左对齐存放数据整数数据扩大了16倍。
采用ADC多通道采集数据,那么不断有数据放到ADC_DR寄存器中,没有及时把数据拿出来。采集到之前的数据就会被之后的数据覆盖。这时候就需要使用到DMA及时把数据搬运出来。(只有ADC1和ADC3具有DMA功能)
使用双ADC模式时,比如ADC1和ADC2,那么AD1采集到的数据就会被存放到ADC_DR寄存器的低16位。ADC2采集到的数据就会被存放到ADC_DR寄存器的高16位,他们是同时存放进ADC_DR数据寄存器中,不需要进行转换排序。
注入通道的数据寄存器
ADC 注入组最多有 4 个通道,刚好注入数据寄存器也有 4 个,每个通道对应着自己的寄存器,不
会跟规则寄存器那样产生数据覆盖的问题。数据也是存放到ADC_JDRx寄存器中。低16位存放数据,高16位保留。
2.7 第七部分:中断
转换结束中断
数据转换结束后,可以产生中断,中断分为三种:规则通道转换结束中断,注入转换通道转换结
束中断,模拟看门狗中断。其中转换结束中断很好理解,跟我们平时接触的中断一样,有相应的
中断标志位和中断使能位,我们还可以根据中断类型写相应配套的中断服务程序
模拟看门狗中断
当被 ADC 转换的模拟电压低于低阈值或者高于高阈值时,就会产生中断,前提是我们开启了模
拟看门狗中断,其中低阈值和高阈值由 ADC_LTR 和 ADC_HTR 设置。例如我们设置高阈值是
2.5V,那么模拟电压超过 2.5V 的时候,就会产生模拟看门狗中断,反之低阈值也一样
三、ADC校验
ADC有一个内置自校准模式。校准可大幅减小因内部电容器组的变化而造成的准精度误差。校准期间,在每个电容器上都会计算出一个误差修正码(数字值),这个码用于消除在随后的转换中每个电容器上产生的误差,建议在每次上电后执行一次校准启动校准前, ADC必须处于关电状态超过至少两个ADC时钟周期
四、电压转换
模拟电压经过 ADC 转换后,是一个 12 位的数字值,如果通过串口以 16 进制打印出来的话,可读性比较差,那么有时候我们就需要把数字电压转换成模拟电压,也可以跟实际的模拟电压(用万用表测)对比,看看转换是否准确。
我们一般在设计原理图的时候会把 ADC 的输入电压范围设定在: 0~3.3v,因为 ADC 是 12 位的,那么 12 位满量程对应的就是 3.3V, 12 位满量程对应的数字值是: 2^12。数值 0 对应的就是 0V。如果转换后的数值为 X , X 对应的模拟电压为 Y,那么会有这么一个等式成立: 2^12 / 3.3 = X/Y, => Y = (3.3 * X ) / 2^12。
五、ADC单通道采集-中断读取
ADC.H
#ifndef __ADC_H
#define __ADC_H
extern uint16_t Get_ADC_Value;
//GPIO_ADC
#define RCC_GPIO_CLK RCC_APB2Periph_GPIOA
#define GPIO_X GPIOA
#define GPIO_ADC_PEAD GPIO_Pin_1
//ADC
#define RCC_ADC_CLK RCC_APB2Periph_ADC1
#define ADC_X ADC1
void ADC_Init_Config(void);
#endif
ADC.C
#include "stm32f10x.h"
#include "adc.h"
uint16_t Get_ADC_Value;
static void ADCx_GPIO_Config(void)//ADC引脚初始化
{
RCC_APB2PeriphClockCmd(RCC_GPIO_CLK ,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;//模拟输入
GPIO_InitStructure.GPIO_Pin=GPIO_ADC_PEAD;
GPIO_Init(GPIO_X,&GPIO_InitStructure);
}
static void ADCx_Mode_Config(void)//ADC工作模式配置
{
RCC_APB2PeriphClockCmd(RCC_ADC_CLK,ENABLE);
ADC_InitTypeDef ADC_InitStructure;
ADC_InitStructure.ADC_Mode=ADC_Mode_Independent;//配置ADC模式为独立模式
ADC_InitStructure.ADC_ContinuousConvMode=ENABLE;//连续转换模式
ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right;//ADC数据对齐为右对齐
ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//配置为软件触发
ADC_InitStructure.ADC_NbrOfChannel=1;//配置采集ADC通道数为1
ADC_InitStructure.ADC_ScanConvMode=DISABLE;//配置为单通道
ADC_Init(ADC_X,&ADC_InitStructure);
RCC_ADCCLKConfig(RCC_PCLK2_Div8);//ADC时钟6分频(72/6)=12
ADC_RegularChannelConfig(ADC_X,ADC_Channel_1,1,ADC_SampleTime_55Cycles5);//(ADC规则通道选择)指定ADC,选择规则通道号,通道采样顺序,配置采样时间
ADC_ITConfig(ADC_X,ADC_IT_EOC,ENABLE);//(开始ADC中断)指定ADC,指定中断源为规则通道,
ADC_Cmd(ADC_X,ENABLE);//开启ADC
ADC_ResetCalibration(ADC_X);//初始化ADC校验
//****************ADC校准*********************
while(ADC_GetResetCalibrationStatus(ADC_X));//等待校准初始化完成
ADC_StartCalibration(ADC_X);//启动指定的ADC校准
while(ADC_GetCalibrationStatus(ADC_X));//等待校准完成
ADC_SoftwareStartConvCmd(ADC_X,ENABLE);//启用指定ADC软件启动转换
//*******************************************
}
static void NVIC_Config(void)//中断分组
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel=ADC1_2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
NVIC_Init(&NVIC_InitStructure);
}
void ADC_Init_Config(void)//ADC初始化
{
NVIC_Config();
ADCx_GPIO_Config();
ADCx_Mode_Config();
}
void ADC1_2_IRQHandler(void)//ADC中断函数
{
if(ADC_GetITStatus(ADC_X,ADC_IT_EOC)==SET)//判断规则通道标志位是否触发中断
{
Get_ADC_Value=ADC_GetConversionValue(ADC_X);//获取ADC采样后的数据
}
ADC_ClearITPendingBit(ADC_X,ADC_IT_EOC);//清除规则通道标志位
}
Main.c
#include "stm32f10x.h" // Device header
#include "led.h"
#include "serial.h"
#include "adc.h"
#include "delay.h"
float ADC_Num;
int main(void)
{
Serial_Init();
ADC_Init_Config();
printf("STM32战舰板ADC测试\r\n");
while(1)
{
ADC_Num=(float)Get_ADC_Value/4096*3.3;
printf("ADC数字量的值为0X%4X\r\n",Get_ADC_Value);
printf("ADC模拟量的值为%f V\r\n",ADC_Num);
Delay(0xFFFFEE);
}
}
六、ADC单通道采集-DMA读取
ADC.H
#ifndef __ADC_H
#define __ADC_H
extern uint16_t Get_ADC_Value;
//GPIO_ADC
#define RCC_GPIO_CLK RCC_APB2Periph_GPIOA
#define GPIO_X GPIOA
#define GPIO_ADC_PEAD GPIO_Pin_1
//ADC
#define RCC_ADC_CLK RCC_APB2Periph_ADC1
#define ADC_X ADC1
//DMA
#define RCC_DMA_CLK RCC_AHBPeriph_DMA1
#define DMA_X DMA1_Channel1
void ADC_Init_Config(void);
#endif
ADC.C
#include "stm32f10x.h"
#include "adc.h"
uint16_t Get_ADC_Value;
static void ADCx_GPIO_Config(void)
{
RCC_APB2PeriphClockCmd(RCC_GPIO_CLK ,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;//模拟输入
GPIO_InitStructure.GPIO_Pin=GPIO_ADC_PEAD;
GPIO_Init(GPIO_X,&GPIO_InitStructure);
}
static void ADCx_Mode_Config(void)
{
RCC_APB2PeriphClockCmd(RCC_ADC_CLK,ENABLE);//开启指定的ADC时钟
RCC_AHBPeriphClockCmd(RCC_DMA_CLK,ENABLE);//开启指定的DMA时钟
DMA_InitTypeDef DMA_InitStructure;
DMA_InitStructure.DMA_PeripheralBaseAddr=(uint32_t)&ADC1->DR;//外设存储器地址
DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_HalfWord;//外设数据的大小
DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;//外设地址不递增
DMA_InitStructure.DMA_MemoryBaseAddr=(uint32_t)&Get_ADC_Value;//内部存储器地址
DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_HalfWord;//内部数据大小
DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Disable;//内部地址不递增
DMA_InitStructure.DMA_BufferSize=1;//数据缓冲区大小
DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralSRC;//外设为源地址
DMA_InitStructure.DMA_M2M=DMA_M2M_Disable;//不开启内部存储器到内部存储器模式
DMA_InitStructure.DMA_Mode=DMA_Mode_Circular;//工作模式为循环模式
DMA_InitStructure.DMA_Priority=DMA_Priority_High;//DMA通道优先级
DMA_Init(DMA_X,&DMA_InitStructure);
DMA_Cmd(DMA_X,ENABLE);//开启DMA
ADC_InitTypeDef ADC_InitStructure;
ADC_InitStructure.ADC_Mode=ADC_Mode_Independent;//配置ADC模式为独立模式
ADC_InitStructure.ADC_ContinuousConvMode=ENABLE;//连续转换模式
ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right;//ADC数据对齐为右对齐
ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//配置为软件触发
ADC_InitStructure.ADC_NbrOfChannel=1;//配置采集ADC通道数为1
ADC_InitStructure.ADC_ScanConvMode=DISABLE;//配置为单通道
ADC_Init(ADC_X,&ADC_InitStructure);
RCC_ADCCLKConfig(RCC_PCLK2_Div8);//ADC时钟6分频(72/6)=12
ADC_RegularChannelConfig(ADC_X,ADC_Channel_1,1,ADC_SampleTime_55Cycles5);//(ADC规则通道选择)指定ADC,选择规则通道号,通道采样顺序,配置采样时间
ADC_DMACmd(ADC_X,ENABLE);//开启DMA请求
ADC_Cmd(ADC_X,ENABLE);//开启ADC
ADC_ResetCalibration(ADC_X);//初始化ADC校验
while(ADC_GetResetCalibrationStatus(ADC_X));//等待校准初始化完成
ADC_StartCalibration(ADC_X);//启动指定的ADC校准
while(ADC_GetCalibrationStatus(ADC_X));//等待校准完成
ADC_SoftwareStartConvCmd(ADC_X,ENABLE);//启用指定ADC软件启动转换
}
void ADC_Init_Config(void)//ADC初始化
{
ADCx_GPIO_Config();
ADCx_Mode_Config();
}
Main.c
#include "stm32f10x.h" // Device header
#include "led.h"
#include "serial.h"
#include "adc.h"
#include "delay.h"
float ADC_Num;
int main(void)
{
Serial_Init();
ADC_Init_Config();
printf("STM32战舰板ADC测试\r\n");
while(1)
{
ADC_Num=(float)Get_ADC_Value/4096*3.3;
printf("ADC数字量的值为%d\r\n",Get_ADC_Value);
printf("ADC模拟量的值为%f V\r\n",ADC_Num);
Delay(0xFFFFEE);
}
}
七、ADC多通道采集-DMA读取
ADC.H
#ifndef __ADC_H
#define __ADC_H
extern uint16_t Get_ADC_Value[];
//GPIO_ADC
#define RCC_GPIO_CLK RCC_APB2Periph_GPIOA
#define GPIO_X GPIOA
#define GPIO_ADC_PEAD1 GPIO_Pin_0
#define GPIO_ADC_PEAD2 GPIO_Pin_1
#define GPIO_ADC_PEAD3 GPIO_Pin_2
#define GPIO_ADC_PEAD4 GPIO_Pin_3
#define GPIO_ADC_PEAD5 GPIO_Pin_4
#define GPIO_ADC_PEAD6 GPIO_Pin_5
//ADC
#define RCC_ADC_CLK RCC_APB2Periph_ADC1
#define ADC_X ADC1
//DMA
#define RCC_DMA_CLK RCC_AHBPeriph_DMA1
#define DMA_X DMA1_Channel1
#define SIZE 6
void ADC_Init_Config(void);
#endif
ADC.C
#include "stm32f10x.h"
#include "adc.h"
uint16_t Get_ADC_Value[SIZE];
static void ADCx_GPIO_Config(void)
{
RCC_APB2PeriphClockCmd(RCC_GPIO_CLK ,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;//模拟输入
GPIO_InitStructure.GPIO_Pin=GPIO_ADC_PEAD6 | GPIO_ADC_PEAD1 | GPIO_ADC_PEAD2 | GPIO_ADC_PEAD3 | GPIO_ADC_PEAD4 | GPIO_ADC_PEAD5;
GPIO_Init(GPIO_X,&GPIO_InitStructure);
}
static void ADCx_Mode_Config(void)
{
RCC_APB2PeriphClockCmd(RCC_ADC_CLK,ENABLE);
RCC_AHBPeriphClockCmd(RCC_DMA_CLK,ENABLE);
DMA_InitTypeDef DMA_InitStructure;
DMA_InitStructure.DMA_PeripheralBaseAddr=(uint32_t)&ADC1->DR;//外设存储器地址
DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_HalfWord;//外设数据的大小
DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;//外设地址不递增
DMA_InitStructure.DMA_MemoryBaseAddr=(uint32_t)Get_ADC_Value;//内部存储器地址
DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_HalfWord;//内部数据大小
DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable;//内部地址递增
DMA_InitStructure.DMA_BufferSize=SIZE;//数据缓冲区大小
DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralSRC;//外设为源地址
DMA_InitStructure.DMA_M2M=DMA_M2M_Disable;//不开启内部存储器到内部存储器模式
DMA_InitStructure.DMA_Mode=DMA_Mode_Circular;//工作模式为循环模式
DMA_InitStructure.DMA_Priority=DMA_Priority_High;//DMA通道优先级
DMA_Init(DMA_X,&DMA_InitStructure);
DMA_Cmd(DMA_X,ENABLE);//开启DMA
ADC_InitTypeDef ADC_InitStructure;
ADC_InitStructure.ADC_Mode=ADC_Mode_Independent;//配置ADC模式为独立模式
ADC_InitStructure.ADC_ContinuousConvMode=ENABLE;//连续转换模式
ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right;//ADC数据对齐为右对齐
ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//配置为软件触发
ADC_InitStructure.ADC_NbrOfChannel=6;//配置采集ADC通道数为6
ADC_InitStructure.ADC_ScanConvMode=ENABLE;//配置为单通道
ADC_Init(ADC_X,&ADC_InitStructure);
RCC_ADCCLKConfig(RCC_PCLK2_Div8);//ADC时钟6分频(72/6)=12
ADC_RegularChannelConfig(ADC_X,ADC_Channel_0,1,ADC_SampleTime_55Cycles5);//(ADC规则通道选择)指定ADC,选择规则通道号,通道采样顺序,配置采样时间
ADC_RegularChannelConfig(ADC_X,ADC_Channel_1,2,ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC_X,ADC_Channel_2,3,ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC_X,ADC_Channel_3,4,ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC_X,ADC_Channel_4,5,ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC_X,ADC_Channel_6,6,ADC_SampleTime_55Cycles5);
ADC_DMACmd(ADC_X,ENABLE);//开启DMA请求
ADC_Cmd(ADC_X,ENABLE);//开启ADC
ADC_ResetCalibration(ADC_X);//初始化ADC校验
while(ADC_GetResetCalibrationStatus(ADC_X));//等待校准初始化完成
ADC_StartCalibration(ADC_X);//启动指定的ADC校准
while(ADC_GetCalibrationStatus(ADC_X));//等待校准完成
ADC_SoftwareStartConvCmd(ADC_X,ENABLE);//启用指定ADC软件启动转换
}
void ADC_Init_Config(void)
{
ADCx_GPIO_Config();
ADCx_Mode_Config();
}
Main.c
#include "stm32f10x.h" // Device header
#include "led.h"
#include "serial.h"
#include "adc.h"
#include "delay.h"
float ADC_Num[6];
int main(void)
{
Serial_Init();
ADC_Init_Config();
printf("STM32战舰板ADC测试\r\n");
while(1)
{
ADC_Num[0]=(float)Get_ADC_Value[0]/4096*3.3;
ADC_Num[1]=(float)Get_ADC_Value[1]/4096*3.3;
ADC_Num[2]=(float)Get_ADC_Value[2]/4096*3.3;
ADC_Num[3]=(float)Get_ADC_Value[3]/4096*3.3;
ADC_Num[4]=(float)Get_ADC_Value[4]/4096*3.3;
ADC_Num[5]=(float)Get_ADC_Value[5]/4096*3.3;
// printf("ADC1数字量的值为%d\r\n",Get_ADC_Value[0]);
printf("ADC1模拟量的值为%f V\r\n",ADC_Num[0]);
// printf("ADC2数字量的值为%d\r\n",Get_ADC_Value[1]);
printf("ADC2模拟量的值为%f V\r\n",ADC_Num[1]);
// printf("ADC3数字量的值为%d\r\n",Get_ADC_Value[2]);
printf("ADC3模拟量的值为%f V\r\n",ADC_Num[2]);
// printf("ADC4数字量的值为%d\r\n",Get_ADC_Value[3]);
printf("ADC4模拟量的值为%f V\r\n",ADC_Num[3]);
// printf("ADC5数字量的值为%d\r\n",Get_ADC_Value[4]);
printf("ADC5模拟量的值为%f V\r\n",ADC_Num[4]);
// printf("ADC6数字量的值为%d\r\n",Get_ADC_Value[5]);
printf("ADC6模拟量的值为%f V\r\n",ADC_Num[5]);
Delay(0xFFFFEE);
}
}
八、双ADC采集(规则同步模式)-DMA读取
ADC.H
#ifndef __ADC_H
#define __ADC_H
#define SIZE 2
extern uint32_t Get_ADC_Value[SIZE];
//GPIO_ADC
#define RCC_GPIO_CLK RCC_APB2Periph_GPIOA
#define GPIO_X GPIOA
#define GPIO_ADC_PEAD1 GPIO_Pin_1
#define GPIO_ADC_PEAD2 GPIO_Pin_4
//ADC
#define RCC_ADC1_CLK RCC_APB2Periph_ADC1
#define ADCX_1 ADC1
#define RCC_ADC2_CLK RCC_APB2Periph_ADC2
#define ADCX_2 ADC2
#define ADC1_PassageX ADC_Channel_1
#define ADC2_PassageX ADC_Channel_4
//DMA
#define RCC_DMA_CLK RCC_AHBPeriph_DMA1
#define DMA_X DMA1_Channel1
void ADC_Init_Config(void);
#endif
ADC.C
#include "stm32f10x.h"
#include "adc.h"
uint32_t Get_ADC_Value[SIZE];
static void ADCx_GPIO_Config(void)
{
RCC_APB2PeriphClockCmd(RCC_GPIO_CLK ,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;//模拟输入
GPIO_InitStructure.GPIO_Pin=GPIO_ADC_PEAD1 | GPIO_ADC_PEAD2;
GPIO_Init(GPIO_X,&GPIO_InitStructure);
}
static void ADCx_Mode_Config(void)
{
RCC_APB2PeriphClockCmd(RCC_ADC1_CLK | RCC_ADC2_CLK,ENABLE);
RCC_AHBPeriphClockCmd(RCC_DMA_CLK,ENABLE);
DMA_InitTypeDef DMA_InitStructure;
DMA_InitStructure.DMA_PeripheralBaseAddr=(uint32_t)&ADC1->DR;//外设存储器地址
DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Word;//外设数据的大小
DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;//外设地址不递增
DMA_InitStructure.DMA_MemoryBaseAddr=(uint32_t)Get_ADC_Value;//内部存储器地址
DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_Word;//内部数据大小
DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Disable;//内部地址不递增
DMA_InitStructure.DMA_BufferSize=SIZE;//数据缓冲区大小
DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralSRC;//外设为源地址
DMA_InitStructure.DMA_M2M=DMA_M2M_Disable;//不开启内部存储器到内部存储器模式
DMA_InitStructure.DMA_Mode=DMA_Mode_Circular;//工作模式为循环模式
DMA_InitStructure.DMA_Priority=DMA_Priority_High;//DMA通道优先级
DMA_Init(DMA_X,&DMA_InitStructure);
DMA_Cmd(DMA_X,ENABLE);//开启DMA
//**********ADC1的工作模式配置************
ADC_InitTypeDef ADC_InitStructure;
ADC_InitStructure.ADC_Mode=ADC_Mode_RegSimult;//配置ADC模式为双ADC规则同步模式
ADC_InitStructure.ADC_ContinuousConvMode=ENABLE;//连续转换模式
ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right;//ADC数据对齐为右对齐
ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//配置为软件触发
ADC_InitStructure.ADC_NbrOfChannel=1;//配置采集ADC通道数为1
ADC_InitStructure.ADC_ScanConvMode=DISABLE;//配置为单通道
ADC_Init(ADCX_1,&ADC_InitStructure);
RCC_ADCCLKConfig(RCC_PCLK2_Div8);//ADC时钟6分频(72/6)=12
//(ADC规则通道选择)指定ADC,选择规则通道号,通道采样顺序,配置采样时间
ADC_RegularChannelConfig(ADCX_1,ADC1_PassageX,1,ADC_SampleTime_55Cycles5);
ADC_DMACmd(ADCX_1,ENABLE);//开启DMA请求
ADC_Cmd(ADCX_1,ENABLE);//开启ADC
//****************************************************
//**********ADC2的工作模式配置************
ADC_InitStructure.ADC_Mode=ADC_Mode_RegSimult;//配置ADC模式为双ADC规则同步模式
ADC_InitStructure.ADC_ContinuousConvMode=ENABLE;//连续转换模式
ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right;//ADC数据对齐为右对齐
ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//配置为软件触发
ADC_InitStructure.ADC_NbrOfChannel=1;//配置采集ADC通道数为1
ADC_InitStructure.ADC_ScanConvMode=DISABLE;//配置为单通道
ADC_Init(ADCX_2,&ADC_InitStructure);
// RCC_ADCCLKConfig(RCC_PCLK2_Div8);//ADC时钟6分频(72/6)=12
ADC_RegularChannelConfig(ADCX_2,ADC2_PassageX,1,ADC_SampleTime_55Cycles5);//(ADC规则通道选择)指定ADC,选择规则通道号,通道采样顺序,配置采样时间
ADC_Cmd(ADCX_2,ENABLE);//开启ADC
//****************************************************
ADC_ExternalTrigConvCmd(ADCX_2,ENABLE);//ADC2使用外部触发采样
//************ADC1校验********************
ADC_ResetCalibration(ADCX_1);//初始化ADC校验
while(ADC_GetResetCalibrationStatus(ADCX_1));//等待校准初始化完成
ADC_StartCalibration(ADCX_1);//启动指定的ADC校准
while(ADC_GetCalibrationStatus(ADCX_1));//等待校准完成
ADC_SoftwareStartConvCmd(ADCX_1,ENABLE);//ADC1启用软件启动转换
//**************************************************
//************ADC2校验********************
ADC_ResetCalibration(ADCX_2);//初始化ADC校验
while(ADC_GetResetCalibrationStatus(ADCX_2));//等待校准初始化完成
ADC_StartCalibration(ADCX_2);//启动指定的ADC校准
while(ADC_GetCalibrationStatus(ADCX_2));//等待校准完成
//**************************************************
}
void ADC_Init_Config(void)
{
ADCx_GPIO_Config();
ADCx_Mode_Config();
}
Main.c
#include "stm32f10x.h" // Device header
#include "led.h"
#include "serial.h"
#include "adc.h"
#include "delay.h"
float ADC1_Num;
float ADC2_Num;
int main(void)
{
Serial_Init();
ADC_Init_Config();
printf("STM32战舰板ADC测试\r\n");
while(1)
{
ADC1_Num=(float) ((Get_ADC_Value[0] & 0xFFFF0000)>>16)/4096*3.3;
printf("ADC数字量的值为%d\r\n",Get_ADC_Value[0]>>16);
printf("ADC模拟量的值为%f V\r\n",ADC1_Num);
ADC2_Num=(float) ((Get_ADC_Value[0] & 0x0000FFFF))/4096*3.3;
printf("ADC数字量的值为%d\r\n",(Get_ADC_Value[0] & 0x0000FFFF));
printf("ADC模拟量的值为%f V\r\n",ADC2_Num);
Delay(0xFFFFEE);
}
}