上一篇下一篇
ADC 实例 4 :单通道 ADC 过采样实例,使用 DMA


3.5)内部温度传感器读取

STM32 各系列 MCU 中内部温度传感器的相关数据:

在这里插入图片描述

上电在 HAL_ADC_ConfigChannel() 函数中执行。

① 温度计算公式:

T ( ℃ ) = ( V 25 − V S E N S E A v g _ S l o p e ) + 25 \large T(℃) = (\frac{V_{25}−V_{SENSE}}{Avg\_Slope})+25 T(℃)=(Avg_SlopeV25​−VSENSE​​)+25

V 25 V_{25} V25​ = 25 ℃ 时的 V S E N S E V_{SENSE} VSENSE​ 值(典型值为: 1.43)

A v g _ S l o p e Avg\_Slope Avg_Slope = 温度与 V S E N S E V_{SENSE} VSENSE​ 曲线的平均斜率(单位: mv/℃ 或 uv/℃)(典型值:4.3mv/℃)

V S E N S E V_{SENSE} VSENSE​ 是 ADC 采集到内部温度传感器的电压值(换算后的)

② 实验简要:

  • 功能描述:
    • 通过 ADC1 通道16 芯片内部温度传感器的电压,将电压值换算成温度后,用串口打印
  • 确定最小刻度:
    • V R E F + = 3.3 V V_{REF+} = 3.3V VREF+​=3.3V → 0 V ≤ V I N ≤ 3.3 V 0V≤V_{IN}≤3.3V 0V≤VIN​≤3.3V → 最小刻度 = 3.3 / 4096 V 3.3/4096V 3.3/4096V
  • 确定转换时间:
    • 采样时间设置为最大值 239.5 个 ADC 时钟周期,可以得到转换时间为 21us
  • 模式组合:
    • 单次转换模式、不使用扫描模式(即不使用 DMA 传输)
  • 注意:
    • 在单片机内部,调用 HAL_ADC_ConfigChannel() 函数的时候,会判断是否为温度传感器,是则给其上电。

③ 代码:

adc.c 文件代码:

#include "adc.h"
#include "delay.h"
#include "usart.h"


ADC_HandleTypeDef adc_handle;


/**
 * @brief   ADC初始化函数
 * @param   none
 * @retval  none
 * @note    单通道、单次转换模式、不使用扫描模式(不使用DMA)
 */
void adc_temperature_init(void)
{
    ADC_ChannelConfTypeDef adc_ch_conf;

    // 配置ADC工作参数
    adc_handle.Instance = ADC1;                           
    adc_handle.Init.DataAlign = ADC_DATAALIGN_RIGHT;        // 对齐方式:右对齐
    adc_handle.Init.ScanConvMode = ADC_SCAN_DISABLE;        // 扫描模式:失能
    adc_handle.Init.ContinuousConvMode = DISABLE;           // 连续转换模式:失能
    adc_handle.Init.NbrOfConversion = 1;                    // 转换通道总数
    adc_handle.Init.DiscontinuousConvMode = DISABLE;        // 不用管:直接失能
    adc_handle.Init.NbrOfDiscConversion = 0;                // 不用管:直接赋0
    adc_handle.Init.ExternalTrigConv = ADC_SOFTWARE_START;  // 软件触发
    HAL_ADC_Init(&adc_handle);
    
    // ADC校准
    HAL_ADCEx_Calibration_Start(&adc_handle);
    
    // 配置ADC通道相关参数
    adc_ch_conf.Channel = ADC_CHANNEL_16;                   // 输入通道号:通道16,内部温度传感器
    adc_ch_conf.Rank = ADC_REGULAR_RANK_1;                  // 转换顺序:第一个转换
    adc_ch_conf.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;  // 采样时间:239.5个周期
    HAL_ADC_ConfigChannel(&adc_handle, &adc_ch_conf);
}


/**
 * @brief   ADC MSP初始化函数
 * @param   ADC 句柄
 * @retval  none
 * @note    定义通道1 → PA1、使能时钟
 */
void HAL_ADC_MspInit(ADC_HandleTypeDef *hadc)
{
    if(hadc->Instance == ADC1)
    {
        RCC_PeriphCLKInitTypeDef adc_clk_init = {0};
        
        // 时钟使能:ADC1
        __HAL_RCC_ADC1_CLK_ENABLE();
        
        // 配置ADC1时钟
        adc_clk_init.PeriphClockSelection = RCC_PERIPHCLK_ADC;
        adc_clk_init.AdcClockSelection = RCC_ADCPCLK2_DIV6;  // 6分频,72/6=12MHz
        HAL_RCCEx_PeriphCLKConfig(&adc_clk_init);
    }
}


/**
 * @brief   ADC结果获取函数
 * @param   none
 * @retval  uint32_t类型的转换结果(实际是低16位有效)
 * @note    开始转换 → 等待转换 → 获取结果(读取DR寄存器)
 */
uint32_t adc_get_result(void)
{
    HAL_ADC_Start(&adc_handle);                      // 开始转换
    HAL_ADC_PollForConversion(&adc_handle, 10);      // 等待10ms
    return (uint16_t)HAL_ADC_GetValue(&adc_handle);  // 获取结果
}


/**
 * @brief   获取内部温度传感器温度值
 * @param   none
 * @retval  温度值(double型)
 */
double adc_get_temperature(void)
{
    uint32_t adcx;
    double temperature;

    adcx = adc_get_result();
    temperature = adcx * (3.3 / 4096);  // 电压值
    temperature = (1.43 - temperature) / 0.0043 + 25;  // 计算温度
    return temperature;
}

adc.h 文件代码如下:

#ifndef __ADC_H
#define __ADC_H

#include "sys.h"

void adc_temperature_init(void);    // ADC初始化
uint32_t adc_get_result(void);      // 获取ADC转换结果
double adc_get_temperature(void);    // 温度计算函数

#endif 

main.c 文件代码如下:

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "key.h"
#include "string.h"
#include "dma.h"
#include "adc.h"

// ====================================================================

int main(void)
{
    /* 局部变量 */
    float temp;
    
    /* 初始化函数 */
    HAL_Init();                         // 初始化HAL库    
    Stm32_Clock_Init(RCC_PLL_MUL9);     // 设置时钟,72M
    delay_init(72);                     // 初始化延时函数
    LED_Init();                         // 初始化LED
    KEY_Init();                         // 按键初始化
    uart_init(115200);                  // 串口1初始化
    adc_temperature_init();             // ADC读取温度函数初始化

    while(1)
    {
        temp = adc_get_temperature();            // 获取ADC转换结果
        printf("温度为:%f 摄氏度", temp);
        
        LED0=!LED0;
        delay_ms(100);
    }
}

实验结果为:

在这里插入图片描述


更多推荐