超级版主
 
- 积分
- 5644
- 金钱
- 5644
- 注册时间
- 2019-5-8
- 在线时间
- 1511 小时
|
|
第三十四章 内部温度传感器实验
1)实验平台:正点原子STM32H7R7开发板
2)章节摘自【正点原子】STM32H7R7开发指南 V1.1
3)购买链接: https://detail.tmall.com/item.htm?id=820823382459
4)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boards/stm32/zdyz_stm32h7rx.html
5)正点原子官方B站:https://space.bilibili.com/394620890
6)正点原子STM32开发板技术交流群:756580169
本章,我们将介绍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
- * [url=home.php?mod=space&uid=271674]@param[/url] 无
- * @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 内部温度传感器实验测试图
大家可以看看你的温度值与实际是否相符合(因为芯片会发热,所以一般会比实际温度偏高) |
|