第三十四章 内部温度传感器实验
本章,我们将介绍STM32H7R7的内部温度传感器并使用它来读取温度值,然后在LCD模块上显示出来。
本章分为如下几个小节:
34.1 内部温度传感器简介
34.2 硬件设计
34.3 程序设计
34.4 下载验证
34.1 内部温度传感器简介
STM32H7R7有一个内部的温度传感器,可以用来测量CPU及周围的温度(TA)。对于STM32H7系列来说,该温度传感器在内部和ADC1_IN16输入通道相连接,此通道把传感器输出的电压转换成数字值。STM32H7R7的内部温度传感器支持的温度范围为:-40~125度。精度为±3℃左右。
STM32H7R7内部温度传感器的使用很简单,只要设置一下内部ADC,并激活其内部温度传感器通道就差不多了。关于ADC的设置,我们在上一章已经进行了详细的介绍,这里就不再多说。接下来我们介绍一下和温度传感器设置相关的两个地方。
第一个地方,我们要使用STM32H7R7的内部温度传感器,必须先激活ADC的内部通道,这里通过ADC_CCR的TSEN位(bit23)设置。设置该位为1则启用内部温度传感器。
第二个地方,STM32H7R7L8H6H的内部温度传感器固定的连接在ADC1的通道16上,所以,我们在设置好ADC1之后只要读取通道16的值,就是温度传感器返回来的电压值了。根据这个值,我们就可以计算出当前温度。计算公式如下:

式子中:
TS_CAL1 是温度传感器在30℃时的校准值,固定保存在芯片内部的:0x08FFF814 ~ 0x08FFF815这两个地址(16位)。
TS_CAL2 是温度传感器在110℃时的校准值,固定保存在芯片内部的:0x08FFF818 ~ 0x08FFF819这两个地址(16位)。
TS_DATA:ADC1通道16读取到的当前温度传感器转换值。
利用以上公式,我们就可以方便的计算出当前温度传感器的温度了。
34.2 硬件设计
1. 例程功能
通过ADC1的通道16读取STM32H7R7内部温度传感器的电压值,并将其转换为温度值,显示在TFTLCD屏上。LED0闪烁用于提示程序正在运行。
2. 硬件资源
1)LED灯
LED0: LED0 – PD14
2)串口1(PB14/PB15连接在板载USB转串口芯片CH340上面)
3)正点原子2.8/3.5/4.3/7/10寸TFTLCD模块(包括MCU屏和RGB屏,都支持)
4)ADC1 通道16
5)内部温度传感器
34.3 程序设计
34.3.1 ADC的HAL库驱动
本实验用到的ADC的HAL库API函数前面都介绍过,具体调用情况请看程序解析部分。下面介绍读取内部温度传感器ADC值的配置步骤。
读取内部温度传感器ADC值配置步骤
1)开启ADC时钟
通过__HAL_RCC_ADC1_CLK_ENABLE函数开启ADC1的时钟。
2)设置ADC1,开启内部温度传感器
调用HAL_ADC_Init函数来设置ADC1时钟分频系数、分辨率、模式、扫描方式、对齐方式等信息。
注意:该函数会调用:HAL_ADC_MspInit回调函数来完成对ADC底层的初始化,包括:ADC1时钟使能、ADC1时钟源的选择等。
3)配置ADC通道并启动AD转换器
调用HAL_ADC_ConfigChannel()函数配置ADC1通道16,根据需求设置通道、序列、采样时间和校准配置单端输入模式或差分输入模式等。然后通过HAL_ADC_Start函数启动AD转换器。
4)读取ADC值,计算温度
这里选择查询方式读取,在读取ADC值之前需要调用HAL_ADC_PollForConversion等待上一次转换结束。然后就可以通过HAL_ADC_GetValue来读取ADC值。最后根据上面介绍的公式计算出温度传感器的温度值。
34.3.2 程序解析
1. adc驱动代码
这里我们只讲解核心代码,详细的源码请大家参考光盘本实验对应源码。ADC驱动源码包括两个文件:adc.c和adc.h。
adc.h头文件只有一些函数的声明,我们直接看adc.c:
ADC_CHANNEL_TEMPSENSOR就是ADC1通道16连接内部温度传感器的宏定义。
下面我们直接看ADC初始化函数,其定义如下:
/**
* @brief 初始化ADC
* @param 无
* @retval 无
*/
void adc_init(void)
{
/* 初始化ADC */
g_adc_handle.Instance = ADC1;
g_adc_handle.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV8;
/* 时钟源和预分频系数 */
g_adc_handle.Init.Resolution = ADC_RESOLUTION_12B; /* 分辨率 */
g_adc_handle.Init.DataAlign = ADC_DATAALIGN_RIGHT; /* 数据对齐 */
g_adc_handle.Init.ScanConvMode = ADC_SCAN_DISABLE; /* 扫描转换模式 */
g_adc_handle.Init.EOCSelection = ADC_EOC_SINGLE_CONV; /* EOC */
g_adc_handle.Init.LowPowerAutoWait = DISABLE; /* 低功耗自动延迟 */
g_adc_handle.Init.ContinuousConvMode = DISABLE; /* 连续转换模式 */
g_adc_handle.Init.NbrOfConversion = 1; /* 连续转换模式下的转换数量 */
g_adc_handle.Init.DiscontinuousConvMode = DISABLE; /* 非连续转换模式 */
g_adc_handle.Init.NbrOfDiscConversion = 1; /* 非连续转换模式下的转换数量 */
g_adc_handle.Init.ExternalTrigConv = ADC_SOFTWARE_START;
/* 规则组转换外部触发源 */
g_adc_handle.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
/* 规则组转换外部触发源的有效沿 */
g_adc_handle.Init.SamplingMode = ADC_SAMPLING_MODE_NORMAL;
/* 采样模式 */
g_adc_handle.Init.ConversionDataManagement = ADC_CONVERSIONDATA_DR;
/* 管理转换数据 */
g_adc_handle.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN; /* 溢出行为 */
g_adc_handle.Init.OversamplingMode = DISABLE; /* 过采样模式 */
HAL_ADC_Init(&g_adc_handle);
/* ADC自动自校准 */
HAL_ADCEx_Calibration_Start(&g_adc_handle, ADC_SINGLE_ENDED);
}
该函数调用adc_init函数配置了ADC的基础功能参数,我们对内部温度传感器的初始化步骤与普通ADC类似。
下面是获得ADC转换后的结果函数,其定义如下:
/**
* @brief 获取内部温度传感器结果
* @param 无
* @retval 温度值(单位:摄氏度)
*/
int32_t adc_get_temperature(void)
{
/* HAL库中TEMPSENSOR_CAL1_ADDR和TEMPSENSOR_CAL2_ADDR的定义有误 */
#ifdef TEMPSENSOR_CAL1_ADDR
#undef TEMPSENSOR_CAL1_ADDR
#define TEMPSENSOR_CAL1_ADDR ((uint16_t*)(0x08FFF814UL))
#endif
#ifdef TEMPSENSOR_CAL2_ADDR
#undef TEMPSENSOR_CAL2_ADDR
#define TEMPSENSOR_CAL2_ADDR ((uint16_t*)(0x08FFF818UL))
#endif
uint32_t result;
result = adc_get_result_average(ADC_CHANNEL_TEMPSENSOR, 10);
return __HAL_ADC_CALC_TEMPERATURE(VREFINT_CAL_VREF, result,
ADC_RESOLUTION_12B);
}
该函数先是调用adc_get_result_average函数取获取通道ch的转换值,然后通过温度转换公式,返回温度值。
2. main.c代码
在main.c里面编写如下代码:
int main(void)
{
int32_t temperature;
sys_mpu_config(); /* 配置MPU */
sys_cache_enable(); /* 使能Cache */
HAL_Init(); /* 初始化HAL库 */
sys_stm32_clock_init(300, 6, 2); /* 配置时钟,600MHz */
delay_init(600); /* 初始化延时 */
usart_init(115200); /* 初始化串口 */
led_init(); /* 初始化LED */
hyperram_init(); /* 初始化HyperRAM */
lcd_init(); /* 初始化LCD */
adc_init(); /* 初始化ADC */
lcd_show_string(30, 50, 200, 16, 16, "STM32", RED);
lcd_show_string(30, 70, 200, 16, 16, "Temperature TEST", RED);
lcd_show_string(30, 90, 200, 16, 16, "ATOM@ALIENTEK", RED);
lcd_show_string(30, 110, 200, 16, 16, "TEMPERATE: 00C", BLUE);
while (1)
{
/* 获取内部温度传感器结果 */
temperature = adc_get_temperature();
printf("0x%08X\r\n", temperature);
/* 显示温度 */
if (temperature < 0)
{
temperature = -temperature;
lcd_show_string(30 + 10 * 8, 110, 16, 16, 16, "-", BLUE);
}
else
{
lcd_show_string(30 + 10 * 8, 110, 16, 16, 16, " ", BLUE);
}
lcd_show_xnum(30 + 11 * 8, 110, temperature, 2, 16, 0, BLUE);
LED0_TOGGLE();
delay_ms(100);
}
}
该部分的代码逻辑很简单,先是得到温度值,再根据温度值判断正负值,来显示温度符号,再显示温度值。
34 .4 下载验证
将程序下载到开发板后,可以看到LED0不停的闪烁,提示程序已经在运行了。LCD显示的内容如图34.4.1所示:

图34.4.1 内部温度传感器实验测试图
大家可以看看你的温度值与实际是否相符合(因为芯片会发热,所以一般会比实际温度偏高)
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70040860/viewspace-3094734/ ,如需转载,请注明出处,否则将追究法律责任。