ADC_STM32

一、ADC简介

  • ADC(Analog-Digital Converter)模拟-数字转换器
  • ADC可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量,建立模拟电路到数字电路的桥梁。(即将引脚上的模拟电压转化为寄存器中的数字变量,供MCU使用
  • STM32中的ADC外设,是12位逐次逼近型ADC,转化频率为1MHZ(即1微秒转化一次)
    • 逐次逼近型ADC:通过一个DAC生成对比电压,与端口电压进行比较,再改变DAC生成的电压重新比较,用二分法找出端口电压。
  • 输入电压范围:0-3.3V;转换结果范围:0-4095(即2^12-1),中间都为一一对应的线性关系
  • STM32的ADC最多有18个输入通道,可测量16个外部(GPIO口)和2个内部(内部CPU温度传感器、内部基准电压)信号源
  • STM32的ADC可以一次性对一个组的模拟电压进行转换,而不需要一个一个进行转化。有两个转换单元:规则组(常规使用)、注入组(突发事件)
    • 在ADC转换器中(DAC电压与端口电压比较的过程),可以一次选中多个通道同时比较,规则组最多可选择16个通道,注入组最多可以选择4个通道。
    • 规则组只有一个数据寄存器,这导致多个通道同时进行ADC转换的话,会出现数据覆盖的情况,可以和DMA配合使用。
    • 注入组有四个数据寄存器,多个通道同时进行ADC转换也不会出现数据覆盖。
  • ADC触发控制的方式有两种:
    • 软件触发:程序调用代码,触发ADC转换。
    • 硬件触发:指定触发源(来自定时器)触发ADC转换。
  • ADC外设中有模拟看门狗,可以自动监测输入电压范围,在输入电压超过阈值高限/低限时,自动触发中断

二、ADC基本结构

ADC_STM32_第1张图片

  • AD转换器转换完成后有一个EOC信号输出,可以通向NVIC申请中断
  • AD转换器工作模式可以选择:单次转换/连续转换,扫描模式/非扫描模式
    • 非扫描模式一次只能对一个通道进行AD转换,扫描模式能够对序列中的通道都进行AD转换
    • 连续转换模式只需要AD触发控制信号触发一次,就能持续的执行AD转换,单次转换模式每次触发控制信号触发一次只能执行一次AD转换。
  • 由于AD转换器是12位的,但数据寄存器确是16位的,因此可以选择数据是左对齐还是右对齐,一般使用右对齐,高位补零,此时直接读取即为AD转换结果。
  • ADC配置流程:开启RCC时钟(ADC, GPIO) → 配置ADCCLK分频器 → 配置GPIO → 配置多路开关 → 配置ADC转换器 → (如果需要)配置模拟看门狗,配置NVIC → 开关控制,开启ADC → 校准

三、配置ADC

'1.开启RCC时钟'
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);		// ADC在总线APB2上
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
'2.配置ADCCLK分频器'
RCC_ADCCLKConfig(RCC_PCLK2_DIV6);		// ADCCLK配置函数,在rcc.h文件中;可以选择2,4,6,8分频
'3.配置GPIO'
// 略,需要配置为AIN模拟输入模式
'4.配置多路开关'
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_1Cycle5);
// ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_1Cycle5);	// 配置多通道就依次配置即可
'5.配置ADC转换器'
ADC_InitTypeDef ADC_InitStructure;						// 定义结构体变量
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;		// 配置ADC工作模式(独立ADC模式/双ADC模式)
ADC_InitStructure.ADC_ScanConvMode = DISABLE;			// 配置扫描/非扫描模式,此处DISABLE表示非扫描模式
ADC_InitStructure.ADC_NbrOfChannel = 1;					// 配置扫描模式下的通道数目
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;		// 配置连续/单次转换模式,此处DISABLE表示单次转换模式
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;	// 配置触发控制的触发源,此处选择软件触发
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;	// 配置ADC数据寄存器左/右对齐

ADC_Init(ADC1,&ADC_InitStructure);
'6.(如果需要)配置模拟看门狗和NVIC'
'7.开关控制,开启ADC'
ADC_Cmd(ADC1, ENABLE);
'8.校准'
// 依次调用校准相关的函数即可
ADC_ResetCalibration(ADC1);
while(ADC_GetResetCalibrationStatus(ADC1) == SET);	// 此处循环,等待标志位其置1,表示复位校准完成
ADC_StartCalibration(ADC1);
while (ADC_GetCalibrationStatus(ADC1) == SET);		// 此处循环,等待标志位置1,表示校准完成
'*.ADC初始化已完成,还需编写函数以软件触发ADC并获取结果'
uint16_t AD_GetValue(void)
{
	ADC_SoftwareStartConvCmd(ADC, ENABLE);		// 开启软件触发ADC
	while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);		// 循环等待AD转换完成
	return ADC_GetConversionValue(ADC1);		// 返回AD转换结果
}

四、ADC常用库函数

void ADC_DeInit(ADC_TypeDef* ADCx);
		// 复位函数
void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct);
		// ADC初始化函数
void ADC_StructInit(ADC_InitTypeDef* ADC_InitStruct);
		// 结构体初始化函数
void ADC_Cmd(ADC_TypeDef* ADCx, FunctionalState NewState);
		// 开关控制函数,用于开启ADC
void ADC_DMACmd(ADC_TypeDef* ADCx, FunctionalState NewState);
		// DMA开启函数,用于开启DMA输出信号
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);
		// 以上四个为ADC校准相关函数,ADC初始化完成后,依次调用即可
void ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
		// ADC软件触发函数
FlagStatus ADC_GetSoftwareStartConvStatus(ADC_TypeDef* ADCx);
		// 获取SWSTART标志位,但实际上该标志位并不能用来判断AD是否转换完成,因此该函数基本无用。
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);
		// ADC规则组通道配置函数,即配置规则组的转换序列的函数
		// 参数:ADCx;通道号;序列号;采样时间
void ADC_ExternalTrigConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
		// ADC外部触发转换控制函数
uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx);
		// 获取ADC转换值,即读取转换结果
uint32_t ADC_GetDualModeConversionValue(void);
		// 获取双ADC模式转换值
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);
		// 以上9个函数是对注入组的配置,略
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);
		// ADC温度传感器、参考电压控制,用于开启内部的两个通道
FlagStatus ADC_GetFlagStatus(ADC_TypeDef* ADCx, uint8_t ADC_FLAG);
		// 获取标志位状态,可用于判断AD转换是否完成
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的实现:
    • 扫描模式+DMA转运:最优解
    • 扫描模式+手动转运数据:由于扫描模式下多通道全部完成ADC转换后EOC标志位才置1,因此需要使用间断模式,每完成一个通道的AD转换就间断一次 → Delay → 手动转运 → 转换下一个通道,但效率低下
    • 非扫描模式+单次转换,但多次调用软件触发函数,实现多通道的ADC。

Reference
STM32入门教程-2023版(江科大)

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