文章目录
ADC - 模拟数字转换
ADC :Analog to Digital,模拟数字转换器
1-三个独立的ADC 1 / 2 / 3
2-分辨率为12位
3-每个ADC具有18个通道,其中外部通道16个
ADC功能框图
1-电压输入范围
2-输入通道
3-转换顺序
4-触发源
5-转换时间
6-数据寄存器
7-中断
电压输入范围
输入电压:VREF- ≤ VIN ≤ VREF+
决定输入电压的引脚:VREF-、 VREF+ 、 VDDA 、 VSSA
VSSA 和 VREF-接地,把 VREF+和 VDDA 接 3V3,得到ADC 的输入电压范围为: 0~3.3V。
超出0~3.3V的电压怎么测?
ADC可以测量:-10V~10V
根据基尔霍夫定律(KCL),节点流入的电流等于流出的电流
(Vint – Vout)/R2 + (3V3-Vout)/R1 = Vout / R3
Vout = (Vint + 10) /6
R1 = 100K, R2 = 300K, R3 = 150K, 效果会更好
输入通道
外部的 16 个通道在转换的时候又分为规则通道和注入通道,其中规则通道最多有 16路,注入通道最多有 4 路。那这两个通道有什么区别?在什么时候使用?
规则通道: 顾名思意,规则通道就是很规矩的意思,我们平时一般使用的就是这个通道。
注入通道: 注入,可以理解为插入,插队的意思,是一种不安分的通道。它是一种在规则通道转换的时候强行插入要转换的一种。这点跟中断程序很像,都是不安分的主。所以,注入通道只有在规则通道存在时才会出现。
通道转换顺序
触发源
1、软件触发:ADC_CR2 :ADON/SWST ART/JSWSTART
2、外部事件触发: 内部定时器/外部IO
选择:ADC_CR2 :EXTSEL[2:0]和 JEXTSEL[2:0]
激活:ADC_CR2 :EXTEN 和 JEXTEN
转换时间
转换时间T: conv = 采样时间 + 12.5 个周期
ADC_CLK: ADC模拟电路时钟,最大值为14M,由PCLK2提供,还可分频,2/4/6/8 (一般只能分频6),RCC_CFGR 的 ADCPRE[1:0]设置。PCLK2=72M。
数字时钟: RCC_APB2ENR,用于访问寄存器
采样时间:ADC 需要若干个 ADC_CLK 周期完成对输入的模拟量进行采样,采样的周期数可通过ADC 采样时间寄存器 ADC_SMPR1 和 ADC_SMPR2 中的 SMPx[2:0]位设置, ADC_SMPR2控制的是通道 0~9, ADC_SMPR1 控制的是通道 10~17。每个通道可以分别用不同的时间采样。其中采样周期最小是 1.5 个,即如果我们要达到最快的采样,那么应该设置采样周期为 31.5个周期,这里说的周期就是 1/ADC_CLK。
最短的转换时间: Tconv = 采样时间 + 12.5 个周期
PCLK2 = 72M,ADC_CLK = 72/6 = 12M
Tconv = 1.5+12.5 = 14周期 = 14/12us=1.17us
数据寄存器
一切准备就绪后, ADC 转换后的数据根据转换组的不同,规则组的数据放在ADC_DR 寄存器,注入组的数据放在 JDRx。
1-16位有效,用于存放独立模式转换完成数据
2- ADC_CR2 :ALIGN
3-只有一个,多通道采集的是最好使用DMA
1-16位有效,用于存放注入通道转换完成数据
2- ADC_CR2 :ALIGN
3-有4个这样的寄存器
中断
1-ADC_SR,ADC_CR1
2- ADC_HTR,ADC_LTR
电压转换
怎么根据数据量算出模拟量
1-电压输入范围为:0~3.3V
2-分辨率为12位
3-最小精度为:3.3/2^12
4-设数字量为X,则有模拟量 Y = (3.3 / 2^12)*X
ADC初始化结构体
ADC_InitTypeDef
ADC_MODE:模式选择,ADC_CR1:DUALMOD
ADC_ScanConvMode:扫描模式,ADC_CR1:SCAN
ADC_ContinuousConvMode:连续转换模式,ADC_CR2:CON
ADC_ExternalTrigConv:外部触发转换选择,ADC_CR2:EXTTRIG和EXTSEL[2:0]
ADC_MODE:模式选择,ADC_CR1:DUALMOD
ADC_ScanConvMode:扫描模式,ADC_CR1:SCAN
ADC_DataAlign:数据对齐格式,ADC_CR2:ALIGN
ADC_NbrOfChannel:转换的通道数,配置规则序列寄存器和注入序列寄存器
几个常用的固件库函数
ADC_Init(); 429
RCC_ADCCLKConfig(); 680
ADC_RegularChannelConfig(); 442
ADC_Cmd(); 431 //单ADC模式使用
ADC_SoftwareStartConvCmd(); 438 //单ADC模式使用
ADC_ExternalTrigConvCmd(); 443 //双ADC模式使用
ADC_DMACmd(); 432
代码实例
指南者ADC接口
1-独立模式-单通道-中断读取
1-初始化ADC用到的GPIO
2-初始化ADC初始化结构体
3-配置ADC时钟,配置通道的转换顺序和采样时间
4-使能ADC转换完成中断,配置中断优先级
中断源在
stm32f10x.h
里查找,中断服务函数在启动文件里查找
5-使能ADC,准备开始转换
6-校准ADC
7-软件触发ADC,真正开始转换
8-编写中断服务函数,读取ADC转换数据
中断源在
stm32f10x.h
里查找,中断服务函数在启动文件里查找
9-编写main函数,把转换的数据打印出来
bsp_adc.h
#ifndef _BSP_ADC_H
#define _BSP_ADC_H
#include "stm32f10x.h"
#define ADC_GPIO_CLK RCC_APB2Periph_GPIOC
#define ADC_PORT GPIOC
#define ADC_PIN GPIO_Pin_1
#define ADC_x ADC2
#define ADC_CHANNEL ADC_Channel_11
#define ADC_CLK RCC_APB2Periph_ADC2
#define ADC_IRQ ADC1_2_IRQn //ADC1和ADC2都用这个中断源和中断服务函数
#define ADC_IRQHandler ADC1_2_IRQHandler
void ADCx_Init(void);
#endif /*_BSP_ADC_H*/
bsp_adc.c
#include "bsp_adc.h"
static void ADCx_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(ADC_GPIO_CLK,ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_Pin = ADC_PIN;
GPIO_Init(ADC_PORT,&GPIO_InitStructure);
}
static void ADCx_Mode_Config(void)
{
ADC_InitTypeDef ADC_InitStruct;
RCC_APB2PeriphClockCmd(ADC_CLK ,ENABLE);
ADC_InitStruct.ADC_ContinuousConvMode = ENABLE;
ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None ; // 不用外部触发转换,软件开启即可
ADC_InitStruct.ADC_Mode = ADC_Mode_Independent; // 只使用一个ADC,属于独立模式
ADC_InitStruct.ADC_NbrOfChannel = 1;
ADC_InitStruct.ADC_ScanConvMode = DISABLE; //禁止扫描模式,多通道才要,单通道不需要
ADC_Init(ADC_x, &ADC_InitStruct);
// 配置ADC时钟为PCLK2的8分频,即9MHz
RCC_ADCCLKConfig(RCC_PCLK2_Div8);
// 配置 ADC 通道转换顺序和采样时间
ADC_RegularChannelConfig(ADC_x,ADC_CHANNEL,1,ADC_SampleTime_55Cycles5);
// ADC 转换结束产生中断,在中断服务程序中读取转换值
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转换
ADC_SoftwareStartConvCmd(ADC_x, ENABLE);
}
static void ADC_NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStruct;
//优先级分组
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
//配置中断优先级
NVIC_InitStruct.NVIC_IRQChannel = ADC_IRQ;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
NVIC_Init(&NVIC_InitStruct);
}
void ADCx_Init(void)
{
ADCx_GPIO_Config();
ADCx_Mode_Config();
ADC_NVIC_Config();
}
mian.c
#include "stm32f10x.h"
#include "bsp_led.h"
#include "bsp_usart.h"
#include "./adc/bsp_adc.h"
// ADC 单通道采集,不使用DMA,一般只有ADC2才这样使用,因为ADC2不能使用DMA
extern __IO uint16_t ADC_ConversionValue;
//局部变量用于保存转换计算后的电压值
float ADC_ConvertedValueLocal;
// 软件延时
void Delay(__IO uint32_t nCount)
{
for(; nCount != 0; nCount--);
}
int main(void)
{
USART_Config();
ADCx_Init();
printf("\r\n ----这是一个ADC单通道中断读取实验----\r\n");
while(1)
{
ADC_ConvertedValueLocal = (float) ADC_ConversionValue/4096*3.3;
printf("\r\n The current AD value = 0x%04x \r\n", ADC_ConversionValue);
printf("\r\n The current AD value = %f V \r\n", ADC_ConvertedValueLocal);
Delay(0xffffee);
}
}
stm32f10x_it.c
__IO uint16_t ADC_ConversionValue;
void ADC_IRQHandler(void)
{
if(ADC_GetITStatus(ADC_x, ADC_IT_EOC) == SET)
{
ADC_ConversionValue = ADC_GetConversionValue(ADC_x);
}
ADC_ClearITPendingBit(ADC_x, ADC_IT_EOC);
}
2-独立模式-单通道-DMA读取
bsp_adc.c
#include "bsp_adc.h"
__IO uint16_t ADC_ConversionValue;
static void ADCx_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(ADC_GPIO_CLK,ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_Pin = ADC_PIN;
GPIO_Init(ADC_PORT,&GPIO_InitStructure);
}
static void ADCx_Mode_Config(void)
{
DMA_InitTypeDef DMA_InitStructure;
ADC_InitTypeDef ADC_InitStruct;
// 开启DMA时钟
RCC_AHBPeriphClockCmd(ADC_DMA_CLK, ENABLE);
DMA_DeInit(ADC_DMA_CHANNEL);
// 设置DMA源地址:ADC数据寄存器地址*/
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&(ADC_x->DR));
// 内存地址
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADC_ConversionValue;
// 方向:从外设到内存
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
// 传输大小
DMA_InitStructure.DMA_BufferSize = 1;
// 外设地址不增
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
// 内存地址不增
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
// 外设数据单位
DMA_InitStructure.DMA_PeripheralDataSize =
DMA_PeripheralDataSize_HalfWord;
// 内存数据单位
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
// DMA模式,循环模式
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular ;
//DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
// 优先级:高
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
// 禁止内存到内存的传输
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
// 配置DMA通道
DMA_Init(ADC_DMA_CHANNEL, &DMA_InitStructure);
// 使能DMA
DMA_Cmd (ADC_DMA_CHANNEL,ENABLE);
RCC_APB2PeriphClockCmd(ADC_CLK ,ENABLE);
ADC_InitStruct.ADC_ContinuousConvMode = ENABLE;
ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None ; // 不用外部触发转换,软件开启即可
ADC_InitStruct.ADC_Mode = ADC_Mode_Independent; // 只使用一个ADC,属于独立模式
ADC_InitStruct.ADC_NbrOfChannel = 1;
ADC_InitStruct.ADC_ScanConvMode = DISABLE; //禁止扫描模式,多通道才要,单通道不需要
ADC_Init(ADC_x, &ADC_InitStruct);
// 配置ADC时钟为PCLK2的8分频,即9MHz
RCC_ADCCLKConfig(RCC_PCLK2_Div8);
// 配置 ADC 通道转换顺序和采样时间
ADC_RegularChannelConfig(ADC_x,ADC_CHANNEL,1,ADC_SampleTime_55Cycles5);
// 产生ADC DMA 请求
ADC_DMACmd(ADC_x, ENABLE);
ADC_Cmd(ADC_x,ENABLE);
// ADC开始校准
ADC_StartCalibration(ADC_x);
//等待ADC校准完成
while(ADC_GetCalibrationStatus(ADC_x));
// 由于没有采用外部触发,所以使用软件触发ADC转换
ADC_SoftwareStartConvCmd(ADC_x, ENABLE);
}
void ADCx_Init(void)
{
ADCx_GPIO_Config();
ADCx_Mode_Config();
}
bsp_adc.h
#ifndef _BSP_ADC_H
#define _BSP_ADC_H
#include "stm32f10x.h"
#define ADC_GPIO_CLK RCC_APB2Periph_GPIOC
#define ADC_PORT GPIOC
#define ADC_PIN GPIO_Pin_1
#define ADC_x ADC1
#define ADC_CHANNEL ADC_Channel_11
#define ADC_CLK RCC_APB2Periph_ADC1
#define ADC_DMA_CLK RCC_AHBPeriph_DMA1
#define ADC_DMA_CHANNEL DMA1_Channel1
void ADCx_Init(void);
#endif /*_BSP_ADC_H*/
mian.c
#include "stm32f10x.h"
#include "bsp_led.h"
#include "bsp_usart.h"
#include "./adc/bsp_adc.h"
// ADC 单通道采集,不使用DMA,一般只有ADC2才这样使用,因为ADC2不能使用DMA
extern __IO uint16_t ADC_ConversionValue;
//局部变量用于保存转换计算后的电压值
float ADC_ConvertedValueLocal;
// 软件延时
void Delay(__IO uint32_t nCount)
{
for(; nCount != 0; nCount--);
}
int main(void)
{
USART_Config();
ADCx_Init();
printf("\r\n ----这是一个ADC独立模式-单通道-DMA读取实验----\r\n");
while(1)
{
ADC_ConvertedValueLocal = (float) ADC_ConversionValue/4096*3.3;
printf("\r\n The current AD value = 0x%04x \r\n", ADC_ConversionValue);
printf("\r\n The current AD value = %f V \r\n", ADC_ConvertedValueLocal);
Delay(0xffffee);
}
}
3-独立模式-多通道-DMA读取
bsp_adc.c
#include "bsp_adc.h"
__IO uint16_t ADC_ConversionValue[NUMCHANNEL] = {0,0,0,0,0,0};
static void ADCx_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(ADC_GPIO_CLK,ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_Pin = ADC_PIN1;
GPIO_InitStructure.GPIO_Pin = ADC_PIN2;
GPIO_InitStructure.GPIO_Pin = ADC_PIN3;
GPIO_InitStructure.GPIO_Pin = ADC_PIN4;
GPIO_InitStructure.GPIO_Pin = ADC_PIN5;
GPIO_InitStructure.GPIO_Pin = ADC_PIN6;
GPIO_Init(ADC_PORT,&GPIO_InitStructure);
}
static void ADCx_Mode_Config(void)
{
DMA_InitTypeDef DMA_InitStructure;
ADC_InitTypeDef ADC_InitStruct;
// 开启DMA时钟
RCC_AHBPeriphClockCmd(ADC_DMA_CLK, ENABLE);
DMA_DeInit(ADC_DMA_CHANNEL);
// 设置DMA源地址:ADC数据寄存器地址*/
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&(ADC_x->DR));
// 内存地址
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADC_ConversionValue;
// 方向:从外设到内存
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
// 传输大小
DMA_InitStructure.DMA_BufferSize = NUMCHANNEL;
// 外设地址不增
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
// 内存地址不增
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
// 外设数据单位
DMA_InitStructure.DMA_PeripheralDataSize =
DMA_PeripheralDataSize_HalfWord;
// 内存数据单位
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
// DMA模式,循环模式
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular ;
//DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
// 优先级:高
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
// 禁止内存到内存的传输
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
// 配置DMA通道
DMA_Init(ADC_DMA_CHANNEL, &DMA_InitStructure);
// 使能DMA
DMA_Cmd (ADC_DMA_CHANNEL,ENABLE);
RCC_APB2PeriphClockCmd(ADC_CLK ,ENABLE);
ADC_InitStruct.ADC_ContinuousConvMode = ENABLE;
ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None ; // 不用外部触发转换,软件开启即可
ADC_InitStruct.ADC_Mode = ADC_Mode_Independent; // 只使用一个ADC,属于独立模式
ADC_InitStruct.ADC_NbrOfChannel = NUMCHANNEL;
ADC_InitStruct.ADC_ScanConvMode = ENABLE; //使能扫描模式,多通道才要,单通道不需要
ADC_Init(ADC_x, &ADC_InitStruct);
// 配置ADC时钟为PCLK2的8分频,即9MHz
RCC_ADCCLKConfig(RCC_PCLK2_Div8);
// 配置 ADC 通道转换顺序和采样时间
ADC_RegularChannelConfig(ADC_x,ADC_CHANNEL1,1,ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC_x,ADC_CHANNEL2,2,ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC_x,ADC_CHANNEL3,3,ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC_x,ADC_CHANNEL4,4,ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC_x,ADC_CHANNEL5,5,ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig(ADC_x,ADC_CHANNEL6,6,ADC_SampleTime_55Cycles5);
// 产生ADC DMA 请求
ADC_DMACmd(ADC_x, ENABLE);
ADC_Cmd(ADC_x,ENABLE);
// ADC开始校准
ADC_StartCalibration(ADC_x);
//等待ADC校准完成
while(ADC_GetCalibrationStatus(ADC_x));
// 由于没有采用外部触发,所以使用软件触发ADC转换
ADC_SoftwareStartConvCmd(ADC_x, ENABLE);
}
void ADCx_Init(void)
{
ADCx_GPIO_Config();
ADCx_Mode_Config();
}
bsp_adc.h
#ifndef _BSP_ADC_H
#define _BSP_ADC_H
#include "stm32f10x.h"
#define ADC_GPIO_CLK RCC_APB2Periph_GPIOC
#define ADC_PORT GPIOC
#define ADC_PIN1 GPIO_Pin_0
#define ADC_PIN2 GPIO_Pin_1
#define ADC_PIN3 GPIO_Pin_2
#define ADC_PIN4 GPIO_Pin_3
#define ADC_PIN5 GPIO_Pin_4
#define ADC_PIN6 GPIO_Pin_5
#define ADC_x ADC1
#define NUMCHANNEL 6
#define ADC_CHANNEL1 ADC_Channel_10
#define ADC_CHANNEL2 ADC_Channel_11
#define ADC_CHANNEL3 ADC_Channel_12
#define ADC_CHANNEL4 ADC_Channel_13
#define ADC_CHANNEL5 ADC_Channel_14
#define ADC_CHANNEL6 ADC_Channel_15
#define ADC_CLK RCC_APB2Periph_ADC1
#define ADC_DMA_CLK RCC_AHBPeriph_DMA1
#define ADC_DMA_CHANNEL DMA1_Channel1
void ADCx_Init(void);
#endif /*_BSP_ADC_H*/
mian.c
#include "stm32f10x.h"
#include "bsp_led.h"
#include "bsp_usart.h"
#include "./adc/bsp_adc.h"
// ADC 单通道采集,不使用DMA,一般只有ADC2才这样使用,因为ADC2不能使用DMA
extern __IO uint16_t ADC_ConversionValue[NUMCHANNEL];
//局部变量用于保存转换计算后的电压值
float ADC_ConvertedValueLocal[NUMCHANNEL];
// 软件延时
void Delay(__IO uint32_t nCount)
{
for(; nCount != 0; nCount--);
}
int main(void)
{
USART_Config();
ADCx_Init();
printf("\r\n ----这是一个ADC独立模式-多通道-DMA读取实验----\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;
ADC_ConvertedValueLocal[3] = (float) ADC_ConversionValue[3]/4096*3.3;
ADC_ConvertedValueLocal[4] = (float) ADC_ConversionValue[4]/4096*3.3;
ADC_ConvertedValueLocal[5] = (float) ADC_ConversionValue[5]/4096*3.3;
printf("\r\n The CH0 AD value = %f V \r\n", ADC_ConvertedValueLocal[0]);
printf("\r\n The CH1 AD value = %f V \r\n", ADC_ConvertedValueLocal[1]);
printf("\r\n The CH2 AD value = %f V \r\n", ADC_ConvertedValueLocal[2]);
printf("\r\n The CH3 AD value = %f V \r\n", ADC_ConvertedValueLocal[3]);
printf("\r\n The CH4 AD value = %f V \r\n", ADC_ConvertedValueLocal[4]);
printf("\r\n The CH5 AD value = %f V \r\n", ADC_ConvertedValueLocal[5]);
printf("\r\n\r\n");
Delay(0xffffee);
}
}
4-双重模式-多通道-规则同步
bsp_adc.c
#include "bsp_adc.h"
__IO uint32_t ADC_ConversionValue[NUMCHANNEL] = {0};
static void ADCx_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(ADC_GPIO_CLK,ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_Pin = ADC_1_PIN | ADC_2_PIN;
GPIO_Init(ADC_PORT,&GPIO_InitStructure);
}
static void ADCx_Mode_Config(void)
{
DMA_InitTypeDef DMA_InitStructure;
ADC_InitTypeDef ADC_InitStruct;
// 开启DMA时钟
RCC_AHBPeriphClockCmd(ADC_DMA_CLK, ENABLE);
DMA_DeInit(ADC_DMA_CHANNEL);
// 设置DMA源地址:ADC数据寄存器地址*/
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&(ADC_1->DR));
// 内存地址
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADC_ConversionValue;
// 方向:从外设到内存
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
// 传输大小
DMA_InitStructure.DMA_BufferSize = NUMCHANNEL;
// 外设地址不增
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
// 内存地址不增
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
// 外设数据单位
DMA_InitStructure.DMA_PeripheralDataSize =
DMA_PeripheralDataSize_Word;
// 内存数据单位
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
// DMA模式,循环模式
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular ;
//DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
// 优先级:高
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
// 禁止内存到内存的传输
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
// 配置DMA通道
DMA_Init(ADC_DMA_CHANNEL, &DMA_InitStructure);
// 使能DMA
DMA_Cmd (ADC_DMA_CHANNEL,ENABLE);
//ADC1
RCC_APB2PeriphClockCmd(ADC_1_CLK ,ENABLE);
ADC_InitStruct.ADC_ContinuousConvMode = ENABLE;
ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None ; // 不用外部触发转换,软件开启即可
ADC_InitStruct.ADC_Mode = ADC_Mode_RegSimult;
ADC_InitStruct.ADC_NbrOfChannel = NUMCHANNEL;
ADC_InitStruct.ADC_ScanConvMode = DISABLE; //使能扫描模式,多通道才要,单通道不需要
ADC_Init(ADC_1, &ADC_InitStruct);
// 配置ADC时钟为PCLK2的8分频,即9MHz
RCC_ADCCLKConfig(RCC_PCLK2_Div8);
// 配置 ADC 通道转换顺序和采样时间
ADC_RegularChannelConfig(ADC_1,ADC_1_CHANNEL,1,ADC_SampleTime_55Cycles5);
//ADC2
RCC_APB2PeriphClockCmd(ADC_2_CLK ,ENABLE);
ADC_InitStruct.ADC_ContinuousConvMode = ENABLE;
ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None ; // 不用外部触发转换,软件开启即可
ADC_InitStruct.ADC_Mode = ADC_Mode_RegSimult;
ADC_InitStruct.ADC_NbrOfChannel = NUMCHANNEL;
ADC_InitStruct.ADC_ScanConvMode = DISABLE; //使能扫描模式,多通道才要,单通道不需要
ADC_Init(ADC_2, &ADC_InitStruct);
// 配置ADC时钟为PCLK2的8分频,即9MHz
RCC_ADCCLKConfig(RCC_PCLK2_Div8);
// 配置 ADC 通道转换顺序和采样时间
ADC_RegularChannelConfig(ADC_2,ADC_2_CHANNEL,1,ADC_SampleTime_55Cycles5);
// 产生ADC DMA 请求
ADC_DMACmd(ADC_1, ENABLE);
ADC_Cmd(ADC_1,ENABLE);
// ADC开始校准
ADC_StartCalibration(ADC_1);
//等待ADC校准完成
while(ADC_GetCalibrationStatus(ADC_1));
ADC_Cmd(ADC_2,ENABLE);
// ADC开始校准
ADC_StartCalibration(ADC_2);
//等待ADC校准完成
while(ADC_GetCalibrationStatus(ADC_2));
//使能ADC2为外部触发
ADC_ExternalTrigConvCmd(ADC_2,ENABLE);
// 由于没有采用外部触发,所以使用软件触发ADC转换
ADC_SoftwareStartConvCmd(ADC_1, ENABLE);
}
void ADCx_Init(void)
{
ADCx_GPIO_Config();
ADCx_Mode_Config();
}
bsp_adc.h
#ifndef _BSP_ADC_H
#define _BSP_ADC_H
#include "stm32f10x.h"
/*
双模式时,ADC1和ADC2转换的数据都存在ADC1的数据寄存器
ADC1的在低16位,ADC2的在高16位
双ADC模式的第一个ADC,必须是ADC1,第二个ADC,必须是ADC2
*/
#define ADC_GPIO_CLK RCC_APB2Periph_GPIOC
#define ADC_PORT GPIOC
#define ADC_1_PIN GPIO_Pin_1
#define ADC_2_PIN GPIO_Pin_4
#define ADC_1 ADC1
#define ADC_2 ADC2
#define NUMCHANNEL 1
#define ADC_1_CHANNEL ADC_Channel_11
#define ADC_2_CHANNEL ADC_Channel_14
#define ADC_1_CLK RCC_APB2Periph_ADC1
#define ADC_2_CLK RCC_APB2Periph_ADC2
#define ADC_DMA_CLK RCC_AHBPeriph_DMA1
#define ADC_DMA_CHANNEL DMA1_Channel1
void ADCx_Init(void);
#endif /*_BSP_ADC_H*/
mian.c
#include "stm32f10x.h"
#include "bsp_led.h"
#include "bsp_usart.h"
#include "./adc/bsp_adc.h"
// ADC 单通道采集,不使用DMA,一般只有ADC2才这样使用,因为ADC2不能使用DMA
extern __IO uint32_t ADC_ConversionValue[NUMCHANNEL];
//局部变量用于保存转换计算后的电压值
float ADC_ConvertedValueLocal[NUMCHANNEL*2] = {0,0};
// 软件延时
void Delay(__IO uint32_t nCount)
{
for(; nCount != 0; nCount--);
}
int main(void)
{
uint16_t temp0 = 0, temp1 = 0;
USART_Config();
ADCx_Init();
printf("\r\n ----这是一个ADC双重模式-多通道-规则同步读取实验----\r\n");
while(1)
{
//取出ADC1数据寄存器高16位,这个是ADC2的转换数据
temp0 = (ADC_ConversionValue[0] & 0XFFFF0000) >>16;
//取出ADC1数据寄存器低16位,这个是ADC1的转换数据
temp1 = (ADC_ConversionValue[0] & 0X0000FFFF);
ADC_ConvertedValueLocal[0] = (float) temp0/4096*3.3;
ADC_ConvertedValueLocal[1] = (float) temp1/4096*3.3;
printf("\r\n ADC1 AD Value = %f V \r\n", ADC_ConvertedValueLocal[1]);
printf("\r\n ADC2 AD Value = %f V \r\n", ADC_ConvertedValueLocal[0]);
printf("\r\n\r\n");
Delay(0xffffee);
}
}