BFM1143 Embedded System Programming - Week 5: ADC & Sensor Interfacing
Analog Signals
- An analog signal is a continuous-time signal representing physical parameters with smoothly varying values over time.
- It allows for an infinite number of values within a range, unlike digital signals which have discrete states.
Core Characteristics
- Continuity: No gaps in the signal; it can have any value within a range.
- Amplitude Range: Often voltage-based, such as 0-5V for Arduino Uno analog inputs.
- Time-Varying: Changes over time in real-time scenarios.
- Smooth Curves: Graphs are smooth, without steps or jumps.
Analog Signal Parameters
- Amplitude (A): The peak value of the signal.
- Peak-to-Peak Amplitude (Vpp): The difference between the maximum and minimum values of the signal.
- RMS Voltage (Vrms): The root mean square voltage, representing the effective voltage of the signal.
- Period (T): The time it takes for one complete cycle of the signal.
- Frequency (f): The number of cycles per second, f=1/T.
- Phase (ϕ): The initial angle of the signal at time zero.
- Offset (Vo): The DC component of the signal, shifting the entire waveform up or down.
Analog vs Digital Signals
| Feature | Analog Signal | Digital Signal |
|---|
| Nature | Continuous (smooth curve) | Discrete (step-wise values) |
| Values | Infinite within a range | Finite - typically two (0 and 1) |
| Form | Varying voltage over time | High or Low, ON or OFF, 0s and 1s |
| Representation | Real-world phenomena | Binary logic |
| Susceptibility | Prone to noise/interference | More noise-resistant |
| Processing | Needs ADC for microcontrollers | Directly compatible with digital logic |
Real-World Examples
| Real-Life Source | Signal Behavior | Type of Sensor |
|---|
| Voice from microphone | Varies with loudness/pitch | Microphone |
| Temperature in a room | Increases or decreases smoothly | LM35 / Thermistor |
| Light intensity | Gradual brightness changes | LDR (Light Dependent Resistor) |
| Potentiometer knob | Changes voltage based on position | Potentiometer |
Importance in Embedded Systems
- Sensors produce analog data like temperature, light, and pressure.
- Arduino reads analog signals to:
- Detect environmental conditions.
- Make decisions (e.g., turn on fan when hot).
- Control devices like LEDs, motors, and servos.
ADC (Analog-to-Digital Converter)
- ADC translates continuous analog voltage (e.g., 0-5V) into a discrete digital value that a microcontroller can process.
- Analog → Digital = Physical quantity → Binary number
- The
analogRead() function in Arduino Uno (ATmega328P) performs this conversion.
ADC Block Diagram
- Sampler: Takes samples from the continuous analog signal at a specific sampling frequency, converting the signal into continuous amplitude-discrete time.
- Holding Circuit: Holds the sampled value until the next sample arrives.
- Quantizer: Converts the continuous amplitude-discrete time signal into a discrete time-discrete amplitude signal by splitting the samples into small parts.
- Encoder: Generates the digital signal in binary form.
ADC Characteristics in Arduino Uno (ATmega328P)
| Feature | Specification |
|---|
| Resolution | 10-bit → 0 to 1023 |
| Voltage Range | 0V to Vref (usually 5V) |
| Number of Channels | 6 analog input pins (A0–A5) |
| Default Ref. | 5V (from USB or external supply) |
| Internal Ref. | 1.1V (optional via analogReference(INTERNAL)) |
Internal Reference Voltage (Vref)
- The internal reference voltage is a fixed, stable voltage generated inside the microcontroller used as the upper limit for ADC conversions.
Why Use an Internal Reference?
- The default 5V supply can fluctuate, introducing noise or inaccuracy.
- Solution: Use the internal 1.1V reference for more stable and precise ADC results, especially when measuring low-voltage sensors.
Available Reference Options
| Reference Type | Voltage | Description |
|---|
| DEFAULT | ~5.0V | Vcc (from USB or external) |
| INTERNAL | 1.1V | Internal stable reference (built-in) |
| EXTERNAL | Custom | Voltage applied to AREF pin (< 5V) ! |
Use Case Example
- Measuring voltage from an LM35 temperature sensor (10mV per °C):
- Using 5V reference: 1∘C change = ~2 digital steps (low precision).
- Using 1.1V internal ref: 1∘C change = ~9 steps (better resolution).
Basic Conversion Process
- Sensor produces analog voltage (e.g., 2.3V).
- ADC samples this voltage and converts it to a digital number.
- Based on:
- Reference voltage
- Resolution (bit depth)
Example:
- With 10-bit ADC & 5V reference.
Example Code
void setup() {
Serial.begin(9600);
}
void loop() {
int rawValue = analogRead(A0);
float voltage = rawValue * (5.0 / 1023.0);
Serial.print("Raw ADC: ");
Serial.print(rawValue);
Serial.print(" Voltage: ");
Serial.println(voltage, 3); // 3 decimal places
delay(500);
}
How to Use INTERNAL Reference
void setup() {
analogReference(INTERNAL); // Set ADC reference to 1.1V
Serial.begin(9600);
}
void loop() {
int sensorValue = analogRead(A0);
float voltage = sensorValue * (1.1 / 1023.0); // Use 1.1V as reference
Serial.println(voltage);
delay(500);
}
Resolution in ADC
- Resolution is the smallest measurable change in analog input that the ADC can detect.
- Higher resolution (more bits) means finer granularity of measurements.
- Formula for Resolution: Resolution=2nVref
- Where:
- Vref is the reference voltage.
- n is the bit depth of the ADC (10 for Arduino Uno).
Resolution Calculation for Arduino Uno (10-bit ADC)
- ADC range is 0 to 1023 (210−1).
- Vref is 5V (default).
- Resolution=2105V=10245V≈0.0049V≈4.9mV
Sampling Rate in ADC
- Sampling Rate is the number of times per second the analog signal is sampled (measured) by the ADC.
- Measured in samples per second (SPS) or Hertz (Hz).
- For Arduino Uno (ATmega328P):
- The default sampling rate for
analogRead() is approximately 9.6 kHz (9600 samples per second).
Calculation of Arduino Sampling Rate
- ADC Clock is derived from the system clock (16 MHz) and divided by a prescaler.
- Sampling rate is affected by the ADC clock and conversion time per sample.
- The formula for the sampling rate (samples per second) is:
- SamplingRate=ConversionTimeADCClock
- For Arduino Uno (16 MHz clock and default prescaler of 128):
- ADC conversion time per sample is approximately 104 µs.
- SamplingRate=128×104×10−616×106≈9.6kHz
Why is Sampling Rate Important?
- Higher Sampling Rate = More Accurate Representation.
- Trade-Offs:
- Higher Sampling Rate → More power consumption, higher processing load.
- Lower Sampling Rate → Lower accuracy for high-frequency signals.
Example Scenarios:
- Scenario 1: Low Sampling Rate (Slow Signal)
- Measuring a slowly varying signal like temperature; a lower sampling rate is sufficient.
- Scenario 2: High-Frequency Signal
- Measuring an audio signal or fast-changing waveform; a sampling rate of 9.6 kHz might not be enough, as you may lose important details. A faster microcontroller or external ADC with a higher sampling rate may be necessary.
Practical Considerations
- Analog Signal Frequency: Ensure the signal you're measuring is below half of the sampling rate to avoid aliasing (Nyquist Theorem).
- With a sampling rate of 9.6 kHz, you can accurately sample signals up to 4.8 kHz.
- Arduino’s Sampling Rate Limitation: The Arduino Uno is limited by the ADC clock and processing power.
- If you need a faster sampling rate, consider using external high-speed ADCs.
Practical Example:
- Reading data from an accelerometer, which typically has a high-frequency signal (up to several kHz), may require a faster ADC.
Optimizing Sampling Rate in Arduino
- To increase the sampling rate of
analogRead() on Arduino Uno:- Reduce the delay between readings.
- Use
analogRead() with a lower resolution (if lower precision is acceptable). - Consider using direct register access to bypass some of the default overhead in Arduino's
analogRead().
Practical Setups
Practical Setup #1 - Potentiometer
void setup() {
Serial.begin(9600);
}
void loop() {
int potValue = analogRead(A0);
Serial.println(potValue);
delay(100);
}
- Open Tools > Serial Plotter in Arduino IDE to visualize the potentiometer values.
Practical Setup #2 - LM35 Temperature Sensor
void setup() {
Serial.begin(9600);
}
void loop() {
int raw = analogRead(A1);
float voltage = raw * (5.0 / 1023.0);
float temperatureC = voltage * 100;
Serial.print("Temp: ");
Serial.print(temperatureC);
Serial.println(" °C");
delay(1000);
}
Challenge
- Read both potentiometer and LM35.
- Display both in Serial Monitor.
Improving Accuracy in ADC Readings
- Raw analog readings can fluctuate due to:
- Electrical noise
- Sensor instability
- Rapid environmental changes
- Unstable readings lead to inaccurate measurements.
Common Accuracy-Improving Techniques
| Technique | Description |
|---|
| Averaging (Smoothing) | Take multiple samples and compute their average. |
| Median Filtering | Remove outliers by choosing the middle value. |
| Software Debouncing | Ignore fast spikes/noise in analog inputs. |
| Shielding/Grounding | Physically protect wires from EMI (hardware-level). |
| Low-pass Filtering | Filter high-frequency noise in software or hardware. |
Benefits of Averaging
- Reduces noise from erratic ADC readings.
- Especially useful in:
- Temperature sensors (LM35, DHT11 analog mode)
- Light sensors (LDRs)
- Potentiometers for stable input tracking
- Adds minimal computational overhead.
Rolling Average (Moving Average Filter)
- Keeps a fixed number of past readings, adds the new one, removes the oldest, and averages the rest.
- Keeps your data responsive but smooth.
Use When:
- You want stable but fast-reacting values.
- You're smoothing data in real time (e.g., sensor-based UI sliders).
Exponential Smoothing (Low-Pass Filter)
- Blends the previous smoothed value and the new sensor reading using a weighting factor (alpha).
- Formula: SmoothValue=α×Raw+(1−α)×SmoothValue
const int sensorPin = A0;
float alpha = 0.1; // Smoothing factor (try 0.05 - 0.3)
float smoothValue = 0;
void setup() {
Serial.begin(9600);
smoothValue = analogRead(sensorPin); // Initialize with first reading
}
void loop() {
int raw = analogRead(sensorPin);
smoothValue = alpha * raw + (1 - alpha) * smoothValue;
Serial.println((int) smoothValue); // Print smoothed value as int
delay(50);
}
Rolling vs. Exponential Smoothing
| Feature | Rolling Average | Exponential Smoothing |
|---|
| Memory Usage | Higher (needs array) | Very low |
| Reacts to Changes | Slower (delayed by N) | Faster |
| Best For | Stable, noise-heavy data | Real-time feedback with smoothness |
| Complexity | Moderate | Simple |