如何理解STM32ADC外设的内部实现原理及代码实现

分享知识,希望对各位读者有所帮助!

前言

前文介绍了外挂ADC芯片,本文介绍STM32F103内置的ADC外设


一、ADC(模数转换器)

(1)作用

ADC外设可以将引脚上连续变化的模拟电压转换为数字变量。

(2)精度

ADC转换的精度与位数有关,位数越多,精度越精准。

本文介绍的ADC外设是12位的,那么 0V ~ 3.3V范围就是0 ~ 2^{12} - 1 >>0 ~ 4095。

(3)硬件参数

芯片ADC外设最多有18个输入通道,分别是16个GPIO口、内部温度传感器和内部1.2V的基准电压。

  • 温度传感器可以用来测量CPU温度
  • 基础电压可以用来校准输入信号是否正确。

二、ADC转换原理

ADC的转换原理为逐次逼近型

取一个已知值来与输入未知值进行比较,例如目前转换范围是0 ~ 256,此时取128与未知值进行比较,若比128小,则再取64进行比较,以此类推,就可以确定未知值是多少了。

三、ADC转换原理 

根据上文,我们知道了ADC的基础知识,那么ADC内部转换到底是怎么完成的呢?

我们可以根据下图ADC框图来进行总结

  • 可以看到ADC在GPIO端口共有16个输入通道,并且在芯片内部还有温度传感器和基准电压两个输入源。 
  • 在模拟至数字转换器中,有一个注入通道和规则通道
  • 注入通道可以同时对四个ADC通道进行转换,并将四个转换结果同时存入注入通道数据寄存器。
  • 规则通道可以同时对16个ADC通道进行转换,但规则通道数据寄存器只能存放一个转换结果。若将16个转换结果都放入数据寄存器中,那么只有最后一个转换结果会存在,前15个都会被覆盖。
  • 规则通道和注入通道转换结束后,都会在状态寄存器中将标志位(EOC 和 JEOC) 置1。同时这个标志位还可以用来触发中断
  • 那么如何触发转换呢?我们可以看到触发源来自定时器,为避免频繁进中断而导致程序出错,我们选择TIM_TRGO更新事件触发更为保险

四、ADC转换模式

(1)单次转换,非扫描模式

只能对一个ADC通道进行转换,并且每次转换前都要进行触发

(2)连续转换,非扫描模式

只能对一个ADC通道进行转换,并且触发一次后,就可以不断地进行转换

(3) 单次转换,扫描模式

可以对最多16个ADC通道进行连续转换,并且每次转换前都要进行触发

(4) 连续转换,扫描模式

可以对最多16个ADC通道进行连续转换,并且触发一次后,就可以不断地进行转换

五、ADC多通道配置代码实现 

(1)硬件连接 

光敏传感器------AOPA0
热敏传感器----- AOPA1
对射式红外传感器---AOPA2

(2)代码实现

AD.c

/*
	函数:初始化ADC引脚,模式
	参数:无
    返回值:无
*/
void MyADC1_Init(void)
{

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);	//开启ADC1外设的时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	//开启GPIOA的时钟
	
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);						//将分频系数设置为6,ADCCLK时钟频率为 72M/6 = 12M
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模式为模拟输入,近似引脚断开,避免引脚变化影响数值转换
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2; //初始化ADC1外设的0、1、2通道
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);				
	
	ADC_InitTypeDef ADC_InitStructure;			
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;		//选择独立模式,即只使用ADC1
	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;					//规则组的通道数为1
	ADC_Init(ADC1, &ADC_InitStructure);				
	

	ADC_Cmd(ADC1, ENABLE);									//使能ADC1,ADC开始运行
	
	/*ADC校准*/
	ADC_ResetCalibration(ADC1);				
	while (ADC_GetResetCalibrationStatus(ADC1) == SET);
	ADC_StartCalibration(ADC1);
	while (ADC_GetCalibrationStatus(ADC1) == SET);
}
/*
	函数:获取AD转换后的值
	参数:某个通道
    返回值:转换后的值
*/
uint16_t MyADC_GetValue(uint8_t ADC_Channel)
{
	ADC_RegularChannelConfig(ADC1, ADC_Channel, 1, ADC_SampleTime_55Cycles5);	
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);					//软件触发AD转换一次
	while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);	//等待EOC标志位 置1,即等待AD转换结束
	return ADC_GetConversionValue(ADC1);					//读数据寄存器,得到AD转换的结果
}

main.c

uint16_t AD0, AD1, AD2;	//定义AD值变量

int main(void)
{
	
	MyADC1_Init();
	
	OLED_Init();

	OLED_ShowString(0, 0, "AD0:", OLED_8X16);
	OLED_ShowString(0, 16, "AD1:", OLED_8X16);
	OLED_ShowString(0, 32, "AD2:", OLED_8X16);
	
	while (1)
	{
		AD0 = MyADC_GetValue(ADC_Channel_0);//ADC1外设通道0
		AD1 = MyADC_GetValue(ADC_Channel_1);//ADC1外设通道1
		AD2 = MyADC_GetValue(ADC_Channel_2);//ADC1外设通道2
		
		OLED_ShowNum(32,  0, AD0, 4, OLED_8X16);
		OLED_ShowNum(32,  16, AD1, 4, OLED_8X16);
		OLED_ShowNum(32,  32, AD2, 4, OLED_8X16);
		
		Delay_ms(100);
		OLED_Update();
	}
}

 (3)实验现象

实验结果:功能显示正常,三个通道的AD值均可被外界所影响,且数值变化正确


总结

本文介绍了STM32F103芯片的内置ADC外设及基本代码实现,希望对各位读者有所帮助。

  • 11
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值