EVERY PART IN THE BOX · 29 LESSONS · 8 PROJECTS

Everything left to build, and why each circuit works.

You have finished sixteen lessons. This manual covers those again as reference, then every part still sitting in the tray, then eight projects that combine them. Wiring maps, pin tables, the theory gathered in one place, and answers to every question worth asking — not just the steps.

D135VGNDA03V3D9
16already built
13still ahead
8projects
51questions answered

Start here

6

START HERE

How to read this manual

Every lesson below is built the same way, so you can jump to any of them and know where to look.

  • The wiring map. A drawing of your UNO with only the pins you need lit up, and a coloured wire to every part. Wire colours are consistent everywhere in this document: red is 5 V, black is ground, blue, amber, green and purple are signals, orange is 3.3 V. Where a resistor belongs, it is drawn on the wire itself with its real colour bands, so you can match it against the part in your hand.
  • The pin table. The same information as a checklist. Wire from the table, then check against the map.
  • Why it works. The part you actually asked for. Not the procedure, the reason.
  • The catch. The one mistake that costs people an hour on that particular circuit.

The maps deliberately show connections rather than a photo of a breadboard. A photo hides half the wires behind the components; a map never does. What the map does not show is which breadboard row you use, because that part is free choice: any two holes in the same row are the same electrical point. The next section explains that.

START HERE

Seven rules that stop the smoke

Nothing here is fussiness. Each rule maps to a specific way beginners destroy a board.

  1. Unplug the USB cable before you change wiring. Rewiring a live circuit is how you short 5 V to ground with your fingers still on the jumper.
  2. Never wire 5 V straight to GND. That is a short circuit. The USB port will shut itself off if you are lucky, and the board's polyfuse will get hot if you are not.
  3. Never connect a motor, relay coil or anything with a magnet directly to an Arduino pin. A pin can supply about 20 mA comfortably and 40 mA absolute maximum. A motor wants ten times that. See Lesson 17.
  4. The whole 5 V pin can supply roughly 400–500 mA over USB, shared by everything. Add up your parts before you plug in.
  5. Every LED gets a resistor. An LED has no internal resistance to speak of; without a resistor the only thing limiting current is the pin itself, and the pin loses.
  6. 3.3 V parts get 3.3 V. The RFID reader in your kit (Lesson 23) is destroyed by 5 V on its power pin. It is the single most commonly killed module in this kit.
  7. Everything shares one ground. If you power a motor from a battery and the Arduino from USB, the battery's negative terminal must still connect to an Arduino GND pin. Signals are measured against ground; two circuits with no shared ground have no agreed zero, so the signal means nothing.

START HERE

Voltage, current, resistance

Three quantities, one relationship, and the whole kit falls out of it.

Voltage is a difference in electrical pressure between two points. That word difference is the important one. There is no such thing as the voltage at a point, only the voltage between two points. When we say "pin D13 is at 5 V" we always mean 5 V above ground, and ground is simply the point everyone agreed to call zero. This is why every circuit in this manual has a black wire in it: without a shared zero, "5 V" is a sentence with no subject.

Current is the flow of charge, measured in amps. Current is what actually does the work and what actually destroys things. Heat in a component is proportional to current squared, which is why a small mistake in current is a large mistake in temperature.

Resistance is how much a material objects to that flow, in ohms. Ohm's law ties them together:

V = I × R   →   I = V / R   →   R = V / I

The useful mental habit is this: voltage is applied, current is the consequence. You choose what voltage to put across something; the circuit decides how much current results. A 220 Ω resistor with 3 V across it will pass 3/220 = 0.0136 A = 13.6 mA, whether or not that suits you. Your only lever is the resistance.

The water analogy holds up well as long as you keep it honest: voltage is pressure difference, current is litres per second, resistance is the narrowness of the pipe. A pump raises pressure but the pipe decides flow. The place the analogy fails is that water can leak out of an open pipe, while current cannot flow unless there is a complete loop back to where it came from. There is no such thing as half a circuit.

Power is the fourth quantity you meet as soon as motors appear: P = V × I, in watts. It tells you how much energy per second is being turned into heat, light or motion, and it is the number that decides whether something gets warm or gets destroyed.

START HERE

The breadboard, honestly explained

+ - 1 6 11 16 21 A B C D E F G H I J 74HC595 THE + RAILevery hole across this row isone single connection FIVE HOLES, ONE POINTa column group above thechannel, connected together THE CENTRE CHANNELbreaks the connection, so achip can straddle it safely A DIFFERENT POINTthe same column below thechannel is NOT connected above THE - RAILone connection too. Run GNDhere once and use it anywhere

A breadboard is a grid of holes with metal clips hidden underneath, and those clips are connected in a specific pattern. Almost every "my circuit does nothing" problem is a misunderstanding of this pattern.

The two long rails at the top and bottom (marked with a red line and a blue or black line) run the full length of the board. Every hole along the red line is one single electrical point; the same for the blue line. These are for power and ground, and they exist because nearly every part needs both, so it would be miserable to run a separate wire back to the Arduino each time. You run one red wire from 5 V to the red rail and one black wire from GND to the blue rail, and now power is available everywhere.

The main area is completely different: it is connected in short rows of five holes, running across the board, and the channel down the middle breaks the connection. So holes A1 B1 C1 D1 E1 are one point, and F1 G1 H1 I1 J1 are a different point, even though they are in the same numbered row. The gap is not decoration.

That centre channel is exactly the width of a DIP chip like your 74HC595, and this is why: the chip straddles the channel so that its left row of legs and its right row of legs land on different, unconnected groups. If the channel were not there, every leg would be shorted to the one opposite it and the chip would do nothing.

Two habits that pay for themselves: put components across the channel or across separate rows so their legs never share a row by accident, and keep your rails consistent across every project — red on top, black on the bottom, always. Muscle memory prevents reversed-polarity mistakes better than care does.

START HERE

The resistor has exactly three jobs

You already noticed this pattern and it is worth stating as a rule, because from here on almost every resistor you place is one of these three, and knowing which one tells you how to choose its value.

Job 1 — Current limiter

Placed in series with something that would otherwise take too much current. The classic case is an LED. An LED is not a resistor: once it reaches its forward voltage it conducts almost freely, so the current is set entirely by what else is in the loop. You size it with Ohm's law using the leftover voltage:

R = (Vsupply − VLED) / Idesired

For a red LED on 5 V: (5 − 2.0) / 0.015 = 200 Ω, so 220 Ω is the nearest standard value and that is why the kit ships so many of them. Blue and white LEDs drop about 3.2 V, so the same 220 Ω gives them less current and they look dimmer — that is expected, not a fault.

Job 2 — Pull-down (or pull-up)

A digital input pin that is not connected to anything does not read zero. It floats: it is a tiny capacitor with no one driving it, so it picks up mains hum and your hand's static and reports random values. A pull-down resistor ties that pin weakly to ground so it reads LOW when nothing else is happening, but weakly enough that when your button connects it to 5 V, 5 V wins. 10 kΩ is the standard compromise: strong enough to beat the noise, weak enough to waste almost nothing (5 V across 10 kΩ is 0.5 mA when the button is pressed).

A pull-up is the same idea, upside down: tie the pin to 5 V, and let the button connect it to ground. The pin then reads HIGH when idle, LOW when pressed. The ATmega328P has pull-up resistors built into every pin, which you switch on with pinMode(pin, INPUT_PULLUP), and that is why most of the later lessons in this manual use pull-ups: it is one fewer part and one fewer wire.

Job 3 — Half of a voltage divider

Here the resistor is not protecting anything, it is a reference. Two resistors in series across 5 V split that voltage in proportion to their resistances, and the point between them can be measured:

Vout = 5 V × Rbottom / (Rtop + Rbottom)

This is how every resistive sensor in your kit is read: the photoresistor, the thermistor, the flame sensor. The sensor is one of the two resistors, the fixed resistor is the other, and the Arduino measures the point between them. Your tug-of-war picture is exactly right — the fixed resistor pulls the midpoint toward ground, the sensor pulls it toward 5 V, and the reading tells you who is winning.

The value of the fixed resistor sets where the circuit is most sensitive. The divider gives its biggest voltage change per unit of sensor change when the two resistances are roughly equal, so you pick the fixed resistor near the middle of the sensor's working range. A 10 kΩ photoresistor gets a 10 kΩ partner for exactly this reason, not by tradition.

Reading the bands

Four-band resistors: first two bands are digits, third is the number of zeros, fourth (gold) is tolerance.

brown black orange = 1, 0, +3 zeros = 10,000 Ω = 10 kΩ
red red brown = 2, 2, +1 zero = 220 Ω

Digits in band order: black 0, brown 1, red 2, orange 3, yellow 4, green 5, blue 6, violet 7, grey 8, white 9. When in doubt, measure it — but the gold band always goes on the right.

START HERE

Digital, analog, PWM and the ADC

Four ideas that are constantly confused with each other, so it is worth separating them cleanly.

Digital output

digitalWrite(pin, HIGH) connects that pin to 5 V through a transistor inside the chip. LOW connects it to ground. There is nothing in between. The pin is a switch, not a supply — it can source or sink about 20 mA before its output voltage starts to sag, and it is permanently damaged around 40 mA.

Digital input

digitalRead(pin) compares the pin voltage against thresholds. On a 5 V ATmega328P, above roughly 3 V reads HIGH, below roughly 1.5 V reads LOW. In between is undefined — the pin will report something, but not reliably the same thing twice. This gap is exactly why floating inputs are a problem and why pull-ups and pull-downs exist.

Analog input, and what the ADC really does

Pins A0 to A5 feed an analog-to-digital converter. It compares the incoming voltage against a reference (5 V by default) and reports where it falls, as a whole number from 0 to 1023. That is 10 bits of resolution, so one step is 5 V / 1024 = about 4.9 mV.

volts = analogRead(pin) × 5.0 / 1023.0

Two things follow from this that catch everyone. First, the ADC measures voltage, not resistance — which is precisely why a bare sensor plugged into A0 does nothing useful, and why you always need the divider. Second, the reading is relative to the 5 V reference, so if your 5 V rail sags because a servo just started moving, every analog reading in your sketch shifts at the same moment. If your temperature readings jump whenever a motor runs, this is why.

PWM is not analog output

analogWrite(pin, 128) does not produce 2.5 V. It produces a square wave that is at 5 V half the time and 0 V the other half, switching about 490 times per second on most pins. The average is 2.5 V, and anything slow enough to respond only to the average — your eye looking at an LED, a motor's inertia, a speaker cone — behaves as if it received 2.5 V. Anything fast enough to see the individual pulses does not. Only the pins marked with a tilde (~3, ~5, ~6, ~9, ~10, ~11) can do this.

The value you pass is 0 to 255, which is 8 bits. Note the asymmetry that trips people up: analog in is 0–1023, analog out is 0–255. Converting between them, or to any other range, is what map() is for.

Lessons you have built

16

LESSON 02

Push button

Why an unconnected input pin lies to you

Built
You needPush button10 kΩ resistor3 jumper wires
5VD2GNDD13GND Push button (4 legs)leg A to 5 Vleg B to D2opposite corners, not adjacent ones LED (optional feedback)anode +cathode - 10k 220 5VsignalGND The 10k pull-down and the button both connect to the same breadboard row as D2.
ArduinoGoes toWhy
5VOne leg of the buttonThe voltage the button will deliver when pressed.
D2The other leg, plus one end of the 10 kΩ resistorBoth meet at the same breadboard row. That shared point is what the pin measures.
GNDOther end of the 10 kΩ resistorThe weak tie to zero that holds the pin down when the button is open.

A four-legged tactile button is really two pairs of legs. Within a pair the legs are permanently joined; pressing connects one pair to the other. If your button seems always pressed, you have wired two legs that were already connected — use legs on opposite corners.

The floating input problem. Suppose you skip the resistor and wire only 5 V through the button to D2. Pressed, D2 sees 5 V and reads HIGH. Released, D2 is connected to nothing at all. It does not read LOW; it reads whatever charge happens to be sitting on it. The pin is a tiny capacitor with an extremely high input impedance, so the mains hum radiating through your body and the wire is more than enough to swing it back and forth across the logic threshold. You get a button that appears to work until you move your hand near it.

What the pull-down does. The 10 kΩ resistor to ground gives the pin a definite path to zero at all times. Released, no current flows through it (the input pin draws essentially nothing), so there is no voltage drop across it and the pin sits at a solid 0 V. Pressed, the pin is connected to 5 V through the button's near-zero resistance and to ground through 10 kΩ. Look at it as a voltage divider: Rtop is near zero, Rbottom is 10 k, so the pin reads essentially the full 5 V. The button wins because it is far stronger.

Why 10 kΩ and not something else. Too large (say 10 MΩ) and it becomes too weak to overcome the noise it was meant to defeat. Too small (say 100 Ω) and it works fine, but pressing the button now burns 5 V/100 Ω = 50 mA straight to ground for nothing. 10 kΩ costs 0.5 mA and is immune to any noise you will meet on a desk.

Bouncing. A mechanical button does not close once. The metal dome flexes and makes contact several times over roughly 1–20 ms. The Arduino is fast enough to see every one of those as a separate press. If you are counting presses and the count jumps by three, you are seeing bounce, not a bug in your logic. The fix is to ignore any change that arrives within a few tens of milliseconds of the last one.

Two ways to solve the same problem
pinMode(2, INPUT);        // with an external 10k pull-down
// or, with no resistor at all:
pinMode(2, INPUT_PULLUP); // internal pull-up; wire the button to GND
// note this inverts the logic: LOW now means pressed
ConceptsdigitalRead()pull-down resistorfloating inputsdebouncing

LESSON 03

Flowing LEDs

Eight outputs, arrays, and the current budget

Built
You need8 LEDs8 × 220 Ωbreadboardjumpers
D2D3D4D5D6D7D8D9GND Eight LEDs in a rowLED 1 anodeLED 2 anodeLED 3 anodeLED 4 anodeLED 5 anodeLED 6 anodeLED 7 anodeLED 8 anodeall cathodes joinedeach anode gets its own 220 ohm resistor 220 signalGND All eight cathodes share one row, which connects once to the ground rail.
ArduinoGoes toWhy
D2 – D9One LED anode each, through its own 220 ΩOne resistor per LED, never one shared resistor.
GNDThe joined cathodesA single return path is fine; ground can carry all eight currents.

Nothing new electrically — this is Lesson 1 eight times — but two ideas appear that matter later.

Why every LED needs its own resistor. It is tempting to put one resistor on the shared cathode line. Do not. Resistors limit current, and a shared resistor limits the total. Turn on one LED and it gets the full 13 mA and is bright; turn on all eight and they share that current, so each gets under 2 mA and all eight are dim. Worse, LEDs of different colours have different forward voltages, so the one with the lowest forward voltage hogs the current and the others barely light. Individual resistors give each LED its own independent budget.

The current budget. Eight LEDs at 13.6 mA is 109 mA if they are all on at once. That is fine for the 5 V rail, but note the other limit that is not printed on the board: the ATmega328P has an absolute maximum of 200 mA total through all its pins combined, and a per-port limit of 100 mA. Eight LEDs is close enough to that per-port figure to be worth knowing about, and it is the reason Lesson 14 exists — a shift register drives LEDs from its own supply rather than from the microcontroller's pins.

Arrays. The reason to write int leds[] = {2,3,4,5,6,7,8,9}; instead of eight separate variables is not brevity, it is that an array turns "which LED" into a number you can compute with. Once the pin number is an index, a sweep is a loop, a bounce is a loop that counts backwards, and a random sparkle is a random index. The wiring did not get smarter; the addressing did.

The pin number becomes an index
int leds[] = {2, 3, 4, 5, 6, 7, 8, 9};
for (int i = 0; i < 8; i++) {
  digitalWrite(leds[i], HIGH);
  delay(80);
  digitalWrite(leds[i], LOW);
}
Conceptsarraysfor loopscurrent budget

LESSON 04

Active buzzer

A part that makes its own tone

Built
You needActive buzzer2 jumpers
D8GND Active buzzer+ (marked, longer leg)- (short leg)sealed top, usually a sticker over it signalGND Active buzzer: apply DC and it decides the frequency for you.
ArduinoGoes toWhy
D8Buzzer +Any digital pin. HIGH sounds it, LOW silences it.
GNDBuzzer -Return path.

Your kit has two buzzers that look nearly identical and behave completely differently. This one, the active buzzer, has an oscillator circuit built into it. Apply a steady DC voltage and it produces its own fixed tone — typically around 2 kHz — for as long as the voltage is there. You cannot change the pitch, because the pitch was decided at the factory.

Telling them apart. The active one is usually the taller of the two, is sealed on top, and if you briefly touch it across a 3 V coin cell it will beep. The passive one has an exposed disc visible underneath and will only click. If you check resistance with a meter, the active buzzer typically reads as an open circuit or a high value, while the passive one reads around 8–16 Ω like a small speaker.

The current question. A small active buzzer draws roughly 25–30 mA, which is right at the edge of what a pin should supply. It works, and every starter kit does it this way, but it is not a habit to generalise: this is the point where "drive it straight from a pin" stops being obviously safe. For anything hungrier, you switch it with a transistor and the pin only controls the transistor. That is the entire idea behind Lessons 16 and 17.

Buzzers also contain a coil, which means they are inductive: when you switch one off, the collapsing magnetic field briefly generates a reverse voltage spike. It is small enough here not to matter, but keep the phrase in mind — it becomes very important with relays and motors, where the same effect is large enough to destroy a transistor.

There is no pitch control here, by design
digitalWrite(8, HIGH);  // on, at whatever pitch the buzzer was born with
delay(200);
digitalWrite(8, LOW);
Conceptsdigital outputinductive load basics

LESSON 05

Passive buzzer

You supply the frequency

Built
You needPassive buzzer100 Ω resistor (optional)2 jumpers
D8GND Passive buzzer+ signal- groundexposed disc underneath, behaves like a tiny speaker 100 signalGND The 100 ohm resistor is optional. It reduces volume and eases the load on the pin.
ArduinoGoes toWhy
D8Buzzer +, optionally through 100 Ωtone() works on any digital pin.
GNDBuzzer -Return path.

A passive buzzer is a piezoelectric disc with no electronics inside. A DC voltage makes it flex once and hold — a click, then silence. To get a sustained note you have to keep flexing it, which means feeding it an alternating signal at the frequency you want to hear.

tone(pin, 440) tells one of the ATmega's hardware timers to generate a 440 Hz square wave on that pin and then returns immediately. The timer keeps running in the background while your sketch carries on, which is why tone() does not block the way delay() does. It runs until you call noTone() or start a different tone.

Why this is not analogWrite(). Both produce square waves, and that is where the resemblance ends. PWM holds the frequency fixed (about 490 Hz) and varies the duty cycle — the proportion of time spent HIGH — because what you want to control is average power. tone() holds the duty cycle fixed at 50% and varies the frequency, because what you want to control is pitch. Try analogWrite() on a passive buzzer and you will hear one unchanging 490 Hz buzz that only changes volume slightly.

Notes are frequencies. Musical pitch is logarithmic: each octave doubles. A4 is 440 Hz, A5 is 880 Hz, A3 is 220 Hz. Each semitone multiplies by the twelfth root of two, about 1.0595. The pitches.h header that ships with the Arduino examples is just that table pre-computed, which is why every melody sketch includes it.

One limitation worth knowing. tone() uses Timer 2 on an UNO, and Timer 2 also generates PWM on pins 3 and 11. While a tone is playing, analogWrite() on those two pins will not behave. If your RGB LED misbehaves whenever music plays, that is the cause, and moving the LED to pins 5, 6, 9 or 10 fixes it.

tone() is non-blocking; the delay after it is not
tone(8, 440);      // A4, generated by a hardware timer
delay(500);        // the sketch waits, but the timer does the work
noTone(8);
Conceptstone()frequencyPWM vs tone

LESSON 06

Photoresistor

Measuring a resistance with a voltmeter

Built
You needPhotoresistor (LDR)10 kΩ resistor3 jumpers
5VA0GND Photoresistor (LDR)leg 1 to 5 Vleg 2 to A0no polarity, either leg can be either side 10k 5VsignalGND The LDR and the 10k form the divider. A0 taps the point between them.
ArduinoGoes toWhy
5VOne LDR legTop of the divider.
A0Other LDR leg and one end of the 10 kΩThe midpoint. This is the only thing the Arduino actually measures.
GNDOther end of the 10 kΩBottom of the divider.

A photoresistor is a strip of cadmium sulphide whose resistance falls when light hits it: roughly 1 kΩ in bright light, hundreds of kilohms in darkness. The Arduino cannot measure resistance. It can only measure voltage. So the entire job of this circuit is to convert a changing resistance into a changing voltage.

What happens without the 10 kΩ. Wire only 5 V through the LDR to A0 and the reading pins at 1023 in all conditions. The reason is that the ADC input draws almost no current — its input impedance is in the megohms. With no current flowing through the LDR, there is no voltage drop across it (V = I × R, and I is essentially zero), so A0 sees the full 5 V no matter what the LDR's resistance is. The sensor is doing its job; there is simply nothing to read.

What the 10 kΩ changes. Adding it to ground creates a complete path from 5 V through the LDR, through the 10 kΩ, to ground. Now current flows, now each resistance drops a share of the 5 V, and now the midpoint is a real number that moves:

VA0 = 5 × 10k / (RLDR + 10k)

Bright light, RLDR = 1 k: V = 5 × 10/11 = 4.5 V, reading about 930.
Darkness, RLDR = 200 k: V = 5 × 10/210 = 0.24 V, reading about 49.

The tug-of-war picture you had is exactly the mechanism: the fixed resistor pulls the midpoint toward ground, the LDR pulls it toward 5 V, and the reading reports the balance of the contest.

Which side to put the sensor on. Swap the LDR and the resistor and everything still works — but the reading inverts, going up in darkness instead of down. Neither is more correct. Pick one and know which you picked.

Calibrate, do not guess. Do not hunt for the "right" threshold number in a tutorial. Print analogRead(A0) to the Serial Monitor, cover the sensor, uncover it, note the two extremes in your room, and put your threshold between them. Those numbers depend on your specific LDR, your resistor's tolerance and your lighting, so nobody else's numbers are meaningful.

From count, to volts, to ohms
int raw = analogRead(A0);              // 0..1023
float volts = raw * 5.0 / 1023.0;      // what the pin actually sees
// resistance, if you want it:  R = 10000.0 * (5.0 - volts) / volts;
Conceptsvoltage divideranalogRead()ADCsensor calibration

LESSON 07

RGB LED

Three LEDs sharing a package, and colour by average

Built
You needRGB LED3 × 220 Ω4 jumpers
D9D10D11GND RGB LED (common cathode)R red anodecommon longest legG green anodeB blue anodelongest leg is the common; on this kit it goes to GND 220 signalGND All three pins must be PWM-capable, marked with a tilde on the board.
ArduinoGoes toWhy
~D9Red anode through 220 ΩPWM pin. Sets red brightness 0–255.
~D10Green anode through 220 ΩPWM pin.
~D11Blue anode through 220 ΩPWM pin.
GNDCommon (longest) legFor a common-cathode part. If yours is common anode, this leg goes to 5 V instead.

An RGB LED is three separate dies in one plastic package, sharing one leg. Which leg they share determines the type. In a common cathode part all three cathodes are joined and that leg goes to ground, so a HIGH on a colour pin lights it. In a common anode part all three anodes are joined and that leg goes to 5 V, so the logic inverts completely: 0 is full brightness and 255 is off.

How to tell which you have without a datasheet: wire the long leg to GND through a 220 Ω resistor and touch one of the other legs to 5 V. If it lights, you have common cathode. If nothing happens, try the long leg on 5 V and a short leg to ground instead. This takes ten seconds and saves an hour of confused debugging.

Colour is a timing trick. There is no circuitry inside doing colour mixing. Each PWM pin switches its die on and off hundreds of times a second, and your eye — which cannot resolve changes that fast — integrates the pulses into an apparent brightness. Three apparent brightnesses land on your retina from nearly the same spot, and your visual system reports a single blended colour. The LED is only ever fully on or fully off.

Why the colours never look right at first. Setting all three to 255 rarely gives clean white. Three reasons: the human eye is far more sensitive to green than to blue, so equal drive does not look equal; the three dies have different forward voltages (red about 2 V, green and blue about 3 V) so identical 220 Ω resistors deliver different currents; and brightness perception is not linear in drive. Fixing it means using different resistor values or scaling the channels in software. Reaching for a bigger resistor on the red channel is a legitimate engineering answer, not a hack.

Three resistors, not one. Same reasoning as Lesson 3, and here it is worse: a shared resistor on the common leg means the three colours steal current from each other, so the colour visibly shifts as you change any single channel.

Values are 0-255, not 0-1023
analogWrite(9,  255);   // red   full
analogWrite(10,  80);   // green partial
analogWrite(11,   0);   // blue  off
// common anode? use 255 - value on every channel
ConceptsPWMcommon cathode vs anodecolour mixing

LESSON 08

Servo motor

A motor that is told where to be, not how fast to spin

Built
You needSG90 servo3 jumpers
D95VGND SG90 servoorange / yellow signalred +5 Vbrown / black GNDcolours are standard across hobby servos signal5VGND One small servo can run from the board 5 V. Two cannot.
ArduinoGoes toWhy
~D9Signal (orange or yellow)The Servo library can use any pin, but it disables PWM on pins 9 and 10 while active.
5VPower (red)One SG90 idles near 10 mA and pulls 100–250 mA while moving, more if stalled.
GNDGround (brown or black)Must be shared with the Arduino even if the servo is powered separately.

A hobby servo is a closed loop in a box: a small DC motor, a gearbox, a potentiometer geared to the output shaft, and a control circuit. The potentiometer tells the circuit where the shaft currently is. Your signal tells it where the shaft should be. The circuit drives the motor in whichever direction reduces the difference, and stops when it reaches zero. This is why a servo holds its position against a push, and why it buzzes if you ask for an angle it cannot reach — it never stops trying to correct an error it cannot eliminate.

The signal is a pulse width, not a voltage and not PWM in the usual sense. Every 20 ms the servo expects a pulse. A pulse about 1 ms long means one extreme, about 1.5 ms means centre, about 2 ms means the other extreme. What carries the information is entirely the duration of the pulse; the gap between pulses just tells the servo you are still there. The Servo library generates these using a hardware timer, which is why it does not block your sketch and why it takes over PWM on pins 9 and 10.

Speed is not directly controllable. write(90) means go to 90 degrees, at whatever speed the servo can manage. To make motion look slow and deliberate you step the angle a little at a time with a short pause between steps, so what you are really controlling is the rate of change of the target, not the motor.

Power is the real gotcha. A servo's current draw is not steady — it spikes at the instant it starts moving and again if it meets resistance. That spike pulls the 5 V rail down for a moment, and everything else sharing that rail feels it. Symptoms: the Arduino resets when the servo starts, an LCD fills with garbage, or analog readings jump. The fix is a separate 5 V supply for the servo with its ground tied to the Arduino's ground, plus a large capacitor across the servo's supply if you have one.

You command position; the servo handles the rest
#include <Servo.h>
Servo s;
s.attach(9);
s.write(90);      // "be at 90 degrees" - a target, not a speed
// smooth motion: step the target, do not step the motor
for (int a = 0; a <= 180; a++) { s.write(a); delay(15); }
Conceptsposition controlpulse widthServo librarypower draw

LESSON 09

LCD1602

Sixteen characters, two rows, and a bus you can halve

Built
You needLCD160210 kΩ potentiometer220 Ω~16 jumpers
GND5VD12GNDD11D5D4D3D2 LCD1602 (16 pins)VSS GNDVDD 5 VV0 contrastRS register selectRW read / writeE enableD4D5D6D7A backlight +K backlight -D0-D3 are left unconnected in 4-bit mode 10k potentiometerleg 1 5 Vwiper to V0leg 3 GND 220 GND5Vsignal Note the crossover: Arduino D5 goes to LCD D4, D4 to D5, D3 to D6, D2 to D7.
ArduinoGoes toWhy
D12RSSelects whether the byte you send is a character or a command.
D11EEnable. The falling edge is what actually latches the data in.
D5, D4, D3, D2LCD D4, D5, D6, D7The upper four data lines. The pin numbers cross over; that is normal.
5V / GNDVDD / VSS, and RW to GNDRW tied low means write-only, which is all you need.
Pot wiperV0Contrast. Without this the screen is blank or solid boxes.

The HD44780 controller behind this display is from 1980 and it shows, which is educationally useful: you can see the whole bus operating.

Why the wiring order looks scrambled. The display has eight data lines D0 to D7, but it can be operated using only the upper four. Each byte is sent as two nibbles, high half first, then low half. That is twice as many operations but it saves four Arduino pins, and the display is so much slower than the processor that the cost is invisible. In 4-bit mode D0–D3 are simply left unconnected, and the library's constructor LiquidCrystal(12, 11, 5, 4, 3, 2) reads as RS, E, then the four Arduino pins that connect to the display's D4, D5, D6, D7 in that order.

RS, RW and E. RS answers "is this byte data or an instruction" — a character to display, or a command like "clear" or "move the cursor". RW chooses read or write; you tie it to ground permanently because reading back from an LCD is almost never useful and it costs a pin. E is the clock: you place your bits on the data lines, then pulse E, and the falling edge is the moment the display commits to reading them. This pattern — set up data, then pulse a line to say "now" — is the same idea as the latch pin on your 74HC595 in Lesson 14. Once you see it, you see it everywhere in digital electronics.

Contrast is not brightness. V0 sets the bias voltage for the liquid crystal itself, which decides how dark the pixels appear against the background. It needs a fraction of a volt, adjustable, and the potentiometer supplies it. If V0 is left floating or at 5 V you get a blank screen; at 0 V you get a row of solid black boxes. Solid boxes on the top row is the display's way of saying "I am powered but nobody has initialised me" — so it usually means a data or E wire is wrong, not that the display is broken.

The backlight is a separate circuit. Pins A and K are just an LED behind the glass, electrically unrelated to everything else. It needs its own current-limiting resistor — many modules include one, many do not, and 220 Ω is safe either way.

setCursor takes column then row, which catches everyone once
#include <LiquidCrystal.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);  // RS, E, D4, D5, D6, D7
lcd.begin(16, 2);
lcd.setCursor(0, 1);   // column first, then row - both count from 0
lcd.print("hello");
Conceptsparallel bus4-bit modeLiquidCrystalcontrast

LESSON 10

Thermistor

The same divider, a much harder maths problem

Built
You needThermistor 10 kΩ10 kΩ resistor3 jumpers
5VA0GND Thermistor (10k NTC)leg 1 to 5 Vleg 2 to A0no polarity 10k 5VsignalGND Electrically identical to Lesson 6. Only the maths afterwards changes.
ArduinoGoes toWhy
5VOne thermistor legTop of the divider.
A0Other leg plus the 10 kΩMidpoint.
GNDOther end of the 10 kΩBottom of the divider.

The circuit is Lesson 6 with a different resistor in the top position, and that is the point worth noticing: every resistive sensor is read the same way. Once you own the divider, adding a new sensor is a datasheet problem, not a circuit problem.

NTC means negative temperature coefficient: resistance falls as temperature rises. "10 k thermistor" means 10 kΩ at 25 °C, which is also why the partner resistor is 10 kΩ — the divider is then most sensitive around room temperature, where you will be testing.

The hard part is that it is not linear. A photoresistor being non-linear does not matter much because "brighter" is usually enough. A temperature reading in degrees has to be right. The relationship between resistance and temperature is exponential, and the standard model is the Steinhart-Hart equation. The simplified B-parameter version is what almost every sketch uses:

1/T = 1/T₀ + (1/B) × ln(R/R₀)

with temperatures in kelvin, T₀ = 298.15 K (25 °C), R₀ = 10 kΩ, and B around 3950 for these parts. Subtract 273.15 at the end for Celsius. If your readings are consistently off by a few degrees, B is the number to adjust — it varies between manufacturers and the value is a specification, not a constant of nature.

Where the error comes from. Your 10 kΩ reference resistor probably has a 5% tolerance (gold band), so it might really be 9.5 k or 10.5 k. That error passes straight into the calculated resistance and then through a logarithm into your temperature. Measuring the actual resistor and putting the true value in your code is the single highest-value calibration step available to you. The ADC's own resolution, by contrast, contributes well under a tenth of a degree here — the reference resistor dominates.

Self-heating is real but small. Current through the thermistor warms it slightly. With a 10 k divider on 5 V you are dissipating well under a milliwatt, which is negligible. It becomes a genuine concern only with much smaller resistances.

Count, to resistance, to kelvin, to Celsius
int raw = analogRead(A0);
float R = 10000.0 * (1023.0 / raw - 1.0);       // thermistor resistance
float T = 1.0 / (1.0/298.15 + log(R/10000.0)/3950.0) - 273.15;
Conceptsnon-linear sensorsSteinhart-Hartcalibration

LESSON 11

Voltmeter

Skipped before, and worth doing now

Skipped — worth doing
You need10 kΩ potentiometerLCD1602 from Lesson 9jumpers
5VA0GND 10k potentiometerleg 1 to 5 Vwiper to A0leg 3 to GNDan adjustable voltage divider in one part 5VsignalGND Add the Lesson 9 LCD to display the result, or just use the Serial Monitor.
ArduinoGoes toWhy
5VPot leg 1Top of the track.
A0Wiper (centre pin)The tap point. Turning the knob moves it along the track.
GNDPot leg 3Bottom of the track.

You skipped this one and it is a five-minute build, but it earns its place because it makes the divider tangible: a potentiometer is a voltage divider whose two halves you can change by hand. The resistive track goes from leg 1 to leg 3; the wiper is a contact that slides along it. Turn the knob and you move the boundary — Rtop grows as Rbottom shrinks, and their sum stays 10 kΩ. The wiper voltage sweeps smoothly from 0 V to 5 V.

Reading it and converting gives you a working voltmeter for the range 0–5 V:

volts = analogRead(A0) × 5.0 / 1023.0

Why 1023 and not 1024. The ADC reports 0 for 0 V and 1023 for a voltage at (or above) the reference. There are 1024 possible codes but only 1023 gaps between the endpoints, so dividing by 1023 makes full scale read exactly 5.00 V. Dividing by 1024 is defensible on other grounds and the difference is one part in a thousand; it is not worth an argument, but it is worth knowing why you see both.

The honest limitation. This voltmeter is only as accurate as its reference, and the default reference is your 5 V rail — which over USB is usually more like 4.7–4.9 V and moves around as the board's load changes. So the instrument's zero point drifts with whatever else your circuit is doing. Two fixes: measure the real 5 V with a multimeter and use that number in your formula, or switch to the internal 1.1 V reference with analogReference(INTERNAL), which is far more stable but limits you to 0–1.1 V unless you add a divider in front.

Measuring more than 5 V. Never put more than 5 V on an analog pin. To measure a 9 V battery you put a divider in front — two 10 kΩ resistors halve it, so 9 V becomes 4.5 V — and then multiply by two in software. That is the third resistor job doing exactly what it is for.

Accuracy is limited by the reference, not the ADC
float v = analogRead(A0) * 5.0 / 1023.0;
Serial.print(v, 3);  Serial.println(" V");
// for a 2:1 external divider, multiply v by 2.0
ConceptsADC scalingfloating pointreference voltage

LESSON 12

Ultrasonic distance

Not in your kit, but the theory transfers

Part not in your kit
You needHC-SR04 (not included)4 jumpers
5VD9D10GND HC-SR04 (not in this kit)VCC 5 VTrig trigger inEcho echo outGNDabout 2 dollars if you decide to add one 5VsignalGND Wiring shown for completeness. This module is not part of your kit.
ArduinoGoes toWhy
D9TrigYou send a 10 microsecond HIGH pulse to start a measurement.
D10EchoThe module holds this HIGH for exactly as long as the sound was in flight.
5V / GNDVCC / GNDDraws about 15 mA.

Your kit does not contain this module, so this entry is here for two reasons: so the lesson numbering matches the official course, and because the technique — measuring time to infer distance — is worth understanding even if you never buy the part.

The module emits a burst of 40 kHz sound, above human hearing, and listens for the reflection. Sound travels about 343 m/s in room-temperature air, which is 0.0343 cm per microsecond. The module raises its Echo pin for exactly as long as the sound was travelling, so:

distance = (echo duration in µs × 0.0343) / 2

The division by two is the part people forget: the sound made a round trip, out and back, so the pulse measures twice the distance to the object.

What is interesting here is that this is the first sensor where the information is carried by time rather than by voltage. No divider, no ADC. pulseIn() blocks the processor and counts microseconds until the pin changes, which makes it accurate and also makes it a poor citizen in a busy sketch — a reading that times out can stall you for a full second unless you pass a shorter timeout.

Why it is temperature dependent. The speed of sound rises roughly 0.6 m/s per degree Celsius. Between a cold room and a hot one the error is over 2%. If you ever pair this with your DHT11, you can correct for it — a genuinely satisfying two-sensor project.

Soft, angled or fabric surfaces scatter the pulse instead of reflecting it, so the module will simply see nothing. That is a limitation of the physics, not a fault.

Distance from time of flight
digitalWrite(trig, HIGH); delayMicroseconds(10); digitalWrite(trig, LOW);
long us = pulseIn(echo, HIGH, 30000);   // always pass a timeout
float cm = us * 0.0343 / 2.0;
Conceptstime of flightpulseIn()speed of sound

LESSON 13

Four-digit 7-segment display

Persistence of vision, exploited deliberately

Built
You need4-digit display8 × 220 Ω12 jumpers
D2D3D4D5D6D7D8D9D10D11D12D13 4-digit 7-segment display8888seg aseg bseg cseg dseg eseg fseg gseg dpdigit 1 commondigit 2 commondigit 3 commondigit 4 commonsegments through 220 ohm each; commons direct 220 signal Twelve pins control 32 LEDs, because only one digit is ever lit at a time.
ArduinoGoes toWhy
D2 – D9Segments a, b, c, d, e, f, g, dpOne 220 Ω per segment. These are shared by all four digits.
D10 – D13The four digit commonsOnly one is enabled at any instant.

Four digits of seven segments plus decimal points is 32 LEDs. Wiring each one individually would need 32 pins, which an UNO does not have. The display solves this with a matrix: the segment pins are shared across all four digits, and each digit has its own common pin that acts as an enable.

So the segment lines say what shape, and the digit commons say which digit gets it. Enable digit 1, put the pattern for "3" on the segment lines, and digit 1 shows 3 while the others show nothing — they are receiving the same pattern but are not enabled, so no current flows through them.

Multiplexing. You cannot show four different digits at once, so you cycle: light digit 1 with its pattern, turn it off, light digit 2 with its pattern, and so on, fast enough that your eye cannot follow. Above roughly 50–60 refreshes per second the flicker disappears and your visual system reports four steady digits. Nothing is steady; you are being fooled, deliberately and reliably. This is exactly the same effect that makes film and screens work.

The brightness consequence. Each digit is only lit a quarter of the time, so it is dimmer than a single digit driven continuously. This is why multiplexed displays often use lower-value resistors than you would calculate for a static LED — you are compensating for the duty cycle. Do not push it too far: the peak current during the on-quarter is what stresses the pins.

Why this is where millis() becomes non-negotiable. A stopwatch has to refresh the display roughly every 4 ms and keep counting time and watch for a button. Any delay() longer than a few milliseconds makes the display visibly flicker. The pattern that replaces it:

if (millis() - lastTime >= interval) { lastTime = millis(); ... }

You are not pausing, you are checking whether it is time yet, and returning immediately if not. The loop keeps spinning and every task gets a chance on every pass. Once you have written this once, delay() starts to look like what it is: a blunt instrument that only ever suits a program with one job.

Subtracting like that also survives the moment millis() overflows back to zero after about 49 days, provided you use unsigned long. The subtraction wraps correctly. Comparing millis() > target instead does not.

Check the clock, never stop it
unsigned long last = 0;
void loop() {
  if (millis() - last >= 1000) { last += 1000; seconds++; }
  display.refreshDisplay();   // must run thousands of times per second
}
Conceptsmultiplexingpersistence of visionmillis()SevSeg

LESSON 14

74HC595 shift register

Trading time for pins

Built
You need74HC5958 LEDs8 × 220 Ωjumpers
D11D12D85VGNDGND 74HC595 (16-pin DIP)14 DS data in11 SH_CP shift clock12 ST_CP latch clock16 VCC 5 V8 GND13 OE output enable10 MR master resetQA - QH eight outputspin 1 is left of the notch; count anticlockwise Eight LEDsfrom QA - QHcathodes to GNDone 220 ohm resistor per LED 220 signal5VGND Three Arduino pins control eight outputs. OE low keeps outputs enabled; MR high keeps the register from clearing.
ArduinoGoes toWhy
D11DS, pin 14Data. One bit at a time.
D12SH_CP, pin 11Shift clock. Each rising edge pushes one bit in.
D8ST_CP, pin 12Latch clock. Copies the shift register to the outputs.
5VVCC pin 16 and MR pin 10MR is active low, so it is held HIGH to stay out of reset.
GNDGND pin 8 and OE pin 13OE is active low, so grounding it enables the outputs.

The 74HC595 contains two separate eight-bit registers, and understanding why there are two is the whole lesson.

The shift register is a chain of eight flip-flops. Each rising edge of SH_CP makes every stage hand its value to the next one down the line, and whatever is on DS at that moment enters the first stage. Eight clock pulses and eight bits later, your byte is sitting in the chain. But notice what happens during those eight pulses: the contents are being shoved sideways, one position at a time. If those stages drove the outputs directly, the LEDs would visibly scramble on every update — you would see the data marching across.

The storage (latch) register is the fix. It sits between the shift register and the output pins and holds its own separate copy. A rising edge on ST_CP copies all eight bits across in one instant. So the sequence is: shift in quietly, then latch once, and the outputs change cleanly and simultaneously. This is the same "set up the data, then pulse a line to say now" pattern as the LCD's E pin in Lesson 9.

What you are really trading. Parallel is fast and expensive in pins; serial is slower and cheap in pins. Eight outputs cost three pins here, and — this is the good part — sixteen outputs also cost three pins, because you can daisy-chain: connect QH' (pin 9, the overflow output) of the first chip to DS of the second, share the clocks, and now sixteen bits shift through. The pin count stops growing entirely.

OE and MR. Both are marked with a bar over the name because both are active low. OE (output enable) grounded means outputs are on; taken HIGH it puts all outputs into a high-impedance state, disconnected — useful for blanking a display instantly without touching the data. MR (master reset) tied HIGH means "do not clear"; pulling it LOW empties the shift register. Beginners leave these two floating and get random behaviour, so tie them deliberately.

Bit order and your digit table. shiftOut(data, clock, LSBFIRST, value) sends the least significant bit first. Because bits keep shifting along, the first bit sent ends up furthest down the chain — at QH — and the last bit sent stays at QA. So with LSBFIRST, bit 0 of your byte lands on QH and bit 7 lands on QA. Wire your segments in order QA to QH and the mapping between a byte and a shape is fixed by that geometry alone. The table you derived experimentally was never arbitrary; it is a direct consequence of your wiring order plus the bit order you chose. Switch to MSBFIRST and every entry in the table reverses, which is a satisfying thing to verify once.

Shift quietly, then latch
digitalWrite(latch, LOW);              // outputs frozen, safe to shift
shiftOut(data, clock, LSBFIRST, value); // eight clock pulses
digitalWrite(latch, HIGH);             // all eight outputs change at once
Conceptsshift registerlatchshiftOut()serial vs parallelLSBFIRST

LESSON 15

Joystick

Two potentiometers and a switch in one thumb

Built
You needJoystick module5 jumpers
5VGNDA0A1D2 Joystick moduleGND+5VVRx X axisVRy Y axisSW push switchSW is open until pressed, then shorts to GND 5VGNDsignal SW needs no external resistor if you use INPUT_PULLUP.
ArduinoGoes toWhy
A0VRxRoughly 0 at one extreme, 1023 at the other, about 512 centred.
A1VRySame, on the other axis.
D2SWReads LOW when pressed, with pinMode(2, INPUT_PULLUP).
5V / GND+5V / GNDPowers both potentiometer tracks.

There is nothing new inside this module — it is two 10 kΩ potentiometers mounted at right angles with a gimbal, plus a momentary switch under the stick. Moving the stick turns both wipers. You already understand every component; the interesting part is what you do with the numbers.

The centre is never 512. Springs return the stick to approximately centre, and approximately is the operative word. Your particular joystick might rest at 508 on one axis and 517 on the other, and the resting value drifts slightly with temperature and wear. Never hard-code 512. Read the resting value at startup and store it as your zero.

Dead zones are mandatory, not a refinement. Even at rest the reading jitters by a few counts from electrical noise and mechanical slop. Feed that straight into a motor or a cursor and it creeps constantly. The fix is to treat anything within about ±20 counts of your measured centre as exactly zero. Every game controller ever made does this.

Why SW uses the internal pull-up. The switch connects the SW pin to ground when pressed and to nothing when released — a floating input, which you know from Lesson 2 is unreadable. Rather than adding an external pull-up resistor, INPUT_PULLUP switches on a resistor of roughly 20–50 kΩ inside the chip. The logic inverts as a result: HIGH is idle, LOW is pressed. Slightly awkward to read, one less component to lose.

A useful shape for the reading. Mapping each axis to a signed range centred on zero, say −100 to +100, makes everything downstream easier: sign gives direction, magnitude gives speed, and zero means stop. That single conversion turns a raw sensor into a control input.

Calibrate the centre, then apply a dead zone
pinMode(2, INPUT_PULLUP);
int x = analogRead(A0) - centreX;        // measure centreX at startup
if (abs(x) < 20) x = 0;                 // dead zone
bool pressed = (digitalRead(2) == LOW); // pull-up inverts the logic
Conceptsdual analog inputINPUT_PULLUPdead zonecalibration

LESSON 16

Relay

A tiny current commanding a large one, and how to drive a bare coil

Built
You needRelay (bare, 5 V coil)ULN2003 driver board4 x AA packjumpers
D7GND ULN2003 driver boardIN1 control in+ coil supply- groundOUT1 in the white plugits built-in diodes are why no extra parts are needed Relay (bare, 5 V coil)RLYcoil pin to board +coil pin to OUT1COM the pole being switchedNO open until energisedNC closed until energisedthe two coil pins have no polarity 4 x AA pack (6 V)9V+ to board +- to board - and GND5 V from the Arduino works, but is marginal signalGND5V The Arduino pin carries about 1 mA. The coil current never goes near it.
ArduinoGoes toWhy
D7ULN2003 IN1The control signal. HIGH energises the coil, LOW releases it.
GNDBoard − and battery −The shared zero. Without it the driver has nothing to switch against.
Battery +Board + (the 5–12 V header)The coil supply. Do not wire this to the Arduino 5 V pin.
Board +One coil pinThe coil sits between the supply and the driver output.
OUT1The other coil pinIn the white 5-pin plug. Find it with the LED trick below.
COM / NO / NCYour switched circuitNothing here touches the Arduino electrically.

A relay is a switch operated by an electromagnet. Current through a coil makes a magnetic field, the field pulls a metal armature, and the armature drags a set of contacts across. The critical property is that the coil circuit and the contact circuit share no electrical connection at all — they are coupled only by a magnetic field across an air gap. That is why a 5 V Arduino can switch a much larger circuit without that circuit ever having a path back into the microcontroller.

The three terminals. COM is the common pole, the wire that gets switched. NO (normally open) is disconnected from COM when the coil is off and connects when it is on. NC (normally closed) is the opposite: connected at rest, disconnected when energised. "Normally" always means "with no power applied", and this matters for safety-critical design — you generally wire things so that the safe state is the unpowered state.

Why a bare relay cannot go on a pin, and what solves it

A relay coil needs roughly 70–80 mA. An Arduino pin can supply about 20 mA comfortably and 40 mA absolute maximum, so a coil is somewhere between two and four times over the limit. It also needs a flyback diode, for the reason below. A pre-made relay module contains both of those things — a transistor and a diode — which is exactly why modules exist.

With a bare relay and no transistor, the ULN2003 board that came with your stepper motor is the answer, and it is a genuinely good one rather than a workaround. That chip is seven Darlington transistor pairs, each rated 500 mA, with flyback diodes already built in. It is quite literally a chip designed for driving relay coils; relay driving is the first application on its datasheet. Your pin drives IN1 with about 1 mA, the Darlington pulls the other end of the coil down to ground, and the coil current flows entirely within the driver circuit.

The flyback diode

This is the piece worth carrying to every future project. An inductor resists changes in current. When you cut the current to a coil, the collapsing magnetic field tries to keep the current flowing, and to do so it generates a reverse voltage that can reach hundreds of volts for a few microseconds. That spike destroys whatever transistor just switched it off. A diode across the coil, reverse-biased in normal operation, gives that current a harmless loop to circulate in until it dies away.

Inside the ULN2003 these diodes all connect to one pin called COM, and on your driver board COM is already wired to the plus terminal of the power header. So as long as you power the board through its own power header, the protection is present and connected. You do not need to add a diode, and this is precisely why the ULN2003 lets you build this lesson without buying anything.

Why 6 volts and not 5

A Darlington pair does not switch all the way down to zero — it drops about 1 V while conducting. Feed the board 5 V and your coil only sees about 3.9 V, which is below the 75% of nominal that most 5 V relays need in order to pull in reliably. It may click, it may chatter, it may work on a fresh battery and fail on a tired one. Four AA cells give 6 V, the coil sees about 5 V, and it latches solidly every time. Try the Arduino 5 V pin first if you like, but if the relay is unreliable this is why, and it is not a wiring fault.

Finding the right output pin

The board only brings its outputs out through the white 5-pin plug. Nothing can be damaged by guessing, so find it empirically: power the board, set IN1 HIGH, and watch which of the four LEDs lights. Then move one coil wire between the plug's pins until the relay clicks. If you happen to land on the plug's common pin, both coil wires are on plus and nothing happens — harmless.

One board, one job at a time. The stepper motor uses the same four outputs through the same plug, so the stepper and the relay cannot both be connected at once. Plan around that, or buy a second ULN2003 board — they cost very little.

Mains voltage. Relays like this are often rated for it. Do not use yours for that unless you already know what you are doing with mains wiring, because the failure modes are not "the LED does not light". Switching a 12 V strip or a battery-powered lamp teaches exactly the same principles at no risk.

Note the logic is NOT inverted here, unlike a relay module
pinMode(7, OUTPUT);
digitalWrite(7, HIGH);   // IN1 high -> Darlington conducts -> coil energised
delay(1000);
digitalWrite(7, LOW);    // released; the internal diode absorbs the spike
Conceptselectrical isolationCOM/NO/NCflyback diodeDarlington driver

Lessons still ahead

7

LESSON 17

DC motor and fan

Real speed control, using the driver board you already own

Not built yet
You need3 V DC motorThree-leaf fanULN2003 driver board3 x AA pack
D5GND ULN2003 driver boardIN1 from D5+ motor supply- groundOUT1 in the white plugflyback diodes are already inside the chip DC motor (3 V)Mred to board +black to OUT1fit the fan blade only after it spins 3 x AA pack (4.5 V)9V+ to board +- to board - and GNDthe driver drops about 1 V, so the motor sees ~3.5 V signalGND5V D5 must be a PWM pin. The motor current flows entirely between the battery and the driver.
ArduinoGoes toWhy
~D5ULN2003 IN1A PWM pin, so analogWrite gives you speed control. About 1 mA.
GNDBoard − and battery −The shared zero. Skipping it is the classic mistake.
Battery +Board + (the 5–12 V header)The motor supply. Never the Arduino 5 V pin.
Board +Motor redThe motor hangs between the supply and the driver output.
OUT1Motor blackIn the white 5-pin plug.

This is the lesson where "just plug it into a pin" finally stops working, and understanding exactly why is worth more than the project itself.

Three numbers. An Arduino pin can supply about 20 mA comfortably, 40 mA absolute maximum. A small DC motor running free draws around 100–200 mA. The same motor with the fan blade held still — stalled — draws far more, often 500 mA to over an amp, because a stalled motor is electrically just a short piece of copper wire. And a motor is stalled every single time it starts, for the first few tens of milliseconds, before it gets moving. So even a motor that "only" needs 150 mA hits the pin with a much larger surge at every switch-on.

Back EMF. A motor is a coil rotating in a magnetic field, which means it is also a generator. Spinning, it produces a voltage that opposes the one you applied — this is what limits its current at speed, and why current is highest at stall when there is no opposing voltage. And when you cut the power, the collapsing field produces the same reverse spike a relay coil does, only larger. Motors also generate constant electrical noise from their brushes sparking, which propagates down the power rails and upsets everything else.

So the pin must not carry the motor current at all. The pin's job is to carry information, and something else carries the power.

Why the ULN2003 is the right part for this

Your kit's driver board is seven Darlington transistor pairs in one chip. A Darlington is two transistors arranged so the first one's output drives the second's input, which multiplies their amplification: a microamp at the input controls hundreds of milliamps at the output. Each channel is rated 500 mA, and — crucially — the flyback diodes are already inside the chip, wired to the COM pin, which your board connects to the plus terminal of its power header. You own everything this circuit needs.

Low-side switching. Notice what the driver actually does: it does not connect the motor to the supply, it connects the motor to ground. The motor's other end sits permanently on plus. The switch is on the low side, between the load and ground, which is how nearly all simple transistor switching is done because it is easier to turn a transistor on when its reference is ground.

What it cannot do. It can only switch on and off. Reversing a motor means being able to swap which end is positive, and that needs four switches in an H-bridge (an L293D or L9110S). If you want the fan to run both ways, that is the part to buy.

Speed control, and stiction

Because a Darlington switches in microseconds, analogWrite() works properly here. The motor is far too slow to follow the individual pulses, so it responds to their average — exactly the PWM idea from the foundations section, applied to something with real inertia.

You will find the motor does not start below roughly 90–110 out of 255, but once turning it will keep going at a much lower value. That gap is stiction: static friction in the bearings and brushes is greater than sliding friction, so it takes more force to start moving than to keep moving. Every small motor has it, and a common trick is a brief full-power "kick" to break away before dropping to the speed you actually want.

Power

Do not run the motor from the Arduino's 5 V pin. The startup surge will drag the rail down and reset the board. Three AA cells give 4.5 V, the Darlington drops about 1 V, and your 3 V motor sees roughly 3.5 V — close to its rating. Four cells will run it faster and hotter.

The shared ground rule, concretely. Battery negative connects to the board's minus terminal and to an Arduino GND pin. Not because the Arduino needs the battery's current, but because "HIGH" and every other voltage in the system is measured against a zero that both circuits have to agree on.

Finding the right output pin

The outputs only come out through the white 5-pin plug. Power the board, set IN1 HIGH, and see which of the four LEDs lights. Then move the motor's black wire between the plug's pins until it spins. Landing on the plug's common pin puts both motor wires on plus, so nothing happens — nothing can be damaged by guessing.

If the chip gets hot or the motor stalls, parallel two channels: jumper IN1 and IN2 to the same Arduino pin and connect the motor's black wire to both OUT1 and OUT2. The current splits between two Darlingtons and your headroom doubles. Warm is normal; too hot to touch is not.

Keep the fan blade clear of fingers, and push it onto the shaft gently — forcing it can bend the shaft.

The kick-then-settle trick for a reluctant motor
#define MOTOR 5              // must be a PWM pin
pinMode(MOTOR, OUTPUT);

analogWrite(MOTOR, 255);     // kick it out of stiction
delay(120);
analogWrite(MOTOR, 140);     // then settle to the speed you wanted
// analogWrite(MOTOR, 0);    // coast to a stop
Conceptsstall currentback EMFlow-side switchingPWM speed control

LESSON 18

Stepper motor

Rotation counted, not measured

Not built yet
You need28BYJ-48 stepperULN2003 driver board6 jumpers
D8D9D10D115VGND ULN2003 driver boardIN1IN2IN3IN4+ 5 V- GNDthe motor plugs into the white connector 28BYJ-48 stepper motor5-pin plug into the boardonly fits one way round signal5VGND The driver board carries the coil current; the four Arduino pins only carry timing.
ArduinoGoes toWhy
D8, D9, D10, D11IN1, IN2, IN3, IN4Four signals, one per coil. Order matters and the library order is not the obvious one.
5VBoard +Draws 200–300 mA when moving. Borderline over USB; use a separate 5 V supply if the board resets.
GNDBoard −Shared ground.

A DC motor spins when you apply voltage and stops somewhere unpredictable. A stepper does not spin at all in the usual sense — it moves in fixed increments, one per electrical pulse, so if you count your pulses you know exactly where the shaft is without any sensor. That is the whole appeal: precise position, no feedback loop, no encoder.

How stepping works. Inside are four coils arranged around a toothed magnetic rotor. Energise coil 1 and the rotor aligns to it. Energise coil 2 and it steps around to that one. Walk through the coils in order and the rotor follows. Reverse the order and it goes backwards. The speed is set entirely by how quickly you walk the sequence, and the position by how many steps you have taken.

The gearbox is why it is slow and strong. The 28BYJ-48 has a 64:1 reduction gearbox. Its internal motor makes 64 steps per revolution, so the output shaft needs 64 × 64 = 4096 half-steps, or 2048 full steps, for one turn. That is why it moves at a leisurely pace and why it has surprisingly good torque for its size. It also means one step of the output shaft is about 0.176 degrees, which is finer than you can see.

The pin order trap. With the Arduino Stepper library the constructor is Stepper(2048, 8, 10, 9, 11) — note that the middle two are swapped relative to IN1..IN4. This is not a typo. The library expects the coils in the order it energises them, and the ULN2003 board's IN numbering does not match that order. Wire it as IN1..IN4 to D8..D11 and swap the numbers in the constructor. If your motor buzzes and vibrates without turning, this is almost always the reason.

Open loop has a failure mode. Because nothing reports back, a stepper that is asked to move faster than it physically can will simply miss steps — and your code will never know. Your count and reality quietly diverge. If your project needs to be sure, you add a limit switch and return to a known home position occasionally.

Holding current. A stepper holds its position by keeping a coil energised, which means it draws current while doing nothing at all, and gets warm. If your application does not need holding torque, de-energise the coils when idle: it saves power and heat.

2048 steps is one turn of the output shaft
#include <Stepper.h>
Stepper motor(2048, 8, 10, 9, 11);   // note the swapped middle pair
motor.setSpeed(10);                  // rpm; this motor tops out near 15
motor.step(2048);                    // exactly one full revolution
Conceptsstep sequencesgear reductionholding torqueopen loop control

LESSON 19

IR receiver and remote

Light you cannot see, carrying data

Not built yet
You needIR receiver (VS1838B)Remote control3 jumpers
D11GND5V IR receiver (VS1838B)OUT signalGNDVCC 5 Vdome facing you, legs down: OUT, GND, VCC Remote controlno wiring - infraredpull the plastic tab out of the battery holder signalGND5V Verify the pinout against your kit sheet before powering up. Reversed power destroys this part.
ArduinoGoes toWhy
D11OUTIdles HIGH and pulses LOW while a signal is arriving.
5VVCCDraws about 1.5 mA.
GNDGNDMiddle pin on this package.

Your remote has an infrared LED in the end of it. It is a perfectly ordinary LED, just emitting at about 940 nm where your eye has no sensitivity. Point it at a phone camera and press a button — most phone sensors can see it, and you will get a free way to check whether the remote's battery is alive.

Why the light is flickering at 38 kHz. The world is full of infrared: sunlight, incandescent bulbs, your own body heat. If the remote just switched its LED on and off, the receiver could not distinguish it from the room. So the remote switches its LED on and off about 38,000 times a second, and the receiver contains a filter tuned to that exact frequency. Anything that is not flickering at 38 kHz is ignored as background. This is the same trick a radio uses: put your information on a carrier, and tune to the carrier.

So there are two layers. The carrier is the 38 kHz flicker, and the data is bursts of that carrier separated by gaps. A long burst might mean one, a short burst zero, depending on the protocol. The VS1838B does the hard part: it strips off the carrier and hands you a clean digital line that goes LOW during each burst. Your Arduino only has to time the pulses.

Protocols. NEC is the most common for cheap remotes and encodes 32 bits: an address, its inverse, a command, and its inverse. The inverted copies are an error check — if they do not match, the transmission was corrupted and gets thrown away. The IRremote library recognises the common protocols and hands you a code number per button.

Do not look up your remote's codes online. They vary between remotes that look identical. Run the library's receive-and-print example, press every button, write the codes down. That list is your remote's, and it is a five-minute job.

Range and interference. Expect a few metres, line of sight. Sunlight and some fluorescent or LED lamps produce enough 38 kHz-ish noise to reduce range significantly, which is a real effect and not a broken sensor.

Version warning. IRremote changed its API substantially at version 3. Sketches written for version 2 will not compile against version 3 and vice versa. If an example fails to compile, check the version before rewriting anything.

Print the codes, do not look them up
#include <IRremote.h>
IrReceiver.begin(11);
if (IrReceiver.decode()) {
  Serial.println(IrReceiver.decodedIRData.command, HEX);
  IrReceiver.resume();   // forgetting this means you only ever get one press
}
Concepts38 kHz carriermodulationprotocol decodingIRremote library

LESSON 20

DHT11 temperature and humidity

A sensor that talks instead of resisting

Not built yet
You needDHT11 module3 jumpersDHT library
D25VGND DHT11 moduleS or DATA signal+ or VCC 5 V- or GNDmodule version has the pull-up resistor fitted already signal5VGND Three wires. All the analog work happens inside the module.
ArduinoGoes toWhy
D2S / DATAA bidirectional single-wire bus. Any digital pin works.
5V+ / VCCWorks on 3.3–5.5 V; about 1 mA while measuring.
GND− / GNDShared ground.

This is a different species from the thermistor, and the difference is worth dwelling on. Your thermistor is a passive component: it changes resistance, and you build the divider, read the ADC and do the maths. The DHT11 contains its own sensing elements, its own ADC and its own small microcontroller. It does the measuring and sends you a finished number.

The trade. You give up the ability to see inside and you gain simplicity — three wires, a library call, a number in degrees. This is the pattern for nearly every module you will ever buy: it packages the analog messiness behind a digital interface. Knowing how the thermistor works is what lets you understand what the DHT11 is doing on your behalf.

How the single wire works. The line idles HIGH, held there by a pull-up resistor (already fitted on your module version — you would need to add a 10 kΩ one yourself with a bare four-pin DHT11). The Arduino pulls it LOW for at least 18 ms to say "wake up and send me a reading", then releases it and switches to being an input. The sensor answers with 40 bits, encoding each bit as a HIGH pulse whose length means zero or one — about 26 µs for a zero, about 70 µs for a one. Both devices take turns on the same wire, which is why it is called a bidirectional bus.

The 40 bits are five bytes: humidity integer, humidity decimal, temperature integer, temperature decimal, and a checksum which is the sum of the first four. If the checksum does not match, the library returns a failure rather than a wrong number. That is why isnan() checks appear in every DHT sketch — occasional failed reads are normal and expected, not a sign of a broken sensor.

It is slow, and this is not negotiable. The DHT11 needs about two seconds between readings. Poll it faster and you get stale data or errors. The humidity element physically needs time to equilibrate with the air; this is a property of the sensor, not the code.

Accuracy, honestly. The DHT11 is the cheapest device in its class: roughly ±2 °C on temperature, ±5% on humidity, whole-number resolution, and a range of 0–50 °C. It is fine for "is the room humid", useless for anything demanding. Its sibling the DHT22 is several times more accurate for a little more money and wires identically.

Always check for failed reads
#include <DHT.h>
DHT dht(2, DHT11);
float t = dht.readTemperature();     // Celsius
float h = dht.readHumidity();
if (isnan(t) || isnan(h)) return;    // failed reads are routine
Conceptsdigital sensorssingle-wire protocolsampling rate limits

LESSON 21

DS1302 real time clock

Time that survives a power cut

Not built yet
You needDS1302 moduleCR2032 cell5 jumpers
5VGNDD6D7D8 DS1302 RTC moduleVCC 5 VGNDCLK or SCLKDAT or I/ORST or CEfit the coin cell the right way up: + faces outward 5VGNDsignal Three signal wires, not two: this bus needs an explicit chip-enable line.
ArduinoGoes toWhy
D6CLK / SCLKClock. One bit per edge.
D7DAT / I/OData, bidirectional. Same wire in and out.
D8RST / CEChip enable. Must be HIGH for the whole transfer.
5V / GNDVCC / GNDUnder 1 mA. The coin cell takes over when this is removed.

Your Arduino already counts time with millis(), so why add a chip? Two reasons. First, millis() resets to zero every time the board is powered up or reset — it measures elapsed time since boot, not time of day. Second, it is derived from a ceramic resonator that is accurate to about 0.5%, which sounds fine until you work out that 0.5% is roughly seven minutes of drift per day.

What the crystal buys you. The DS1302 uses a 32.768 kHz quartz crystal. That odd-looking number is 215, so a simple chain of fifteen binary dividers turns it into exactly one pulse per second — no arithmetic, just flip-flops. Quartz is used because it is piezoelectric and mechanically resonant: it vibrates at a frequency set by how it was cut, and that frequency barely changes with voltage or age. Typical drift is a few seconds a week rather than minutes a day.

The coin cell. The DS1302 draws under a microamp in backup mode, so a CR2032 keeps it running for years. Unplug the Arduino, come back tomorrow, and the time is still right. That is the entire point of the module — everything else it does, your Arduino could do.

The three-wire bus. Unlike the LCD's parallel bus, this sends one bit at a time. RST (better named CE, chip enable) must be held HIGH for the whole conversation; dropping it aborts the transfer. Each clock pulse on CLK moves one bit on DAT, and the same DAT wire is used for both directions — the chip switches from listening to talking partway through. This "assert enable, clock the bits, release enable" shape is exactly the same idea as the 74HC595's latch pin, and the same idea again in the SPI bus you will meet in Lesson 23. Three different chips, one recurring pattern.

BCD, and why the numbers look wrong raw. The DS1302 stores time in binary-coded decimal: each decimal digit gets its own four bits. The number 25 is stored as 0x25, not as 25 decimal (which would be 0x19). This is a convenience for driving digit displays directly, and a nuisance if you read the registers yourself — libraries convert for you, but if you ever see a clock reading 37 when it should read 25, you are looking at unconverted BCD.

Setting the time. Most sketches set the clock once from a hard-coded value, then comment that line out and re-upload. Leave it in and the clock resets to that fixed moment every time the board restarts, which is a confusing bug to chase because everything looks like it is working.

Set the time once, then remove the line
#include <ThreeWire.h>
#include <RtcDS1302.h>
ThreeWire wire(7, 6, 8);      // DAT, CLK, RST
RtcDS1302<ThreeWire> rtc(wire);
RtcDateTime now = rtc.GetDateTime();
Conceptscrystal oscillatorsbattery backupthree-wire serialBCD

LESSON 22

Sound sensor

Detecting that a sound happened, which is not the same as hearing

Not built yet
You needSound sensor module3 or 4 jumpers
5VGNDD2A0 Sound sensor moduleVCC 5 VGNDDO digital outAO analog out (if fitted)the small blue trimmer sets the DO threshold 5VGNDsignal Three-pin modules have DO only. Wire AO if your module has four pins.
ArduinoGoes toWhy
D2DOGoes active when the sound crosses the threshold set by the trimmer.
A0AO (four-pin modules)A continuously varying level rather than a yes/no.
5V / GNDVCC / GNDA few milliamps.

The microphone is an electret capsule: a thin diaphragm with a permanent electrostatic charge, so sound pressure changes its capacitance and produces a tiny voltage — microvolts to a few millivolts. Far too small for the ADC, which resolves 4.9 mV steps, so the module has an amplifier stage first. That is what the small IC on the board is for.

What the digital output really tells you. After amplification, a comparator asks a single question: is this signal louder than the reference level set by the trimmer potentiometer? Louder, and DO flips. That is all. It reports that a threshold was crossed, with no information about pitch, direction or what made the sound. A clap and a door slam are indistinguishable. Calling this a sound sensor is fair; calling it a microphone input is not.

Setting the threshold. The trimmer is not a volume control, it is the comparison level. Turn it until the onboard LED is just barely off in a quiet room, then test with a clap. Too sensitive and it triggers on your own breathing; too insensitive and only a shout works. It is a mechanical adjustment and it takes patience.

Why the analog output is less useful than it looks. Audio is a waveform oscillating hundreds or thousands of times per second. analogRead() takes about 100 µs, giving roughly 9,600 samples per second at best, and only if your loop does nothing else. By the Nyquist limit that caps you at about 4.8 kHz — enough for the general envelope of a sound, nowhere near enough to record or analyse speech or music. What you can usefully do with AO is measure loudness over a window: sample for 50 ms, take the difference between the highest and lowest readings, and treat that spread as a volume level. That works well and is the basis of any VU-meter project.

Detecting a clap properly. A clap is a sharp peak followed by silence, and it will trigger DO several times as the sound rings. Take the first trigger and then ignore the input for 200 ms or so — the same debouncing idea as the button in Lesson 2, applied to sound. For a double clap, look for two triggers separated by a gap in a plausible range, roughly 150 to 600 ms.

Debouncing, but for sound
// clap detect with a lockout, so one clap counts once
if (digitalRead(2) == HIGH && millis() - lastClap > 200) {
  lastClap = millis();
  claps++;
}
Conceptscomparatorsthresholdssampling rate limitsenvelope vs waveform

LESSON 23

RC522 RFID reader

SPI, and the 3.3 volt rule

Not built yet
You needRC522 moduleCard and key fob7 jumpers
3V3GNDD9D10D13D11D12 RC522 RFID reader3.3V power NOT 5 VGNDRST resetSDA / SS chip selectSCK clockMOSI data to moduleMISO data from moduleIRQ is left unconnected 3.3VGNDsignal The orange wire is 3.3 V. Connecting this module to 5 V destroys it.
ArduinoGoes toWhy
3.3VModule 3.3VThe only correct power pin for this module. Not 5 V.
D13SCKHardware SPI clock on an UNO. Fixed, cannot be moved.
D11MOSIMaster out, slave in. Fixed.
D12MISOMaster in, slave out. Fixed.
D10SDA / SSChip select. Any pin, but D10 is conventional.
D9RSTAny pin.
GNDGNDShared ground.

Start with the rule that matters. The RC522 is a 3.3 V device with no regulator on board. Connect its power pin to 5 V and you will destroy it, usually permanently and usually immediately. This is the most frequently killed module in kits like yours. Its signal pins tolerate 5 V logic well enough in practice, which is why the wiring above works without level shifters, but the power pin has no such tolerance.

How a card with no battery answers. The reader's flat spiral antenna transmits a 13.56 MHz field. The card contains its own coil, and a changing magnetic field through a coil induces a voltage in it — the same physics as a transformer. The card harvests that energy, powers its tiny chip, and replies by changing how much energy it absorbs from the field, which the reader detects as a change in its own antenna's load. The card is not transmitting in the usual sense; it is modulating its absorption. Range is a few centimetres because induction falls off very steeply with distance.

SPI, the fourth version of the same pattern. You have now met four buses. The LCD used eight parallel wires. The 74HC595 used shift-plus-latch. The DS1302 used enable-clock-data. SPI is that idea properly standardised: SCK is the clock, MOSI carries data from Arduino to module, MISO carries data back, and SS selects which device is being addressed. Data goes both ways simultaneously, one bit per clock edge. It is fast and it costs pins, which is the same trade you have seen every time.

On an UNO, SCK, MOSI and MISO are wired to fixed pins (13, 11, 12) because they connect to dedicated hardware inside the chip. SS and RST can be any pins. Multiple SPI devices can share the three bus wires as long as each has its own SS line — that is what chip select is for.

UIDs, and what they are not. Every card has a unique identifier, typically four or seven bytes, and reading it is what almost every project does. Be clear that a UID is an identity, not a secret: it is broadcast to anything that asks, and cloneable cards are sold openly. MIFARE Classic cards do have encrypted sectors you can write to, but the encryption was broken years ago. This is excellent for a project that recognises which fob is which; it is not a security system, and it is worth knowing the difference.

Soldering. These modules usually ship with the header strip loose in the bag. It has to be soldered on. Pressing a header into the holes and hoping is the source of most "my reader does not respond" reports.

The UID is your identity token
#include <SPI.h>
#include <MFRC522.h>
MFRC522 rfid(10, 9);        // SS, RST
if (rfid.PICC_IsNewCardPresent() && rfid.PICC_ReadCardSerial()) {
  for (byte i = 0; i < rfid.uid.size; i++) Serial.print(rfid.uid.uidByte[i], HEX);
}
ConceptsSPI businductive coupling3.3 V logicUIDs

Parts nobody wrote a lesson for

6

LESSON 24

Flame sensor

The divider again, tuned to infrared

Not built yet
You needFlame sensor10 kΩ resistor3 jumpers
5VA0GND Flame sensor (IR photodiode)short leg cathode to 5 Vlong leg anode to A0dark blue or black lens, sensitive to 760-1100 nm 10k 5VsignalGND If the reading barely moves near a flame, reverse the sensor and try again.
ArduinoGoes toWhy
5VCathode (short leg)Reverse-biasing the photodiode is what makes it sensitive.
A0Anode plus the 10 kΩThe divider midpoint again.
GNDOther end of the 10 kΩBottom of the divider.

By now you should be able to predict this circuit before reading it, and that is the point of including it: your kit's flame sensor is a bare two-legged photodiode, so it is read exactly like the photoresistor in Lesson 6. Same divider, same 10 kΩ, same analog pin. Three lessons, one circuit.

What is different is the physics of the part. A photoresistor changes resistance. A photodiode generates a current proportional to the light falling on it, and it is polarity-sensitive. It is used reverse biased — cathode toward the positive supply — which sounds backwards but is correct: reverse bias widens the depletion region inside the junction, making it a bigger target for photons and giving a faster, more linear response. Almost no current flows in darkness, and light produces a small current proportional to intensity. That current through your 10 kΩ produces the voltage you read.

Why it responds to flame specifically. This diode's lens is tinted to pass roughly 760–1100 nm, the near-infrared. Flames emit strongly there. So do sunlight, incandescent bulbs and your TV remote, all of which will trigger it — the sensor detects near-infrared, and "flame" is an interpretation you impose. A real fire detector uses two wavelengths and compares them, or looks for the characteristic flicker of a flame around 10 Hz. You could implement that flicker check yourself with the analog reading and a bit of maths, which would be a genuinely interesting project.

Getting the orientation right. If you cannot tell the legs apart, wire it up, note the reading, then reverse it and note the reading again. The orientation that gives a large swing when you bring a lighter near it (from a safe distance) is the correct one. Experiment beats guessing, and it costs nothing here because a photodiode is not damaged by being reversed at 5 V.

Safety. Test with a lighter or candle at arm's length, on a clear desk, with nothing flammable nearby. The sensor works from a surprising distance — you do not need to hold a flame close to it.

Calibrate in your own room, as always
int ir = analogRead(A0);
// calibrate first: note the value in a dark room and near a flame,
// then put your threshold between the two.
if (ir > threshold) { /* something bright in the near-IR */ }
Conceptsphotodiodesreverse biasspectral sensitivity

LESSON 25

Water level sensor

Measuring by conductivity, and fighting corrosion

Not built yet
You needWater level sensor3 jumpers
A0D7GND Water level sensorS signal to A0+ power from D7- groundkeep the pins and header out of the water signal5VGND Power the sensor from a digital pin, not from 5 V, and switch it on only while reading.
ArduinoGoes toWhy
A0SHigher reading means more traces submerged.
D7+Deliberately a pin, not the 5 V rail, so you can switch the sensor off between readings.
GNDShared ground.

The board has two interleaved combs of copper traces. One comb is connected to the supply, the other through a resistor to the signal pin. Water bridges the traces, and because water conducts (thanks to dissolved ions, not the H₂O itself — genuinely pure water is a poor conductor), current crosses between them. The deeper the water, the more pairs of traces are bridged, the lower the resistance, the higher the voltage at the signal pin. It is a voltage divider whose top resistor is made of water.

It measures conductivity, so it measures the water too. Tap water, distilled water and salt water give different readings at the same depth. So do temperature and dissolved minerals. This means the sensor gives you a relative reading in your water, not an absolute depth in millimetres. Calibrate by dipping it to known depths in the actual liquid you care about.

The corrosion problem, and the good fix. Passing DC through water electrolyses it. Ions migrate, gas forms at the electrodes, and metal is stripped from the positive trace. Leave this sensor powered continuously in water and you can watch the copper visibly degrade within days.

The fix is elegant and worth internalising: do not power the sensor from the 5 V rail. Power it from a digital pin. Then your code turns the pin HIGH, waits about 10 ms for the reading to settle, takes the measurement, and turns the pin LOW again. If you sample once a minute, the sensor is energised for a hundredth of a percent of the time, and it lasts effectively forever instead of weeks. The sensor draws under 20 mA so a pin can supply it comfortably.

This trick — power a sensor from a pin so you can switch it — generalises to any sensor that degrades, drifts when warm, or wastes power in a battery project. It is one of those small techniques that separates a project that works from one that keeps working.

Keep the electronics dry. Only the striped trace area is meant to be wet. Submerging the header pins shorts things and corrodes the joints.

Energise, read, de-energise
digitalWrite(7, HIGH);      // power the sensor
delay(10);                  // let it settle
int level = analogRead(A0);
digitalWrite(7, LOW);       // and off again - this is what saves the traces
Conceptsconductive sensingelectrolysispowering a sensor from a pin

LESSON 26

Tilt ball switch

The simplest sensor in the kit

Not built yet
You needTilt ball switch2 jumpers
D2GND Tilt ball switchleg 1 to D2leg 2 to GNDno polarity, either way round signalGND No external resistor: INPUT_PULLUP supplies one inside the chip.
ArduinoGoes toWhy
D2One legReads LOW when the ball is bridging the contacts.
GNDOther legThat is the entire circuit.

Inside the metal can is a small conductive ball and two contacts. Tilt it one way and the ball rolls onto both contacts, closing the circuit. Tilt it the other way and the ball rolls off. It is a switch operated by gravity, with no electronics whatsoever.

Wiring is identical to a push button using the internal pull-up: one leg to the pin, the other to ground, pinMode(2, INPUT_PULLUP), and LOW means closed. No external resistor, no polarity to get wrong.

What it can and cannot tell you. It reports one bit: past a certain angle, or not. It cannot tell you the angle, the direction of tilt, or how fast you moved. A mounting orientation is therefore a design decision — you choose which way to point it so that the transition happens where you want it. If you need real orientation, that is an accelerometer, a different part entirely.

It bounces badly. Much worse than a button. A rolling ball rattles as it settles, so a single tilt produces a burst of open-close transitions over tens of milliseconds. Reading it in a tight loop gives you dozens of false triggers. The remedy is the same as Lesson 2: ignore any change within, say, 50 ms of the previous one. Shaking the switch produces a rapid stream of transitions, and counting those transitions over a short window is actually a decent shake detector — turning the bounce from a defect into the measurement.

Where it is genuinely useful. It is a wake-up trigger. A battery project can sleep until motion occurs, using this switch on an interrupt pin (D2 and D3 on an UNO) to wake it. That is more valuable than it looks: the cheapest, lowest-power motion detector available.

Same debounce pattern as the button
pinMode(2, INPUT_PULLUP);
bool tilted = (digitalRead(2) == LOW);
if (tilted != lastState && millis() - lastChange > 50) {
  lastChange = millis();  lastState = tilted;
}
Conceptsmechanical switchingINPUT_PULLUPdebouncingorientation sensing

LESSON 27

SMD RGB module

Lesson 7 in surface-mount form

Not built yet
You needSMD RGB module3 × 220 Ω4 jumpers
D9D10D11GND SMD RGB module (KY-009)R redG greenB blue- common cathodeno resistors on this board - you must add them 220 signalGND The KY-009 has no onboard resistors. Adding them is not optional.
ArduinoGoes toWhy
~D9, ~D10, ~D11R, G, B through 220 Ω eachPWM pins, same as Lesson 7.
GND− (common)Common cathode.

Electrically this is Lesson 7 again, which makes it a five-minute build and a good chance to notice something about modules generally.

SMD means surface mount. Instead of legs pushed through holes, the component is a tiny block soldered onto pads on the surface of the board. Nearly all modern electronics is built this way — it is smaller, cheaper to assemble by machine, and better at high frequencies. The trade-off is that it is not breadboard-friendly, which is exactly why it arrives already mounted on a little carrier board with normal pins.

The dangerous assumption. A part arriving on a board makes people assume the board takes care of things. Sometimes it does — your ULN2003 board has flyback diodes built into the chip, your DHT11 module has its pull-up fitted. The KY-009 has nothing. It is an LED on a carrier, and without external resistors you will be driving three LED junctions straight from three pins.

So the habit worth forming: when you meet a new module, ask what it includes. Look for resistors near the pins, look for a regulator, look for a diode across any coil. If you cannot see them, assume they are not there and provide them yourself. Reading the small printed part number (KY-009 here) and searching for its schematic takes two minutes and settles the question.

A small practical note. The SMD emitter is physically tiny and very bright at close range, and the three dies are packed closer together than in the 5 mm through-hole LED. That makes the colour mixing look better from a short distance — the individual colours blend more convincingly. Put a scrap of paper or a ping-pong ball over it and the effect improves further.

Identical to the through-hole version
analogWrite(9, r); analogWrite(10, g); analogWrite(11, b);
// same code as Lesson 7 - only the packaging changed
ConceptsSMD packagingmodule pinoutsPWM

LESSON 28

Single-digit 7-segment display

The building block underneath Lesson 13

Not built yet
You need1-digit 7-segment display8 × 220 Ω9 jumpers
D2D3D4D5D6D7D8D9GND 1-digit 7-segment display8888a topb top rightc bottom rightd bottome bottom leftf top leftg middledp decimal pointcommon either pin 3 or pin 8the two common pins are joined internally 220 signalGND Segments are lettered a to g clockwise from the top, with g in the middle.
ArduinoGoes toWhy
D2 – D8Segments a to g, each through 220 ΩOne resistor per segment.
D9dpOptional decimal point.
GNDCommonFor a common-cathode part. Common anode goes to 5 V and the logic inverts.

Doing this after Lesson 13 rather than before is the right order, because now you can see plainly what the four-digit display was hiding. This is eight independent LEDs sharing one common leg, arranged in the shape of a figure eight. There is no controller, no decoding, no cleverness — you turn on the segments you want and a digit appears.

The lettering is a standard. Segment a is the top bar, then b, c, d, e, f run clockwise around the outside, and g is the middle bar. dp is the decimal point. Every 7-segment datasheet in the world uses this convention, which is what makes segment tables portable between projects.

Digits are patterns. The number 7 is segments a, b and c. The number 4 is f, g, b and c. Because the mapping is arbitrary from the processor's point of view, you store it as a lookup table — a byte per digit, one bit per segment — and displaying a number becomes an array index rather than ten branches of logic. This is exactly the table you derived for the 74HC595 in Lesson 14, and the reason it worked there is the reason it works here: the bit-to-segment relationship is fixed the moment you choose your wiring order, so any consistent order gives a valid table.

Determining the type. Two of the pins (usually 3 and 8, at the middle of each side) are the common, joined internally, so you can use either. Put 5 V through a 220 Ω resistor onto any segment pin and touch the common to ground. If a segment lights, it is common cathode. If not, try it the other way. Ten seconds, no ambiguity.

Worth doing next. Drive this display through your 74HC595 instead of directly. Eight segments is exactly eight outputs, so it fits perfectly, and it drops the pin cost from nine to three. That combination — shift register plus display — is the foundation of every multi-digit driver, including the four-digit module you already used.

A lookup table beats ten if-statements
// bit order a,b,c,d,e,f,g,dp - one byte per digit
const byte digits[10] = {
  0b11111100, 0b01100000, 0b11011010, 0b11110010, 0b01100110,
  0b10110110, 0b10111110, 0b11100000, 0b11111110, 0b11110110 };
Conceptssegment mappingcommon cathode vs anodelookup tables

LESSON 29

Running without the USB cable

Power, regulators and the 9 V battery

Not built yet
You need9 V batteryBattery connector with DC plug
VINGND 9 V battery with DC plug9Vplug into the barrel jackor red wire to VINblack wire to GNDthe barrel jack has reverse protection; VIN does not 5VGND Using the barrel jack instead needs no wires at all, and protects against reversed polarity.
ArduinoGoes toWhy
Barrel jack9 V plugPreferred. Goes through the protection diode and the regulator.
VINBattery +Same regulator, but no reverse-polarity protection. Get it backwards and the board is damaged.
GNDBattery −Shared ground, as always.

Once a project works, you want it off the desk and off the USB cable. Understanding the board's power path makes that safe.

Two ways in, and they are not equivalent. The barrel jack and the VIN pin both feed the onboard regulator, but the jack passes through a reverse-polarity protection diode first. Wire a battery backwards into VIN and you can destroy the board; do the same into the jack and nothing happens. Use the jack.

The 5 V pin is an output, not an input. This trips people up. When the board is powered from USB or the jack, the 5 V pin supplies 5 V to your circuit. Feeding 5 V into that pin from an external supply bypasses the regulator and the protection entirely — it works, and it is what people mean by "powering through the 5 V pin", but there is nothing standing between your supply and the processor. A mistake there is not recoverable.

Why 7 to 12 volts. Below about 7 V the linear regulator cannot maintain 5 V and the board becomes unreliable in ways that look like software bugs. Above 12 V it overheats. The reason is what a linear regulator actually does: it burns off the excess as heat. It is not efficient, it is a controlled waste. At 9 V input with the board drawing 50 mA, the regulator is dissipating (9 − 5) × 0.05 = 0.2 W. Feed it 12 V and that becomes 0.35 W and the chip runs hot to the touch. This is exactly why 9 V is the sweet spot and why the regulator, not the battery, sets the upper limit.

A 9 V battery is a poor power source and it is worth being blunt about it. A PP3 alkaline holds around 500 mAh, and it delivers that only at low current. An Arduino with a couple of LEDs draws about 50 mA, so expect a handful of hours. Add a servo or a motor and you will be measuring the life in minutes. For anything that has to run, four AA cells in series give you 6 V with several times the capacity, or a USB power bank gives you regulated 5 V and far more energy — plugging a power bank into the USB socket is genuinely the most practical answer for a portable project.

Budget before you build. Add up the current: the board itself is roughly 45 mA, each LED 15 mA, a servo 100–250 mA while moving, a relay coil 75 mA, the RC522 about 25 mA. If the total approaches 400 mA you are at the limit of what a USB port or the onboard regulator will deliver, and things start browning out in confusing, intermittent ways. Motors and servos always get their own supply.

The most common battery bug is a power bug
// Nothing to write. But do measure:
// unplug USB, run on battery, and check the sketch still behaves.
// Brown-out failures look exactly like software bugs.
Conceptslinear regulatorsVIN vs 5V pinpower budgetingheat

Projects that combine everything

8

PROJECT 01

Desk weather station

DHT11 + LCD1602 + DS1302 — the three-module project that teaches integration

Built
You needDHT11LCD1602DS130210k pot220 Ω
D12D11D5D4D3D2D13D6D7D8 LCD1602 (4-bit)RSED4D5D6D7power, contrast and backlight wired as in Lesson 9 DHT11S signal+ to 5 V, - to GND DS1302 RTCCLKDATRSTVCC to 5 V, GND to GND signal Power and ground for all three modules run on the breadboard rails, not shown here.
ArduinoGoes toWhy
D12, D11, D5, D4, D3, D2LCD RS, E, D4–D7Straight from Lesson 9.
D13DHT11 signalAny spare digital pin.
D6, D7, D8RTC CLK, DAT, RSTStraight from Lesson 21.
A0freeAdd your photoresistor to dim the backlight at night.

The first project that is genuinely about integration rather than about a part. Nothing here is new — you have built all three pieces — but making them coexist teaches things that single-component lessons cannot.

Pin budgeting comes first, not last. Six pins for the LCD, three for the clock, one for the sensor: ten of your fourteen digital pins gone before you add a single button. Count pins on paper before you wire, and know your escape routes: the LCD can move to an I2C backpack and drop to two pins; the 74HC595 can expand outputs; the analog pins A0–A5 can serve as ordinary digital pins when you run short, which many people never realise.

Three different update rates in one loop. The DHT11 must not be read more than every two seconds. The clock only needs reading once a second. The LCD should only be rewritten when something changed, because rewriting it constantly makes it flicker. So you end up with three independent millis() timers running at different intervals in the same loop — and that is the real lesson. A single delay() anywhere in this sketch breaks all three.

Write only what changed. Calling lcd.clear() every pass causes a visible flash. Instead, keep the layout fixed and overwrite just the characters that moved. Pad numbers to a constant width, otherwise going from "100" to "99" leaves a stray digit on screen — the classic display artefact, and one you will only diagnose once.

Build it in stages

Wire and test the LCD alone. Add the DHT11 and print to the LCD. Add the clock last. If you wire all three and it does not work, you have three suspects and no information; if you add them one at a time, every failure has exactly one cause. This is the single most useful habit in hardware work.

Where to take it

Record the daily high and low with their timestamps. Add the photoresistor on A0 and switch the backlight off in a dark room. Add the water level sensor and turn it into a plant monitor. Log readings over serial and plot them.

Conceptscombining librariespin budgetingupdate rates

PROJECT 02

RFID access control

RC522 + servo + buzzer + LEDs — a lock that knows your fob

Built
You needRC522SG90 servoActive buzzer2 LEDs2 × 220 Ω
3V3D9D10D13D11D12D3D4D5D6 RC522 (3.3 V only)3.3VRSTSSSCKMOSIMISOGND to the ground rail SG90 servosignalred to 5 V, brown to GND Feedback partsgreen LED +red LED +buzzer +LEDs through 220 ohm; all negatives to GND 220 3.3Vsignal SPI occupies D11, D12 and D13 permanently on an UNO.
ArduinoGoes toWhy
D9–D13RC522 RST, SS, MOSI, MISO, SCKPower on 3.3 V. Not 5 V.
D3Servo signalThe lock mechanism.
D4, D5Green and red LEDsGranted and denied.
D6BuzzerAudible confirmation.

The circuit is straightforward; the reason to build it is the software shape it forces on you.

This project needs a state machine. The lock is in exactly one of a small set of states — Locked, Unlocking, Open, Closing, Denied — and events move it between them. Written with delay() it appears to work and is unusable: while the servo turns and the sketch sits in delay(2000), no card can be read, no button responds, nothing else exists. Written as a state machine with millis(), the loop runs thousands of times a second and every part of the system stays alive.

The shape is: a variable holding the current state, a variable holding when the state was entered, and a switch that decides what to do and when to move on. It is a small pattern and once you have written it once you will use it in everything.

Comparing UIDs. A UID is an array of bytes, not a number, so == will not do what you want — it compares pointers. Compare the bytes in a loop, or use memcmp(). Store your authorised UIDs in an array of arrays and loop over them.

What this is and is not. Say it plainly: this is not security. A UID is broadcast to any reader that asks and blank cloneable cards are freely sold. What you have built is a system that recognises a fob, which is genuinely useful for a drawer, a toy or a project — just do not conflate it with a lock that resists an attacker.

Power planning. The servo is the problem child, as always: its startup surge can pull the rail down enough to reset the board or corrupt an SPI transfer, which shows up as a card that reads correctly nine times and garbage the tenth. Give the servo its own 5 V supply with a common ground, and this class of intermittent fault disappears.

Where to take it

Add an enrolment mode: hold a master fob for three seconds, and the next card presented is added to the list. Store authorised UIDs in EEPROM so they survive a power cut. Add the RTC and log who opened it and when. Add the tilt switch as a tamper detector.

Conceptsstate machinesUID matchingtimed actions without delay

PROJECT 03

Clap-controlled lamp

Sound sensor + relay — pattern recognition in twenty lines

Built
You needSound sensorRelay (bare coil)ULN2003 board4 x AA pack
D2D7GND Sound sensorDO digital outVCC to 5 V, GND to GND ULN2003 driver boardIN1 control in+ 6 V from AA pack- groundOUT1 in the white plugrelay coil sits between + and OUT1, as Lesson 16 Relay (bare coil)RLYcoil to board +coil to OUT1COM and NO the lampthe lamp circuit stays entirely on this side signalGND5V Sound in on one pin, relay out on another. The lamp never touches the Arduino.
ArduinoGoes toWhy
D2Sound DOBest on D2 or D3 if you want to use an interrupt.
D7ULN2003 IN1HIGH energises the coil. Not inverted, unlike a relay module.
GNDBoard − and battery −Shared zero.
Board + / OUT1The two relay coil pinsSix volts from four AA cells, as Lesson 16.

A small project with a disproportionately useful idea in it: turning a stream of timing events into a recognised pattern.

One clap is not one event. A clap rings, echoes and decays, so the comparator output flips several times over perhaps 100 ms. Your first job is to collapse that burst into a single event, using the same lockout you used for the button: register the first transition, then ignore the input for 200 ms.

Detecting a double clap. Once single claps are reliable, a double clap is two claps separated by a gap in a plausible window — roughly 150 to 600 ms. Shorter and it is echo; longer and it is two unrelated noises. So you record the time of the last clap and, when a new one arrives, check the interval. That is the entire algorithm, and it generalises directly to Morse code, button double-clicks and gesture recognition. You are not detecting sound, you are detecting rhythm, and rhythm is just intervals between events.

Why require two claps. Because a single clap detector will be triggered by a door, a dropped book and a cough. Requiring a pattern is a cheap and dramatic improvement in false-positive rate — the same reason a garage remote sends a code rather than a pulse.

Tuning. The trimmer on the sensor and the timing windows in your code interact. Set the trimmer so a normal clap triggers from across the room and a conversation does not, then adjust the windows. Print every detected interval to the Serial Monitor while you tune; guessing at these numbers is much slower than measuring them.

Where to take it

Three claps for a different device. Use the second relay channel if you get one. Add the RTC so it ignores claps after midnight. Add an LED that flashes once per detected clap so you can see what the sensor is actually hearing while you tune it, which makes the whole thing far less mysterious.

Conceptsevent timingpattern detectionlockout windows

PROJECT 04

Plant watering monitor

Water level + LCD + buzzer — a sensor that has to last

Built
You needWater level sensorLCD1602Active buzzerLED
A0D13D12D11D5D4D3D2D7D6 Water level sensorS to A0+ from D13- to GND LCD1602RSED4D5D6D7as Lesson 9 Alert partsbuzzer +LED +LED through 220 ohm 220 signal5V D13 powers the sensor only during a reading, which is what makes it survive.
ArduinoGoes toWhy
A0Sensor SAnalog level.
D13Sensor +Switched power. This is the whole trick.
D12, D11, D5, D4, D3, D2LCDAs Lesson 9.
D7, D6Buzzer, LEDThe alert.

The engineering content here is not the circuit, it is designing something that keeps working for months, which is a different problem from making something work once.

Duty cycling. As covered in Lesson 25, a conductive sensor sitting permanently powered in water corrodes away. Powering it from D13 and switching it on for 10 ms per reading, once a minute, cuts its energised time by a factor of about six thousand. Same sensor, same code, vastly longer life. This is the sort of decision that separates a demo from a device.

Hysteresis, and why a single threshold is always wrong. Suppose you alarm below 300. The reading will sit near 300 and jitter — 299, 301, 298 — so the buzzer chatters on and off. The fix is two thresholds: alarm when it drops below 300, but do not clear the alarm until it rises above 350. The gap between them means the reading has to genuinely change to flip the state, not just wobble. Thermostats, float switches and Schmitt triggers all do exactly this, and once you notice hysteresis you will find it everywhere in control systems.

Alerts that people do not disable. A continuous buzzer is unbearable, so it gets unplugged, and then it protects nothing. Better: a short chirp every thirty seconds, with the LED and the LCD carrying the persistent state. Design the alert so someone will tolerate living with it.

Calibrate in the real container. The reading depends on your water, your container and how deep the sensor sits. Dip it to the levels you care about, write the numbers down, and use those. Any threshold copied from a tutorial is meaningless in your setup.

Where to take it

Add the DHT11 for humidity as a second signal. Add the RTC and record when the level last dropped, which tells you the consumption rate. Add the relay through the ULN2003 and a small pump, and it becomes a closed-loop system rather than a monitor — at which point hysteresis stops being a nicety and becomes the thing that stops the pump cycling itself to death.

Conceptsduty cycling a sensorhysteresisalert design

PROJECT 05

Fire and heat alarm

Flame sensor + DHT11 + buzzer — two sensors that disagree

Built
You needFlame sensor10k resistorDHT11BuzzerRGB LED
A0D2D8D9D10 Flame sensoranode to A0cathode to 5 V, 10k from A0 to GND DHT11S signal+ to 5 V, - to GND Alarm outputbuzzer +RGB redRGB greenRGB legs through 220 ohm, common to GND 220 signal Two independent sensors, so a single false reading cannot raise the alarm.
ArduinoGoes toWhy
A0Flame sensor divider midpointNear-infrared level.
D2DHT11 signalTemperature, checked as confirmation.
D8BuzzerThe alarm.
~D9, ~D10RGB red and greenGreen for normal, red for alarm.

The interesting problem here is not detection, it is not crying wolf.

Your flame sensor lies regularly. It responds to near-infrared, and so does sunlight through a window, an incandescent bulb, and a TV remote. A one-sensor alarm will go off constantly, and an alarm that goes off constantly gets switched off, which makes it worse than no alarm at all.

Sensor fusion, at its simplest. A real fire is hot as well as bright in the infrared. So require both: the flame reading above threshold and the temperature rising. Sunlight through a window is bright but does not raise the DHT11's reading by several degrees in a minute. A radiator is warm but not bright in the near-IR. Two independent signals must agree, and the false-positive rate collapses.

Rate of change beats absolute value. A room at 30 °C in summer is normal; a room that rose 5 °C in two minutes is not. Keep the reading from a few minutes ago and compare. This is a broadly useful idea: derivatives often carry more information than levels, and they are naturally immune to slow drift and calibration error.

Confirmation delay. Do not alarm on a single reading. Require the condition to hold for several consecutive samples. A brief glint of sunlight passes; a fire does not. A few seconds of confirmation costs nothing in a real emergency and removes most spurious triggers.

Say the obvious thing. This is a learning project. It is not a smoke detector, it will not detect a smouldering fire that produces smoke and little flame, and it must not be relied on for safety. Build it to learn about sensor fusion, and keep the real detector on the ceiling.

Where to take it

Look for flicker: real flames modulate at roughly 5–15 Hz, so sampling A0 quickly and detecting oscillation in that band distinguishes a flame from steady sunlight far better than any threshold. That is a properly satisfying signal-processing exercise using only parts you already own.

Conceptssensor fusionfalse positivesconfirmation logic

PROJECT 06

Infrared remote control centre

Remote + relay + servo + RGB — one input, many outputs

Built
You needIR receiverRemoteRelay + ULN2003ServoRGB LED
D2D7D3D9D10D11 IR receiverOUT signalVCC to 5 V, GND to GND ULN2003 + bare relayIN1 controlcoil across board + and OUT1, wired as Lesson 16 SG90 servosignalits own 5 V supply if it misbehaves RGB LEDRGB220 ohm each, common to GND 220 signal One input pin controls four outputs. The complexity is entirely in software.
ArduinoGoes toWhy
D2IR OUTEvery command arrives here.
D7ULN2003 IN1Power switching, through the relay coil.
D3Servo signalPosition control.
~D9, ~D10, ~D11RGB channelsColour.

This project is a software architecture exercise wearing a hardware costume, and it is the one that most changes how you write sketches.

Dispatch. Every button produces a code. A long chain of if (code == 0x...) works and becomes unreadable at about ten buttons. The better shape is a table mapping codes to actions, and a loop that finds the match and calls the corresponding function. Adding a button then means adding one row, not editing control flow. Once your input is data rather than branches, you can do things that are awkward otherwise: print the whole command list, remap buttons at runtime, ignore commands when the system is in a particular state.

Nothing may block. The receiver must be checked constantly, so no action may take time. "Sweep the servo from 0 to 180" cannot be a loop with delays in it; it has to be a target angle plus a timer that nudges the servo one step per pass. Same for a colour fade, same for a blink. Every output becomes a small state machine and the main loop becomes a scheduler that gives each one a turn. This is genuinely how larger embedded systems are structured, and this project is a comfortable place to learn it.

The timer collision to expect. The Servo library and the IRremote library both want hardware timers, and on an UNO they can conflict, producing servo jitter while the receiver is active. If you hit it, the usual fixes are to configure IRremote to use a different timer, or to detach the servo when it is not moving. Worth knowing in advance, because the symptom looks like a wiring fault.

Modes. Once you have several outputs, a mode variable pays off: the same four arrow buttons can mean colour in one mode and servo angle in another, which makes a cheap remote go a long way.

Where to take it

Add the LCD to show the current mode. Record a sequence of commands and play it back. Add the RTC and let a command schedule an action for later. Use the numeric keys as a PIN to enable the relay.

Conceptscommand dispatchmapping inputs to actionsnon-blocking output

PROJECT 07

Reaction timer game

Button + 4-digit display + buzzer — measuring in milliseconds

Built
You need4-digit display2 buttons8 × 220 ΩBuzzer
D2D10A0A1D13 4-digit display8888segments a-g, dpdigit commons 1-4wired exactly as Lesson 13 Two buttonsplayer button to D0start button to D1both use INPUT_PULLUP, other legs to GND Buzzer+- to GND 220 signal Display wiring is abbreviated here; it is identical to Lesson 13. Buttons use A0 and A1 as digital pins.
ArduinoGoes toWhy
D2 – D9Display segmentsFrom Lesson 13.
D10 – D13Digit commons and buzzerMove the buzzer if you need all four digits.
A0, A1Two buttonsAnalog pins used as ordinary digital inputs with INPUT_PULLUP.

Everything is familiar and the project is still worth building, because it puts a number on your own hardware.

Analog pins as digital pins. A0 to A5 are ordinary digital pins that happen to also connect to the ADC. pinMode(A0, INPUT_PULLUP) and digitalRead(A0) work exactly as on D2. This effectively gives an UNO twenty usable digital pins instead of fourteen, and most beginners never find out.

Timing that is honest. Human reaction time is 200–300 ms, and millis() resolves 1 ms, so it is entirely adequate — but note that your measurement includes the button's bounce time and the display's refresh cycle. Using micros() gives you microsecond resolution and lets you see how much of your measurement is really the hardware. Measuring your own measurement error is a genuinely valuable exercise.

The delay must be unpredictable. If the light comes on exactly two seconds after the start button, players learn the rhythm and anticipate. random(2000, 6000) fixes that. And note that Arduino's random() produces the same sequence on every boot unless you seed it — randomSeed(analogRead(A5)) with A5 unconnected uses the floating pin's noise as entropy. It is a pleasing use of a property that is a defect everywhere else in this manual.

Anti-cheat is a state machine. A player who holds the button down will register zero. So the button must be released before the round starts, and pressing early has to be detected and penalised. Expressed as states — Idle, Waiting, Go, Result, Cheated — with rules for each transition, this is easy. Expressed as nested if-statements, it is a mess. Same lesson as the RFID lock, in a friendlier setting.

Where to take it

Keep a best score. Two-player mode with two buttons and a shared display. Store the high score in EEPROM. Add a false-start penalty. Play a rising tone as the wait grows, so the tension is audible.

Conceptsmicrosecond timingrandomnessanti-cheat logic

PROJECT 08

Stepper dial and combination lock

Joystick + stepper + display — closing the loop between input and motion

Built
You needStepper + ULN2003Joystick4-digit display or LCD
D8D9D10D11A0A1D12D13 ULN2003 + stepperIN1IN2IN3IN4board + to 5 V, - to GND JoystickVRx to A0SW to A1+5V and GND to the rails LCD1602 (optional)RSED4-D7 as Lesson 9 signal The stepper takes four pins and the display takes six, so the joystick moves to analog pins.
ArduinoGoes toWhy
D8 – D11IN1 – IN4Remember the swapped pair in the Stepper constructor.
A0Joystick VRxDirection and speed.
A1Joystick SWConfirm, with INPUT_PULLUP.
D12, D13LCD RS and EIf you fit the display.

The last project, and the one that ties input, output and state together into something that behaves like a real machine.

Absolute versus relative. The joystick is absolute: its reading is a position, and it returns to centre when released. The stepper is relative: it only knows how many steps it has taken. So you cannot map one to the other directly. Instead the joystick's displacement becomes a velocity — how far you push decides how fast the shaft turns and in which direction — and the shaft position is whatever your accumulated step count says it is. Position controls velocity, velocity integrates to position. That relationship is the heart of every motion control system, and building it once makes it obvious.

Acceleration is not decoration. Command a stepper to jump from stopped to full speed and it will miss steps, because the rotor's inertia cannot follow. Ramp the speed up and down over a few hundred milliseconds and you can run considerably faster without losing position. This is why real motion controllers all have acceleration profiles.

Homing. On power-up, the stepper has no idea where it is — open loop means no feedback, as Lesson 18 explained. Real machines solve this by driving slowly toward a limit switch until it triggers, and calling that point zero. You have a tilt switch that can serve as a crude limit switch, and building a homing routine will teach you more about position control than any amount of reading.

The combination lock. Turn the dial to a number, press to confirm, repeat three times. This needs a state machine with a step counter, an entry buffer and a comparison. It is the RFID lock's logic with a mechanical input instead of a card — and noticing that the two projects share a structure, despite sharing no components, is exactly the kind of pattern recognition that makes the next project easier.

Where to take it

Add a physical pointer to the shaft and mark a dial on paper. Add the buzzer for feedback on each entry. Add the RFID reader as a second factor. Log failed attempts with the RTC.

Conceptsrelative vs absolute positionaccelerationhoming

Theory in one place

7

THEORY

Electrical fundamentals

The five ideas everything else is built on

Voltageeverywhere

A difference in electrical pressure between two points, in volts. There is no voltage at a point, only between two points. "Pin D13 is at 5 V" always means 5 V above ground. This is why every circuit has a black wire in it.

Currenteverywhere

The flow of charge, in amps. Current does the work and current destroys things. Heat rises with the square of current, so a small error in current is a large error in temperature.

Resistanceeverywhere

How much a material objects to that flow, in ohms. Resistance is your only lever: you choose the voltage, and resistance decides what current results.

Ohm's lawLessons 1, 6, 10

V = I × R. Rearranged: I = V/R, R = V/I. The habit worth building is voltage is applied, current is the consequence. A 220 Ω resistor with 3 V across it passes 13.6 mA whether that suits you or not.

PowerLessons 17, 29

P = V × I, in watts. Energy per second turned into heat, light or motion. This is the number that decides whether something gets warm or gets destroyed, and the reason a linear regulator on 12 V runs hotter than on 9 V.

Groundeverywhere

The point everyone agreed to call zero. Two circuits with separate grounds are two islands with no agreed reference, so signals cannot cross between them. This is why a motor on its own battery still needs its negative tied to an Arduino GND pin.

Series and parallelLessons 1, 3

In series, the same current flows through everything and the voltages add: R = R1 + R2. In parallel, the same voltage sits across everything and the currents add: 1/R = 1/R1 + 1/R2. This is why one shared resistor cannot serve eight LEDs.

Short circuitthe rule that prevents smoke

A path from supply to ground with almost no resistance. Ohm's law then predicts an enormous current, and something has to absorb it: a fuse, a trace, or a chip.

Open circuitLesson 1

A break in the loop. Current cannot flow unless there is a complete path back to where it came from. A reversed LED and a broken wire look identical from the outside, which is why an LED that does not light should be turned around first.

THEORY

The resistor and its three jobs

One component, three completely different purposes

Job 1: current limiterLessons 1, 3, 7

In series with something that would otherwise take too much current. Sized from the leftover voltage: R = (Vsupply − VLED) / I. For a red LED on 5 V that is (5 − 2) / 0.015 = 200 Ω, hence 220 Ω.

Job 2: pull-down or pull-upLessons 2, 15, 26

Ties an input pin weakly to a definite level so it reads reliably when nothing else drives it, but weakly enough that a button connecting it to the opposite rail wins. 10 kΩ is the standard compromise. The ATmega328P has pull-ups built in, which is what INPUT_PULLUP switches on.

Job 3: voltage divider referenceLessons 6, 10, 11, 24

Not protecting anything — providing a reference. Vout = Vin × Rbottom / (Rtop + Rbottom). Every resistive sensor in the kit is read this way: the sensor is one resistor, the fixed value is the other, and the Arduino measures the point between them.

Choosing the fixed valueLessons 6, 10

A divider is most sensitive when its two resistances are roughly equal, so you match the fixed resistor to the middle of the sensor's range. A 10 kΩ photoresistor gets a 10 kΩ partner by calculation, not tradition.

Colour codethe bench skill

Four bands: two digits, then the number of zeros, then gold for tolerance. Black 0, brown 1, red 2, orange 3, yellow 4, green 5, blue 6, violet 7, grey 8, white 9. Red-red-brown = 220 Ω. Brown-black-orange = 10 kΩ. Gold always sits on the right.

ToleranceLesson 10

A gold band means ±5%, so a 10 kΩ resistor might really be 9.5 k or 10.5 k. In a thermistor circuit that error passes through a logarithm into your temperature reading, and it dominates all other error sources. Measuring the actual value and using it in code is the highest-value calibration step available.

THEORY

Digital and analog

What the pins can and cannot actually do

Logic levelsLesson 2

On a 5 V board, above roughly 3 V reads HIGH and below roughly 1.5 V reads LOW. In between is undefined — the pin will report something, but not the same thing twice.

Floating inputLessons 2, 15, 26

An input connected to nothing does not read zero. It is a tiny capacitor with enormous input impedance, so mains hum and static swing it across the threshold. The symptom is a circuit that behaves differently when your hand is near it.

ADCLessons 6, 10, 11

The analog-to-digital converter compares the pin voltage against a reference and reports 0 to 1023. One step is 5 V / 1024 = about 4.9 mV. It measures voltage, not resistance, which is the entire reason the divider exists.

Reference voltageLesson 11

Readings are relative to the 5 V rail, which over USB is often 4.7–4.9 V and moves with load. If a motor starting makes every analog reading jump at once, this is why, not noise on the sensor.

Resolution vs accuracyLessons 10, 20

Two different things. The ADC resolves 4.9 mV steps, but a DHT11 is only accurate to ±2 °C. Printing four decimal places from a sensor with whole-number accuracy is inventing precision that does not exist.

PWMLessons 7, 17, 27

Not analog output. A square wave at 5 V for part of each cycle, about 490 Hz on most pins. Anything too slow to see the individual pulses — your eye, a motor's inertia, a speaker cone — responds to the average. Only pins marked ~ can do it.

Duty cycleLessons 7, 17

The proportion of each cycle spent HIGH, passed to analogWrite as 0–255. Note the asymmetry that catches everyone: analog in is 0–1023, analog out is 0–255.

tone() vs analogWrite()Lesson 5

Both make square waves. PWM fixes the frequency and varies duty cycle, because you want to control power. tone() fixes duty cycle at 50% and varies frequency, because you want to control pitch.

Sampling rate and NyquistLesson 22

analogRead() takes about 100 µs, giving at best 9,600 samples per second. You can only reconstruct frequencies below half your sampling rate, so about 4.8 kHz — enough for the envelope of a sound, nowhere near enough to record it.

THEORY

Getting more from few pins

The recurring trade: time for pins

MultiplexingLesson 13

Sharing lines between several devices by enabling only one at a time and cycling fast. Four digits of seven segments is 32 LEDs driven by 12 pins, because only one digit is ever actually lit.

Persistence of visionLesson 13

Above roughly 50–60 refreshes per second your visual system stops resolving the individual flashes and reports a steady image. Nothing on a multiplexed display is steady; you are being fooled, deliberately and reliably.

Shift registerLesson 14

A chain of flip-flops. Each clock pulse hands every stage's value to the next and admits one new bit. Eight pulses later a whole byte is loaded, using one data pin instead of eight.

Latch (storage register)Lesson 14

A second register holding its own copy, between the shift register and the output pins. Without it you would watch the data march sideways across your LEDs on every update. Shift quietly, then latch once, and all outputs change together.

Set-up then strobeLessons 9, 14, 21, 23

The same pattern in four different chips: place the data on the wires, then pulse a separate line to say "now". The LCD calls it E, the 74HC595 calls it ST_CP, SPI calls it the clock edge. Once you see it, you see it everywhere.

Serial vs parallelLessons 9, 14, 23

Parallel is fast and expensive in pins. Serial is slower and cheap in pins. Every bus in this kit is a point on that trade, and the choice is nearly always driven by how many pins you have left.

The buses you have metLessons 9, 14, 20, 21, 23

Parallel (LCD1602, eight lines reduced to four). Shift-and-latch (74HC595). One-wire bidirectional (DHT11). Three-wire with chip enable (DS1302). SPI with clock, two data lines and chip select (RC522). I²C, which you have not used yet, needs only two wires for many devices and lives on A4 and A5.

THEORY

Driving real loads

Where "plug it into a pin" stops working

Pin current limitsLessons 3, 4, 16, 17

About 20 mA per pin comfortably, 40 mA absolute maximum, 100 mA per port, 200 mA for the whole chip, and roughly 400–500 mA available from the 5 V rail over USB. Everything in this section follows from these numbers.

Transistor as a switchLessons 16, 17

A small current at the control terminal permits a much larger one to flow elsewhere. The pin carries information; the transistor carries power. This is the answer every time a load is too hungry for a pin.

Darlington pairLessons 16, 17, 18

Two transistors arranged so the first drives the second, multiplying their gain: microamps in, hundreds of milliamps out. Your ULN2003 is seven of them, rated 500 mA each, with flyback diodes already inside.

Low-side switchingLessons 16, 17

The switch sits between the load and ground rather than between the supply and the load. The load's other end stays permanently on positive. Easier to build, and how nearly all simple transistor switching is done.

Inductive loadLessons 4, 16, 17, 18

Anything with a coil: relay, motor, solenoid, buzzer. An inductor resists changes in current, which makes switching one off a violent event rather than a quiet one.

Back EMF and flyback diodesLessons 16, 17

When current to a coil is cut, the collapsing magnetic field generates a reverse voltage that can reach hundreds of volts for a few microseconds, destroying the transistor that just switched it. A diode across the coil gives that current a harmless loop to die out in. Not optional, not a refinement.

Stall currentLesson 17

A motor that is not turning is electrically just a piece of copper wire, so it draws far more than its running current — often 500 mA to over an amp. Every motor is stalled for the first instant of every start.

Electrical isolationLesson 16

A relay's coil and contacts share no electrical connection, only a magnetic field across an air gap. That is what lets a 5 V microcontroller switch a circuit that could never be allowed to reach it.

H-bridgeLesson 17

Four switches arranged so the supply can be applied to a motor in either polarity, which is the only way to reverse a brushed DC motor. The ULN2003 cannot do this; an L293D or L9110S can.

BrownoutLessons 8, 17, 18

A supply sagging under a sudden load. The symptoms look like software bugs: random resets, garbage on the LCD, analog readings that jump. The cure is a separate supply for the hungry part, plus a shared ground.

THEORY

Working with sensors

Turning a reading into a decision

Passive vs digital sensorsLessons 6, 10 vs 20

A photoresistor or thermistor changes resistance and leaves the measuring to you. A DHT11 contains its own sensing element, ADC and microcontroller, and hands you a finished number. You trade visibility for simplicity — and understanding the first kind is what lets you trust the second.

CalibrationLessons 6, 10, 24, 25

Never copy a threshold from a tutorial. Print the raw value, create the two conditions you care about, note the extremes in your room with your parts, and set the threshold between them.

HysteresisProjects 1, 4

Two thresholds instead of one. Alarm below 300 but do not clear until above 350. Without the gap, a reading jittering around a single number makes the output chatter. Thermostats, float switches and Schmitt triggers all do this.

DebouncingLessons 2, 22, 26

A mechanical contact does not close once; it rattles for 1–20 ms, and the Arduino sees every bounce. Ignore any change within about 50 ms of the last one. The same pattern handles claps, tilt switches and buttons.

Dead zoneLesson 15

A joystick at rest jitters by a few counts, and its centre is never exactly 512. Measure the resting value at startup and treat anything within about ±20 of it as zero. Every game controller ever made does this.

Rate of change beats absolute valueProject 5

A room at 30 °C is normal; a room that rose 5 °C in two minutes is not. Comparing against a reading from a few minutes ago is immune to slow drift and calibration error in a way that a fixed threshold never is.

Sensor fusionProject 5

Requiring two independent signals to agree. A flame sensor alone fires on sunlight; a flame sensor plus a rising temperature does not. The false-positive rate collapses for almost no extra code.

Duty cycling a sensorLesson 25

Power a sensor from a digital pin rather than the 5 V rail, so you can switch it on only while reading. For the water sensor this cuts electrolytic corrosion by a factor of thousands. It generalises to anything that degrades, drifts when warm, or drains a battery.

THEORY

Programming concepts

The patterns that keep recurring

delay() is a blockadeLessons 1, 13

It parks the processor in a counting loop. Nothing else runs — no button is noticed, no sensor read, no display refreshed. Fine for a single blinking LED, unworkable for anything with two jobs.

millis() and non-blocking timingLesson 13 onward

if (millis() - last >= interval) { last = millis(); ... }. You are not pausing, you are asking whether it is time yet and returning immediately if not. Several of these at different intervals can coexist in one loop.

unsigned longLesson 13

millis() returns an unsigned long, and timing variables must match. Subtracting as above also survives the moment millis() wraps to zero after about 49 days; comparing millis() > target does not.

Arrays and lookup tablesLessons 3, 14, 19, 28

Turning "which one" into a number you can compute with. A digit pattern table replaces ten branches of logic; a command table replaces a chain of if-statements. Once your data is data rather than control flow, you can print it, remap it, or index it randomly.

State machinesProjects 2, 3, 6, 7, 8

A variable holding the current state, a variable holding when it was entered, and a switch deciding what happens next. This is what replaces delay() in anything with several things happening at once, and it is how real embedded systems are structured.

Function prototypesPlatformIO

In C++ a function must be declared before it is called. The Arduino IDE generates these for you invisibly; a .cpp file in PlatformIO does not, which is why calling a function defined lower in the file fails to compile there but not in the IDE.

The F() macroall sketches

String literals are normally copied into SRAM at startup, and an UNO has only 2 KB. F("text") leaves them in the 32 KB of flash. Running out of SRAM does not produce a compile error — it produces garbled Serial output and random crashes.

map() and constrain()Lesson 15

map() rescales a value from one range to another; constrain() clamps it between limits. Mapping a joystick to a signed range centred on zero turns a raw sensor into a control input, where sign is direction and magnitude is speed.

Bitwise thinkingLessons 14, 28

One byte can hold eight independent on/off facts. shiftOut sends them one at a time; a segment table stores a shape per byte. LSBFIRST sends bit 0 first, so it ends up furthest along the chain — which is exactly why your digit table came out the way it did.

LibrariesLessons 8, 9, 13, 18–23

Someone else's solved problem. Worth reading the examples that ship with them, and worth checking the version: IRremote version 3 broke compatibility with version 2, and sketches written for one will not compile against the other.

Questions answered

51

Q AND A · 15

The questions you asked along the way

Collected from the whole course, answered in one place

Why does an LED need a resistor?

An LED is not a resistor. Once it reaches its forward voltage — about 2 V for red, 3.2 V for blue or white — it conducts almost freely and stops opposing current. So the current is decided entirely by whatever else is in the loop.

With a resistor, the arithmetic is comfortable: the LED drops 2 V, leaving 3 V across 220 Ω, which gives 13.6 mA. Without one, the only things limiting current are the wire and the pin's internal transistor, worth a few tens of ohms. Current shoots to a hundred milliamps or more. The LED may survive briefly; the pin may not.

What is the difference between the active and passive buzzer?

The active buzzer has an oscillator built in. Apply steady DC and it produces its own fixed tone, decided at the factory. You cannot change the pitch.

The passive buzzer is a bare piezoelectric disc with no electronics. DC makes it flex once and hold — a click. To get a note you must feed it an alternating signal at the frequency you want, which is what tone() generates.

Telling them apart: the active one is usually taller and sealed on top; the passive one has a visible disc underneath. On a meter, the passive one reads 8–16 Ω like a small speaker, the active one reads high or open.

Why do I need a voltage divider at all?

Because the Arduino cannot measure resistance. It can only measure voltage.

Wire only 5 V through a photoresistor to A0 and the reading sits at 1023 in every lighting condition. The ADC input draws essentially no current, and with no current flowing there is no voltage drop across the sensor (V = I × R, and I is zero). A0 sees the full 5 V regardless of what the sensor is doing. The sensor is working perfectly; there is simply nothing to read.

Adding the fixed resistor to ground completes a path, so current flows, so each resistance drops its share of the 5 V, and the midpoint becomes a number that moves.

Why do the thermistor, LDR and flame sensor all use 10 kΩ?

It is not a convention, it is a calculation. A divider produces its largest change in output voltage per unit change in the sensor when the two resistances are roughly equal. So you pick the fixed resistor near the middle of the sensor's working range, and that is where the circuit is most sensitive.

A "10 k thermistor" is 10 kΩ at 25 °C, which is where you will be testing it. A common photoresistor swings between about 1 kΩ and a few hundred kilohms, and 10 kΩ sits usefully inside that. If you were measuring a sensor that lived around 1 kΩ, 1 kΩ would be the right partner.

What exactly is PWM?

A square wave that switches between fully on and fully off, hundreds of times per second, where you control the proportion of time spent on. That proportion is the duty cycle, and you pass it as 0–255.

The pin is only ever at 5 V or 0 V. What makes it useful is that anything too slow to follow the individual pulses responds to the average instead: your eye sees a dimmer LED, a motor's inertia turns it into a slower speed, a heater sees less power.

So why is analogWrite() not really analog output?

Because analogWrite(9, 128) does not put 2.5 V on the pin. It puts 5 V on the pin half the time and 0 V the other half. If you measured it with a meter you would read about 2.5 V — but only because the meter is also averaging.

The distinction matters as soon as something is fast enough to see the pulses. Feed PWM into an audio amplifier and you hear a 490 Hz buzz, not a quiet tone. Feed it to another logic input and it reads as a rapid stream of HIGHs and LOWs, not as a middle value. A true analog output needs a DAC, which the UNO does not have.

Why use INPUT_PULLUP instead of a resistor?

Because the resistor is already inside the chip. Every ATmega328P pin has a 20–50 kΩ pull-up resistor built in, and INPUT_PULLUP simply switches it on. One less component, one less wire, one less thing to work loose.

The trade is that the logic inverts. The pin idles HIGH and reads LOW when your switch connects it to ground, so if (digitalRead(2) == LOW) means pressed. Slightly awkward to read the first few times, and then it becomes normal.

There is no built-in pull-down, which is why Lesson 2 uses an external 10 kΩ and most later lessons use pull-ups instead.

What do COM, NO and NC mean on a relay?

COM is the common pole — the wire being switched. NO (normally open) is disconnected from COM at rest and connects when the coil is energised. NC (normally closed) is connected at rest and disconnects when energised.

"Normally" always means with no power applied. That matters for design: you generally arrange things so the safe state is the unpowered state, because that is what you get during a power cut or a crashed sketch.

Why can the Arduino not drive a relay or motor directly?

Two separate reasons, and both have to be solved.

Current. A pin supplies about 20 mA comfortably and 40 mA at absolute maximum. A relay coil wants 70–80 mA. A small motor wants 100–200 mA running and often over 500 mA at the instant it starts. The pin loses.

Back EMF. Both are coils. When current is cut, the collapsing magnetic field generates a reverse spike that can reach hundreds of volts for a few microseconds, and that spike destroys whatever switched it off. A flyback diode is required, not advisable.

A transistor solves the first and a diode the second. Your ULN2003 board contains both, which is why it can drive either.

What is the difference between voltage and current?

Voltage is pressure difference; current is flow. The pump raises pressure, but the pipe decides how much flows.

The practical version: you choose the voltage, and the circuit decides the current. You cannot apply 5 V and also demand 10 mA — resistance settles that. When something overheats or fails, current is nearly always the quantity that did it, and voltage is what you changed to cause it.

Where the water analogy fails: water leaks out of an open pipe, but current cannot flow at all without a complete loop back to its source. There is no such thing as half a circuit.

How does a servo know what angle to go to?

By the length of a pulse, not by voltage and not by PWM duty cycle in the usual sense. Every 20 ms the servo expects a pulse: about 1 ms means one extreme, 1.5 ms is centre, 2 ms is the other extreme. The gap between pulses only tells the servo you are still there.

Inside is a motor, a gearbox, and a potentiometer geared to the output shaft. The potentiometer reports where the shaft is; your pulse says where it should be; the circuit drives the motor in whichever direction shrinks the difference. That closed loop is why a servo resists being pushed, and why it buzzes when asked for an angle it cannot reach.

Why does my LCD show blank or solid boxes?

Almost always contrast. The V0 pin needs a fraction of a volt from the potentiometer, and it is not optional — at 5 V the screen is blank, at 0 V you get a row of solid black rectangles.

Turn the pot through its full range before suspecting anything else. If you get solid boxes on the top row and nothing changes, that is the display saying "I am powered but nobody has initialised me", which points at the E line or the four data lines rather than at contrast.

Why did my 74HC595 digit table come out the way it did?

Because of two choices you made, not because of anything arbitrary.

shiftOut with LSBFIRST sends bit 0 first. Bits keep shifting along the chain, so the first bit sent ends up furthest down it — at QH — and the last bit sent stays at QA. Combine that with wiring your segments in order QA to QH and the relationship between a byte and a shape is completely determined.

Your table was correct because your wiring and your bit order were consistent. Switch to MSBFIRST and every entry reverses, which is worth doing once just to watch it happen.

How do I calibrate the water level sensor?

Not with numbers from a tutorial, because the reading depends on conductivity, and that changes with your water, its mineral content, its temperature and your container.

Dip the sensor to the depths you actually care about in the actual liquid, note the raw value at each, and use those. Then add hysteresis — two thresholds with a gap between them — or the reading will jitter across a single threshold and your alarm will chatter.

And power it from a digital pin rather than 5 V, switching it on only for the 10 ms it takes to read. Continuous DC through water electrolyses it and strips the copper off the traces within days.

What is the difference between the sound sensor's DO and AO pins?

DO is a comparator output: it answers one question, "is this louder than the level set by the trimmer", and flips. It carries no information about pitch, direction or what made the sound. A clap and a slammed door are identical to it.

AO is the amplified signal itself. It sounds more useful than it is, because analogRead() manages roughly 9,600 samples per second at best, which caps you at about 4.8 kHz — far too slow to record or analyse audio. What AO is genuinely good for is loudness: sample for 50 ms and take the spread between the highest and lowest readings.

Some modules have three pins and only give you DO.

Q AND A · 7

Wiring and breadboards

The questions that come up in the first week

Which breadboard holes are connected to each other?

The two long rails at the top and bottom run the full length of the board: every hole along the red line is one electrical point, and the same for the blue line. These are for power and ground.

The main area is different. It is connected in short rows of five holes running across the board, and the channel down the middle breaks the connection completely. A1 to E1 are one point; F1 to J1 are a different point.

That channel is exactly the width of a DIP chip, which is the whole reason it exists: the chip straddles it so its two rows of legs land on unconnected groups.

Does it matter which way round a resistor goes?

No. A resistor has no polarity and works identically either way. The colour bands are only there for you to read, and the gold tolerance band conventionally sits on the right.

LEDs, diodes, electrolytic capacitors, transistors and most modules do have polarity. When in doubt, check before powering.

Which leg of the LED is positive?

The longer leg is the anode and goes toward positive. The shorter leg is the cathode and goes toward ground.

If the legs have been trimmed, look at the plastic case: there is a flat spot on the cathode side. And if you are still unsure, just try it — an LED wired backwards does not light and is not damaged at these voltages.

Can I use any digital pin?

Mostly yes, with five exceptions worth knowing.

D0 and D1 are the USB serial link; anything wired there fights the uploader. D2 and D3 are the only interrupt-capable pins, so save them for things that must not be missed. D3, D5, D6, D9, D10, D11 are the only PWM pins. D10 to D13 are the SPI bus, fixed in hardware. D13 has the onboard LED loading it, which makes it a poor input.

Also: A0 to A5 work as ordinary digital pins. That gives you 20 usable pins, not 14, which rescues more projects than any other single fact.

What does the ~ symbol next to some pins mean?

PWM capable. Those are the only pins where analogWrite() produces a varying output; on any other pin it behaves like digitalWrite, snapping to fully on or fully off at 128.

Two libraries steal them: Servo disables PWM on D9 and D10 while attached, and tone() disables it on D3 and D11 while playing. If your LED dimming stops working the moment music starts, that is why.

Why does my circuit behave differently when I touch it?

You have a floating input. Your body is an antenna picking up mains hum, and an unconnected input pin has such high impedance that your proximity is enough to swing it across the logic threshold.

The fix is to give the pin a definite level at all times: a pull-down resistor to ground, or INPUT_PULLUP with the switch wired to ground.

My circuit worked, then stopped, and I changed nothing.

Suspect the breadboard and the jumper wires, in that order, before you suspect the component.

Breadboard clips lose their grip after enough insertions, especially in rows you use constantly. Cheap jumper wires break inside the insulation where you cannot see it, and the break is intermittent. Move the circuit to a fresh row and swap the wire; it takes thirty seconds and it is the cause more often than anything else.

Q AND A · 6

Power

Where most mysterious faults actually come from

Can I power everything from the 5 V pin?

Up to a point. Over USB you have roughly 400–500 mA total, shared by the board itself (about 45 mA) and everything you add.

Rough figures: an LED 15 mA, a relay coil 75 mA, the RC522 about 25 mA, a servo 100–250 mA while moving, a stepper 200–300 mA, a DC motor 150 mA running and far more starting. Add them up before you build. Anything with a coil or a magnet should have its own supply.

What is the difference between VIN and the 5 V pin?

VIN is an input that feeds the onboard regulator, expecting 7–12 V. The 5 V pin is an output from that regulator.

You can feed 5 V into the 5 V pin, and it works, but it bypasses the regulator and every protection on the board — there is nothing between your supply and the processor. A mistake there is not recoverable.

Also prefer the barrel jack to VIN: the jack has a reverse-polarity protection diode, VIN does not.

Why 7 to 12 volts, and can I use a 9 V battery for everything?

Below about 7 V the linear regulator cannot maintain 5 V and the board becomes unreliable in ways that look exactly like software bugs. Above 12 V it overheats, because a linear regulator works by burning off the excess as heat: at 12 V in and 50 mA drawn, it is dissipating 0.35 W.

As for the 9 V battery — it is a poor power source and worth being blunt about. A PP3 holds about 500 mAh at low current. An Arduino with a couple of LEDs gets you a few hours; add a servo or motor and you are measuring life in minutes. Four AA cells or a USB power bank are both far better.

Why does my board reset when the servo or motor starts?

That is a brownout, not a bug. The startup surge drags the 5 V rail below what the processor needs and it restarts.

Three fixes, in order of effectiveness: give the motor or servo its own supply with a shared ground; add a large electrolytic capacitor (470 µF or so) across the supply close to the hungry part, to absorb the spike; and avoid starting several things at the same instant.

Do I really need a common ground?

Yes, always, without exception.

Every voltage in a circuit is measured against ground. If your motor battery and your Arduino have separate grounds, there is no agreed zero, so a "HIGH" from the Arduino means nothing to the driver — the two circuits are islands. Tie the battery negative to an Arduino GND pin and they share a reference.

This is the single most common omission in projects that use an external supply, and the symptom is usually "nothing happens at all".

How do I know whether a module wants 3.3 V or 5 V?

Read the silkscreen on the board and look up the part number. Most modules in this kit are 5 V tolerant.

The important exception is the RC522 RFID reader, which is 3.3 V and has no regulator. Connecting its power pin to 5 V destroys it immediately and permanently. It is the most frequently killed module in kits like this one. Its signal pins tolerate 5 V logic in practice; the power pin does not.

Q AND A · 8

Code and compiling

Including the PlatformIO differences

Why does my code compile in the Arduino IDE but not in PlatformIO?

Two things the IDE does silently that PlatformIO does not.

It adds #include <Arduino.h>. A .ino file gets it injected automatically; a .cpp file does not. Without it, pinMode, Serial, HIGH, delay and A0 are all undeclared — the compiler has never heard of the Arduino API.

It generates function prototypes. In real C++ a function must be declared before it is called, so calling a function defined lower down the file fails. Add a line like void takeReading(); near the top for each one, or define your functions above the code that uses them.

PlatformIO is doing the correct thing here; the IDE is being helpful in a way that hides how C++ actually works.

Why does everything stop while delay() runs?

Because that is literally what it does. delay(1000) parks the processor in a counting loop for a full second and refuses to do anything else. No button is read, no sensor sampled, no display refreshed.

Replace it with the millis() pattern: check whether enough time has passed and return immediately if not. Then several timers at different intervals can coexist in the same loop, which is what every project past Lesson 13 needs.

Why must timing variables be unsigned long?

millis() returns an unsigned long, and mixing types breaks the arithmetic. An int overflows after 32 seconds; a signed long mishandles the wrap.

Writing millis() - last >= interval also survives the moment millis() wraps back to zero, which happens after about 49 days, because unsigned subtraction wraps correctly. Writing millis() > target does not, and that bug is invisible for seven weeks.

Why is analogRead 0–1023 but analogWrite 0–255?

Different hardware with different resolutions. The ADC is 10 bits, so 210 = 1024 possible values. The PWM timers are 8 bits, so 28 = 256.

They are unrelated pieces of silicon that happen to have similarly named functions. To feed one into the other, divide by four or use map(reading, 0, 1023, 0, 255).

Why do I get nan from the DHT11?

The sensor sends a checksum with every reading, and the library returns NaN ("not a number") rather than hand you data that failed it. Occasional failures are completely normal.

Two common causes: reading faster than once every two seconds, which the sensor physically cannot support; or a loose signal or ground wire. Always test with isnan(t) — never t == NAN, because NaN is not equal to anything, including itself.

What is the F() macro for?

It keeps string literals in flash memory instead of copying them into SRAM at startup. An UNO has 32 KB of flash but only 2 KB of SRAM, and every quoted string in your sketch consumes the scarce one by default.

Running out of SRAM does not produce a compile error. It produces garbled Serial output, corrupted variables and random resets — a genuinely horrible class of bug. Using F() on constant text costs nothing and prevents it.

What is the difference between = and ==?

= assigns. == compares. if (x = 5) sets x to 5 and is always true; if (x == 5) asks whether x is 5.

The compiler usually warns about this, and the warning is worth reading rather than scrolling past.

Where do libraries actually live, and which version do I have?

In the Arduino IDE they are installed through Sketch → Include Library → Manage Libraries. In PlatformIO they go in your project's lib_deps in platformio.ini, which is better because the project then carries its own dependencies.

Version matters more than beginners expect. IRremote changed its API completely at version 3, so version 2 examples will not compile against version 3 and vice versa. If an official example fails to compile, check the version before you rewrite anything.

Q AND A · 5

Components and parts

Identifying what you are holding

How do I tell common cathode from common anode?

Test it, do not guess — it takes ten seconds and nothing can be damaged.

Put the common leg on GND and touch any other leg to 5 V through a 220 Ω resistor. If it lights, it is common cathode. If nothing happens, try the common leg on 5 V and another leg to ground instead.

With a common-anode part all your logic inverts: 0 becomes full brightness and 255 becomes off. You can either rewire or subtract from 255 in software.

Do I really need a separate resistor for every LED?

Yes. A shared resistor limits the total current, so one LED alone is bright and eight together are dim.

Worse, LEDs of different colours have different forward voltages, and the lowest one hogs the current while the others barely light. Individual resistors give each LED an independent budget. Same reasoning for the three channels of an RGB LED.

Why does one button press count as three?

Switch bounce. The metal dome inside flexes and makes contact several times over 1–20 ms, and the Arduino is fast enough to see every one as a separate press.

Ignore any change that arrives within about 50 ms of the last one. A tilt ball switch bounces far worse than a button, because a rolling ball rattles as it settles.

What is the difference between a module and a bare component?

A module is the component plus whatever support circuitry it needs, on a small carrier board with normal pins. A relay module adds a transistor and a flyback diode; a DHT11 module adds its pull-up resistor.

The dangerous assumption is that every module includes what it needs. The KY-009 RGB module has no resistors at all. When you meet a new module, look for resistors near the pins, a regulator, or a diode across any coil — and if you cannot see them, assume they are not there.

What does the 74HC595 actually buy me?

Pins. Eight outputs for three pins, and — the good part — sixteen outputs for the same three pins, because you can chain a second chip off QH′ and share the clocks. The pin count stops growing.

The cost is time: eight clock pulses per byte instead of setting eight pins at once. On a microcontroller running at 16 MHz driving LEDs, that cost is invisible.

Q AND A · 5

When something is wrong

A short diagnostic order of operations

Nothing works at all. Where do I start?

Power, then ground, then one thing at a time.

Is the board's power LED on? Is GND connected — really connected, to the row you think? Is the part actually in the rows you believe, and not straddling the centre channel by accident?

Then reduce. Unplug everything except the one part that should work, prove it works alone, and add the next piece. A fault you can reproduce is nearly solved; a fault you keep disturbing by rewiring everything is not.

Can I damage the Arduino by wiring something wrong?

Yes, though it is harder than beginners fear. The genuinely destructive mistakes are: shorting 5 V to GND, putting more than 5 V on any pin, connecting a motor or relay coil directly to a pin, reversing power into VIN, and putting 5 V on the RC522.

Most other mistakes produce nothing rather than damage. A reversed LED, a wrong digital pin, a missing resistor on an input — these fail quietly and are recoverable.

The one habit that prevents nearly all of it: unplug the USB cable before you change wiring.

How do I know if I have killed a component?

Warmth is the main tell. A part that gets warm when it should not is passing current where it should not, and you should disconnect it immediately.

Otherwise, substitute. Swap the suspect part for a known-good one, or move it to a circuit you know works. This is why a multimeter is the highest-value thing you can buy: continuity testing turns "is this wire broken" from a guess into a two-second measurement.

My Serial Monitor shows gibberish.

Baud rate mismatch, nine times out of ten. The number in Serial.begin() must match the dropdown in the monitor — usually 9600.

If the baud is right, suspect SRAM exhaustion: too many string literals without F(), corrupting memory. And check that nothing is wired to D0 or D1, which are the serial lines themselves.

Is it safe to plug and unplug things while powered?

No, and this is worth being strict about. Rewiring a live circuit is how you briefly short 5 V to ground with a jumper, or connect power backwards for the half second it takes to realise.

The exception in this manual is deliberately safe: probing the ULN2003's output connector to find which pin drives your motor cannot damage anything, because the worst case simply puts both load wires on the same node.

Q AND A · 5

Where this goes next

Honest answers about the step after the kit

Have I actually learned the fundamentals, or just followed instructions?

A fair test: can you look at an unfamiliar sensor and predict how to wire it? If it is resistive, you know it needs a divider and roughly what value. If it is a module with three pins, you know two are power and one is signal. If it has a coil, you know it needs a driver and a diode.

That transfer is the thing worth having, and it is why the later lessons in this manual felt repetitive — they were meant to. The circuits stopped being new some time around Lesson 10; what kept changing was the maths and the software around them.

Am I ready for an ESP32 or STM32?

For the ESP32, yes. It uses the same Arduino framework and the same functions, and it adds WiFi and Bluetooth, far more memory, and a 12-bit ADC. The main adjustments are that it runs at 3.3 V — so 5 V on a pin damages it — and that its ADC is noticeably less linear than the UNO's.

STM32 is a bigger step, and more worthwhile after you have met interrupts, timers and peripheral registers on the AVR you already have. There is no rush; an UNO can teach those.

Do I need to learn C++ properly?

Enough of it, yes, and you have already met the parts that matter: types and why unsigned long is not int, arrays, functions and prototypes, scope, and structs when your data starts having shape.

The pieces you have not needed — classes, templates, dynamic allocation — are also the pieces that embedded code mostly avoids, because 2 KB of SRAM does not forgive a heap. Learning what a library is doing internally is a better next step than learning the whole language.

What is the difference between an Arduino and a PLC?

Reliability requirements, mostly, and everything that follows from them. A PLC is built for industrial environments: isolated inputs that survive electrical noise and wiring mistakes, outputs that switch real loads directly, deterministic scan cycles, and diagnostics that tell a maintenance technician what failed.

An Arduino is a development board. It is superb for learning and prototyping, and the concepts transfer almost completely — a PLC input card is doing exactly the debouncing and level-detection you now write by hand. What it does not have is the isolation, the certification, or the failure behaviour that a factory needs.

If industrial control interests you, the concepts to look at next are ladder logic, Modbus RTU, and 4–20 mA current loops. That last one is a lovely idea: sensors transmit a current rather than a voltage, so a broken wire reads 0 mA and is instantly distinguishable from a genuine zero reading of 4 mA.

Should I learn to solder?

Yes, and sooner than you think. Half the "intermittent fault" reports in hobby electronics are breadboard contact problems, and a soldered circuit simply does not have them.

It is also the gate to a whole category of parts: your RC522 needs its header soldered on, and most interesting modules arrive that way. A basic temperature-controlled iron and some 0.7 mm leaded solder is a small investment for how much frustration it removes.

Reference

5

REFERENCE

Which pin can do what

Read this before planning any project that uses more than four parts

PinRoleWhat to know
D0, D1Digital in/outAlso the USB serial link. Anything wired here fights the uploader. Leave them free unless you are short.
D2, D3Digital in/out, interruptsThe only two pins that can trigger an interrupt on an UNO. Reserve them for things that must not be missed.
~D3, ~D5, ~D6PWManalogWrite() capable. D5 and D6 run at 980 Hz, the rest at 490 Hz.
D4, D7, D8Digital in/outPlain pins. Nothing special, which makes them the ones to use first.
~D9, ~D10PWMThe Servo library takes these over whenever it is active.
D10SPI SSChip select by convention. Any pin works, but libraries assume D10.
~D11PWM, SPI MOSIFixed for SPI. Shared with tone() timer 2.
D12SPI MISOFixed for SPI.
D13SPI SCK, onboard LEDFixed for SPI. The onboard LED loads this pin slightly, so it is a poor input.
A0 – A5Analog in, or digital in/outAll six work as ordinary digital pins with digitalRead and digitalWrite.
A4, A5I2C SDA, SCLIf you add an I2C LCD backpack or sensor, these are the pins it uses.
AREFAnalog referenceOnly if you drive the ADC reference externally. Leave it alone otherwise.
VINRaw power in7–12 V. No reverse protection, unlike the barrel jack.
5VRegulated outputAn output, not an input. About 400–500 mA available over USB, shared by everything.
3.3VRegulated outputOnly about 50 mA. Enough for the RC522, not for much else.

An UNO has 14 digital pins and 6 analog pins, and the analog ones work as digital pins too — so the real budget is 20, not 14. That single fact rescues more projects than any other.

REFERENCE

Libraries you need

All installed from Sketch → Include Library → Manage Libraries

LibraryWhere fromNote
ServoBuilt inLesson 8. Disables PWM on D9 and D10 while attached.
LiquidCrystalBuilt inLesson 9. Constructor order is RS, E, D4, D5, D6, D7.
SevSegLibrary ManagerLesson 13. Handles the multiplexing refresh for you.
StepperBuilt inLesson 18. Watch the swapped coil order.
IRremoteLibrary ManagerLesson 19. Version 3 broke compatibility with version 2 sketches.
DHT sensor libraryAdafruit, Library ManagerLesson 20. Also needs Adafruit Unified Sensor.
Rtc by MakunaLibrary ManagerLesson 21. Use the ThreeWire variant for the DS1302.
MFRC522Library ManagerLesson 23. Needs the built-in SPI library alongside it.

REFERENCE

Every formula in this manual

There are only nine, and you already understand all of them

Ohm's law

V = I × R

The one you will use every day.

Power

P = V × I

Watts. Tells you what gets hot.

LED resistor

R = (Vsupply − VLED) / I

(5 − 2) / 0.015 = 200, so use 220 Ω.

Voltage divider

Vout = Vin × Rbottom / (Rtop + Rbottom)

Every resistive sensor in the kit.

ADC to volts

V = reading × 5.0 / 1023.0

Analog in is 0–1023.

PWM duty

average V = 5 × value / 255

Analog out is 0–255. Note the different range.

Series resistors

R = R₁ + R₂

Same current through both.

Parallel resistors

1/R = 1/R₁ + 1/R₂

Same voltage across both.

Stepper revolution

2048 full steps

For the 28BYJ-48 with its 64:1 gearbox.

REFERENCE

When it does not work

Symptom first, then the cause it almost always turns out to be

Nothing happens at all
Check power before anything else. Is the board LED on? Is GND connected? On a breadboard, is the part actually in the rows you think it is, and not straddling the centre channel by accident?
It worked, then stopped
Suspect the breadboard and the jumper wires, in that order. Breadboard clips wear out and cheap jumpers break inside the insulation where you cannot see it. Move the circuit to a different row and swap the wire before you doubt the component.
An LED does not light
Reverse it. A backwards LED is indistinguishable from a broken circuit, and it is the single most common cause.
Analog reading pinned at 1023 or 0
Your divider has only one leg. Either the fixed resistor is missing, or its ground connection is loose.
A digital input reads randomly
The pin is floating. Add a pull-down, or switch to INPUT_PULLUP and wire the switch to ground.
The board resets when something moves
A brownout, not a bug. The servo, motor or relay is dragging the 5 V rail down. Give it a separate supply and share the grounds.
Readings jump when a motor runs
Same cause. The ADC measures against the 5 V rail, so when the rail sags every reading shifts at once.
The LCD shows solid boxes
It is powered but not initialised, or the contrast is wrong. Turn the pot through its full range first, then check E and the four data lines.
One press counts as three
Switch bounce. Ignore any change within 50 ms of the last one.
The sketch behaves differently on battery
Check the supply voltage under load. Below about 7 V into VIN the regulator cannot hold 5 V and everything becomes unreliable in ways that look like software faults.
A module does nothing and gets warm
Stop. Unplug it. Warm means current where there should not be current, usually reversed power or a short.

One habit underneath all of these: change one thing at a time. When a circuit fails, the temptation is to rewire everything. Resist it. Isolate the smallest piece that should work, prove it works, then add the next piece. A fault you can reproduce is nearly solved; a fault you keep disturbing is not.

REFERENCE

What to buy next

In order of how much they change what you can build

  1. A multimeterThe single biggest upgrade available to you. Continuity testing alone will save you more hours than every other purchase combined.
  2. A second ULN2003 driver boardYour one board is shared between the stepper, the DC motor and the relay, so only one of them can be plugged in at a time. A spare costs almost nothing and removes that constraint.
  3. An L293D or L9110S H-bridgeThe one thing the ULN2003 cannot do: reverse a motor. Needed for anything that has to drive both ways.
  4. A handful of 1N4007 diodes and some NPN transistors (2N2222)For driving a coil when the ULN2003 is busy, and for understanding what that chip is doing internally.
  5. An I2C backpack for the LCDDrops the display from six pins to two, which changes what projects are possible.
  6. Assorted electrolytic capacitors (100 µF, 470 µF)Across the supply near a servo or motor, they absorb current spikes and stop brownouts.
  7. A 4 x AA battery holderSix volts into VIN, far more capacity than a 9 V PP3, and a sensible motor supply.
  8. An HC-SR04 ultrasonic sensorAbout two dollars, and it completes Lesson 12.
  9. A proper breadboard power supply moduleFeeds 5 V and 3.3 V to the rails from a barrel jack, independent of the Arduino.