32ADC模数转换器&AD单通道&多通道

目录

一.简介

二.逐次逼近法​编辑

三.结构框图

四.小tips

(1)转换模式

(2)触发控制

 (3)数据对齐

(4)转换时间

(5)校准

(6)硬件电路 

五.相关函数

六.代码实现

(1)单通道

(2)多通道


一.简介

32ADC模数转换器&AD单通道&多通道_第1张图片

数字电路只有高低电平,没有几伏电压的概念 

PWM就是DAC的功能,同时PWM只有完全导通和完全断开的两种状态,这两种状态都没有功率损耗

12位(0~2的12次方减1=0~4095),位数越高,量化结果就越精细,对应的分辨率就越高

1us对应AD转换频率为1MHz(最快),ADC转换的信号频率不要超过AD最快转换频率

温度传感器可以测量CPU的温度 

规则组:常规使用;注入组:用于突发事件

模拟看门狗可以检测某些通道,当AD值高于或低于设定的上阈值或低于下阈值时,就会申请中断执行对应的操作

二.逐次逼近法32ADC模数转换器&AD单通道&多通道_第2张图片

32ADC模数转换器&AD单通道&多通道_第3张图片32ADC模数转换器&AD单通道&多通道_第4张图片

三.结构框图

32ADC模数转换器&AD单通道&多通道_第5张图片32ADC模数转换器&AD单通道&多通道_第6张图片32ADC模数转换器&AD单通道&多通道_第7张图片

四.小tips

(1)转换模式

32ADC模数转换器&AD单通道&多通道_第8张图片

每次转换都需要进行触发,且要判断是否结束,并没有使用到列表

32ADC模数转换器&AD单通道&多通道_第9张图片

只用在最开始的时候进行触发,每次转换完成后立刻开始下一次转换,并没有使用到列表

32ADC模数转换器&AD单通道&多通道_第10张图片32ADC模数转换器&AD单通道&多通道_第11张图片

扫描模式下,每个单独的通道转换完之后,不会产生标志位,也不会触发中断 

(2)触发控制

 32ADC模数转换器&AD单通道&多通道_第12张图片

 (3)数据对齐

32ADC模数转换器&AD单通道&多通道_第13张图片

(4)转换时间

32ADC模数转换器&AD单通道&多通道_第14张图片

(5)校准

32ADC模数转换器&AD单通道&多通道_第15张图片

(6)硬件电路 

32ADC模数转换器&AD单通道&多通道_第16张图片32ADC模数转换器&AD单通道&多通道_第17张图片

五.相关函数

32ADC模数转换器&AD单通道&多通道_第18张图片

问题: 

数值跳变得太剧烈、

解决:

(1)

施密特触发原理

32ADC模数转换器&AD单通道&多通道_第19张图片

(2)滤波,让AD值变得平滑

均值滤波,读取多个值,取平均值,作为滤波的AD值

(3)裁剪分辨率,去除数据的尾数

六.代码实现

(1)单通道

AD.c

#include "stm32f10x.h"                  // Device header
uint16_t i;
void AD_Init()
{
	GPIO_InitTypeDef GPIO_InitStructure;//必须要写在程序的开头位置
	ADC_InitTypeDef ADC_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);//ADC都是APB2上的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;
	//在AIN模式下GPIO是无效的,专门为ADC服务
	//断开GPIO,防止GPIO的输入和输出对模拟电压造成干扰
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);//分频设置ADC时钟,ADCCLK=12MHz
	
	
	ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5);
	//若想要在多个序列填充多个通道,可以复制19行进行填充,配置不同的采样时间
	ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right;//数据右对齐
	ADC_InitStructure.ADC_Mode=ADC_Mode_Independent;//配置ADC独立模式
	ADC_InitStructure.ADC_ScanConvMode=DISABLE;//是否为扫描模式
	ADC_InitStructure.ADC_NbrOfChannel=1;//扫描模式下会用到的通道数目
	ADC_InitStructure.ADC_ContinuousConvMode=DISABLE;//配置成单次转换
	ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//不使用外部触发源
	ADC_Init(ADC1,&ADC_InitStructure);
	
	ADC_Cmd(ADC1,ENABLE);//开启ADC电源
	
	ADC_ResetCalibration(ADC1);
	while(ADC_GetResetCalibrationStatus(ADC1) == SET);//复位校准完成后硬件自动置0
	ADC_StartCalibration(ADC1);
	while(ADC_GetCalibrationStatus(ADC1)== SET);//校准完成后硬件自动置0
	
	
}
uint16_t ADC_GetValue(void)
{
	ADC_SoftwareStartConvCmd(ADC1,ENABLE);//软件触发转换
			//软件触发在扫描连续转换模式,要放在ADC_Init结尾
	while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC) == RESET);//软件触发在扫描连续转换模式,可以去除这一句
	//规则组或注入组完成时都会置1,可以由软件清除或由读取ADC_DR时清除
	//等待时间=68/12MHz=5.6us,68=55.5+12.5
	return ADC_GetConversionValue(ADC1);//读取ADC_DR
	
}
float ADC_VA(uint16_t i)
{
	float Temp;
	i=ADC_GetValue();
	Temp = (float)i*3.3/(float)4095;
	return Temp;
}

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"  
#include "OLED.h" 
#include "AD.h" 
uint16_t ADC_Value;
float VA;
int main()
{
	OLED_Init();
	AD_Init();
	OLED_ShowString(1,1,"ADC:");
	OLED_ShowString(2,1,"Va:0.00V");
	while(1)
	{
		ADC_Value=ADC_GetValue();
		VA=ADC_VA(ADC_Value);
		OLED_ShowNum(1,5,ADC_Value,5);
		OLED_ShowNum(2,4,VA,1);
		OLED_ShowNum(2,6,(int)(VA*100)%100,2);
	}	
}
	

(2)多通道

多通道的实现最好采用DMA转运数据,但这里还没有学到,所以不采用真正的多通道实现

可以用单次转换,非扫描模式,每转换一个通道就用ADC_RegularChannelConfig(ADC1,ADC_Channel,1,ADC_SampleTime_55Cycles5);

对通道进行更新,多次读值

AD.c

#include "stm32f10x.h"                  // Device header
uint16_t i;
void AD_Init()
{
	GPIO_InitTypeDef GPIO_InitStructure;//必须要写在程序的开头位置
	ADC_InitTypeDef ADC_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);//ADC都是APB2上的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;
	//在AIN模式下GPIO是无效的,专门为ADC服务
	//断开GPIO,防止GPIO的输入和输出对模拟电压造成干扰
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);//分频设置ADC时钟,ADCCLK=12MHz
	
	
	//若想要在多个序列填充多个通道,可以复制19行进行填充,配置不同的采样时间
	ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right;//数据右对齐
	ADC_InitStructure.ADC_Mode=ADC_Mode_Independent;//配置ADC独立模式
	ADC_InitStructure.ADC_ScanConvMode=DISABLE;//是否为扫描模式
	ADC_InitStructure.ADC_NbrOfChannel=1;//扫描模式下会用到的通道数目
	ADC_InitStructure.ADC_ContinuousConvMode=DISABLE;//配置成单次转换
	ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//不使用外部触发源
	ADC_Init(ADC1,&ADC_InitStructure);
	
	ADC_Cmd(ADC1,ENABLE);//开启ADC电源
	
	ADC_ResetCalibration(ADC1);
	while(ADC_GetResetCalibrationStatus(ADC1) == SET);//复位校准完成后硬件自动置0
	ADC_StartCalibration(ADC1);
	while(ADC_GetCalibrationStatus(ADC1)== SET);//校准完成后硬件自动置0
}
uint16_t ADC_GetValue(uint8_t ADC_Channel)
{
	ADC_RegularChannelConfig(ADC1,ADC_Channel,1,ADC_SampleTime_55Cycles5);

	ADC_SoftwareStartConvCmd(ADC1,ENABLE);//软件触发转换
	while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC) == RESET);
	//规则组或注入组完成时都会置1,可以由软件清除或由读取ADC_DR时清除
	//等待时间=68/12MHz=5.6us,68=55.5+12.5
	return ADC_GetConversionValue(ADC1);//读取ADC_DR
}

main.c 

#include "stm32f10x.h"                  // Device header
#include "Delay.h"  
#include "OLED.h" 
#include "AD.h" 
uint16_t AD1,AD2,AD3,AD4;
float VA;
int main()
{
	OLED_Init();
	AD_Init();
	OLED_ShowString(1,1,"AD1:");
	OLED_ShowString(2,1,"AD2:");
	OLED_ShowString(3,1,"AD3:");
	OLED_ShowString(4,1,"AD4:");
	

	while(1)
	{
		AD1 = ADC_GetValue(ADC_Channel_0);
		AD2 = ADC_GetValue(ADC_Channel_1);
		AD3 = ADC_GetValue(ADC_Channel_2);
		AD4 = ADC_GetValue(ADC_Channel_3);
		OLED_ShowNum(1,5,AD1,5);
		OLED_ShowNum(2,5,AD2,5);
		OLED_ShowNum(3,5,AD3,5);
		OLED_ShowNum(4,5,AD4,5);
		Delay_ms(100);

	}	
}

32ADC模数转换器&AD单通道&多通道_第20张图片32ADC模数转换器&AD单通道&多通道_第21张图片

你可能感兴趣的:(单片机,嵌入式硬件)