基于STM32战舰开发板的内部温度传感器实验

基于STM32战舰开发板的内部温度传感器实验

内部温度传感器简介

测量的温度位置

内部温度传感器集成在芯片中,测量的是芯片的温度。

如何测量对应位置的温度?

 

温度传感器与ADC1_CH16相连,另外ADC1_CH17是与内部参照电压VREF+相连,因此我们可以通过ADC1的第16路通道测量芯片温度实时对应的电压转换得来的数字量,也可以通过ADC1的第17路通道测量内部参照电压对应的数字量。

我们知道STM32的ADC转换DATA是12Bits的,因此输入电压(小于3.3V大于0V)ADC转换为数字量的值为“大于0小于4096”。

 

我们由“T-V关系图”,“V的数字量”和“ADC量程”,可以得知“此时的温度”。

 

内部传感器配置注意事项

① 读取内部温度传感器数据的周期应大于17.1us;

② 内部温度传感器的温度测量误差约为1.5℃,因此内部温度传感器更适合于检测温度的变化,而不是测量绝对的温度。如果需要测量精确的温 度,应该使用一个外置的温度传感器。

内部温度传感器配置流程

所属函数位置

执行步骤

ADCx的初始化函数

使能相应总线上(APB1或者APB2)ADCx与GPIOx的外设时钟

配置GPIOx口中ADCx对应的引脚为模拟输入模式(ADC外设对应的GPIO模式)

将ADCx复位为缺省值(就是将ADCx的所有设过的属性全部重设为默认值)

设置ADCx时钟分频

将ADCx的校准寄存器恢复为默认值(此时应用对应的标志位来判断此步过程是否完成,如果完成再执行下一步)

将ADCx的校准寄存器初始化,开始校准(此时应用对应的标志位来判断此步过程是否完成,如果完成再执行下一步)

使能ADC1_CH16对应的内部温度传感器

使能ADCx外设

ADCx_CHy通道数值读取函数

配置ADCx_CHy(ADCx对应的y通道)的转换序号与转换周期

启动ADCx_CHy继续转换(此时应用对应标志位判断ADCx外设所有通道是否转换完成)

读取ADCx_CHy通道的数字量的值

ADCx_CHy通道读取的数据的后期处理函数

对n次读取的数据进行取平均值处理

温度与电压数字量之间的转换函数

用温度与电压数字量之间的对应关系进行转换

内部温度传感器实验代码解析

ADC初始化代码

void ADC_InitConfig()  
{  
    ADC_InitTypeDef ADC_InitStructure;  
      
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);  
      
    ADC_DeInit(ADC1);  
    RCC_ADCCLKConfig(RCC_PCLK2_Div6);  
      
    ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;  
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Left;  
    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_TempSensorVrefintCmd(ENABLE); // 使能内部温度传感器  
      
    ADC_Cmd(ADC1,ENABLE); // 使能ADC1  
      
    ADC_ResetCalibration(ADC1); // 开始ADC1的校准寄存器复位  
    while(ADC_GetResetCalibrationStatus(ADC1));  
      
    ADC_StartCalibration(ADC1); // 开始ADC1的自动校准功能  
    while(ADC_GetCalibrationStatus(ADC1));  
      
    delay_init();  
}  

我们应该注意到:ADC1_CH16连接着内部温度传感器,不用初始化具体的GPIO口引脚,只需要将寄存器的相应位使能即可:

 

我们有些同学在用如下“等待”代码的时候有些疑问:

ADC_ResetCalibration(ADC1); // 开始ADC1的校准寄存器复位  
while(ADC_GetResetCalibrationStatus(ADC1));  
  
ADC_StartCalibration(ADC1); // 开始ADC1的自动校准功能  
while(ADC_GetCalibrationStatus(ADC1));  

我们用while循环为ADC外设提供执行任务所需的等待时间,但是我们一对比如下while代码,就有点懵了:

ADC_SoftwareStartConvCmd(ADC1, ENABLE);     //使能指定的ADC1的软件转换启动功能  
  
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束  

在while循环中,应该“取非”?这个是个让人不解的问题。

我们此时应该看寄存器,看寄存器中位与状态的对应关系:

ADC1复位校准功能与ADC1执行校准功能分别对应“ADC控制寄存器 2(ADC_CR2)”对应的如下两个位:

 

我们看到上图,可以得到如下结论:

功能

状态

位标志

检验ADC校准功能复位状态(完成/进行中)

复位执行中

1(SET)

复位完成(复位指令执行完毕)

0(RESET)

检验执行ADC校准功能的状态(完成/进行中)

正在开始执行ADC校准功能

1(SET)

ADC校准功能执行完毕

0(RESET)

此外,ADC_SR状态寄存器中的标志位EOC位代表着“ADC转换工作是否结束”:

 

功能

状态

位标志

查看ADC转换是否结束

ADC转换结束

1(SET)

ADC转换完成

0(RESET)

ADC转换函数

u16 ADC_GetValue()  
{     
    ADC_RegularChannelConfig(ADC1, ADC_Channel_16, 1, ADC_SampleTime_239Cycles5 );  //ADC1,ADC通道3,第一个转换,采样时间为239.5周期                      
   
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);     //使能指定的ADC1的软件转换启动功能  
      
    while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束  
      
    return ADC_GetConversionValue(ADC1);    //返回最近一次ADC1规则组的转换结果  
}  

注意:我们一定要在读取ADC通道转换值得函数中去执行:

ADC_SoftwareStartConvCmd(ADC1, ENABLE);     //使能指定的ADC1的软件转换启动功能  
      
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束 

我们初始化时只想初始化ADCx设备的属性,而函数“ADC_SoftwareStartConvCmd”得功能是根据ADCx各个引脚的属性启动ADCx外设进行转换操作。显然,初始化时不应进行获取转换值得操作。

多次读取取平均函数

 //获取通道ch的转换值  
//取times次,然后平均  
u16 T_Get_Adc_Average(u8 ch,u8 times)  
{  
    u32 temp_val=0;  
    u8 t;  
    for(t=0;t<times;t++)  
    {  
        temp_val+=T_Get_Adc(ch);  
        delay_ms(5);  
    }  
    return temp_val/times;  
} 

ADC转换的数字量转换为所需温度的函数

//得到温度值  
//返回值:温度值(扩大了100倍,单位:℃.)  
short Get_Temprate(void)    //获取内部温度传感器温度值  
{  
    u32 adcx;  
    short result;  
    double temperate;  
    adcx=T_Get_Adc_Average(ADC_Channel_16,20);  //读取通道16,20次取平均  
    temperate=(float)adcx*(3.3/4096);       //电压值   
    temperate=(1.43-temperate)/0.0043+25;   //转换为温度值       
    result=temperate*=100;                  //扩大100倍.  
    return result;  
}

总体代码示例

TempSensor.c

#include "TempSensor.h"  
#include "stm32f10x.h"  
#include "delay.h"  
  
void ADC_InitConfig()  
{  
    ADC_InitTypeDef ADC_InitStructure;  
      
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);  
      
    ADC_DeInit(ADC1);  
    RCC_ADCCLKConfig(RCC_PCLK2_Div6);  
      
    ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;  
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Left;  
    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_TempSensorVrefintCmd(ENABLE); // 使能内部温度传感器  
      
    ADC_Cmd(ADC1,ENABLE); // 使能ADC1  
      
    ADC_ResetCalibration(ADC1); // 开始ADC1的校准寄存器复位  
    while(ADC_GetResetCalibrationStatus(ADC1));  
      
    ADC_StartCalibration(ADC1); // 开始ADC1的自动校准功能  
    while(ADC_GetCalibrationStatus(ADC1));  
      
    delay_init();  
}  
  
u16 ADC_GetValue()  
{     
    ADC_RegularChannelConfig(ADC1, ADC_Channel_16, 1, ADC_SampleTime_239Cycles5 );  //ADC1,ADC通道3,第一个转换,采样时间为239.5周期                      
   
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);     //使能指定的ADC1的软件转换启动功能  
      
    while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束  
      
    return ADC_GetConversionValue(ADC1);    //返回最近一次ADC1规则组的转换结果  
}  
  
u16 ADC_GetAverageValue()  
{  
    u8 i = 0;  
    u16 temp = 0;  
      
    for(;i<5;i++)  
    {  
        temp += ADC_GetValue();  
        delay_ms(5);  
    }  
    return temp/5;  
}  
  
u16 DigitalValueConversion()  
{  
    float temp = ADC_GetAverageValue();  
    return ((1.43-3.3*(temp/4096))/0.043+25)*100;  
}  

TempSensor.h

#ifndef _TEMPSENSOR_H  
#define _TEMPSENSOR_H  
  
#include "sys.h"  
  
void ADC_InitConfig();  
u16 ADC_GetValue();  
u16 ADC_GetAverageValue();  
u16 DigitalValueConversion();  
  
#endif  

Main.c

#include "TempSensor.h"  
#include "stm32f10x.h"  
#include "usart.h"  
#include "delay.h"  
#include "lcd.h"  
  
int main()  
{  
    u16 temp = 0;  
      
    ADC_InitConfig();  
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);  
    uart_init(115200);  
    delay_init();  
    LCD_Init();  
    LCD_Clear(BLUE);  
      
    temp = DigitalValueConversion();  
      
    POINT_COLOR=RED;//设置字体为红色   
    LCD_ShowString(30,50,200,16,16,"WarShip STM32");      
    LCD_ShowString(30,70,200,16,16,"Temperature TEST");   
    LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");  
    LCD_ShowString(30,110,200,16,16,"2015/1/14");  
    LCD_ShowString(30,140,200,16,16,"TEMPERATE: 00.00C");  
      
    while(1)  
    {  
        temp = DigitalValueConversion();  
        LCD_ShowNum(30+11*8,140,temp/100,2,16);  
        LCD_ShowNum(30+14*8,140,temp%100,2,16);  
        delay_ms(150);  
    }  
}  

程序运行结果

 

猜你喜欢

转载自blog.csdn.net/weixin_45590473/article/details/108677470