Exercise: Build a Sensor Acquisition Chain
This exercise turns the data-conversion lessons into a complete measurement path. You will specify a sensor front end, choose ADC settings, implement conversion code, and verify expected behavior with known inputs.
Learning Objectives
You will:
- map a sensor voltage range to ADC codes;
- choose a reference, input filter, and sampling rate;
- write buildable conversion code;
- verify calibration and failure behavior;
- debug noise, clipping, and scaling errors.
Prerequisites
- ADC resolution, quantization, and reference-voltage concepts.
- Basic C programming for embedded systems.
- Ability to measure DC voltage with a multimeter.
- A development board with an ADC, or a simulator that can feed sample codes.
Task
Build a temperature acquisition chain for an analog sensor with output range 0.5 V to 2.5 V, representing 0 degree C to 100 degree C. Use a 12-bit ADC with 3.3 V reference. Sample at 100 samples/s and report temperature in centi-degrees Celsius.
Required design decisions:
- ADC reference:
3.3 V. - Input protection: series resistor plus clamp strategy appropriate to your board.
- Input filter: choose a low-pass cutoff near
10 Hz. - Firmware: convert raw ADC code to millivolts and temperature.
- Verification: test at
0.5 V,1.5 V, and2.5 V.
Front-End Design
Use a simple first-order RC input filter when the ADC input can tolerate the source impedance. Choose a cutoff near 10 Hz:
$$
f_c = \frac{1}{2\pi RC}
$$
For R = 10 kOhm and C = 1.5 uF:
$$
f_c = \frac{1}{2\pi \times 10000 \times 1.5\times10^{-6}} \approx 10.6 Hz
$$
Check the MCU data sheet before copying these values. Some SAR ADCs require a lower source impedance or a longer sampling time so the internal sample capacitor can settle. If the sensor is far from the MCU, add ESD protection, keep the return path clean, and test with the real cable.
Implementation
#include <stdint.h>
#include <stdio.h>
#define ADC_BITS 12u
#define ADC_MAX ((1u << ADC_BITS) - 1u)
#define VREF_MV 3300u
#define SENSOR_MIN_MV 500
#define SENSOR_MAX_MV 2500
static uint32_t adc_to_mv(uint16_t code) {
return ((uint32_t)code * VREF_MV + (ADC_MAX / 2u)) / ADC_MAX;
}
static int32_t mv_to_centi_c(uint32_t mv) {
if (mv <= SENSOR_MIN_MV) return 0;
if (mv >= SENSOR_MAX_MV) return 10000;
return (int32_t)((mv - SENSOR_MIN_MV) * 10000u /
(SENSOR_MAX_MV - SENSOR_MIN_MV));
}
int main(void) {
uint16_t tests[] = {621, 1861, 3102};
for (unsigned i = 0; i < 3; ++i) {
uint32_t mv = adc_to_mv(tests[i]);
int32_t tc = mv_to_centi_c(mv);
printf("code=%u mv=%lu temp=%ld.%02ld C\n",
tests[i], (unsigned long)mv,
(long)(tc / 100), (long)(tc % 100));
}
return 0;
}
Approximate ADC code:
$$
code = \frac{V_{IN}}{V_{REF}}(2^N-1)
$$
Expected Behavior
| Input | ADC code | Expected temperature |
|---|---|---|
0.5 V |
621 |
0 degree C |
1.5 V |
1861 |
50 degree C |
2.5 V |
3102 |
100 degree C |
Small rounding differences are acceptable if they are documented.
Verification Steps
- Calculate expected codes for the three test voltages.
- Build and run the C code on a host computer.
- Feed the board ADC from a known voltage source or divider.
- Log at least
100samples at each test point. - Confirm average value, min/max noise, and no clipping.
- Disconnect or short the input safely and confirm fault handling.
- Repeat while nearby digital loads, relays, radios, or motors are active.
- Confirm the ADC sampling time is long enough for the selected source impedance.
Common Failure Symptoms
| Symptom | Likely cause |
|---|---|
| temperature reads too high everywhere | wrong reference voltage or scaling |
| correct at one point but wrong slope | sensor min/max constants wrong |
| noisy output | poor grounding, missing filter, long wires |
| stuck near 0 or 100 | input clipping or ADC channel mismatch |
| changes when motor runs | return-current or EMI coupling |
Debugging Guidance
- Print raw code before converting to engineering units.
- Measure ADC pin voltage directly.
- Verify
VREFwith a meter. - Check integer overflow and rounding.
- Check ADC sample time, input impedance, and acquisition-window settings.
- Temporarily average more samples to separate random noise from scale error.
- Disable nearby switching loads to isolate coupling problems.
Extension Challenge
Add two-point calibration. Store measured code at 0 degree C and 100 degree C, then compute temperature from the calibrated slope instead of fixed voltage limits.
Explained Solution
The ADC maps 0 V to code 0 and 3.3 V to code 4095. The sensor uses only 0.5 V to 2.5 V, so the code range is approximately 621 to 3102. Firmware first converts code to millivolts, then linearly maps 500 mV to 0 degree C and 2500 mV to 100 degree C. Clamping prevents impossible values from propagating when the input is slightly outside the calibrated range.
Summary
A sensor acquisition chain includes input scaling, reference choice, filtering, sampling rate, firmware conversion, calibration, and noisy-environment verification.
Further Reading
- STMicroelectronics and Microchip ADC notes on source impedance and sampling time.
- Texas Instruments Analog Engineer's Circuit Cookbook.
- Analog Devices data conversion handbook chapters on grounding and references.