STM32-ADC模数转换器

目录

一、ADC简介

二、逐次逼近型ADC内部结构

三、STM32内部ADC转换结构

四、ADC基本结构

五、输入通道

六、转换模式

6.1单次转换,非扫描模式

6.2连续转换,非扫描模式

6.3单次转换,扫描模式

6.4连续转换,扫描模式

七、触发控制

​编辑

八、数据对齐

九、转换时间

十、硬件电路

十一、开发步骤

十二、ADC库函数

十三、实验

[13.1 AD单通道](#13.1 AD单通道)

[13.2 AD多通道](#13.2 AD多通道)


一、ADC简介

>ADC(Analog-Digital Converter)模拟-数字转换器

>ADC可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量,建立模拟电路到数字电路的桥梁

>12位逐次逼近型ADC(表示范围:0-2^12-1(4095)),1us转换时间(频率:1MHz)

>输入电压范围:0~3.3V,转换结果范围:0~4095

>18个输入通道,可测量16个外部和2个内部信号源

>规则组和注入组两个转换单元

>模拟看门狗自动监测输入电压范围

>STM32F103C8T6 ADC资源:ADC1、ADC2,10个外部输入通道

二、逐次逼近型ADC内部结构

三、STM32内部ADC转换结构

ADCCLK来源于APB2

四、ADC基本结构

五、输入通道

六、转换模式

6.1单次转换,非扫描模式

6.2连续转换,非扫描模式

6.3单次转换,扫描模式

6.4连续转换,扫描模式

七、触发控制

八、数据对齐

(一般采用右对齐,读出来的数据直接就是结果)

九、转换时间

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

②STM32 ADC的总转换时间为:

TCONV = 采样时间 + 12.5个ADC周期(12位)

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

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

十、硬件电路

十一、开发步骤

①开启RCC时钟,包括ADC和GPIO,ADCCLK的分频器也要配置

②配置GPIO,模拟输入模式

③配置多路开关,将通道接入规则组列表中

④结构体配置ADC转换器(单次/多次、扫描/非扫描、通道数、触发源、数据对齐方式)

(可选)⑤模拟看门狗,配置阈值和监测通道,开启中断ITConfig,NVIC

⑤开关控制,调用ADC_Cmd函数,开启ADC,校准

十二、ADC库函数

/*rcc.h*/

void RCC_ADCCLKConfig(uint32_t RCC_PCLK2);

作用:配置ADCCLK分频器

/*adc.h*/

void ADC_DeInit(ADC_TypeDef* ADCx);//恢复缺省配置

void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct);//Init初始化

void ADC_StructInit(ADC_InitTypeDef* ADC_InitStruct);//StructInit结构体初始化

void ADC_Cmd(ADC_TypeDef* ADCx, FunctionalState NewState);//使能ADC

void ADC_DMACmd(ADC_TypeDef* ADCx, FunctionalState NewState);//开启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);//获取开始校准状态

=====================================================================

void ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);

//ADC_软件开始转换控制,用于软件触发的函数(重要)

FlagStatus ADC_GetSoftwareStartConvStatus(ADC_TypeDef* ADCx);

//ADC获取软件开始转换状态(一般不用)

============================间断模式==================================

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

②ADC_Channel,通道

③Rank,序列几的位置

④ADC_SampleTime,指定通道的采样时间

=====================================================================

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

//获取标志位状态

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

//清除中断挂起位状态

十三、实验

13.1 AD单通道

实验现象:用电位器产生一个0~3.3V连续变化的模拟电压信号,接到PA0,ADC读取数据显示到屏幕上

参考代码:

AD.c

复制代码
#include "stm32f10x.h"                  // Device header

//*本例程使用连续非扫描模式,软件触发一次即可*//
void AD_Init(void)
{
	/*一、开启RCC时钟(ADC,GPIO)*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	
	//ADCCLK分频
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);//72MHz/6=12MHz
	
	/*二、配置GPIO,模拟输入*/
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	/*三、配置多路开关,左边通道接入右边规则组列表(选择规则组的注入通道)*/
	ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5);
	
	/*四、配置ADC转换器*/
	ADC_InitTypeDef ADC_InitStructure;
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;//工作模式(独立/双ADC)
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//数据对齐(左/右)
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//触发源,此处使用软件触发
	ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;//连续转换/单次转换
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;//扫描/非扫描
	ADC_InitStructure.ADC_NbrOfChannel = 1;
	ADC_Init(ADC1,&ADC_InitStructure);//扫描模式下用到几个通道
	
	/*五、开关控制,开启ADC*/
	ADC_Cmd(ADC1,ENABLE);   
	
	//校准
	ADC_ResetCalibration(ADC1);//复位校准
	while(ADC_GetResetCalibrationStatus(ADC1) == SET);//等待复位校准完成
	ADC_StartCalibration(ADC1);//启动校准
	while(ADC_GetCalibrationStatus(ADC1) == SET);//等待校准是否完成
	
	ADC_SoftwareStartConvCmd(ADC1,ENABLE);
}

uint16_t AD_GetValue(void)
{
	return ADC_GetConversionValue(ADC1);
}

AD.h

复制代码
#ifndef __AD_H
#define __AD_H

void AD_Init(void);
uint16_t AD_GetValue(void);

#endif

main.c

复制代码
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "AD.h"

uint16_t ADValue;//AD值
float Voltage;//电压值

int main(void)
{
	OLED_Init();
	AD_Init();
	
	OLED_ShowString(1,1,"ADValue:");
	OLED_ShowString(2,1,"Voltage:0.00V");
	
	while (1)
	{
		ADValue = AD_GetValue();
		Voltage = (float)ADValue/4095*3.3;
		
		OLED_ShowNum(1,9,ADValue,4);
		OLED_ShowNum(2,9,Voltage,1);//整数
		OLED_ShowNum(2,11,(uint16_t)(Voltage*100)%100,2);//小数部分
		
		Delay_ms(100);
	}
}

*OLED代码参考本专栏文章STM32-OLED

13.2 AD多通道

实验设置:将电位器、光敏电阻、热敏电阻、反射红外模块的AO(模拟电压输出端)分别接到PA0/PA1/PA2/PA3

参考代码:

AD.c

复制代码
#include "stm32f10x.h"                  // Device header

//*本例程使用单次非扫描模式*//
void AD_Init(void)
{
	/*一、开启RCC时钟(ADC,GPIO)*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	
	//ADCCLK分频
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);//72MHz/6=12MHz
	
	/*二、配置GPIO,模拟输入*/
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
	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);
	
	/*四、配置ADC转换器*/
	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*/
	ADC_Cmd(ADC1,ENABLE);   
	
	//校准
	ADC_ResetCalibration(ADC1);//复位校准
	while(ADC_GetResetCalibrationStatus(ADC1) == SET);//等待复位校准完成
	ADC_StartCalibration(ADC1);//启动校准
	while(ADC_GetCalibrationStatus(ADC1) == SET);
	
}

uint16_t AD_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);//通过标志位来查看是否转换完成
	return ADC_GetConversionValue(ADC1);
}

AD.h

复制代码
#ifndef __AD_H
#define __AD_H

void AD_Init(void);
uint16_t AD_GetValue(uint8_t ADC_Channel);

#endif

main.c

复制代码
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "AD.h"

uint16_t AD0,AD1,AD2,AD3;

int main(void)
{
	OLED_Init();
	AD_Init();
	
	OLED_ShowString(1,1,"AD0:");
	OLED_ShowString(2,1,"AD1:");
	OLED_ShowString(3,1,"AD2:");
	OLED_ShowString(4,1,"AD3:");

	
	while (1)
	{
		AD0 = AD_GetValue(ADC_Channel_0);
		AD1 = AD_GetValue(ADC_Channel_1);
		AD2 = AD_GetValue(ADC_Channel_2);
		AD3 = AD_GetValue(ADC_Channel_3);
		
		OLED_ShowNum(1,5,AD0,5);
		OLED_ShowNum(2,5,AD1,5);
		OLED_ShowNum(3,5,AD2,5);
		OLED_ShowNum(4,5,AD3 ,5);
		
		Delay_ms(100);
	}
}
相关推荐
酷飞飞6 分钟前
RTC和看门狗基于GD32F407VE的天空星的配置
stm32·单片机·嵌入式硬件·mcu
qq_401700411 小时前
STM32的HardFault错误处理技巧
stm32
WD137298015572 小时前
WD5030A,24V降5V,15A 大电流,应用于手机、平板、笔记本充电器
stm32·单片机·嵌入式硬件·智能手机·汽车·电脑·51单片机
日更嵌入式的打工仔2 小时前
GPIO 中断通用配置指南
stm32·单片机·嵌入式硬件
平凡灵感码头2 小时前
基于 STM32 的智能门锁系统,系统界面设计
stm32·单片机·嵌入式硬件
Truffle7电子3 小时前
STM32理论 —— 存储、中断
stm32·嵌入式硬件·嵌入式·存储·中断
报错小能手3 小时前
linux学习笔记(32)网络编程——UDP
单片机·嵌入式硬件
XiangrongZ5 小时前
江协科技STM32课程笔记(四)—定时器TIM(输入捕获)
笔记·科技·stm32
xyx-3v5 小时前
SPI四种工作模式
stm32·单片机·嵌入式硬件·学习
qiuiuiu4136 小时前
正点原子RK3568学习日志6-驱动模块传参
linux·c语言·开发语言·单片机·学习