10.STM32F407ZGT6-内部温度传感器

news2025/1/12 9:36:46

参考:
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.coloradmin.cn/o/2275431.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

新车月交付突破2万辆!小鹏汽车“激活”智驾之困待解

首次突破月交付2万辆规模的小鹏汽车&#xff0c;稳吗&#xff1f; 本周&#xff0c;高工智能汽车研究院发布的最新监测数据显示&#xff0c;2024年11月&#xff0c;小鹏汽车在国内市场&#xff08;不含出口&#xff09;交付量&#xff08;上险口径&#xff0c;下同&#xff09…

【2024年华为OD机试】 (A卷,100分)- 租车骑绿岛(Java JS PythonC/C++)

一、问题描述 题目描述 部门组织绿岛骑行团建活动。租用公共双人自行车&#xff0c;每辆自行车最多坐两人&#xff0c;最大载重 M。 给出部门每个人的体重&#xff0c;请问最多需要租用多少双人自行车。 输入描述 第一行两个数字 m、n&#xff0c;分别代表自行车限重&#…

AI在零售行业中的应用:提升顾客体验与运营效率

你知道吗&#xff1f;零售行业正悄悄发生着一场革命&#xff01;AI正在改变我们的购物方式&#xff0c;提升体验的同时&#xff0c;还让商家们的运营更高效&#xff01; 1、个性化推荐 AI通过分析你的购物历史和兴趣&#xff0c;精准推荐你喜欢的商品&#xff0c;再也不怕刷到…

人才选拔中,如何优化面试流程

在与某大型央企的深入交流中&#xff0c;随着该企业的不断壮大与业务扩张&#xff0c;对技术人才的需求急剧上升&#xff0c;尽管企业加大了招聘力度并投入了大量资源&#xff0c;但招聘成效却不尽如人意。经过项目组细致调研与访谈&#xff0c;问题的根源逐渐浮出水面&#xf…

Deepin20.9 搭建 JDK 8 开发环境(VS Code)

一、安装指令 sudo apt-get install openjdk-8-jdk 二、切换 java 版本&#xff08;可选&#xff09; sudo update-alternatives --config java sudo update-alternatives --config javac sudo update-alternatives --config javadoc三、查看 java 与 javac 的版本 jav…

可靠的人形探测,未完待续(III)

一不小心&#xff0c;此去经年啊。问大家新年快乐&#xff01; 那&#xff0c;最近在研究毫米波雷达模块嘛&#xff0c;期望用在后续的产品中&#xff0c;正好看到瑞萨的活动送板子&#xff0c;手一下没忍住。 拿了板子就得干活咯&#xff0c;我一路火花带闪电&#xff0c;开整…

论文笔记:FDTI: Fine-grained Deep Traffic Inference with Roadnet-enriched Graph

2023 PKDD 1 intro 一些交通预测下游任务对预测结果的粒度非常敏感&#xff0c;例如交通信号控制、拥堵发现和路径规划 然而&#xff0c;现有的深度学习方法主要关注粗粒度的交通数据&#xff0c;而在细粒度设置下利用深度学习方法解决交通预测任务的研究仍未被探索在细粒度设…

如何BugReport和PowerMonitor图形结合分析功耗问题

一、什么是BugReport和PowerMonitor图形结合呢&#xff1f; Battery Historian是支持PowerMonitor电流图显示的&#xff0c;具体显示效果如下&#xff1a;我们移动鼠标到PowerMonitor的电流波形时就会显示这个时刻的电流情况。 BugReport和PowerMonitor图形结合好处&#xff…

外部获取nVisual所在层级方法

Iframe嵌入nVisual&#xff0c;在iframe渲染完成之后&#xff0c;以后通过增加window.addEventListener()方法监听message事件&#xff0c;来获取nvisual当前的所在层级以及所选中的节点列表以及线缆列表。 nVisualPatrolDiagramIdList 变量是获取nVisual当前所在的层级的ID值…

UI自动化测试框架playwright--初级入门

一、背景&#xff1a;UI自动化的痛点&#xff1a; 1、设计脚本耗时&#xff1a; 需要思考要如何模拟用户的操作&#xff0c;如何触发页面的事件&#xff0c;还要思考如何设计脚本&#xff0c;定位和操作要交互的元素、路径、位置&#xff0c;再编写代码逻辑&#xff0c;往复循…

开放词汇检测新晋SOTA:地瓜机器人开源DOSOD实时检测算法

在计算机视觉领域&#xff0c;目标检测是一项关键技术&#xff0c;旨在识别图像或视频中感兴趣物体的位置与类别。传统的闭集检测长期占据主导地位&#xff0c;但近年来&#xff0c;开放词汇检测&#xff08;Open-Vocabulary Object Detection-OVOD 或者 Open-Set Object Detec…

Jupyter Notebook 安装PyTorch

1、判断当前环境 通过如下命令可以看出是Anaconda 环境 2、Anaconda 环境安装 PyTorch 2.1 要执行的命令 如果你使用的是 Anaconda 环境&#xff0c;可以使用以下命令来安装 PyTorch&#xff1a; conda install pytorch -c pytorch 2.2 执行遇到的问题&#xff1a;没有权…

如何将json字符串格式化

文章目录 如何对json字符串进行格式化显示hutool方案的示例和不足使用fastjson的方案 如何对json字符串进行格式化显示 将json字符串内容进行格式化的输出显示。本文介绍 hutool的方案和alibaba 的fastjson方案 hutool方案的示例和不足 引入依赖 <dependency><grou…

C#使用OpenTK绘制3D可拖动旋转图形三棱锥

接上篇,绘制着色矩形 C#使用OpenTK绘制一个着色矩形-CSDN博客 上一篇安装OpenTK.GLControl后,这里可以直接拖动控件GLControl 我们会发现GLControl继承于UserControl //// 摘要:// OpenGL-aware WinForms control. The WinForms designer will always call the default//…

【Git原理和使用】Git 分支管理(创建、切换、合并、删除、bug分支)

一、理解分支 我们可以把分支理解为一个分身&#xff0c;这个分身是与我们的主身是相互独立的&#xff0c;比如我们的主身在这个月学C&#xff0c;而分身在这个月学java&#xff0c;在一个月以后我们让分身与主身融合&#xff0c;这样主身在一个月内既学会了C&#xff0c;也学…

概率图模型01

机器学习中&#xff0c;线性回归、树、集成和概率图都属于典型的统计学习方法&#xff0c;概率图模型会更深入地体现出‘统计’两字 概率图模型的常见算法 概率图模型中的图 概率图模型如图主要分为两种&#xff0c;即贝叶斯网络和马尔可夫网络&#xff0c;有向图与无向图&…

解决WordPress出现Fatal error: Uncaught TypeError: ftp_nlist()致命问题

错误背景 WordPress版本&#xff1a;wordpress-6.6.2-zh_CN WooCommerce版本&#xff1a;woocommerce.9.5.1 WordPress在安装了WooCommerce插件后&#xff0c;安装的过程中没有问题&#xff0c;在安装完成后提示&#xff1a; 此站点遇到了致命错误&#xff0c;请查看您站点管理…

《HeadFirst设计模式》笔记(下)

11 代理模式 代理要做的就是控制和管理访问。 你的客户对象所做的就像是在做远程方法调用&#xff0c;但其实只是调用本地堆中的“代理”对象上的方法&#xff0c;再由代理处理所有网络通信的低层细节。 Java的RMI提供了客户辅助对象和服务辅助对象&#xff0c;为客户辅助对…

【Uniapp-Vue3】v-if条件渲染及v-show的选择对比

如果我们想让元素根据响应式变量的值进行显示或隐藏可以使用v-if或v-show 一、v-show 另一种控制显示的方法就是使用v-show&#xff0c;使用方法和v-if一样&#xff0c;为true显示&#xff0c;为false则不显示。 二、v-if v-if除了可以像v-show一样单独使用外&#xff0c;还…

【MySQL数据库】基础总结

目录 前言 一、概述 二、 SQL 1. SQL通用语法 2. SQL分类 3. DDL 3.1 数据库操作 3.2 表操作 4. DML 5. DQL 5.1 基础查询 5.2 条件查询 5.3 聚合函数 5.4 分组查询 5.5 排序查询 5.6 分页查询 6. DCL 6.1 管理用户 6.2 权限控制 三、数据类型 1. 数值类…