**1.**STM32F1内部温度传感器介绍
1.1 STM32F1内部温度传感器简介
STM32F1内部含有一个温度传感器,可用来测量 (STM32芯片的)CPU 及周围的温度(TA)。(实际并不用来测周围的温度,仅用来测试CPU的温度)
此温度传感器与ADC1内部输入通道相连接,如下图所示。它连接在ADC1_IN16上。ADC1可以将传感器输出的电压转换成数字值。STM32F1的内部温度传感器支持的温度范围为:-40~125 度,精度为±1.5℃左右。 (因为一方面温度的精度比较差,另一方面STM32工作时CPU会发热,所以不要利用这个温度传感器来测试STM32周围的环境温度,因为太不准确了~)
STM32F1 内部温度传感器的使用很简单,**只要初始化下ADC1_IN16通道,并激活其内部温度传感器通道就差不多了。**关于 ADC 的初始化,在上一节已经进行了详细的介绍,这里就不多说。接下来我们介绍一下和温度传感器设置相关的 2 个地方。
(1)要使用 STM32F1 的内部温度传感器,必须先激活 ADC 的内部通道,这里通过**ADC_CCR 的 TSVREFE 位( bit23)设置。**设置该位为 1 则启用内部温度传感器,否则关闭内部温度传感器。
(2)STM32F103ZET6的内部温度传感器固定的连接在 ADC1_IN16上,所以,我们在设置好 ADC1 之后只要读取通道 16 的AD值,就知道温度传感器返回来的电压值了。根据这个值,我们就可以计算出当前温度。计算公式如下:
T(℃) ={( V25 - Vsense) /Avg_Slope}+25
公式中:
Vsebse:ADC读到并转换成电压的值
V25=Vsense 在 25 度时的数值(典型值为:1.43V)。
Avg_Slope=温度与 Vsense 曲线的平均斜率(单位为 mv/℃或 uv/℃)(典型值为4.3mV/℃,即0.0043V/℃)
通过上面公式,我们就能非常方便的计算出当前内部温度传感器测试的温度。
**2.**内部温度传感器配置步骤
具体步骤如下:(ADC相关库函数在stm32f10x_adc.c和stm32f10x_adc.h文件中)
(1)初始化ADC1_IN16相关参数,开启内度温度传感器
ADC1_IN16的初始化步骤与上一章介绍AD模数转换实验一样,这里我们只需要开启内部温度传感器即可,调用的库函数为:
ADC_TempSensorVrefintCmd(ENABLE);//打开ADC内部温度传感器
(2)读取ADC1_IN16 AD值,将其转换为对应温度
上一步配置好后,我们就可以读取温度传感器的电压值,根据温度计算公式,可以求出对应电压值的温度,具体方法与上一章一样。
**3.**硬件电路
本实验使用到硬件资源如下:
(1)D1指示灯
(2)串口1
(3)内部温度传感器
D1指示灯、串口1电路在前面章节都介绍过,这里就不多说,至于内部温度传感器它属于STM32F1芯片内部的资源,连接的是ADC1_IN16通道。
**4.**编写内部温度传感器控制程序
本实验所要实现的功能是:**通过芯片内部温度传感器读取温度,并将读取的温度数据打印出去,D1****指示灯闪烁提示系统正常运行。**程序框架如下:
(1)初始化内部温度传感器(初始化ADC1_IN16,开启温度传感器)
(2)编写温度读取函数
(3)编写主函数
main.c
cpp
#include "system.h"
#include "led.h"
#include "SysTick.h"
#include "usart.h"
#include "adc_temp.h"
int main()
{
u8 i=0;
int temp=0;
SysTick_Init(72);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断优先级分组
LED_Init();
USART1_Init(9600);
ADC_Temp_Init();
while(1)
{
i++;
if(i%20 ==0)
{
led1=!led1;//LED1闪,用来指示主程序循环是否运行
}
if(i%50==0)
{
temp=Get_Temperature();
if(temp<0)
{
temp=-temp;
printf("芯片内部温度检测值为:-");
}
else
{
printf("芯片内部温度检测值为:+");
}
printf("%.2f 度 \r\n",(float)temp/100);
}
delay_ms(10);
}
}
adc_temp.c
cpp
#include "adc_temp.h"
#include "SysTick.h"
void ADC_Temp_Init()
{
ADC_InitTypeDef ADC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
RCC_ADCCLKConfig(RCC_PCLK2_Div6);//设置ADC的分频因子,6分频,因此ADC时钟频率为12MHZ
ADC_TempSensorVrefintCmd(ENABLE);//打开ADC内部温度传感器
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;//非扫描模式
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;//关闭连续转换
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//禁止触发检测,使用软件触发
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//右对齐
ADC_InitStructure.ADC_NbrOfChannel = 1;//转换通道数量
ADC_Init(ADC1, &ADC_InitStructure);//ADC初始化
ADC_Cmd(ADC1, ENABLE);//开启AD转换器
ADC_ResetCalibration(ADC1);//ADC复位校准
while(ADC_GetResetCalibrationStatus(ADC1)); //等待复位校准结束
ADC_StartCalibration(ADC1); //开始指定 ADC1 的校准状态
while(ADC_GetCalibrationStatus(ADC1)); //等待校准结束
ADC_SoftwareStartConvCmd(ADC1, ENABLE);//ADC开始转换
}
u16 Get_ADC_Temp_Value(u8 ADC_Chanle,u8 times)
{
u8 t;u32 temp=0;
ADC_RegularChannelConfig(ADC1, ADC_Chanle, 1, ADC_SampleTime_239Cycles5 );
for(t=0;t<times;t++)
{
ADC_SoftwareStartConvCmd(ADC1, ENABLE);//ADC开始转换
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束
temp+=ADC_GetConversionValue(ADC1);//读到的值累加
delay_ms(5);
}
return temp/times; //返回累加的平均值
}
int Get_Temperature(void)
{
u16 adc_value;
double voltage;
int temperature;//因为温度可能为负值所以定为int类型
adc_value=Get_ADC_Temp_Value(ADC_Channel_16,10);
voltage=(float)adc_value*(3.3/4096);
temperature=((1.43-voltage)/0.0043+25)*100; //转换为温度值;*100是为了保留小数点后的两位数因为温度为int类型
return temperature;
}
程序写到开发板上,实验结果如下所示。实验是成功的!