ADC (Analog-to-Digital Converter) là một trong những ngoại vi quan trọng nhất trong vi điều khiển STM32, cho phép đọc các tín hiệu tương tự từ thế giới thực như nhiệt độ, điện áp, cảm biến áp suất… và chuyển đổi sang dạng số để xử lý. Bài viết này hướng dẫn toàn diện về ADC trong STM32F1: từ nguyên lý hoạt động, các khái niệm cơ bản đến cấu hình chi tiết bằng thư viện SPL.
ADC là gì?
ADC (Analog-to-Digital Converter) là mạch điện tử nhận điện áp tương tự làm đầu vào và chuyển đổi thành dữ liệu số – một giá trị nhị phân đại diện cho mức điện áp đó.

Về cơ bản, ADC hoạt động bằng cách chia mức tín hiệu tương tự thành nhiều mức rời rạc. Mỗi mức được biểu diễn bằng một giá trị nhị phân tương ứng. Bằng cách so sánh điện áp đầu vào tại mỗi thời điểm lấy mẫu với các mức đã chia, ADC mã hóa tín hiệu tương tự thành chuỗi bit nhị phân.

Các khái niệm cơ bản cần biết
Độ phân giải (Resolution)
Độ phân giải là số bit cần thiết để biểu diễn toàn bộ các mức giá trị số sau quá trình chuyển đổi. ADC của STM32F103 có độ phân giải mặc định là 12 bit, tức là có 2¹² = 4096 mức (từ 0 đến 4095).
Độ phân giải càng cao, dữ liệu số càng gần với tín hiệu gốc:

| Độ phân giải | Số mức | Điện áp mỗi bước (Vref = 3.3V) |
|---|---|---|
| 8-bit | 256 | ~12.9 mV |
| 10-bit | 1024 | ~3.2 mV |
| 12-bit (STM32F1) | 4096 | ~0.8 mV |
| 16-bit | 65536 | ~0.05 mV |
Tần số lấy mẫu (Sampling Rate)
Tần số lấy mẫu cho biết ADC lấy mẫu và số hóa tín hiệu bao nhiêu lần mỗi giây. Thời gian giữa hai lần lấy mẫu càng ngắn, tín hiệu số hóa càng chính xác và khả năng tái tạo lại tín hiệu gốc càng cao (theo định lý Nyquist: tần số lấy mẫu phải ≥ 2 lần tần số tín hiệu).

ADC trong STM32F1
STM32F103 tích hợp 2 bộ ADC (ADC1 và ADC2), mỗi bộ có tối đa 9 kênh (channel) với nhiều chế độ hoạt động linh hoạt.

Đặc điểm chính ADC STM32F103
- Độ phân giải 12-bit – giá trị tối đa là 4095.
- Hỗ trợ Single mode và Continuous mode.
- Có các ngắt hỗ trợ (End of Conversion, Watchdog…).
- Tự động calibration – giảm sai số do điện dung bên trong.
- Có thể kích hoạt bằng Trigger ngoài (Timer, EXTI…).
- Thời gian chuyển đổi nhanh: 1µs tại 65 MHz.
- Điện áp cấp cho ADC: 2.4V → 3.6V → điện áp đầu vào phải trong khoảng này.
- Tích hợp DMA giúp tăng tốc độ xử lý (không chiếm CPU).
- Có 2 kênh đặc biệt: Vref và Temperature Sensor nội.
Tính toán giá trị ADC
Giả sử cần đo điện áp từ 0V đến 3.3V với ADC 12-bit:
- STM32 chia khoảng 0 → 3.3V thành 4096 mức (0 → 4095).
- 0V → giá trị ADC = 0
- 3.3V → giá trị ADC = 4095
- Công thức quy đổi:
Voltage = ADC_Value × 3.3 / 4095
/* Quy đổi giá trị ADC sang điện áp (V) */
float voltage = (float)adc_value * 3.3f / 4095.0f;
Cấu hình ADC trong STM32F103
Bước 1: Cấu hình GPIO (chân analog input)
ADC hỗ trợ nhiều kênh ngõ vào được cấu hình sẵn trên các chân GPIO. Các chân dùng làm ngõ vào ADC phải được cấu hình ở chế độ AIN (Analog Input).

/* Cấu hình PA1 làm Analog Input cho ADC1 Channel 1 */
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN; /* Analog Input */
GPIO_Init(GPIOA, &GPIO_InitStruct);
Bước 2: Cấp xung clock cho ADC
ADC được cấp xung từ RCC APB2. Cần cấp xung cho cả bộ ADC và GPIO Port tương ứng.

/* Cấp xung clock cho ADC1 và GPIOA */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA, ENABLE);
/* Cấu hình prescaler cho ADC clock (tối đa 14 MHz) */
RCC_ADCCLKConfig(RCC_PCLK2_Div6); /* 72MHz / 6 = 12MHz */
Bước 3: Cấu hình struct ADC_InitTypeDef
Các tham số ADC được cấu hình trong struct ADC_InitTypeDef:
| Tham số | Mô tả | Giá trị thường dùng |
|---|---|---|
ADC_Mode | Chế độ đơn kênh (Independent) hay đa kênh | ADC_Mode_Independent |
ADC_NbrOfChannel | Số kênh ADC sử dụng trong một lần quét | 1 |
ADC_ContinuousConvMode | Chuyển đổi liên tục hay một lần rồi dừng | ENABLE / DISABLE |
ADC_ExternalTrigConv | Kích hoạt bằng trigger ngoài hay không | ADC_ExternalTrigConv_None |
ADC_ScanConvMode | Bật chế độ quét lần lượt từng kênh | DISABLE (1 kênh) |
ADC_DataAlign | Căn lề dữ liệu 12-bit trong thanh ghi 16-bit | ADC_DataAlign_Right |
Bước 4: Calibration và khởi động ADC
Sau khi cấu hình, STM32 khuyến nghị thực hiện hiệu chuẩn (calibration) để giảm sai số do điện dung bên trong gây ra:
/* Bật ADC */
ADC_Cmd(ADC1, ENABLE);
/* Reset thanh ghi calibration */
ADC_ResetCalibration(ADC1);
while (ADC_GetResetCalibrationStatus(ADC1));
/* Thực hiện hiệu chuẩn */
ADC_StartCalibration(ADC1);
while (ADC_GetCalibrationStatus(ADC1));
Ví dụ hoàn chỉnh: Đọc ADC1 Channel 1 (PA1)
#include "stm32f10x.h"
void ADC_Init_Config(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
ADC_InitTypeDef ADC_InitStruct;
/* ── 1. Cấp clock ─────────────────────────────── */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1, ENABLE);
RCC_ADCCLKConfig(RCC_PCLK2_Div6); /* ADC clock = 12 MHz */
/* ── 2. GPIO PA1 → Analog Input ──────────────── */
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA, &GPIO_InitStruct);
/* ── 3. Cấu hình ADC1 ────────────────────────── */
ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;
ADC_InitStruct.ADC_NbrOfChannel = 1;
ADC_InitStruct.ADC_ContinuousConvMode = DISABLE;
ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStruct.ADC_ScanConvMode = DISABLE;
ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;
ADC_Init(ADC1, &ADC_InitStruct);
/* ── 4. Cấu hình kênh: CH1, rank 1, 55.5 cycles ─ */
ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_55Cycles5);
/* ── 5. Bật ADC ──────────────────────────────── */
ADC_Cmd(ADC1, ENABLE);
/* ── 6. Calibration ──────────────────────────── */
ADC_ResetCalibration(ADC1);
while (ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
while (ADC_GetCalibrationStatus(ADC1));
}
uint16_t ADC_Read(void)
{
/* Bắt đầu chuyển đổi */
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
/* Chờ chuyển đổi hoàn tất */
while (!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));
/* Trả về giá trị 12-bit (0–4095) */
return ADC_GetConversionValue(ADC1);
}
int main(void)
{
ADC_Init_Config();
while (1) {
uint16_t raw = ADC_Read();
float voltage = (float)raw * 3.3f / 4095.0f;
/* Sử dụng voltage... */
}
}
Lưu ý khi sử dụng ADC trong STM32
- ADC clock tối đa 14 MHz – cấu hình prescaler phù hợp (thường Div6 hoặc Div8 với SYSCLK 72 MHz).
- Điện áp đầu vào phải trong khoảng 0V → VDDA (thường là 3.3V) – tuyệt đối không vượt quá, sẽ hỏng MCU.
- Luôn thực hiện calibration sau khi bật nguồn để đảm bảo độ chính xác.
- Với nhiều kênh đồng thời, dùng Scan mode + DMA để tránh chiếm CPU.
- SampleTime càng dài độ chính xác càng cao nhưng tốc độ chậm hơn – chọn phù hợp với trở kháng nguồn tín hiệu.
- ADC1 có thêm kênh nội: Temperature Sensor (CH16) và Vrefint (CH17).
Kết luận
ADC (Analog-to-Digital Converter) là cầu nối giữa thế giới vật lý và hệ thống số trong các ứng dụng nhúng. STM32F103 tích hợp ADC 12-bit với nhiều tính năng mạnh mẽ: 2 bộ ADC độc lập, nhiều kênh, hỗ trợ trigger ngoài, calibration tự động và tích hợp DMA.
Hiểu rõ các tham số trong ADC_InitTypeDef và quy trình cấu hình đúng thứ tự (GPIO → Clock → Init → Calibration → Start) sẽ giúp bạn đọc tín hiệu analog chính xác và ổn định trong các dự án automotive embedded như đọc cảm biến vị trí bướm ga, cảm biến áp suất, đo điện áp ắc-quy…


