一、温度传感器的简介
内置温度传感器特性
■ STM32有一个内部的温度传感器,可以用来测量CPU测量周围的温度(TA)。
■ STM32内部温度传感器与ADC的通道16相连,与ADC配合使用实现温度测量
■ 温度传感器模拟输入推荐采样时间是17.1μs。
■ STM32的内部温度传感器测量范围–40~125℃,精度 ± 1.5℃。
温度的计算
官方数据手册公式如下:
百度给出了V25和Avg_Slope的值:
最小 | 经典 | 最大 | |
---|---|---|---|
V25 | 1340mV | 1430mV | 1520mV |
Avg_Slope(mV/°C) | 4.0 | 4.3 | 4.3 |
- VSENSE 如何得到?
我们得到的AD结果是ADC_DR这个变量,存在以下的比例关系:
ADC_DR / VSENSE = 212 / 3300mV
所以 VSENSE
= ADC_DR * 3300mV / 212
= ADC_DR* 3300/4096
= ADC_DR* 825/1024
= (ADC_DR*825)>>10 - 例:读到VSENSE = 1. 35V,分别取V25的典型值1340mV和Avg_Slope 的经典值4.3,计算当前温度。
由公式 T = (VSENSE -V25 )/Avg_Slope + 25
得 T = (1430 - 1350)/4.3 + 25 = 43.60
所以温度大约为43.6°C
二、编程
编程思路:
①初始化ADC
②设置ADC CR2的TSVREFE位,打开内部温度传感器
ADC_TempSensorVrefintCmd(ENABLE);
③设置采样时间等于17.1us,配置规则通道参数:选择ADC_ IN16输入通道。
ADC_RegularChannelConfig( );
④启动软件转换
ADC_SoftwareStartConvCmd();
⑤等待转换结束并读取ADC_DR结果
(u32)ADC_GetConversionValue(ADC1);
⑥由ADC_DR结果计算出温度值
代码:
adc.h
#ifndef ADC_H
#define ADC_H
#include "stm32f10x.h"
#include "bsp_systick.h"
#define V25 1370
#define Avg_Slope 4.35
void T_ADC_Configuration(void);
u32 Get_ADC_Average(u8 channel,u8 times);
float Get_InternalSensorTemperate(void);
#endif
adc.c
#include "adc.h"
void T_ADC_Configuration(void)
{
ADC_InitTypeDef ADC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 , ENABLE ); //使能GPIOA,ADC1通道时钟
RCC_ADCCLKConfig(RCC_PCLK2_Div6); //分频因子6时钟为72M/6=12MHz
ADC_DeInit(ADC1); //将外设 ADC1 的全部寄存器重设为缺省值
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //ADC工作模式:ADC1和ADC2工作在独立模式
ADC_InitStructure.ADC_ScanConvMode = ENABLE; //使能扫描
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //设置模数转换工作在连续转换模式
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //转换由软件启动
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //ADC数据右对齐
ADC_InitStructure.ADC_NbrOfChannel = 1; //顺序进行规则转换的ADC通道的数目
ADC_Init(ADC1, &ADC_InitStructure); //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器
ADC_Cmd(ADC1, ENABLE); //使能指定的ADC1
ADC_ResetCalibration(ADC1); //重置指定的ADC1的复位寄存器
while(ADC_GetResetCalibrationStatus(ADC1)); //获取ADC1重置校准寄存器的状态,设置状态则等待
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1)); //获取指定ADC1的校准程序,设置状态则等待
ADC_TempSensorVrefintCmd(ENABLE); //开启内部温度传感器
}
/*******************************************************************
*函数:u8 Get_ADC_Average(u8 channel,u8 times)
*功能:获取adc转换平均值
*输入:
u8 channel, 通道号:ADC_Channel_0 ~ ADC_Channel_17
u8 times, 获取次数
*输出:获取次数的平均值
*特殊说明:
*******************************************************************/
u32 Get_ADC_Average(u8 channel,u8 times)
{
u32 convert_Result=0;
u8 i;
for(i=0;i<times;i++)
{
ADC_RegularChannelConfig(ADC1, channel, 1, ADC_SampleTime_55Cycles5 ); //ADC1,第一个转换,采样时间为28.5周期?
ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能指定的ADC1的软件转换启动功能
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束
convert_Result+=(u32)ADC_GetConversionValue(ADC1);//读取ADC_DR结果数据,此时EOC会自动清除
SysTick_Delay_ms(5);
}
return convert_Result/times;
}
/*******************************************************************
*函数:u8 Get_InternalSensorTemperate(u8 channel,u8 times)
*功能:获取adc转换平均值
*输入:
*输出:获取的温度值
*特殊说明:
*******************************************************************/
float Get_InternalSensorTemperate(void) //获取内部温度传感器温度值
{
int ADC_ConvertedValue;//用来存储ADC转换出来的值
float Current_Temp;
ADC_ConvertedValue = (int)Get_ADC_Average(ADC_Channel_16,20); //20次取平均
ADC_ConvertedValue = (ADC_ConvertedValue*825)>>10;//换算成Vsensor
Current_Temp = (((V25-ADC_ConvertedValue)/Avg_Slope)+25); //计算温度值
return Current_Temp;
}
main.c
#include "stm32f10x.h"
#include "bsp_systick.h"
#include "usart.h"
#include "adc.h"
int main(void)
{
usart1_Init(9600);
printf("start!\n");
T_ADC_Configuration();
u32 adc_DRValue = 0 ;
float temperature;
while(1)
{
adc_DRValue = Get_ADC_Average(ADC_Channel_16,20);//指定ADC_Channel_1,获取ADC的值
printf("adc_DRValue:%d\n",adc_DRValue);//通过串口打印获取ADC的值
temperature=Get_InternalSensorTemperate();//转换ADC的值,得到具体的温度
printf("temperature:%f\n",temperature);//通过串口打印获取电压的值
SysTick_Delay_ms(1500);
}
}
遇到的问题-数据类型问题
代码如下
float Get_Temperate(void) //获取内部温度传感器温度值
{
u32 ADC_ConvertedValue;//用来存储ADC转换出来的值,单位是mV
float Current_Temp;
ADC_ConvertedValue = T_Get_ADC_Average(10); //20次取平均
ADC_ConvertedValue = (ADC_ConvertedValue*825)>>10;//(ADC_ConvertedValue*825)>>10 表示 ADC_ConvertedValue*3300/4096
Current_Temp=(float)(((1370-ADC_ConvertedValue)/4.35)+25); //转换为温度值
return Current_Temp;
}
思来想去,最后发现是数据类型的问题,因为ADC_ConvertedValue会得到负数。
ADC_ConvertedValue由u32改为int类型就得到正确结果。
float Get_Temperate(void) //获取内部温度传感器温度值
{
int ADC_ConvertedValue;//用来存储ADC转换出来的值,单位是mV
float Current_Temp;
ADC_ConvertedValue = (int)T_Get_ADC_Average(20); //20次取平均
ADC_ConvertedValue = (ADC_ConvertedValue*825)>>10;//(ADC_ConvertedValue*825)>>10 表示 ADC_ConvertedValue*3300/4096
Current_Temp = (((1370-ADC_ConvertedValue)/4.35)+25); //转换为温度值
return Current_Temp;
}