Giới Thiệu
Cảm biến nhiệt độ nội bộ trong các MCU STM32 được kết nối với một kênh ADC riêng biệt, chủ yếu dùng để giám sát nhiệt độ trên chip, không phải để đo đạc chính xác môi trường bên ngoài. Tuy nhiên, với thời gian lấy mẫu đúng, bù điện áp tham chiếu và kích hoạt sạch, bạn vẫn có thể có được các giá trị ổn định và lặp lại đủ để kiểm tra sức khỏe hệ thống, điều chỉnh nhiệt độ và logic bảo vệ.
Bài viết này sẽ hướng dẫn bạn cách:
- Kích hoạt cảm biến nhiệt độ nội bộ và các kênh VREFINT
- Kích hoạt chuyển đổi ở tần số 50 Hz thông qua TRGO của TIM3
- Truyền dữ liệu từ hai kênh ADC qua DMA (chế độ vòng)
- Bù cho các thay đổi VDD bằng cách sử dụng giá trị đọc từ VREFINT
- Chuyển đổi VSENSE → °C bằng công thức trong datasheet
- Hiệu chuẩn và ổn định kết quả cho các dự án thực tế
⚠️ Luôn kiểm tra datasheet của MCU cụ thể của bạn: công thức chuyển đổi và các thông số (V25, Avg_Slope) khác nhau tùy theo họ/ dòng và đôi khi theo phiên bản.
Mục Lục
- Cảm Biến Nhiệt Độ Nội Bộ Đo Lường Gì
- Luồng Đọc & Công Thức Chuyển Đổi
- Kiến Trúc Dự Án (Pipeline 50 Hz)
- Cấu Hình CubeMX Từng Bước
- Mã Ví Dụ HAL (Phong Cách STM32F103)
- Mẹo Hiệu Chuẩn & Độ Chính Xác
- Câu Hỏi Thường Gặp
- Kết Luận
1. Cảm Biến Nhiệt Độ Nội Bộ Đo Lường Gì
Cảm biến này báo cáo một điện áp (VSENSE) tỷ lệ thuận với nhiệt độ của chip. Nó được kết nối nội bộ với một kênh ADC riêng. Một kênh nội bộ thứ hai (VREFINT) cung cấp một tham chiếu ổn định để ước lượng VDD thực tế và điều chỉnh các giá trị đọc.
Cảm biến này rất tốt cho việc phát hiện xu hướng và bảo vệ nhiệt, nhưng không được thiết kế như một cảm biến môi trường chính xác.
2. Luồng Đọc & Công Thức Chuyển Đổi
Các bước cơ bản:
- Kích hoạt kênh ADC cho cảm biến nhiệt độ
- Đặt thời gian lấy mẫu ≥ 17 µs (theo datasheet)
- Bắt đầu ADC (tốt nhất với kích hoạt từ bộ định thời)
- Đọc VSENSE và VREFINT
- Chuyển đổi VSENSE → nhiệt độ bằng cách sử dụng các hằng số trong datasheet
Công thức chuyển đổi điển hình (cụ thể theo họ):
Nhiệt độ (°C) = ((V25 - VSENSE) / Avg_Slope) + 25
Trong đó:
- V25 = đầu ra cảm biến ở 25 °C (ví dụ: ~1.43 V trên nhiều phần F1)
- Avg_Slope = mV/°C (ví dụ: ~4.3 mV/°C trên nhiều phần F1)
- VSENSE = tính từ mã ADC thô với bù VDD dựa trên VREFINT
3. Kiến Trúc Dự Án (Pipeline 50 Hz)
Chúng ta sẽ xây dựng một pipeline ổn định với việc lấy mẫu xác định và bù điện áp:
- TIM3 tạo TRGO = Cập nhật ở 50 Hz (chu kỳ = 20 ms)
- ADC1 (nhóm thông thường) được kích hoạt từ bên ngoài bởi TRGO
- Các chuyển đổi thông thường quét hai kênh nội bộ: VREFINT sau đó là TempSensor
- DMA (vòng) chuyển cả hai kết quả vào bộ nhớ mỗi khi kích hoạt
- Trong callback hoàn thành chuyển đổi ADC, chúng ta sẽ thay đổi trạng thái GPIO (để kiểm tra tần suất) và đặt cờ
- Trong vòng lặp chính, chúng ta tính toán VDD, sau đó là VSENSE, sau đó là °C và in qua UART (115200)
4. Cấu Hình CubeMX Từng Bước
MCU/Bảng: ví dụ, STM32F103C8 (Blue Pill). Quy trình này áp dụng rộng rãi; tên có thể khác nhau tùy theo họ.
RCC / Đồng Hồ
- Sử dụng HSE (khoảng tinh thể bên ngoài) → PLL → SYSCLK 72 MHz (điển hình cho F103)
- Đảm bảo đồng hồ ADC ≤ giới hạn trong datasheet (ví dụ: 12 MHz)
ADC1
- Chuyển đổi thông thường: 2 kênh (VREFINT, TempSensor)
- Thời gian lấy mẫu: chọn giá trị gần nhất ≥ 17 µs.
- Ví dụ: tại đồng hồ ADC 12 MHz, 239.5 chu kỳ ≈ 19.96 µs
- Kích hoạt bên ngoài: TIM3 TRGO (sự kiện cập nhật)
- DMA: Thêm 1 kênh, vòng, nửa từ, tăng bộ nhớ được kích hoạt
TIM3
- Nguồn đồng hồ bộ định thời = nội bộ
- Đặt PSC và ARR sao cho Cập nhật = 20 ms (50 Hz)
- Ví dụ tại 72 MHz: PSC = 23, ARR = 59999
- TRGO = Sự kiện cập nhật
USART1
- 115200 8N1 để ghi lại
GPIO
- Một đầu ra (ví dụ: PB0) để xác minh tần suất lấy mẫu (thay đổi trong ISR ADC)
NVIC
- Kích hoạt ngắt toàn cục ADC1
5. Mã Ví Dụ HAL (Phong Cách STM32F103)
Mã ví dụ này sử dụng V25 = 1.43 V và Avg_Slope = 4.3 mV/°C, là những giá trị phổ biến cho nhiều phần F1. Điều chỉnh theo datasheet của bạn. Nếu họ của bạn cung cấp các điểm hiệu chuẩn VREFINT hoặc TS_CAL1/TS_CAL2, hãy ưu tiên sử dụng chúng để có độ chính xác cao hơn.
c
/*
* Demo: Cảm Biến Nhiệt Độ Nội Bộ STM32 (ADC + DMA + TIM3 TRGO @ 50 Hz)
* Kiểu mục tiêu: STM32F103 (điều chỉnh các hằng số & địa chỉ cho MCU của bạn) */
#include "main.h"
#include <stdio.h>
#include <stdint.h>
/* === Các Tham Số Datasheet (điều chỉnh!) === */
#define AVG_SLOPE_mV_per_C (4.3f) // mV/°C
#define V_AT_25C_V (1.43f) // V @ 25°C
#define VREFINT_TYP_V (1.20f) // Tham chiếu nội bộ điển hình (chỉ nếu không có giá trị hiệu chuẩn)
/* HAL xử lý (CubeMX sẽ tạo ra những cái này) */
ADC_HandleTypeDef hadc1;
DMA_HandleTypeDef hdma_adc1;
TIM_HandleTypeDef htim3;
UART_HandleTypeDef huart1;
/* Bộ đệm đôi: [0] = mã ADC VREFINT, [1] = mã ADC VSENSE */
static volatile uint16_t adc_buf[2];
static volatile uint8_t new_sample = 0;
/* Trạng thái ứng dụng */
static float vref_V = 0.0f;
static float vsense_V = 0.0f;
static float temperature_C = 0.0f;
static char line[48];
/* Các định nghĩa được tạo bởi CubeMX */
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_DMA_Init(void);
static void MX_ADC1_Init(void);
static void MX_TIM3_Init(void);
static void MX_USART1_UART_Init(void);
int main(void) {
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_DMA_Init();
MX_ADC1_Init();
MX_TIM3_Init();
MX_USART1_UART_Init();
/* Bắt đầu kích hoạt 50 Hz */
HAL_TIM_Base_Start(&htim3);
/* Hiệu chuẩn & bắt đầu ADC theo chế độ DMA vòng */
HAL_ADCEx_Calibration_Start(&hadc1);
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buf, 2);
for (;;) {
if (new_sample) {
/* Tính toán VDD từ giá trị đọc VREFINT */
const float adc_fullscale = 4095.0f;
const float vrefint_code = (float)adc_buf[0];
const float vsense_code = (float)adc_buf[1];
/* Ước lượng VDD hiệu quả bằng VREFINT */
float vdd_V = (VREFINT_TYP_V * adc_fullscale) / (vrefint_code > 0.5f ? vrefint_code : 0.5f);
/* Bây giờ tính toán VSENSE bằng VDD đó */
vref_V = vdd_V;
vsense_V = (vsense_code * vref_V) / adc_fullscale;
/* Chuyển đổi sang nhiệt độ (°C). Avg_Slope là mV/°C */
temperature_C = (((V_AT_25C_V - vsense_V) * 1000.0f) / AVG_SLOPE_mV_per_C) + 25.0f;
/* In một dòng cho mỗi mẫu (cho Serial Plotter/Monitor) */
int n = snprintf(line, sizeof(line), "%.2f\r\n", temperature_C);
HAL_UART_Transmit(&huart1, (uint8_t*)line, (uint16_t)n, 50);
new_sample = 0;
}
}
}
/* Callback hoàn thành chuyển đổi ADC: một cặp (VREFINT, VSENSE) đã sẵn sàng */
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc) {
if (hadc->Instance == ADC1) {
HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_0); // Xác minh tần suất 50 Hz
new_sample = 1;
}
}
## 6. Mẹo Hiệu Chuẩn & Độ Chính Xác
- **Sử dụng thời gian lấy mẫu đúng:** Kênh nhiệt cần ≥ 17 µs. Nếu bạn lấy mẫu nhanh hơn, giá trị đọc sẽ bị rối loạn hoặc lệch thấp.
- **Bù VDD bằng VREFINT:** Luôn đọc VREFINT cùng với VSENSE và điều chỉnh cho các thay đổi VDD.
- **Hiệu chuẩn từ nhà máy tốt hơn các hằng số thông thường:** Ưu tiên TS_CAL1/TS_CAL2 và VREFINT_CAL khi bộ phận của bạn cung cấp chúng. Chúng ghi lại sự biến đổi theo từng chip.
- **Kiểm tra thực tế nhiệt:** Cảm biến nội bộ báo cáo nhiệt độ die. Tải CPU, đợi flash và hoạt động DC/DC làm nóng silicon. Nó sẽ không giống như một cảm biến môi trường xa.
- **Trung bình và tần suất:** Một trung bình di động đơn giản (ví dụ: 8–16 mẫu) giúp. Đừng lấy mẫu quá nhiều; 10–50 Hz là đủ cho các xu hướng nhiệt.
- **Hiệu chỉnh một lần:** Nếu độ chính xác tuyệt đối quan trọng, hãy hiệu chuẩn đồng thời với một cảm biến bên ngoài tốt đặt gần gói MCU và điều chỉnh độ lệch/độ dốc.
## 7. Câu Hỏi Thường Gặp
**Q: Giá trị đọc của tôi bị ồn hoặc nhảy nhiều.**
- Tăng thời gian lấy mẫu (ví dụ: 239.5 chu kỳ).
- Trung bình nhiều mẫu.
- TRGO đã được cấu hình chưa? Việc kích hoạt bằng phần mềm, lấy mẫu không đều có thể thêm độ nhấp nhô.
**Q: Các con số trôi khi VDD thay đổi.**
- Có thể bạn không sử dụng bù VREFINT. Đọc VREFINT mỗi chu kỳ.
**Q: Tôi nhận được nhiệt độ không đúng (ví dụ: –20 °C ở phòng).**
- Kiểm tra thứ tự kênh (VREFINT so với TempSensor).
- Xác minh các hằng số công thức tham chiếu (V25, Avg_Slope) khớp với MCU của bạn.
- Xác nhận đồng hồ ADC/phân chia và độ phân giải.
**Q: Làm thế nào để tôi xác thực tần suất 50 Hz?**
- Thay đổi một GPIO trong HAL_ADC_ConvCpltCallback() và đo trên một bộ oscilloscope. Bạn nên thấy 20 ms giữa các cạnh.
**Q: Tôi có thể làm điều này mà không cần DMA không?**
- Có, bạn có thể lấy mẫu hoặc ngắt theo mỗi chuyển đổi, nhưng DMA giữ cho CPU tự do và đảm bảo đọc đồng thời hai kênh.
## 8. Kết Luận
Với việc kích hoạt ADC theo bộ định thời, DMA và bù VREFINT, cảm biến nhiệt độ nội bộ của STM32 trở thành một công cụ theo dõi xu hướng đáng tin cậy cho việc quản lý nhiệt và logic an toàn. Để có những con số chính xác hơn, hãy sử dụng các điểm hiệu chuẩn từ nhà máy (khi có) và thực hiện một phép hiệu chỉnh nhanh so với một cảm biến bên ngoài đáng tin cậy.