```C
2.12.2 实验要求
读取芯片内部温度传感器的温度并在软件环境中显示，或者通过串口、数码管等方式显
示。需要学生掌握白 AD 转换的方法和过程，及转换规则和通道的输入使用方式。
2.12.3 实验原理
STM32 有一个内部的温度传感器，可以用来测量 CPU 及周围的温度(TA)。该温度传
感器在内部和 ADCx_IN16 输入通道相连接，此通道把传感器输出的电压转换成数字值。温
度传感器模拟输入推荐采样时间是 17.1μs。 STM32 的内部温度传感器支持的温度范围为：
-40~125 度，精度为±1.5℃左右。
STM32 的 ADC 是 12 位逐次逼近型的模拟数字转换器。它有 18 个通道，可测量 16 
个外部和 2 个内部信号源。各通道的 A/D 转换可以单次、连续、扫描或间断模式执行。
ADC 的结果可以左对齐或右对齐方式存储在 16 位数据寄存器中。
STM32 将 ADC 的转换分为 2 个通道组：规则通道组和注入通道组。规则通道相当于
你正常运行的程序，而注入通道呢，就相当于中断。在你程序正常执行的时候，中断是可以
打断你的执行的。同这个类似，注入通道的转换可以打断规则通道的转换， 在注入通道被
转换完成之后，规则通道才得以继续转换
内部温度传感器固定的连接在 ADC1 的通道 16 上，所以，我们在设置好 ADC1 之后
只要读取通道 16 的值，就是温度传感器返回来的电压值了。
根据这个值，我们就可以计算出当前温度。
配置代码如下：
RCC->APB2ENR|=1<<9; //ADC1 时钟使能 
RCC->APB2RSTR|=1<<9; //ADC1 复位
RCC->APB2RSTR&=~(1<<9);//复位结束 
RCC->CFGR&=~(3<<14); //分频因子清零
//SYSCLK/DIV2=12M ADC 时钟设置为 12M,ADC 最大时钟不能超过 14M!
//否则将导致 ADC 准确度下降! 
RCC->CFGR|=2<<14; 
ADC1->CR1&=0XF0FFFF; //工作模式清零
ADC1->CR1|=0<<16; //独立工作模式 
ADC1->CR1&=~(1<<8); //非扫描模式 
ADC1->CR2&=~(1<<1); //单次转换模式
ADC1->CR2&=~(7<<17); 
ADC1->CR2|=7<<17; //软件控制转换 
ADC1->CR2|=1<<20; //使用用外部触发(SWSTART)!!! 必须使用一个事件来触发
ADC1->CR2&=~(1<<11); //右对齐
ADC1->CR2|=1<<23; //使能温度传感器
ADC1->SQR1&=~(0XF<<20);
ADC1->SQR1|=0<<20; //1 个转换在规则序列中 也就是只转换规则序列 1 
ADC1->SMPR1&=~(7<<3*6);//清除通道 16 原来的设置
ADC1->SMPR1|=7<<(3*6); //通道 16 239.5 周期,提高采样时间可以提高精确度
ADC1->CR2|=1<<0; //开启 AD 转换器
ADC1->CR2|=1<<3; //使能复位校准 
while(ADC1->CR2&1<<3); //等待校准结束
 //该位由软件设置并由硬件清除。在校准寄存器被初始化后该位将被清除。
ADC1->CR2|=1<<2; //开启 AD 校准 
while(ADC1->CR2&1<<2); //等待校准结束
//该位由软件设置以开始校准，并在校准结束时由硬件清除 
2.12.4 实验步骤
1）连接仿真器 USB 线，注意此时 USB 线不要和 PC 连接
2）连接仿真和开发板之间的 20 芯排线
3）仿真器 USB 线插入电脑 USB 接口
4）下载程序并调试，分析并检验实验结果
```

```C
/**
  ******************************************************************************
  * @file    temperature.c
  * @author  STM32 Temperature Sensor Demo
  * @version V1.0.0
  * @date    2026-01-06
  * @brief   ??????????????
  ******************************************************************************
  */

#include "temperature.h"
#include "stm32f10x_adc.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_gpio.h"
#include "stdio.h"

// ?????????(??STM32F10x????)
#define V25         1.43f    // 25°C????(V)
#define AVG_SLOPE   4.3f     // ????(mV/°C)
#define VREF        3.3f     // ????(V)
#define ADC_RES     4096.0f  // 12?ADC???

/**
  * @brief  ????????
  * @param  ?
  * @retval ?
  */
void TemperatureSensor_Init(void)
{
    ADC_InitTypeDef ADC_InitStructure;
    
    // 1. ??ADC1??
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
    
    // 2. ADC??
    RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1, ENABLE);
    RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1, DISABLE);
    
    // 3. ??ADC????
    RCC_ADCCLKConfig(RCC_PCLK2_Div6);  // 72MHz/6 = 12MHz
    
    // 4. ??ADC??
    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
    ADC_InitStructure.ADC_ScanConvMode = DISABLE;
    ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    ADC_InitStructure.ADC_NbrOfChannel = 1;
    
    ADC_Init(ADC1, &ADC_InitStructure);
    
    // 5. ???????
    ADC_TempSensorVrefintCmd(ENABLE);
    
    // 6. ????16(?????)
    ADC_RegularChannelConfig(ADC1, ADC_Channel_16, 1, ADC_SampleTime_239Cycles5);
    
    // 7. ??ADC
    ADC_Cmd(ADC1, ENABLE);
    
    // 8. ADC??
    ADC_ResetCalibration(ADC1);
    while(ADC_GetResetCalibrationStatus(ADC1));
    
    ADC_StartCalibration(ADC1);
    while(ADC_GetCalibrationStatus(ADC1));
}

/**
  * @brief  ?????????ADC?
  * @param  ?
  * @retval ADC???
  */
u16 TemperatureSensor_ReadRaw(void)
{
    // ????
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);
    
    // ??????
    while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));
    
    // ??????
    return ADC_GetConversionValue(ADC1);
}

/**
  * @brief  ?????
  * @param  ?
  * @retval ???(???)
  */
float TemperatureSensor_GetTemperature(void)
{
    u16 adc_value;
    float voltage, temperature;
    
    // ??ADC?
    adc_value = TemperatureSensor_ReadRaw();
    
    // ?????
    voltage = (float)adc_value * VREF / ADC_RES;
    
    // ?????
    // ?? = (V25 - VSENSE) / AVG_SLOPE + 25
    // VSENSE = ???,AVG_SLOPE???V/°C
    temperature = (V25 - voltage) * 1000.0f / AVG_SLOPE + 25.0f;
    
    return temperature;
}

/**
  * @brief  ?????(????)
  * @param  ?
  * @retval ?
  */
void TemperatureSensor_DisplayTemperature(void)
{
    float temperature;
    
    // ????
    temperature = TemperatureSensor_GetTemperature();
    
    // ?????????
    printf("µ±Ç°ÎÂ¶ÈÊÇ%.2f\r\n", temperature);
}

/**
  * @brief  ???printf???(???????)
  * @param  ch: ??
  * @param  f: ????
  * @retval ??
  */
int fputc(int ch, FILE *f)
{
   
    return ch;

}

#ifndef __TEMPERATURE_H
#define __TEMPERATURE_H

#include "stm32f10x.h"

// 温度传感器相关函数声明
void TemperatureSensor_Init(void);
u16 TemperatureSensor_ReadRaw(void);
float TemperatureSensor_GetTemperature(void);
void TemperatureSensor_DisplayTemperature(void);

#endif /* __TEMPERATURE_H */
```
