一、ADC简介

1.ADC简介

小玩笑:ADC是指物理输出核心也就是游戏中常说的射手,哈哈哈哈哈开个玩笑,正式开始。   

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

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

        STM32的ADC是12位逐次逼近型ADC工作模式),1us转换时间

        分辨率:指 ADC 能区分的最小模拟信号变化,一般用多少位来表示,12位的AD值,表示范围为0~2^{12}-1, 量化结果为0~4095,位数越高,量化结果越精细,对应分辨率越高,分辨率越高,转换后的数字信号越接近原始模拟信号,但电路复杂度和成本也会增加。

        转换时间(频率):从AD转换开始到产生结果,需要花1us的时间,对应AD转换的频率就是1MHz。

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

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

        16个外部信号:16个GPIO口

        2个内部信号:内部温度传感器(CPU温度)、内部参考电压(1.2V的基准电压)

        ADC增强单元:规则组(常规事件)和注入组(突发事件)两个转换单元

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

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

2.逐次逼近型ADC(内部结构)

        既然STM32的ADC工作模式是逐次逼近型,那么我们首先来了解一下ADC逐次逼近型内部结构,注意这里不是STM32中的内部结构,而是独立的8位逐次逼近型ADC芯片。

        首先输入通道选择:下面地址锁存和译码,ADDA,ADDB,ADDCADDA、ADDB、ADDC 是 3 根地址线,它们通过二进制编码来指定要选择的模拟输入通道。例如, ADDC = 0、ADDB = 1、ADDA = 0 时,根据表格可知,此时选中的是 IN2 通道,然后给一个ALE锁存信号,即 IN2 通道上的模拟信号将被送入后续的转换电路进行处理。IN0~IN7是8路输入通道,通过通道选择开关,选中一路。

        如何知道这个电压对应的编码数据是多少?这就需要使用逐次逼近的方法来一一比较,输入通道选择完毕后,进入输入比较器,它可以判断两个输入信号电压的大小关系,输出一个高低电平指示谁大谁小,现在输入比较器有两个输入端,一个是待测的电压(外部通道输入的,未知编码的电压),另一个是DAC电压输出端(DAC输出的已知编码的电压),如果DAC输出的电压较大,那就调小DAC数据,如果DAC输出的电压较小,那就增大DAC数据,直到DAC输出的电压和外部通道输入的电压近似相等,这样DAC输入的数据就是外部电压的编码器数据。

        AD转换结束后,DAC的输入数据,就是外部电压的编码器数据,通过DAC右边箭头输出,进入8位三态锁存缓冲器,然后通过D0~D7输出。EOC是转换结束信号。START是开始转换,给一个输入脉冲,开始转换。CLOCK是ADC时钟,因为ADC内部是一步一步进行判断的,所以需要时钟来进行推动。下面VREF(+)和VREF(-)是DAC的参考电压。VVC和GND是整个芯片电路的固定。

        为了最快找到未知电压的编码,通常使用二分法进行寻找,比如图上为8位的ADC,那么编码就是0~255,第一次比较的时候,给ADC输入255的一半,进行比较,依次进行比较。

3.STM32逐次逼近型ADC(内部结构)

 

 

        左边是ADC的输入通道,包括16个GPIO口IN0~IN15和两个内部的通道,一个是内部温度传感器,另一个是内部参考电压,总共18个输入通道 ,然后到达模拟多路开关(指定想要选择的通道),右边是多路开关的输出,进入模数转换器(这个转换寄存器就是上面的逐次逼近型ADC),转换结果会直接放在数据寄存器里,模拟多路开关这里分为规则通道和注入通道,规则通道最多可以进行16个模数转换,但是规则组寄存器一次只能存取一个值,所以需要搭配DMA使用。注入通道最多可以进行4个模数转换,注入寄存器可以存取四个值,所以可以直接使用。

        接下来是外围信号电路的讲解,左下角是触发转换的部分,也就是逐次逼近型ADC结构图中的START信号,那么STM32触发ADC转换的信号有两种,一种是软件触发,就是程序中手动调用一条代码,就可以启动转换。另一种是硬件触发,就是图中的TIM1_TRGO一部分为注入组的触发源和TIM_CH1一部分为规则组的触发源。

        左上角为VREF+,VREF-,VDDA,VSSA,前两个为ADC的参考电压,决定了ADC输入电压的范围,后面两个为ADC的供电引脚,一般情况下VREF+接VDDA,VREF-接VSSA。

        右边ADCCLK,是ADC的时钟也就是逐次逼近型ADC结构图中的CLOCK,用于驱动内部逐次比较的时钟,来自于ADC预分频器,ADC预分频器来源于RCC。

        上面部分EOC是规则组的完成信号,JEOC是注入组的完成信号,这两个信号会在状态寄存器里置一个标志位,读取标志位,就知道是否转换结束。

4.ADC基本结构

        这幅图就是对STM32ADC最基本的结构总结,首先数据选择器左边有16个GPIO口和两个内部通道,经过数据选择器选择需要ADC转换的通道,上面的16代表 规则组转换,规则通道最多可以进行16个模数转换,但是规则组寄存器一次只能存取一个值,下面的四对应注入通道最多可以进行4个模数转换,注入寄存器可以存取四个值。下面为触发控制和时钟选择,如果需要中断,则配置中断控制输出及其NVIC,最后使能ADC。

5.规则组的四种转换模式

        ①单次转换,非扫描模式

                每次ADC转换只能选择一个通道并进行一次转换,转换完成后置EOC标志位,如果需要再次转换,就需要重新触发。如果需要换一个通道,则需要将开始的通道换为新通道,然后启动转换。

        ②连续转换,非扫描模式

                每次ADC转换只能选择一个通道,但在一次转换结束后不会停止,而是立刻开启下一轮的转换,也就是说,如果需要再次转换,就不需要重新触发。但是如果需要换一个通道,则需要将开始的通道换为新通道,然后启动转换。

        ③单次转换,扫描模式

                每次ADC转换可以选择多个通道,并依次对多个通道进行转换,转换结果都放在数据寄存器中,为了防止数据覆盖,就需要使用DMA及时将数据挪走,转换完成后置EOC标志位,如果需要再次转换,就需要重新触发。

        ④连续转换,扫描模式

               每次ADC转换可以选择多个通道,并依次对多个通道进行转换,在一次转换结束后不会停止,而是立刻开启下一轮的转换。

6.规则组的触发源

7.转换时间 

        AD转换的步骤:采样,保持,量化,编码(ADC逐次比较过程)

        STM32 ADC的总转换时间为:

                TCONV = 采样时间 + 12.5个ADC周期

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

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

8.校验

        ADC有一个内置自校准模式。校准可大幅减小因内部电容器组的变化而造成的准精度误差。校准期间,在每个电容器上都会计算出一个误差修正码(数字值),这个码用于消除在随后的转换中每个电容器上产生的误差。

        建议在每次上电后执行一次校准。

        启动校准前, ADC必须处于关电状态超过至少两个ADC时钟周期。

二、ADC库函数

void RCC_ADCCLKConfig(uint32_t RCC_PCLK2);

参数:RCC_PCLK2_Div2、RCC_PCLK2_Div4、RCC_PCLK2_Div6、RCC_PCLK2_Div8

作用:配置ADCCLK分频器

void ADC_DeInit(ADC_TypeDef* ADCx);

作用:恢复缺省配置

void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct);

作用:ADC初始化

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输出信号(使用DMA转运数据,调用该函数)

void ADC_ITConfig(ADC_TypeDef* ADCx, uint16_t ADC_IT, FunctionalState NewState);

作用:中断输出控制,能不能通往NVIC

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软件触发函数,也就是结构图触发控制(给SWSTART位置1,以开始转换)

FlagStatus ADC_GetSoftwareStartConvStatus(ADC_TypeDef* ADCx);

作用:返回SWSTART的状态

(配置间断模式)

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

参数1:ADCx

参数2:指定的通道

参数3:序列几的位置

参数4:通道的采样时间

作用:给序列的每个位置填写指定的通道

void ADC_ExternalTrigConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);

作用:是否允许外部触发转换

uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx);

作用:获取AD转换的数据寄存器(读取转换结果)

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

作用:开启内部两个通道

FlagStatus ADC_GetFlagStatus(ADC_TypeDef* ADCx, uint8_t ADC_FLAG);

作用:获取标志位状态,(第二个参数给EOC的标志位,如果转换结束,EOC标志位置1)

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代码介绍

1.代码1——AD单通道

ADC初始化步骤:

①开启RCC时钟,包括ADC和GPIO的时钟,ADC的CLK也需要配置

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);  //开启RCC时钟, 包括ADC和GPIO的时钟,ADC的CLK也需要配置

RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);

RCC_ADCCLKConfig(RCC_PCLK2_Div6);  // ADCCLK=72MHz/6=12MHz

②配置GPIO,将用到的GPIO口配置成模拟输入的模式

GPIO_InitTypeDef GPIO_InitStructure;  // 配置GPIO

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; // ADC专属模式

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_ContinuousConvMode = DISABLE;

连续转换模式:ENABLE——连续模式、DISABLE——单次模式

ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;  // 对齐方式

数据对齐:ADC_DataAlign_Right——右对齐、ADC_DataAlign_Left——左对齐

ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;  

外部触发转换选择:ADC_ExternalTrigConv_None——内部软件触发

ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;  

ADC的工作模式:ADC_Mode_Independent——独立模式

ADC_InitStructure.ADC_NbrOfChannel = 1;

通道数目,指定扫描模式下,总共会用到几个通道

ADC_InitStructure.ADC_ScanConvMode = DISABLE;

扫描转换模式:ENABLE——扫描模式、DISABLE——非扫描模式

ADC_Init(ADC1, &ADC_InitStructure);

⑤开启ADC电源

ADC_Cmd(ADC1, ENABLE);

⑥校准

ADC_ResetCalibration(ADC1);  //复位校准

while(ADC_GetResetCalibrationStatus(ADC1) == SET); //返回复位校准状态 SET=0

ADC_StartCalibration(ADC1);  // 开始校准

while(ADC_GetCalibrationStatus(ADC1) == SET); // 获取校准状态

AD.c

#include "stm32f10x.h"                  // Device header

void AD_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);  //开启RCC时钟,包括ADC和GPIO的时钟,ADC的CLK也需要配置
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
	
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);
	
	GPIO_InitTypeDef GPIO_InitStructure;  // 配置GPIO
	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_InitTypeDef ADC_InitStructure;
	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;  // 对齐方式
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;  // 外部触发信号
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;  // 四种模式
	ADC_InitStructure.ADC_NbrOfChannel = 1;
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;
	ADC_Init(ADC1, &ADC_InitStructure);
	
	ADC_Cmd(ADC1, ENABLE);
	
	ADC_ResetCalibration(ADC1);  //复位校准
	while(ADC_GetResetCalibrationStatus(ADC1) == SET);  //返回复位校准状态
	ADC_StartCalibration(ADC1);  // 开始校准
	while(ADC_GetCalibrationStatus(ADC1) == SET); // 获取校准状态
}

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 "OLED.h"
#include "AD.h"

uint16_t ADValue;
float Voltage;

int main(void)
{
	OLED_Init();
	OLED_ShowString(1, 1, "ADValue:");
	OLED_ShowString(2, 1, "Voltage:0.00V");
	AD_Init();
	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);
	}	
}

2.AD多通道

AD.c

#include "stm32f10x.h"                  // Device header

void AD_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);  //开启RCC时钟,包括ADC和GPIO的时钟,ADC的CLK也需要配置
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
	
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);
	
	GPIO_InitTypeDef GPIO_InitStructure;  // 配置GPIO
	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_InitTypeDef ADC_InitStructure;
	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;  // 对齐方式
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;  // 外部触发信号
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;  // 四种模式
	ADC_InitStructure.ADC_NbrOfChannel = 1;
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;
	ADC_Init(ADC1, &ADC_InitStructure);
	
	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);
}

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, 4);
		OLED_ShowNum(2, 5, AD1, 4);
		OLED_ShowNum(3, 5, AD2, 4);
		OLED_ShowNum(4, 5, AD3, 4);
		
		Delay_ms(100);
	}	
}

3.DMA+AD多通道

AD.c

#include "stm32f10x.h"                  // Device header

uint16_t AD_Value[4]; // 将数据转运到里面

void AD_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);  //开启RCC时钟,包括ADC和GPIO的时钟,ADC的CLK也需要配置
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
	
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);
	
	GPIO_InitTypeDef GPIO_InitStructure;  // 配置GPIO
	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_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);
	ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_55Cycles5);
	ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_55Cycles5);
	ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4, 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 = ENABLE;   // 单次模式
	ADC_InitStructure.ADC_ScanConvMode = ENABLE;  // 扫描模式
	ADC_InitStructure.ADC_NbrOfChannel = 4;
	ADC_Init(ADC1, &ADC_InitStructure);
	
	DMA_InitTypeDef DMA_InitStructure;
	DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;	// 外设站点基地址——ADC_DR寄存器的地址
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;  //外设站点的传输宽度
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;  // 外设站点的地址自增
	
	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)AD_Value;  // 存储器站点起始地址
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;  // 存储器站点数据宽度
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;  // 存储器站点地址是否自增
	
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;  // 传输方向
	DMA_InitStructure.DMA_BufferSize = 4;  // 传输计数器
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  // 触发方式
	DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;  // 自动重装
	DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;
	DMA_Init(DMA1_Channel1, &DMA_InitStructure);
	
	DMA_Cmd(DMA1_Channel1, ENABLE);
	
	ADC_DMACmd(ADC1, ENABLE);   //DMA到ADC的输出,将数据从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); //软件触发转换
}

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "AD.h"




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)
	{
		
		
		OLED_ShowNum(1, 5, AD_Value[0], 4);
		OLED_ShowNum(2, 5, AD_Value[1], 4);
		OLED_ShowNum(3, 5, AD_Value[2], 4);
		OLED_ShowNum(4, 5, AD_Value[3], 4);
		
		Delay_ms(100);
	}	
}

四、总结

         嵌入式系统的核心(如微控制器 MCU、微处理器 MPU)只能直接处理数字信号(0 和 1 组成的二进制数据),但现实世界中的许多物理量(如温度、声音、光强、压力等)都是通过传感器转换为模拟电信号(连续变化的电压或电流)存在的。ADC 的作用就是搭建 “模拟世界” 与 “数字世界” 之间的桥梁,让嵌入式系统能够感知和处理这些物理量。

Logo

openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。

更多推荐