内部温度传感器简介测量的温度位置 内部温度传感器集成在芯片中,测量的是芯片的温度。
如何测量对应位置的温度?
温度传感器与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) |
DC转换函数
- 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);
- }
- }
复制代码
程序运行结果
|