Loading header...

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:

  1. ADC reference: 3.3 V.
  2. Input protection: series resistor plus clamp strategy appropriate to your board.
  3. Input filter: choose a low-pass cutoff near 10 Hz.
  4. Firmware: convert raw ADC code to millivolts and temperature.
  5. Verification: test at 0.5 V, 1.5 V, and 2.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.

flowchart LR SENSOR["Sensor output\n0.5 V to 2.5 V"] PROTECT["Input protection\nseries resistor\nclamps to rails"] FILTER["RC low-pass\nfc near 10 Hz"] ADC["12-bit ADC\nVref 3.3 V"] FW["Firmware\nmV and temperature"] SENSOR --> PROTECT --> FILTER --> ADC --> FW

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

  1. Calculate expected codes for the three test voltages.
  2. Build and run the C code on a host computer.
  3. Feed the board ADC from a known voltage source or divider.
  4. Log at least 100 samples at each test point.
  5. Confirm average value, min/max noise, and no clipping.
  6. Disconnect or short the input safely and confirm fault handling.
  7. Repeat while nearby digital loads, relays, radios, or motors are active.
  8. 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 VREF with 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.

Mind Map

mindmap root((Sensor Chain Exercise)) Core task Sensor 0.5 to 2.5 V ADC 12 bit 3.3 V Temperature 0 to 100 C Sample 100 per second Formulas code equals Vin over Vref times 4095 mV equals code times 3300 over 4095 temp C equals mV minus 500 over 20 fc equals 1 over 2 pi R C Implementation Series protection RC cutoff near 10 Hz Scale raw code Clamp limits Log samples Add calibration Verification Test 0.5 V Test 1.5 V Test 2.5 V Check noise Check sample time Enable real loads Common mistakes Wrong Vref Channel mismatch Integer overflow Source too high No fault handling