STM32 ADC篇

ADC(Analog-Digital Converter)模拟-数字转换器 :可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量,建立模拟电路到数字电路的桥梁

STM32ADC资源:

  •         12位逐次逼近型ADC,1us转换时间
  •         输入电压范围:0~3.3V,转换结果范围:0~4095
  •         18个输入通道,可测量16个外部和2个内部信号源
  •         规则组和注入组两个转换单元
  •         模拟看门狗自动监测输入电压范围 

ADC框图

        左侧ADCx_INx和内部通道温度传感器、V_REFINT为ADC的18个输入通道,接着进入模拟多路开关,可指定需要的开关,经过开关后进入模数转换器,转换结果放入数据寄存器中,再读取数据寄存器,即可得到ADC转换结果

模拟多路开关:

        在STM32中,模拟多路开关可选择多路通道,转换时可分为两个组:注入通道组和规则通道组,注入通道组最多可选中4个通道,且有四个数据寄存器,规则通道组可一次性最多选中16个通道,但只有一个数据寄存器,故多路输出时需配合DMA。

ADC触发信号源:

        1、软件触发:利用代码触发

        2、硬件触发:由于可能需要频繁触发,为避免使用中断触发导致大大降低cpu运行效率,可采用硬件触发

        3、外部中断触发:通过中断触发ADC

电源电路:

        在输入端上方有V_REF+、V_REF-、V_DDA、V_SSA,前二者是ADC的参考电压,决定ADC输入电压,后二者是ADC供电引脚,一般情况下,前后二者对应的正极接正极,负极接负极

驱动时钟:

                  

        模数转换器右侧ADCCLK是用于驱动内部逐次比较的时钟,来自ADC的预分频器,且最大为14MHz,只能选择6或者8分频,结果为12MHz或者9MHz

模拟看门狗:

        模拟看门狗中可村饭搞一个阈值高限和阈值底限,启动模拟看门狗并指定看门通道后,看门狗会时刻关注对应的通道,一旦超出阈值范围,则会申请模拟看门狗中断通向。

        对于注入组和规则组,转换完成后,也有一个EOC转换完成的信号,其中QOC对应规则组,JEOC对应注入组,会在状态寄存器中置一个标志位,读取标志位即可得知转换是否结束,同时两个标志位也能申请中断

规则组的四种转换模式

        在ADC的初始化结构体中有两个参数,决定了单次转换/连续转换扫描模式/非扫描模式,二者排列组合,即为四种转换模式;其中,单次转换即为一次转换后即停止,下一次触发信号到来时,再进行下一次转换;连续转换则反之,不需要下一个触发信号也能一直转换也无需判断是否转换完成,直接从数据寄存器读取数据即可;非扫描模式下,转换列表中只有第一位有效,一次只能转换一位;扫描模式则反之,一次能转换指定通道数目,并配合DMA存放入数据寄存器

单次转换,非扫描模式

连续转换,非扫描模式

单次转换,扫描模式

连续转换,扫描模式

触发控制

        转换可以由外部事件触发(例如定时器捕获,EXTI线)。如果设置了EXTTRIG控制位,则外部事件就能够触发转换。EXTSEL[2:0]和JEXTSEL2:0]控制位允许应用程序选择8个可能的事件中的 某一个,可以触发规则和注入组的采样。

数据对齐

        数据寄存器为16位,故12位的DMA存在数据对齐的问题

        数据左对齐:12位的数据向右靠,高位补0,读取时直接为结果

        数据右对齐:12位的数据向左靠,低位补0,读取的数据为实际数据*16

转换时间

AD转换的步骤:采样,保持,量化,编码 

STM32 ADC的总转换时间为:  T_CONV = 采样时间 + 12.5个ADC周期

例如:当ADCCLK=14MHz,采样时间为1.5个ADC周期:

        T_CONV = 1.5 + 12.5 = 14个ADC周期 = 1μs

采样时间越大,越能避免部分毛刺信号的干扰;ADC周期即为RCC分频而来的ADCCLK

校准

        ADC有一个内置自校准模式。校准可大幅减小因内部电容器组的变化而造成的准精度误差。校准期间,在每个电容器上都会计算出一个误差修正码(数字值),这个码用于消除在随后的转换中每个电容器上产生的误差,建议在每次上电后执行一次校准,启动校准前, ADC必须处于关电状态超过至少两个ADC时钟周期

实现代码

相关库函数

rcc.h
void RCC_ADCCLKConfig(uint32_t RCC_PCLK2);


adc.h
//规则组
void ADC_DeInit(ADC_TypeDef* ADCx);
void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct);
void ADC_StructInit(ADC_InitTypeDef* ADC_InitStruct);
void ADC_Cmd(ADC_TypeDef* ADCx, FunctionalState NewState);
void ADC_DMACmd(ADC_TypeDef* ADCx, FunctionalState NewState);
void ADC_ITConfig(ADC_TypeDef* ADCx, uint16_t ADC_IT, FunctionalState NewState);
void ADC_ResetCalibration(ADC_TypeDef* ADCx);
FlagStatus ADC_GetResetCalibrationStatus(ADC_TypeDef* ADCx);
void ADC_StartCalibration(ADC_TypeDef* ADCx);
FlagStatus ADC_GetCalibrationStatus(ADC_TypeDef* ADCx);
void ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
FlagStatus ADC_GetSoftwareStartConvStatus(ADC_TypeDef* ADCx);
void ADC_DiscModeChannelCountConfig(ADC_TypeDef* ADCx, uint8_t Number);
void ADC_DiscModeCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime);
void ADC_ExternalTrigConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx);
uint32_t ADC_GetDualModeConversionValue(void);

//注入组
void ADC_AutoInjectedConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
void ADC_InjectedDiscModeCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
void ADC_ExternalTrigInjectedConvConfig(ADC_TypeDef* ADCx, uint32_t ADC_ExternalTrigInjecConv);
void ADC_ExternalTrigInjectedConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
void ADC_SoftwareStartInjectedConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
FlagStatus ADC_GetSoftwareStartInjectedConvCmdStatus(ADC_TypeDef* ADCx);
void ADC_InjectedChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime);
void ADC_InjectedSequencerLengthConfig(ADC_TypeDef* ADCx, uint8_t Length);
void ADC_SetInjectedOffset(ADC_TypeDef* ADCx, uint8_t ADC_InjectedChannel, uint16_t Offset);
uint16_t ADC_GetInjectedConversionValue(ADC_TypeDef* ADCx, uint8_t ADC_InjectedChannel);

//模拟看门狗配置
void ADC_AnalogWatchdogCmd(ADC_TypeDef* ADCx, uint32_t ADC_AnalogWatchdog);
void ADC_AnalogWatchdogThresholdsConfig(ADC_TypeDef* ADCx, uint16_t HighThreshold, uint16_t LowThreshold);
void ADC_AnalogWatchdogSingleChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel);

//开启内部双通道
void ADC_TempSensorVrefintCmd(FunctionalState NewState);

//读取寄存器值、标志位及其清除
FlagStatus ADC_GetFlagStatus(ADC_TypeDef* ADCx, uint8_t ADC_FLAG);
void ADC_ClearFlag(ADC_TypeDef* ADCx, uint8_t ADC_FLAG);
ITStatus ADC_GetITStatus(ADC_TypeDef* ADCx, uint16_t ADC_IT);
void ADC_ClearITPendingBit(ADC_TypeDef* ADCx, uint16_t ADC_IT);

规则组单通道软件触发ADC实现代码

//AD.c
#include "stm32f10x.h"                  // Device header

void AD_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA, ENABLE);
	
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);						//6分频
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;			//模拟输入
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	
	//单通道、多通道配置,若需多通道,则多放几个该函数
	ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_55Cycles5);
	
	ADC_InitTypeDef ADC_InitStructure;
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;		//独立模式
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;	//右对齐
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//软件触发
	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;		//单次转换非扫描模式	
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;
	ADC_InitStructure.ADC_NbrOfChannel = 1;					//一个通道
	ADC_Init(ADC1, &ADC_InitStructure);
	
	ADC_Cmd(ADC1, ENABLE);									//开启AD转换器
	
	//ADC校准
	ADC_ResetCalibration(ADC1);
	while(ADC_GetResetCalibrationStatus(ADC1) == SET);
	ADC_StartCalibration(ADC1);
	while(ADC_GetCalibrationStatus(ADC1) == SET);
	
	//ADC_SoftwareStartConvCmd(ADC1, ENABLE);   				// 使能指定的ADC的软件转换启动功能
}

uint16_t AD_GetValue(void)
{
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);
	while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC) == RESET);
	return ADC_GetConversionValue(ADC1);
}


//main.c
#include "stm32f10x.h"                  // Device header
#include "delay.h"
#include "LED.h"
#include "KEY.h"
#include "OLED.h"
#include "AD.h"

int main(void)
{
	delay_init();
	OLED_Init();
	AD_Init();
	OLED_ShowString(1,1, "ADValue:");
	OLED_ShowNum(1, 9, 0000, 4);
	
	uint16_t AD_Value;
	
	while(1)
	{
		AD_Value = AD_GetValue();
		OLED_ShowNum(1, 9, AD_Value, 4);
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值