Code Along - Chapter 9

Analogue Inputs

Read a knob or sensor with analogRead, turn 0-1023 into volts and percent, switch on a threshold without chattering, and average away the noise.

Estimated time 90-120 minExercises passed 0 / 6

From volts to numbers

analogRead(A0) measures the voltage on an analogue pin and gives a whole number from 0 to 1023 (10 bits). 0 means 0 V and 1023 means 5 V, so each step is about 4.9 mV.

A potentiometer is a voltage divider you can turn: one end to 5 V, the other to GND, the middle wiper to A0. Turn it and the wiper voltage - and the reading - sweeps between the two ends.

Drag the slider on the virtual board while a sketch runs to "turn the knob".

Potentiometer with 5 V at the top, GND at the bottom and the wiper on A0
The wiper gives a voltage between 0 V and 5 V; the ADC turns it into 0-1023.
Worked example

Reading the knob

Press Run, then drag the potentiometer slider and watch both numbers move.

const int POT = A0;

void setup() {
  Serial.begin(9600);
}

void loop() {
  int reading = analogRead(POT);
  Serial.print("reading ");
  Serial.print(reading);
  Serial.print("  volts ");
  Serial.println(reading * 5.0 / 1023, 2);
  delay(500);
}

Turn on JavaScript to edit, run and test this code in the browser.

Expected output
reading 512  volts 2.50
reading 512  volts 2.50
Exercise 9.1

Print the reading

Not started

Read the potentiometer on A0 and print it as A0 = 512, five times a second. The test turns the knob while your sketch runs, so read it every pass - do not store it once.

Sample output
A0 = 512
A0 = 512
A0 = 512
const int POT = A0;

void setup() {
  Serial.begin(9600);
}

void loop() {
  // Print: A0 = 512   then wait 200 ms

}

Turn on JavaScript to edit, run and test this code in the browser.

Exercise 9.2

Knob as a percentage

Not started

0 to 1023 means little to a person. Print the knob position as a percentage instead: Knob: 50 %, twice a second. map(value, 0, 1023, 0, 100) does the scaling.

Sample output
Knob: 50 %
const int POT = A0;

void setup() {
  Serial.begin(9600);
}

void loop() {
  // Read A0, scale it to 0..100 and print: Knob: 50 %

  delay(500);
}

Turn on JavaScript to edit, run and test this code in the browser.

Exercise 9.3

Dark switch

Not started

An LDR divider on A0 reads low when it is dark. Switch the onboard LED on while the reading is below 300, and off otherwise. The test dims and brightens the light for you.

const int LDR = A0;

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  // LED on while the reading is below 300

}

Turn on JavaScript to edit, run and test this code in the browser.

Thresholds that chatter

A single threshold is trouble when the reading sits right on it. Noise of a few counts flips the output on and off dozens of times a second - you can hear it on a relay.

The cure is hysteresis: two thresholds with a gap between them. Switch on when it gets properly dark, switch off when it gets properly light, and in between leave things alone. It is the same dead band as the thermostat in Chapter 3.

Exercise 9.4

Add hysteresis

Not started

Give the dark switch a dead band:

  • below 300: switch the LED on
  • above 400: switch it off
  • between 300 and 400: leave it as it is

lampOn remembers the current state. The test parks the reading in the middle band twice, and the LED must not move then.

const int LDR = A0;
bool lampOn = false;

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
}

void loop() {
  int reading = analogRead(LDR);
  // Below 300: lampOn = true.  Above 400: lampOn = false.  Otherwise: leave it.

  digitalWrite(LED_BUILTIN, lampOn);
}

Turn on JavaScript to edit, run and test this code in the browser.

Exercise 9.5

Average ten readings

Not started

A single analogRead jitters by a count or two. Take ten readings 5 ms apart in setup(), add them up and print the average as Average: 600.

Sample output
Average: 600
const int POT = A0;

void setup() {
  Serial.begin(9600);
  long total = 0;
  // Take 10 readings, 5 ms apart, and add them to total


  Serial.print("Average: ");
  Serial.println(total / 10);
}

void loop() {
}

Turn on JavaScript to edit, run and test this code in the browser.

Exercise 9.6

What is the sensor's resistance?

DeeperNot started

The sensor sits in a divider: 10 kΩ from 5 V down to A0, and the sensor from A0 to GND. Its resistance is

R = 10000 × reading / (1023 − reading)

Print it as Reading 512 = 10019 ohm. Careful: 10000 × 512 does not fit in an int.

Sample output
Reading 512 = 10019 ohm
const int SENSOR = A0;

void setup() {
  Serial.begin(9600);
  int reading = analogRead(SENSOR);

  // Work out the resistance and print: Reading 512 = 10019 ohm

}

void loop() {
}

Turn on JavaScript to edit, run and test this code in the browser.

Try it on a real Uno

Wire a 10 kΩ potentiometer: outer legs to 5 V and GND, wiper to A0. Upload Knob as a percentage and turn it slowly through the whole range.

Then swap the pot for an LDR and a 10 kΩ resistor as in Lesson 20, upload Add hysteresis, and find the two thresholds that suit your room by printing the reading while you cover the sensor.