Fundamentals 16 min read

Master STM32 ADC Sampling and Filtering: From Basics to Advanced Algorithms

This tutorial walks through STM32F103ZET6 ADC fundamentals, explains key parameters, demonstrates how to use the VOFA+ PC tool for data visualization, and provides step‑by‑step implementations of several filtering algorithms—including first‑order complementary, median, arithmetic average, moving average, limit‑average, and Kalman filters—complete with code examples and performance analysis.

Liangxu Linux
Liangxu Linux
Liangxu Linux
Master STM32 ADC Sampling and Filtering: From Basics to Advanced Algorithms

This article provides a hands‑on guide for performing ADC sampling on an STM32F103ZET6 MCU using the HAL library and visualizing the results with the VOFA+ PC tool.

1. ADC Basics

Analog‑to‑Digital Converters (ADCs) transform continuous analog signals (e.g., temperature, humidity) into discrete digital values that can be processed by a microcontroller. Important ADC parameters include measurement range, resolution, sampling time, and sampling rate.

ADC parameters:
1) Measurement range – limits input voltage (e.g., 0‑3.3 V for STM32).
2) Resolution – smallest detectable voltage (e.g., 12‑bit gives 5 V/4096 ≈ 1.22 mV).
3) Sampling time – duration the internal hold circuit keeps the signal stable.
4) Sampling rate – number of samples per second.

2. STM32 ADC Characteristics

STM32F1 series devices have up to three 12‑bit successive‑approximation ADCs with 18 channels (16 external, 2 internal). Conversions can run in single, continuous, scan, or discontinuous modes, and results can be left‑ or right‑aligned in a 16‑bit register.

Resolution = 3300 mV / 4095 ≈ 0.806 mV (full‑scale 3.3 V).

The device separates regular and injected channel groups, allowing injected conversions to interrupt regular ones.

3. VOFA+ Overview

VOFA+ is a cross‑platform (Windows, Linux, macOS) PC application that communicates with the MCU via serial, TCP, or UDP. It supports custom protocols (CSV‑style FireWater, binary JustFloat, raw data) and provides widgets such as waveforms, buttons, LEDs, images, sliders, and a 3‑D cube.

4. Using VOFA+

Typical workflow:

Select serial port, baud rate, and other communication parameters.

Add a waveform widget, configure Y‑axis to display two input channels (e.g., I0 and I1), and open the serial connection.

Run the MCU firmware; VOFA+ will plot the incoming data in real time.

Example FireWater usage (CSV string):

#include "math.h"
#include "stdio.h"
int main(void) {
    float t1 = 0, t2 = 0;
    while (1) {
        t1 += 0.1f;
        t2 += 0.5f;
        printf("simples:%f, %f
", sinf(t1), sinf(t2));
        HAL_Delay(100);
    }
}

5. Filtering Algorithms and Results

Because the STM32 ADC has limited precision and stability, software filtering is often required. The article implements and compares several filters, showing VOFA+ screenshots for each.

5.1 First‑Order Complementary Filter

int firstOrderFilter(int newValue, int oldValue, float a) {
    return a * newValue + (1 - a) * oldValue;
}
// Usage in main loop
HAL_ADC_Start(&hadc1);
Filtering_Value = firstOrderFilter(HAL_ADC_GetValue(&hadc1), ADC_value, 0.3f);
HAL_Delay(10);
printf("ADC_value:%d
", ADC_value);

Result: modest improvement; still noticeable jitter.

5.2 Median Filter

int middleValueFilter(int N) {
    int value_buf[N];
    for (int i = 0; i < N; ++i) {
        value_buf[i] = HAL_ADC_GetValue(&hadc1);
    }
    // Bubble sort
    for (int j = 0; j < N-1; ++j) {
        for (int k = 0; k < N-j-1; ++k) {
            if (value_buf[k] > value_buf[k+1]) {
                int temp = value_buf[k];
                value_buf[k] = value_buf[k+1];
                value_buf[k+1] = temp;
            }
        }
    }
    return value_buf[(N-1)/2];
}

Result: effectively removes outliers and stabilizes the signal.

5.3 Arithmetic Average Filter

int averageFilter(int N) {
    int sum = 0;
    for (short i = 0; i < N; ++i) {
        sum += HAL_ADC_GetValue(&hadc1);
    }
    return sum / N;
}

Result: smooths the signal; larger N yields smoother output but reduces responsiveness.

5.4 Moving Average (Sliding Window) Filter

#define N 10
int value_buf[N];
int sum = 0;
int curNum = 0;
int moveAverageFilter() {
    if (curNum < N) {
        value_buf[curNum] = HAL_ADC_GetValue(&hadc1);
        sum += value_buf[curNum];
        curNum++;
        return sum / curNum;
    } else {
        sum -= sum / N; // remove oldest contribution
        sum += HAL_ADC_GetValue(&hadc1);
        return sum / N;
    }
}

Result: provides smoother output than simple averaging while keeping memory usage modest.

5.5 Limit‑Average Filter

#define A 50   // amplitude limit
#define M 12
int data[M];
int LAverageFilter() {
    int i, temp, sum = 0, flag = 0;
    data[0] = HAL_ADC_GetValue(&hadc1);
    for (i = 1; i < M; i++) {
        temp = HAL_ADC_GetValue(&hadc1);
        if ((temp - data[i-1] > A) || (data[i-1] - temp > A)) {
            i--;
            flag++;
        } else {
            data[i] = temp;
        }
    }
    for (i = 0; i < M; i++) sum += data[i];
    return sum / M;
}

Result: eliminates sudden spikes while consuming more RAM.

5.6 Kalman Filter

int KalmanFilter(int inData) {
    static float prevData = 0;
    static float p = 10, q = 0.001, r = 0.001, kGain = 0;
    p = p + q;
    kGain = p / (p + r);
    inData = prevData + (kGain * (inData - prevData));
    p = (1 - kGain) * p;
    prevData = inData;
    return (int)inData;
}

Result: offers good noise reduction and stability when parameters are tuned, though it requires careful calibration.

6. Conclusions

ADC sampling is essential in embedded projects, and software filtering can compensate for limited hardware performance. Simple filters (median, moving average) are often sufficient, while more sophisticated methods (Kalman) provide superior results at the cost of parameter tuning and memory usage. Choose the filter that best matches the dynamics of your specific application.

实验效果图
实验效果图
STM32 ADC通道结构
STM32 ADC通道结构
VOFA+概览
VOFA+概览
FireWater协议示例
FireWater协议示例
串口设置界面
串口设置界面
波形图配置
波形图配置
波形图实时显示
波形图实时显示
未滤波采样波形
未滤波采样波形
一阶互补滤波效果
一阶互补滤波效果
中值滤波效果
中值滤波效果
算术平均滤波效果
算术平均滤波效果
滑动平均滤波效果
滑动平均滤波效果
限幅平均滤波效果
限幅平均滤波效果
卡尔曼滤波效果
卡尔曼滤波效果
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

c++embeddedfilteringSignal ProcessingSTM32ADC
Liangxu Linux
Written by

Liangxu Linux

Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.