ADC – 内部温度传感器读取(HAL 库)
难度: ⭐⭐(需要了解 ADC 基本概念)
固件库: PY32F0xx_Firmware V1.5.0
芯片: PY32F030
源文件: Projects/PY32F030-STK/Example/ADC/ADC_TempSensor/Src/main.c
这个实验是干嘛的?
PY32F030 芯片内部集成了一个温度传感器,不需要任何外部元件,通过 ADC 采集就能读取芯片当前温度。
有什么用?
- 监测芯片工作温度,防止过热
- 温度补偿(ADC 精度受温度影响)
- 简单的环境温度测量(精度不高,约 ±5 度)
硬件准备
不需要任何外部硬件! 温度传感器在芯片内部。
你只需要:
- PY32F030 开发板
- USB 转串口模块(查看 printf 输出)
完整代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
|
#include "main.h"
/* 温度校准值(出厂写入 OTP,地址固定) */
#define HAL_ADC_TSCAL1 (*(uint32_t *)(0x1fff0f14)) /* 30 度时的 ADC 校准值 */
#define HAL_ADC_TSCAL2 (*(uint32_t *)(0x1fff0f18)) /* 105 度时的校准值 */
#define Vcc_Power 3.3l /* 实际供电电压,按实际修改 */
/* 校准值对应的电压(根据实际 VCC 换算) */
#define TScal1 (float)((HAL_ADC_TSCAL1) * 3.3 / Vcc_Power)
#define TScal2 (float)((HAL_ADC_TSCAL2) * 3.3 / Vcc_Power)
/* 温度计算公式参数 */
#define TStem1 30l /* 校准点 1 的温度:30 度 */
#define TStem2_105 105 /* 校准点 2 的温度:105 度(高温版) */
#define Temp_k_105 ((float)(TStem2_105 - TStem1) / (float)(TScal2 - TScal1))
ADC_HandleTypeDef AdcHandle;
uint16_t aADCxConvertedData;
__IO uint16_t hADCxConvertedData_Temperature_DegreeCelsius = 0;
/* ADC 配置 */
static void APP_AdcConfig(void)
{
ADC_ChannelConfTypeDef sConfig = {0};
/* 复位并使能 ADC 时钟 */
__HAL_RCC_ADC_FORCE_RESET();
__HAL_RCC_ADC_RELEASE_RESET();
__HAL_RCC_ADC_CLK_ENABLE();
AdcHandle.Instance = ADC1;
/* ADC 校准(必须!) */
if (HAL_ADCEx_Calibration_Start(&AdcHandle) != HAL_OK)
{
APP_ErrorHandler();
}
/* ADC 基础配置 */
AdcHandle.Instance = ADC1;
AdcHandle.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; /* ADC 时钟 = PCLK/4 */
AdcHandle.Init.Resolution = ADC_RESOLUTION_12B; /* 12 位分辨率 */
AdcHandle.Init.DataAlign = ADC_DATAALIGN_RIGHT; /* 右对齐 */
AdcHandle.Init.ContinuousConvMode = DISABLE; /* 单次转换 */
AdcHandle.Init.ExternalTrigConv = ADC_SOFTWARE_START; /* 软件触发 */
AdcHandle.Init.SamplingTimeCommon = ADC_SAMPLETIME_239CYCLES_5; /* 采样时间 239.5 周期 */
if (HAL_ADC_Init(&AdcHandle) != HAL_OK)
{
APP_ErrorHandler();
}
/* 配置通道:内部温度传感器 */
sConfig.Channel = ADC_CHANNEL_TEMPSENSOR;
sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
if (HAL_ADC_ConfigChannel(&AdcHandle, &sConfig) != HAL_OK)
{
APP_ErrorHandler();
}
}
int main(void)
{
HAL_Init();
BSP_LED_Init(LED_GREEN);
BSP_USART_Config(); /* 初始化串口(printf 重定向) */
APP_AdcConfig(); /* 配置 ADC */
/* ADC 校准 */
if (HAL_ADCEx_Calibration_Start(&AdcHandle) != HAL_OK)
{
APP_ErrorHandler();
}
/* 启动 ADC */
HAL_ADC_Start(&AdcHandle);
while (1)
{
/* 等待转换完成 */
if (HAL_ADC_PollForConversion(&AdcHandle, 2000) == HAL_OK)
{
/* 读取 ADC 值 */
aADCxConvertedData = HAL_ADC_GetValue(&AdcHandle);
/* 计算温度:线性插值公式 */
hADCxConvertedData_Temperature_DegreeCelsius =
(int16_t)(Temp_k_105 * aADCxConvertedData - Temp_k_105 * TScal1 + TStem1);
printf("Temperature: %d\r\n", (int)hADCxConvertedData_Temperature_DegreeCelsius);
}
HAL_Delay(1000); /* 每秒读一次 */
}
}
void APP_ErrorHandler(void)
{
while (1) {}
}
|
代码分段讲解
1. 温度校准值
1
2
|
#define HAL_ADC_TSCAL1 (*(uint32_t *)(0x1fff0f14))
#define HAL_ADC_TSCAL2 (*(uint32_t *)(0x1fff0f18))
|
PY32F030 出厂时,工厂会在 OTP(一次性可编程存储器)中写入两个校准值:
TSCAL1:30 度时的 ADC 采样值
TSCal2:105 度时的 ADC 采样值
这两个地址是固定的,直接读就行。
2. 温度计算公式
1
|
温度 = k * (ADC值 - TScal1) + 30
|
其中 k = (105 - 30) / (TScal2 - TScal1)
这是线性插值——已知两个点(30 度和 105 度),算出斜率 k,然后根据当前 ADC 值算温度。
3. ADC 配置要点
- 通道:
ADC_CHANNEL_TEMPSENSOR(内部温度传感器)
- 采样时间:239.5 周期(内部传感器阻抗高,需要长采样时间)
- 触发方式:软件触发
- 转换模式:单次转换
4. 校准
1
|
HAL_ADCEx_Calibration_Start(&AdcHandle);
|
必须校准! 芯片工艺偏差会导致 ADC 偏移,校准可以消除这个偏差。
实验现象
串口每秒打印一行:
1
2
3
|
Temperature: 28
Temperature: 29
Temperature: 30
|
- 室温下一般显示 25~35 度
- 用手捂住芯片,温度会升高
- 精度约正负 5 度(内部传感器精度有限)
常见问题
Q: 温度值偏差很大?
- 检查
Vcc_Power 是否与实际供电电压一致(USB 供电约 3.3V,电池可能不同)
- 内部传感器精度有限,正负 5 度是正常的
- 如果需要高精度,用外部传感器(如 DS18B20、SHT30)
Q: 读到的温度是 0 或负数?
- 检查校准值地址是否正确
- 检查是否选择了正确的芯片型号(PY32F030x8)
Q: 想读取外部引脚的电压?
- 把
ADC_CHANNEL_TEMPSENSOR 换成外部通道(如 ADC_CHANNEL_0)
- 去掉温度计算公式,直接用
ADC值 * 3.3 / 4095 算电压
小结
| 概念 |
说明 |
| 内部温度传感器 |
芯片自带,不需要外部元件 |
| OTP 校准值 |
出厂写入,30 度和 105 度的 ADC 值 |
| 线性插值 |
用两个已知点推算任意点的温度 |
| ADC 校准 |
必须做,消除工艺偏差 |
| 采样时间 |
内部传感器阻抗高,需要长采样时间 |
拓展应用
| 项目 |
原理 |
难度 |
| 芯片过热保护 |
温度超阈值时降低频率或关断 |
⭐⭐ |
| 温度补偿 |
根据温度修正 ADC/RTC 等外设的偏差 |
⭐⭐⭐ |
| 简易温度计 |
串口显示 + LCD 显示 |
⭐⭐ |
| 温控风扇 |
温度高时 PWM 加速风扇 |
⭐⭐⭐ |
| 环境监测 |
内部温度 + 外部传感器对比 |
⭐⭐ |