STM32--ADC

一、简介

*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、单次转换,非扫描模式

*单次转换模式下, ADC 只执行一次转换(如果需要再进行转换需要软件来执行)
*如果一个规则通道被转换:转换数据被储存在 16 ADC_DR寄存器中,EOC( 转换结束 )标志被设置为1,如果设置了 EOCIE ,则产生中断。
*非扫描模式,只能用于只有一个转换通道,有多个转换通道时要设置扫描模式

2、连续转换,非扫描模式

 
*在连续转换模式中,当前面 ADC 转换一结束马上就启动另一次转换。此模式可通过外部触发启
动或通过设置 ADC_CR2 寄存器上的 ADON 位启动,此时 CONT 位是 1
*如果一个规则通道被转换:转换数据被储存在 16 ADC_DR寄存器中,EOC( 转换结束 )标志被设置为1,如果设置了 EOCIE ,则产生中断。
*非扫描模式,只能用于只有一个转换通道,有多个转换通道时要设置扫描模式

3、单次转换,扫描模式

*ADC规则通道的转换次序是由由序列1到序列16依次转换(有通道就转换没通道就跳过),如果转换次序需要较高优先级,那就要把该通道放在靠前序列
*连续转换模式是当前面ADC转换一结束马上就启动另一次转换。此模式可通过外部触发启动或通过设置ADC_CR2寄存器上的ADON位启动,此时CONT位是1。
*扫描模式只用于一个规则组中有多个通道需要转换的情况

4、连续转换,扫描模式

*在连续转换模式中,当前面 ADC 转换一结束马上就启动另一次转换。此模式可通过外部触发启
动或通过设置 ADC_CR2 寄存器上的 ADON 位启动,此时 CONT 位是 1
*如果一个规则通道被转换:转换数据被储存在 16 ADC_DR寄存器中,EOC( 转换结束 )标志被设置为1,如果设置了 EOCIE ,则产生中断。
*扫描模式只用于一个规则组中有多个通道需要转换的情况
PS:转换序列里可以可以出现多个相同的转换通道

四、转换顺序

通过设置寄存器里面不同的值,来配置不同通道的转换顺序以及转换的总通道数量

规则通道:

注入通道:

五、代码

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读取_同步规则

*此模式在 规则通道组 上执行。外部触发来自 ADC1 的规则组多路开关 ( ADC1_CR2 寄存器的
EXTSEL[2:0] 选择 ) 它同时给 ADC2 提供同步触发。
*不要在2个ADC上转换相同的通道((两个ADC在同一个通道上的采样时间不能重善)。
* ADC1 ADC2 的转换结束时:产生一个32位DMA传输请求(如果设置了DMA位),32位的ADC1_DR寄存器内容传输到SRAM中,它 上半个字包含ADC2的转换数据, 低半个字包含ADC1的转换数据。
* 当所有 ADC1/ADC2 规则通道都被转换完时,产生 EOC 中断 ( 若任一 ADC 接口开放了中断 )
#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的中断有自己的中断向量。

* ADC_SR 寄存器中有 2 个其他标志,但是它们没有相关联的中断:

九、数据对齐

*ADC_CR2 寄存器中的 ALIGN 位选择转换后数据储存的对齐方式。数据可以左对齐或右对齐
*
注入组通道转换的数据值已经减去了在 ADC_JOFRx 寄存器中定义的偏移量,因此结果可以是一
个负值。 SEXT 位是扩展的符号值。
*对于规则组通道,不需减去偏移值,因此只有 12 个位有效。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/676053.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于Springboot+vue实现的汽车服务管理系统

作者主页&#xff1a;Java码库 主营内容&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app等设计与开发。 收藏点赞不迷路 关注作者有好处 文末获取源码 技术选型 【后端】&#xff1a;Java 【框架】&#xff1a;spring…

Java开发:Spring Boot 实战教程

序言 随着技术的快速发展和数字化转型的深入推进&#xff0c;软件开发领域迎来了前所未有的变革。在众多开发框架中&#xff0c;Spring Boot凭借其“约定大于配置”的核心理念和快速开发的能力&#xff0c;迅速崭露头角&#xff0c;成为当今企业级应用开发的首选框架之一。 《…

露营地管理小程序基于ThinkPHP+FastAdmin+UniApp开发

应用介绍 本文来自&#xff1a;露营地管理小程序基于ThinkPHPFastAdminUniApp开发 - 源码1688 基于ThinkPHPFastAdminUniApp开发的现代化的露营地管理小程序&#xff0c;是专为露营业务设计开发小程序应用。平台拥有多角色管理&#xff0c;同时具有营位预定、门票购买等功能模…

OrangePi AI Pro 测试体验

感谢CSDN活动提供的OrangePi AI Pro &#xff0c;之前一直用的树莓派&#xff0c;正好体验一下新的国产设备&#xff0c; 1、开机体验 整个设备包装不错&#xff0c;链接键盘、屏幕和鼠标&#xff0c;整体开机体验不错&#xff0c;内置OS不错&#xff0c;这个系统内嵌了中文输…

C语言,排序

前言 排序&#xff0c;可以说是数据结构中必不可缺的一环。我们创造数据存储它&#xff0c;要想知道数据之间的联系&#xff0c;比较是必不可少的。不然&#xff0c;费劲心思得来的数据若是不能有更多的意义&#xff0c;那么拿到了又有什么用&#xff1f; 排序是计算机内经常进…

老挝语翻译通App中国人出门在外都在用的老挝语翻译工具,支持老挝文OCR识别、文字转语音、老挝语背单词学习等等功能!

老挝语翻译通App&#xff0c;一款更加符合中国人用语习惯的翻译工具&#xff0c;在国内外都能正常使用的翻译器。当大家选择去东南亚国家旅游、GAP的时候&#xff0c;老挝这个国家是值得一去的&#xff0c;可以让大家感受到另一番风情。 但是&#xff0c;在去之前&#xff0c;需…

关于序列化与反序列化解题

1、[安洵杯 2019]easy_serialize_php <?php$function $_GET[f];function filter($img){$filter_arr array(php,flag,php5,php4,fl1g);$filter /.implode(|,$filter_arr)./i;return preg_replace($filter,,$img); }if($_SESSION){unset($_SESSION); }$_SESSION["use…

Linux学习笔记:日志文件的编写

日志文件Log.hpp 日志文件的作用简单的日志文件编写 日志文件的作用 日志文件可以很好的帮我们显示出程序运行的信息,例如,进程pid,运行时间,运行状况等,通过日志记录程序的执行路径、变量值、函数调用等&#xff0c;可以帮助我们快速定位和修复代码中的错误。 简单的日志文件…

UMG绝对坐标与局部空间

在 Unreal Engine 的 UMG&#xff08;Unreal Motion Graphics&#xff09;中&#xff0c;“绝对坐标”和“局部空间”是两个常见的概念&#xff0c;主要用于描述 UI 元素的位置和大小。 概念与区别 绝对坐标&#xff08;Absolute Coordinates&#xff09;&#xff1a;这是指相…

LeetCode1137第N个泰波那契数

题目描述 泰波那契序列 Tn 定义如下&#xff1a; T0 0, T1 1, T2 1, 且在 n > 0 的条件下 Tn3 Tn Tn1 Tn2给你整数 n&#xff0c;请返回第 n 个泰波那契数 Tn 的值。 解析 递归应该会超时&#xff0c;可以用循环&#xff0c;或者官方解法的矩阵的幂。 public int tr…

索尼CEO宣布全力推进AI电影制作,《蜘蛛侠》制片人坚称不用AI

原标题&#xff1a;索尼互娱制片人与CEO唱反调 易采游戏网6月3日消息&#xff1a;在最近的一次行业会议上&#xff0c;索尼影业高层首席执行官托尼文西奎拉向媒体透露&#xff0c;索尼正在全力推进人工智能(AI)技术的研发与应用&#xff0c;特别是在电影制作流程中。这一策略旨…

彩光大放异彩!《智慧园区以太全光网络建设技术规程》应用案例征集活动结果公布

近日,中国建筑业协会绿色建造与智能建筑分会正式公布了《智慧园区以太全光网络建设技术规程》应用案例征集活动的结果。本次活动旨在推广和应用该规程,进一步推动智慧园区的数字化、智慧化、绿色化建设。众多优秀项目在征集活动中脱颖而出,展示了规程在实际应用中的显著成效。评…

数据结构--关键路径

事件v1-表示整个工程开始&#xff08;源点&#xff1a;入度为0的顶点&#xff09; 事件v9-表示整个工程结束&#xff08;汇点&#xff1a;出度为0的顶点&#xff09; 关键路径&#xff1a;路径长度最长的路径 求解关键路径问题&#xff08;AOE网&#xff09; 定义四个描述量 …

数青蛙 ---- 模拟

题目链接 题目: 分析: 题目的意思是: 一次蛙鸣是一个完整的字符串"croak", 给你一个字符串, 让你求出最少的青蛙数目 示例一: 两次完整的"croak", 可以由一只青蛙完成, 所以答案为1 示例二: 第一次蛙鸣还没有结束, 又出现了"c", 说明有第二只青…

迪丽热巴与大姐的璀璨友情

迪丽热巴与“大姐”的璀璨友情&#xff1a;星光熠熠&#xff0c;友谊长存在娱乐圈的繁华舞台上&#xff0c;有两位耀眼的女星&#xff0c;她们如同夜空中亮的两颗星&#xff0c;交相辉映&#xff0c;共同谱写着一段段动人的佳话。她们&#xff0c;一个是被亲切称为“迪迪”的迪…

03_初识Spring Cloud Gateway

文章目录 一、网关简介1.1 网关提出的背景1.2 网关在微服务中的位置1.3 网关的技术选型1.4 补充 二、Spring Cloud Gateway的简介2.1 核心概念&#xff1a;路由&#xff08;Route&#xff09;2.2 核心概念&#xff1a;断言&#xff08;Predicate&#xff09;2.3 核心概念&#…

【算法训练记录——Day24】

Day24——回溯算法Ⅰ 77.组合 今日内容&#xff1a; ● 理论基础 ● 77. 组合 理论&#xff1a;代码随想录 77.组合 思路&#xff1a;k层for循环&#xff0c;不会 回溯&#xff0c;将组合问题抽象成n叉树&#xff0c;for循环控制宽度&#xff0c;递归的深度控制二叉树的深度 …

云原生架构案例分析_3.某快递公司核心业务系统云原生改造

名称解释&#xff1a; 阿里云ACK&#xff1a;阿里云容器服务 Kubernetes 版 ACK&#xff08;Container Service for Kubernetes&#xff09;集成Kubernetes网络、阿里云VPC、阿里云SLB&#xff0c;提供稳定高性能的容器网络。本文介绍ACK集群网络及阿里云网络底层基础设施的重要…

抄袭瓜!斯坦福作者已删库跑路!面壁和刘知远老师的最新回应

好家伙&#xff0c;AI大模型圈爆料不断&#xff0c;没想到今天最猛的料还是抄袭的瓜啊。 5月29日&#xff0c;一个斯坦福团队高调宣称&#xff0c;只需要500美元&#xff0c;就可以通过他们的新产品&#xff1a;Llama3-v &#xff0c;就可以通过Llama3&#xff0c;训练出一个全…

第二十五章CSS中的技巧(导航栏、下拉列表)

1.CSS精灵 1.什么是CSS精灵 英文叫法 CSS sprites&#xff0c;通常被解释为“CSS图像拼合”或“CSS贴图定位”;其实就是把网页中一些背景图片整合到一张图片文件中&#xff0c;再利用css“background-image”&#xff0c; “background-repeat”,“background-position”的组…