STM32F103(十九)ADC相关的几个实验—内部温度传感器内部参照电压光敏传感器

Posted 自信且爱笑‘

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了STM32F103(十九)ADC相关的几个实验—内部温度传感器内部参照电压光敏传感器相关的知识,希望对你有一定的参考价值。

学习板:STM32F103ZET6
参考:
STM32F103(十八)ADC总结(5W字)

一、前言

上一篇博客总结的ADC的相关寄存器、相关库函数以及如何编程,本博把ADC相关的几个功能实验总结一下,作为上一篇博客ADC的复习。

内部温度传感器在ADC1的16通道、内部参考电压在ADC1的17通道,这俩个功能是在芯片内部的,并没有引脚引出,所以不需要配置引脚。

至于光敏电阻,这个是我板子外设自己添加的,因引脚设计而异,之后再详述。

二、内部温度传感器

1、原理

芯片内部温度传感器的温度与电压关系接近为线性,按照线性方程来解,ST官方给了几个重要参数:25摄氏度时传感器电压输出:1.43V、线性方程的斜率为4.3mV/℃=0.0043V/摄氏度。

则有:

所以只需要得到VT即可根据这个公式得到内部温度传感器的温度显示。

2、代码实现:

ADC的相关内容上一博客都总结过了,再一步步看看代码,含义不在赘述。
(1)使能ADC1

RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);

(2)设置ADC1时钟分频

RCC_ADCCLKConfig(RCC_PCLK2_Div6);

(3)重置ADC1

	ADC_DeInit(ADC1);

(4)ADC1初始化

	ADC_InitStruct.ADC_ContinuousConvMode=DISABLE;//连续模式
	ADC_InitStruct.ADC_DataAlign=ADC_DataAlign_Right;
	ADC_InitStruct.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;
	ADC_InitStruct.ADC_Mode=ADC_Mode_Independent;
	ADC_InitStruct.ADC_NbrOfChannel=1;
	ADC_InitStruct.ADC_ScanConvMode=DISABLE;//不扫描模式
	ADC_Init(ADC1, &ADC_InitStruct);

(5)内部温度传感器使能

 ADC_TempSensorVrefintCmd(ENABLE);

(6)ADC1使能

ADC_Cmd(ADC1,ENABLE);

(7)ADC1复位校准并等待完成

ADC_ResetCalibration(ADC1);
	while(ADC_GetResetCalibrationStatus(ADC1)) //等待复位校准结束
	{
		
	}

(8)ADC1校准并等待校准完成

	ADC_StartCalibration(ADC1);
	while(ADC_GetCalibrationStatus(ADC1))//等待校准结束
	{

	}

(9)写一个获取ADC转换结果的函数
传递参数为:通道数、序列的序号、采用周期

u16 adc_getval(u8 ch,u8 num,u8 ADC_SampleTime) //传递通道、序列序号、采样周期
{
	ADC_RegularChannelConfig(ADC1, ch, num, ADC_SampleTime);//规则通道设置
	ADC_SoftwareStartConvCmd(ADC1,ENABLE);//软件触发、并开启转换
    while(!ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC))
	{
		//转换过程中执行空语句,等待转换完成
	}
	 return ADC_GetConversionValue(ADC1);	
 }

3、完整代码

1、adc.h代码

//adc.h
#ifndef _ADC_
#define _ADC_
#include "stm32f10x.h"
void adc_Init(void);
u16 adc_getval(u8 ch,u8 num,u8 ADC_SampleTime);
#endif

2、adc.c代码

#include "adc.h"
#include "stm32f10x.h"
#include "usart.h"
void adc_Init(void)
{
	ADC_InitTypeDef		 ADC_InitStruct;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);
	
	ADC_DeInit(ADC1);
	
	ADC_InitStruct.ADC_ContinuousConvMode=DISABLE;//连续模式
	ADC_InitStruct.ADC_DataAlign=ADC_DataAlign_Right;
	ADC_InitStruct.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;
	ADC_InitStruct.ADC_Mode=ADC_Mode_Independent;
	ADC_InitStruct.ADC_NbrOfChannel=1;
	ADC_InitStruct.ADC_ScanConvMode=DISABLE;//不扫描模式
	ADC_Init(ADC1, &ADC_InitStruct);
	
   ADC_TempSensorVrefintCmd(ENABLE);
	ADC_Cmd(ADC1,ENABLE);
	
	ADC_ResetCalibration(ADC1);
	while(ADC_GetResetCalibrationStatus(ADC1)) //等待复位校准结束
	{
		
	}
	ADC_StartCalibration(ADC1);
	while(ADC_GetCalibrationStatus(ADC1))//等待校准结束
	{
	}
}

u16 adc_getval(u8 ch,u8 num,u8 ADC_SampleTime) //传递通道、序列序号、采样周期
{
	ADC_RegularChannelConfig(ADC1, ch, num, ADC_SampleTime);//规则通道设置
	ADC_SoftwareStartConvCmd(ADC1,ENABLE);//软件触发、并开启转换
    while(!ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC))
	{
		//转换过程中执行空语句,等待转换完成
	}
	 return ADC_GetConversionValue(ADC1);	
 }

3、main.c

#include "stm32f10x.h"
#include "delay.h"
#include  "adc.h"
#include "usart.h"
u16 a;
float b;
 int main(void)
 {	
	delay_init();
	adc_Init();
	uart_init(115200);	
	
	 while(1)
	 {
	  a=adc_getval(ADC_Channel_16,1,ADC_SampleTime_28Cycles5);\\
		b=(a*(3.3/4096)-1.43)/0.0043+25;
	    printf("ADC= %d        tsensor= %1.3f ℃ \\r\\n",a,b);
	    delay_ms(500);
	 }
 }

4、测试

下载后通过串口监视器察看:

三、内部参考电压

注意一个东西:ADC的参考电压由Vref+、Vref-引脚提供,而内部参考电压与外部电路无关。

1、代码实现

代码与内部温度传感器的代码类似,只有以下不同之处:

2、完整代码:

1、adc.h代码

//adc.h
#ifndef _ADC_
#define _ADC_
#include "stm32f10x.h"
void adc_Init(void);
u16 adc_getval(u8 ch,u8 num,u8 ADC_SampleTime);
#endif

2、adc.c代码

#include "adc.h"
#include "stm32f10x.h"
#include "usart.h"
void adc_Init(void)
{
	ADC_InitTypeDef		 ADC_InitStruct;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);
	
	ADC_DeInit(ADC1);
	
	ADC_InitStruct.ADC_ContinuousConvMode=DISABLE;//连续模式
	ADC_InitStruct.ADC_DataAlign=ADC_DataAlign_Right;
	ADC_InitStruct.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;
	ADC_InitStruct.ADC_Mode=ADC_Mode_Independent;
	ADC_InitStruct.ADC_NbrOfChannel=1;
	ADC_InitStruct.ADC_ScanConvMode=DISABLE;//不扫描模式
	ADC_Init(ADC1, &ADC_InitStruct);
	
   ADC_TempSensorVrefintCmd(ENABLE);
	ADC_Cmd(ADC1,ENABLE);
	
	ADC_ResetCalibration(ADC1);
	while(ADC_GetResetCalibrationStatus(ADC1)) //等待复位校准结束
	{
		
	}
	ADC_StartCalibration(ADC1);
	while(ADC_GetCalibrationStatus(ADC1))//等待校准结束
	{
	}
}

u16 adc_getval(u8 ch,u8 num,u8 ADC_SampleTime) //传递通道、序列序号、采样周期
{
	ADC_RegularChannelConfig(ADC1, ch, num, ADC_SampleTime);//规则通道设置
	ADC_SoftwareStartConvCmd(ADC1,ENABLE);//软件触发、并开启转换
    while(!ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC))
	{
		//转换过程中执行空语句,等待转换完成
	}
	 return ADC_GetConversionValue(ADC1);	
 }

3、main.c

#include "stm32f10x.h"
#include "delay.h"
#include  "adc.h"
#include "usart.h"
u16 a;
float b;
 int main(void)
 {	
	delay_init();
	adc_Init();
	uart_init(115200);	
	 while(1)
	 {
	    a=adc_getval(ADC_Channel_17,1,ADC_SampleTime_28Cycles5);
		b=a*(3.3/4096);
	    printf("ADC= %d        Vrefint= %1.3f V \\r\\n",a,b);
	    delay_ms(500);
	 }
 }

3、测试

下载后通过串口监视器察看:

四、光敏传感器

有的板子上面有光敏传感器,这里做一个总结。

1、原理

先分析一下原理图:


首先,我的实验板上光敏传感器接的ADC3通道6

其次分析一下光敏二极管的工作原理:

没有光照射时,二极管对地反接,二极管两端“电阻”无穷大,ADC3通道6的引脚测的是二极管两端的电压,此时为3.3V,当有光照射时,光敏二极管慢慢开始导通,且根据光照强调不同,其导通能力不同,相当于随着光照的增强,二极管的“电阻”在减小,R34会慢慢增大分压,导致二极管两端电压减小。
所以随着光照的增强,ADC3通道6转换的电压值在减小。

2、代码实现

(1)使能ADC3和PF8时钟

RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3|RCC_APB2Periph_GPIOF, ENABLE);

(2)设置ADC3时钟分频

RCC_ADCCLKConfig(RCC_PCLK2_Div6);

(3)重置ADC3

ADC_DeInit(ADC3);

(4)ADC3初始化

由于只用到一个通道,故设置规则序列为1

	ADC_InitStruct.ADC_ContinuousConvMode=DISABLE;//连续模式
	ADC_InitStruct.ADC_DataAlign=ADC_DataAlign_Right;
	ADC_InitStruct.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;
	ADC_InitStruct.ADC_Mode=ADC_Mode_Independent;
	ADC_InitStruct.ADC_NbrOfChannel=1;
	ADC_InitStruct.ADC_ScanConvMode=DISABLE;//不扫描模式
	ADC_Init(ADC3, &ADC_InitStruct);

(5)使能ADC3

ADC_Cmd(ADC3,ENABLE);

(6)ADC3复位校准并等待完成

	ADC_ResetCalibration(ADC3);
	while(ADC_GetResetCalibrationStatus(ADC3)) //等待复位校准结束
	{
		
	}

(7)ADC3校准并等待完成

	ADC_StartCalibration(ADC3);
	while(ADC_GetCalibrationStatus(ADC3))//等待校准结束
	{

	}
	

(8)编写获取ADC3转换值函数

u16 adc_getval(u8 ch,u8 num,u8 ADC_SampleTime) //传递通道、序列序号、采样周期
{
	ADC_RegularChannelConfig(ADC3, ch, num, ADC_SampleTime);//规则通道设置
	ADC_SoftwareStartConvCmd(ADC3,ENABLE);//软件触发、并开启转换
    while(!ADC_GetFlagStatus(ADC3,ADC_FLAG_EOC))
	{
		//转换过程中执行空语句,等待转换完成
	}
	 return ADC_GetConversionValue(ADC3);	
 }

(9)主函数编写
在while循环中通过循环调用(8)中编写的函数,获取转换值,而转换值为0~4096的值,0对应0V、4096对应3.3V,故需要将这个ADC转换的值映射到0 ~3.3V区间

	 while(1)
	 {
	    a=adc_getval(ADC_Channel_6,1,ADC_SampleTime_28Cycles5);
		b=a*(3.3/4096);
	    printf("ADC= %d        Vrefint= %1.3f V \\r\\n",a,b);
	    delay_ms(500);
	 }

3、完整代码

1、adc.h代码

#ifndef _ADC_
#define _ADC_
#include "stm32f10x.h"
void adc_Init(void);
u16 adc_getval(u8 ch,u8 num,u8 ADC_SampleTime);
#endif

2、adc.c代码

#include "adc.h"
#include "stm32f10x.h"
#include "usart.h"
void adc_Init(void)
{
	ADC_InitTypeDef		 ADC_InitStruct;
	GPIO_InitTypeDef	 GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3|RCC_APB2Periph_GPIOF, ENABLE);
	
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_8;
	GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
	GPIO_Init(GPIOF, &GPIO_InitStructure);

	RCC_ADCCLKConfig(RCC_PCLK2_Div6);
	ADC_DeInit(ADC3);
	
	ADC_InitStruct.ADC_ContinuousConvMode=DISABLE;//连续模式
	ADC_InitStruct.ADC_DataAlign=ADC_DataAlign_Right;
	ADC_InitStruct.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;
	ADC_InitStruct.ADC_Mode=ADC_Mode_Independent;
	ADC_InitStruct.ADC_NbrOfChannel=1;
	ADC_InitStruct.ADC_ScanConvMode=DISABLE;//不扫描模式
	ADC_Init(ADC3, &ADC_InitStruct);
	
  
	ADC_Cmd(ADC3,ENABLE);
	
	ADC_ResetCalibration(ADC3);
	while(ADC_GetResetCalibrationStatus(ADC3)) //等待复位校准结束
	{
		
	}
	ADC_StartCalibration(ADC3);
	while(ADC_GetCalibrationStatus(ADC3))//等待校准结束
	{

	}
}

u16 adc_getval(u8 ch,u8 num,u8 ADC_SampleTime) //传递通道、序列序号、采样周期
{
	ADC_RegularChannelConfig(ADC3, ch, num, ADC_SampleTime);//规则通道设置
	ADC_SoftwareStartConvCmd(ADC3,ENABLE);//软件触发、并开启转换
    while(!ADC_GetFlagStatus(ADC3,ADC_FLAG_EOC))
	{
		//转换过程中执行空语句,等待转换完成
	}
	 return ADC_GetConversionValue(ADC3);	
 }

3、main.c代码

#include "stm32f10x.h"
#include "delay.h"
#include  "adc.h"
#include "usart.h"
u16 a;
float b;
 int main(void)
 {	
	delay_init();
	adc_Init();
	uart_init(115200);	
	 
	 while(1)
	 {
	    a=adc_getval(ADC_Channel_6,1,ADC_SampleTime_28Cycles5);
		b=a*(3.3/4096);
	    printf("ADC= %d        Vrefint= %1.3f V \\r\\n",a,b);
	    delay_ms(500);
	 }
 }

4、测试

下载代码后通过串口监视器:

实验室光照下:

手摁住光敏传感器:

手电筒照射光敏传感器:

可见,ADC3通道6的确可以捕获到电压值,并且与我们之前分析的一致,强光下二极管导通

以上是关于STM32F103(十九)ADC相关的几个实验—内部温度传感器内部参照电压光敏传感器的主要内容,如果未能解决你的问题,请参考以下文章

STM32F103(十八)ADC总结(贼详细)

stm32f103 adc 怎么触发

STM32开发STM32F103 功能应用 —— NTC 温度采集

STM32F103(十八)ADC总结(5W字)

stm32f103rct6的adc有多少通道

stm32F103之ADC模数转换