ADC - 模拟数字转换(单多通道以及中断或DMA读取详细实例)

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);
    
  }
	
  
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值