当前位置: 首页 > news >正文

10.STM32F407ZGT6-内部温度传感器

参考:
1.正点原子
前言:
本笔记的主要目的和意义就是,再次练习ADC的使用。

32.1 内部温度传感器简介

STM32F407 有一个内部的温度传感器,可以用来测量 CPU 及周围的温度(TA)。对于STM32F407 系列来说,该温度传感器在内部和 ADC1_INP16(STM32F40xx/F41xx 系列)或ADC_IN18(STM32F42xx/F43xx)输入通道相连接,此通道把传感器输出的电压转换成数字值。
STM32F4 的内部温度传感器支持的温度范围为:-40~125 度。精度为±1.5℃左右。
STM32F407 内部温度传感器的使用很简单,只要设置一下内部 ADC,并激活其内部温度传感器通道就差不多了。关于 ADC 的设置,我们在上一章已经进行了详细的介绍,这里就不再多说。接下来我们介绍一下和温度传感器设置相关的两个地方。
第一个地方,我们要使用 STM32F407 的内部温度传感器,必须先激活 ADC 的内部通道,这里通过 ADC_CCR 的 VSENSEEN 位(bit23)设置。设置该位为 1 则启用内部温度传感器。
第二个地方,STM32F407ZGT6 的内部温度传感器固定的连接在 ADC1 的通道 16 上,所以,我们在设置好 ADC1 之后只要读取通道 16 的值,就是温度传感器返回来的电压值了。根据这个值,我们就可以计算出当前温度。计算公式如下:
𝑇(℃) ={ (Vsense - V25) / Avg_Slope}+25
式子中:
V25 = Vsense 在 25 度时的数值(典型值为:0.76)
Avg_Slope = 温度与 Vsense 曲线的平均斜率(单位:mv/℃或 uv/℃)(典型值:2.5mv/℃)。
利用以上公式,我们就可以方便的计算出当前温度传感器的温度了。

现在,我们就可以总结一下 STM32 内部温度传感器使用的步骤了,如下:
1)设置 ADC,并开启 ADC_CR2 的 VSENSEEN 位。
关于如何设置 ADC,请参考上一章对单通道 ADC 采集实验的设置,都是大同小异。然后,我们需要设置 ADC_CR2 寄存器的 VSENSEEN 位为 1,开启内部温度传感器。
2)读取 ADC 通道 16 的 AD 值,计算结果。
在设置完之后,我们就可以读取温度传感器的电压值了,得到该值就可以用上面的公式计算温度值了。

32.2 硬件设计

  1. 例程功能
    通过 ADC1 的通道 16 读取 STM32F407 内部温度传感器的电压值,并将其转换为温度值,通过串口输出。
  2. 硬件资源
    1)串口 1(PA9/PA10 连接在板载 USB 转串口芯片 CH340 上面)
    2)ADC1 通道 16
    3)内部温度传感器
  3. 原理图
    ADC 和内部温度传感器都属于 STM32F407 内部资源,实际上我们只需要软件设置就可以正常工作。

32.3 程序设计

32.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 值。最后根据上面介绍的公式计算出温度传感器的温度值。

32.3.3 程序解析

1. adc 驱动代码
首先是 ADC 初始化函数,其定义如下:

void MX_ADC1_Init(void)
{/* USER CODE BEGIN ADC1_Init 0 *//* USER CODE END ADC1_Init 0 */ADC_ChannelConfTypeDef sConfig = {0};/* USER CODE BEGIN ADC1_Init 1 *//* USER CODE END ADC1_Init 1 *//** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)*/hadc1.Instance = ADC1;hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;hadc1.Init.Resolution = ADC_RESOLUTION_12B;hadc1.Init.ScanConvMode = DISABLE;hadc1.Init.ContinuousConvMode = DISABLE;hadc1.Init.DiscontinuousConvMode = DISABLE;hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;hadc1.Init.NbrOfConversion = 1;hadc1.Init.DMAContinuousRequests = DISABLE;hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;if (HAL_ADC_Init(&hadc1) != HAL_OK){Error_Handler();}/** Configure for the selected ADC regular channel its corresponding rank in the sequencer and its sample time.*/sConfig.Channel = ADC_CHANNEL_TEMPSENSOR;    /*ADC16通道*/sConfig.Rank = 1;sConfig.SamplingTime = ADC_SAMPLETIME_3CYCLES;if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)/*配置了ADC16,该函数就会打开内部温度传感器*/{Error_Handler();}/* USER CODE BEGIN ADC1_Init 2 *//* USER CODE END ADC1_Init 2 */}

下面是获得 ADC 转换后的结果函数,其定义如下:

#include "adc_app.h"extern ADC_HandleTypeDef hadc1;/**
* @brief 设置 ADC 通道采样时间
* @param adcx : adc 句柄指针,ADC_HandleTypeDef
* @param ch : 通道号, ADC_CHANNEL_0~ADC_CHANNEL_17
* @param stime: 采样时间 0~7, 对应关系为:
* @arg ADC_SAMPLETIME_3CYCLES, 3 个 ADC 时钟周期ADC_SAMPLETIME_15CYCLES, 15 个 ADC 时钟周期
* @arg ADC_SAMPLETIME_28CYCLES, 28 个 ADC 时钟周期 ADC_SAMPLETIME_56CYCLES, 56 个 ADC 时钟周期
* @arg ADC_SAMPLETIME_84CYCLES, 84 个 ADC 时钟周期 ADC_SAMPLETIME_112CYCLES,112 个 ADC 时钟周期
* @arg ADC_SAMPLETIME_144CYCLES,144 个 ADC 时钟周期ADC_SAMPLETIME_480CYCLES,480 个 ADC 时钟周期
* @param rank: 多通道采集时需要设置的采集编号, 假设你定义 channel1 的 rank=1,channel2 的 rank=2,
* 那么对应你在 DMA 缓存空间的变量数组 AdcDMA[0] 就 i 是 channle1 的转换结果, AdcDMA[1]就是通道 2 的转换结果。单通道 DMA 设置为 ADC_REGULAR_RANK_1
* @arg 编号 1~16:ADC_REGULAR_RANK_1~ADC_REGULAR_RANK_16
* @retval 无
*/
void adc_channel_set(ADC_HandleTypeDef *adc_handle, uint32_t ch, uint32_t rank, uint32_t stime)
{/* 配置对应 ADC 通道 */ADC_ChannelConfTypeDef adc_channel;adc_channel.Channel = ch; /* 设置 ADCX 对通道 ch */adc_channel.Rank = rank; /* 设置采样序列 */adc_channel.SamplingTime = stime; /* 设置采样时间 */HAL_ADC_ConfigChannel( adc_handle, &adc_channel); 
}/**
* @brief 获得 ADC 转换后的结果
* @param ch: 通道值 0~17,取值范围为:ADC_CHANNEL_0~ADC_CHANNEL_17
* @retval 无
*/
uint32_t adc_get_result(uint32_t ch)
{/* 设置通道,序列和采样时间 *///adc_channel_set(&hadc1, ch, 1, ADC_SAMPLETIME_480CYCLES);HAL_ADC_Start(&hadc1); /* 开启 ADC */HAL_ADC_PollForConversion(&hadc1, 10); /* 轮询转换 *//* 返回最近一次 ADC1 规则组的转换结果 */return (uint16_t)HAL_ADC_GetValue(&hadc1);
}/**
* @brief 获取通道 ch 的转换值,取 times 次,然后平均
* @param ch : 通道号, 0~17
* @param times : 获取次数
* @retval 通道 ch 的 times 次转换结果平均值
*/
uint32_t adc_get_result_average(uint32_t ch, uint8_t times)
{uint32_t temp_val = 0;uint8_t t;for (t = 0; t < times; t++) /* 获取 times 次数据 */{temp_val += adc_get_result(ch);}return temp_val / times; /* 返回平均值 */
}/**
* @brief 获取内部温度传感器温度值
* @param 无
* @retval 温度值(扩大了 100 倍,单位:℃.)
*/
float adc_get_temperature(void)
{uint32_t adcx;float result;double temperature;adcx = adc_get_result_average(ADC_CHANNEL_TEMPSENSOR, 10);/* 读取内部温度传感器通道,10 次取平均 */temperature = (float)adcx*(3.3/4096); /* 获取电压值 */temperature = (temperature - 0.76)/0.0025 + 25; /* 将电压值转换为温度值 */result = temperature;return result;
}

该函数先是调用前面 ADC 实验章节写好的 adc_get_result_average 函数取获取通道 ch 的转换值,然后通过温度转换公式,返回温度值。

2. main.c 代码
在 main.c 里面编写如下代码:

int main(void)
{/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_DMA_Init();MX_USART1_UART_Init();MX_TIM6_Init();MX_RTC_Init();MX_ADC1_Init();/* USER CODE BEGIN 2 *//* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){uart_debug_task();XL_TIME6_time_show();    /*周期输出内部温度值*//* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}

3.内部温度周期调用

#include "stdio.h"
#include "tim.h"
#include "usart.h"
#include "rtc.h"
#include "adc_app.h"#define TIME_PERIODIC_1S  (10)      /*1s打印一次*/
#define TIME_PERIODIC_10S  (100)      /*修改为10s打印一次*/static uint32_t g_time_1s = 0;
static uint32_t g_time_10s = 0;void LED_blink(void)
{HAL_GPIO_TogglePin(LED_0_GPIO_Port, LED_0_Pin);HAL_GPIO_TogglePin(LED_1_GPIO_Port, LED_1_Pin);
}void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{if (htim->Instance == TIM6){LED_blink();g_time_1s++;g_time_10s++;}}void XL_TIME6_time_show(void)
{if (g_time_1s >= TIME_PERIODIC_1S){g_time_1s = g_time_1s - TIME_PERIODIC_1S;float tmp_value = adc_get_temperature();printf("tmp_value:%f\r\n", tmp_value);}if (g_time_10s >= TIME_PERIODIC_10S){g_time_10s = g_time_10s - TIME_PERIODIC_10S;RTC_TimeTypeDef sTime = {0};HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN);printf("H:%d, M:%d, S:%d\r\n", sTime.Hours, sTime.Minutes, sTime.Seconds);RTC_DateTypeDef sDate = {0};HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BIN);printf("Y:%d, M:%d, W:%d, D:%d\r\n", sDate.Year, sDate.Month, sDate.WeekDay, sDate.Date);}
}

32.4 下载验证

将程序下载到开发板后,可以看到串口周期输出温度:稳定在31.3度左右(因为芯片会发热,所以一般会比实际温度偏高一点)
在这里插入图片描述

32.5 STM32CubeMX

1.内部温度的配置
在这里插入图片描述

32.6 源代码路径

git clone git@gitee.com:xiaoliangliangcong/stm32.git
STM32F407ZGT6/10.internal_temperature_sensor


http://www.mrgr.cn/news/83394.html

相关文章:

  • 排序的本质、数据类型及算法选择
  • 【跨域问题】
  • 计算机网络——网络层—IP数据报与分片
  • iostat命令详解
  • 【Java知识】Groovy 一个兼容java的编程语言
  • “深入浅出”系列之QT:(6)如何在一个项目中调用另一个项目
  • 【论文+源码】一个基于Vue.js的MOBA类游戏攻略分享平台
  • Java SpringBoot + Vue + Uniapp 集成JustAuth 最快实现多端三方登录!(QQ登录、微信登录、支付宝登录……)
  • C++中 为什么要把基类指针指向子类对象?
  • Java 应用程序CPU 100%问题排查优化实战
  • 图像模糊度(清晰度)检测 EsFFT 算法详细分析
  • Java Web开发进阶——Spring Boot与Thymeleaf模板引擎
  • 计算机的错误计算(二百零八)
  • 一分钟学会文心一言API如何接入,文心一言API接入教程
  • 1.两数之和--力扣
  • 第26章 汇编语言--- 内核态与用户态
  • 01 Oracle自学环境搭建(Windows系统)
  • 超完整Docker学习记录,Docker常用命令详解
  • 模式识别与机器学习
  • 类与对象(上)
  • Python自学 - 类进阶(可调用对象)
  • 《HeadFirst设计模式》笔记(下)
  • 第27章 汇编语言--- 设备驱动开发基础
  • RNN之:LSTM 长短期记忆模型-结构-理论详解(Matlab向)
  • win32汇编环境,怎么进行乘法运算的
  • 测试开发之面试宝典