Mastering_Arduino
Mastering_Arduino
ARDUINO
A Comprehensive Guide to Embedded Systems & IoT
From Hardware Foundations to Advanced Robotics & Wi-Fi
Rebouh Abdallah
Engineer | Embedded Systems & Robotics
MASTERING ARDUINO
A Comprehensive Guide to Embedded Systems & IoT
• NonCommercial (NC) — You may not use the material for commercial
purposes without explicit written permission from the author.
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
I Getting Started 11
Overview: Part I . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
II Core Programming 22
Overview: Part II . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
3
4 CONTENTS
5 Mathematical Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
5.1 Basic Arithmetic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
5.2 Useful Math Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
5.2.1 Constrain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
5.2.2 Map . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
5.2.3 Min, Max, Abs, Pow, Sqrt . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
5.2.4 Trigonometric Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
5.3 Random Numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
5.4 Bitwise Operations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
5.4.1 Bit Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
5.5 Extracting and Combining Bytes . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
7 Analog Input . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
7.1 Reading Analog Values: analogRead() . . . . . . . . . . . . . . . . . . . . . . . . 40
7.2 Converting to Voltage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
7.3 Voltage Divider Diagram . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
7.4 Using map() to Change Ranges . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
7.5 Reading More Than Six Analog Inputs . . . . . . . . . . . . . . . . . . . . . . . . 41
7.6 Measuring Voltages Above 5V . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
7.7 Calibration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
7.8 Smoothing Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
9 Visual Output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
9.1 Connecting and Using LEDs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
9.2 Adjusting LED Brightness (PWM) . . . . . . . . . . . . . . . . . . . . . . . . . . 52
9.3 Controlling RGB LEDs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
9.4 LED Bar Graph . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
9.5 Multiplexing an LED Matrix . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
9.6 7-Segment LED Displays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
9.7 Using Shift Registers (74HC595) . . . . . . . . . . . . . . . . . . . . . . . . . . . 54
10 Physical Output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
10.1 Controlling Servo Motors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
10.2 Controlling Servos with Sensors . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
10.3 Driving Brushed Motors with H-Bridge . . . . . . . . . . . . . . . . . . . . . . . 56
10.4 Driving Stepper Motors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
10.5 Driving Solenoids and Relays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
11 Audio Output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
11.1 Playing Tones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
11.2 Playing a Melody . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58
11.3 Controlling MIDI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
Overview: Part IV . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
12 Serial Communications . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
12.1 Sending Debug Information . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
12.2 Formatting Output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
12.3 Receiving Serial Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
12.4 Sending Binary Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
12.5 Sending and Receiving Multiple Fields . . . . . . . . . . . . . . . . . . . . . . . . 64
12.6 Software Serial . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
13 Using Displays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
13.1 Text LCD Display . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
13.2 Scrolling Text . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
13.3 Creating Custom Characters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
16 Wireless Communication . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
16.1 Bluetooth (HC-05 / HC-06) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
16.2 Low-Cost Wireless Modules (433MHz) . . . . . . . . . . . . . . . . . . . . . . . . 75
16.3 XBee / ZigBee Communication . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
V Advanced Topics 85
Overview: Part V . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
VI Hands-On Projects 97
Overview: Part VI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
24 Beginner Projects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
24.1 Project: Light Dimmer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
24.2 Project: Disco Strobe Light . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
24.3 Project: Plant Monitor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
24.4 Project: Ghost Detector (EMF Detector) . . . . . . . . . . . . . . . . . . . . . . 100
34 Glossary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
The Arduino platform ( ﺃﺭﺩﻭ ) has fundamentally revolutionized electronics and em-
bedded systems since its inception in 2005. Originating as a tool for interactive design
students, it has evolved into a global phenomenon, empowering engineers, educators, and
makers to build projects limited only by their imagination.
• Part II: Core Programming — C/C++ syntax, control flow, and logic.
9
10 Introduction
• Part III: Input and Output — Digital/analog interfacing and sensor integration.
• Part IV: Communication & IoT — Serial, I2C, SPI, Wi-Fi, Bluetooth, MQTT, and cloud
integration.
• Part V: Advanced Topics — Memory management, interrupts, DSP, and PCB design.
Insight
Clarifications, alternative approaches, advanced engineering reflections, and “behind the
scenes” explanations.
Caution
Warnings regarding common coding bugs, hardware voltage limits, logic fallacies, and
potential pitfalls.
Example
Detailed, step-by-step illustrations of specific theories, calculations, or syntax logic in
practice.
Hands-On Project
Complete practical implementations featuring clear objectives, required materials, Bill
of Materials (BOM) with estimated costs, wiring instructions, QR codes for Wokwi
simulations, project-specific common mistakes, and evaluation criteria.
Technical terms include their Arabic translation in parentheses upon their first appearance (e.g.,
Microcontroller ( ﺩ )). Arabic comments are also integrated inside code blocks to clarify
key concepts bilingually.
Part I
Getting Started
11
Overview: Part I
In this first part, we lay the foundation for your journey into embedded systems. We begin
by understanding the Arduino platform—not just as a board, but as a versatile microcontroller
ecosystem. We will explore the hardware specifications of the Arduino Uno, power requirements,
and how to set up the Integrated Development Environment (IDE). By the end of this part, you
will have written your first program (the Blink sketch) and understood the fundamental structure
of every Arduino program.
12
Chapter 1
Caution
Never apply more than 5V directly to any Arduino pin (except Vin or the barrel jack).
Voltages exceeding 5V on digital or analog pins will permanently damage the microcon-
13
14 CHAPTER 1. THE ARDUINO PLATFORM AND IDE
troller.
5. Select the correct board: Tools > Board > Arduino Uno.
1 void setup () {
2 // (setup) ﺍﺩ ﺩﺍ ﺍ
3 // ﺍ ﺓ ﻭﺍ ﺓ ﺍـ ﺩ
4 }
5
6 void loop () {
7 // (loop) ﺍﺭ ﺩﺍ ﺍ
8 // ﺭﺇ ﺍ ﺍـ ﺩ
9 }
1.4. THE BLINK SKETCH 15
Caution
Missing semicolons are the most common cause of compilation errors. Note that the error
message often points to the line after the missing semicolon.
Comments
• Single-line comments: Begin with //.
• Multi-line comments: Enclosed between /* and */.
1 // ﻭﺍ ﺍ
2
3 /* ﺩﺍ ﺍ
4 ﺍـ ﺩ ﺓ ﺡ ﺃ ﺍﺀ ﻡ ُ */
Curly Braces
Curly braces ({ }) define blocks of code. Every opening brace must have a matching closing
brace.
Functions
Functions ( )ﺩﻭﺍﻝare encapsulated blocks of code that perform specific tasks.
Example
Step-by-Step Walkthrough of Blink:
Hands-On Project
Project: Blink Variations
Wokwi Simulation
• 1x LED ($0.10)
Steps:
1. Connect the LED’s anode (long leg) to pin 13 via a 220Ω resistor.
• Pattern 1: 1s on / 1s off.
• Pattern 2: 100ms on / 100ms off (strobe).
• Pattern 3: 2s on / 500ms off.
• LED doesn’t light up: The LED is reversed. The long leg (anode) must go to the
resistor/pin, and the short leg (cathode) to GND.
• Patterns run too fast: Incorrect timing logic in the delay() functions.
Evaluation Criteria:
Extension Ideas:
Exercises
1. What is the primary difference between the setup() and loop() functions?
2. Your LED is blinking so fast it looks continuously on. How would you fix this using
millis() instead of delay()?
3. Design a traffic light sketch that includes an emergency mode (flashing yellow) triggered
by a button.
4. What if you power the Arduino with 12V on the 5V pin instead of Vin? From my experi-
ence, what happens to the chip?
Chapter 2
2. The name.
18
2.3. THE CONST QUALIFIER 19
Insight
The int type on the Arduino Uno (ATmega328P) occupies 2 bytes (16-bit). If you add 1
to 32,767, it “rolls over” to -32,768. This phenomenon is known as integer overflow. On
32-bit architectures like the ESP8266 or ESP32, int occupies 4 bytes.
Caution
Floating-point arithmetic on Arduino is not perfectly precise. Comparing floats for ex-
act equality (e.g., if (value == 0.0)) may fail unexpectedly. Instead, verify that the
absolute difference is below a small threshold:
Insight
Using const instead of int for pin assignments saves RAM—the compiler stores the value
directly in program memory (Flash). The #define preprocessor directive achieves similar
memory savings but lacks type safety. Prefer const for modern C++ practices.
2.4 Arrays
An array ( ) is a collection of variables of the same data type, stored contiguously in
memory:
20 CHAPTER 1. THE ARDUINO PLATFORM AND IDE
Caution
Accessing an array outside its bounds (e.g., ledPins[6] for a 6-element array) will not
trigger a compilation error but will read garbage memory, potentially causing erratic
behavior.
2.5 Strings
2.5.1 Arduino String Class
Exercises
1. What is integer overflow?
2. Your sketch crashes randomly after an hour. You suspect String variables are causing
heap fragmentation. How do you fix this?
3. You have a counter tracking up to 100,000 events. Choose the appropriate data type and
justify why int would fail.
4. What if you use a float to track exact currency in a payment system? Would you face
precision issues?
Part II
Core Programming
22
Overview: Part II
This part delves into the C/C++ programming foundations required to write effective Arduino
sketches. We move beyond the basic Blink sketch, learning how to structure complex programs
using custom functions, control execution flow with loops and conditional statements, and per-
form precise mathematical operations.
23
Chapter 3
1 int main(void) {
2 init (); // ﺓﺍ ﺍ
3 setup (); // ﺍﺩ ﺍ ﺀ ﺩﺍ ﺍ ﺍ
4 for (;;)
5 loop (); // ﺍﺭ ﺍﺭ ﺍ ﺀ ﺩﺍ ﺍ ﺍ
6 return 0;
7 }
Insight
The hidden main() function calls init() to prepare hardware peripherals, invokes your
setup() once, and then repeatedly calls loop(). Understanding this underlying execution
model is key to mastering Arduino’s architecture.
9 // ﻭ ﺩﺍ
10 void blink2 (int count) {
11 while (count > 0) {
12 digitalWrite (13, HIGH);
13 delay (500);
14 digitalWrite (13, LOW);
15 delay (500);
16 count = count - 1;
17 }
18 }
19
24
3.3. PASSING BY REFERENCE 25
20 // ﻭ ﺩﺍ
21 int blink3 (int period ) {
22 int result = 0;
23 while ( digitalRead (2) == HIGH) {
24 digitalWrite (13, HIGH);
25 delay( period );
26 digitalWrite (13, LOW);
27 delay( period );
28 result = result + 1;
29 }
30 return result ;
31 }
Exercises
1. Explain the difference between global and local variable scope.
2. A function assumes its local variable retains its value from the previous call, but it resets
to 0. How would you fix this?
3. You need to pass a large array of sensor data to a processing function. Do you pass by
value or reference, and why?
4. What if you declare a variable inside loop() without static? How does the compiler
handle memory allocation?
Chapter 4
Caution
A single equals sign (=) assigns a value, whereas a double equals sign (==) compares values.
Using if (x = 3) instead of if (x == 3) is a common and frustrating bug.
26
4.2. SWITCH-CASE STATEMENTS 27
1 switch (range) {
2 case 0:
3 Serial . println ("low"); //
4 break;
5 case 1:
6 Serial . println (" medium "); //
7 break;
8 case 2:
9 Serial . println ("high"); //
10 break;
11 default :
12 Serial . println (" unknown "); // ﻭﻑ
13 break;
14 }
Caution
Omitting the break statement causes “fall-through,” where execution continues into the
next case block unintentionally.
1 // ﺍ ﺍ ﻁ while:
2 while ( analogRead ( sensorPin ) > 100) {
3 flashLED ();
4 }
5
Exercises
1. What happens if you forget the break statement in a switch-case?
4. What if you use a while loop with a condition that never becomes false? How does it
affect the loop() function?
Chapter 5
Mathematical Operations
Insight
Integer division truncates the decimal. 3 / 2 evaluates to 1, not 1.5. To obtain floating-
point results, at least one operand must be a float: 3.0 / 2 evaluates to 1.5.
5.2.2 Map
29
30 CHAPTER 5. MATHEMATICAL OPERATIONS
Example
Example: Converting Analog Read to Voltage
Caution
Why A5 instead of A0? On some Arduino boards, A0 may be tied to internal circuitry
or exhibit stable readings due to board layout. Using an unconnected analog pin like A5
ensures real electrical noise, which is ideal for seeding the random number generator.
Insight
Without calling randomSeed(), the Arduino generates the same pseudo-random sequence
upon every boot. Reading an unconnected analog pin provides electrical noise—an excel-
lent source of entropy.
5.4. BITWISE OPERATIONS 31
Insight
Note for ESP8266 users: The ESP8266 features only one analog pin (A0) with a native
range of 0–1V. If using an ESP8266, use analogRead(A0) with a voltage divider, or leave
it floating.
Exercises
1. What is the difference between integer division and floating-point division in Arduino?
2. Why does 3 / 2 yield 1 instead of 1.5? How would you correct the voltage calculation
voltage = sensorValue * (5 / 1023)?
3. You need to map an analog reading to a servo angle (0–180) while ensuring the value never
exceeds bounds. Design the logic using map() and constrain().
4. What if you use randomSeed() with a constant value? How does it affect the randomness
on every boot?
Part III
33
Overview: Part III
In this part, we bridge the gap between the digital realm of the microcontroller and the physical
environment. We will learn how to read digital inputs from buttons and keypads, interpret
analog data from sensors, and generate visual and physical outputs using LEDs, servos, and
motors.
34
Chapter 6
Insight
Pull-up vs. Pull-down Resistors
Pull-up Configuration: The resistor connects the pin to +5V. The switch connects the
pin to GND when pressed.
Result: Pin reads HIGH when switch is open, LOW when pressed.
Pull-down Configuration: The resistor connects the pin to GND. The switch connects
the pin to +5V when pressed.
Result: Pin reads LOW when switch is open, HIGH when pressed.
Arduino microcontrollers feature internal pull-up resistors (20kΩ–50kΩ) that can be en-
abled via software.
35
36 CHAPTER 6. DIGITAL INPUT AND OUTPUT
10kΩ
Switch
GND
GND
Reads LOW when open
Reads HIGH when open Reads HIGH when pressed
Reads LOW when pressed
1 long lastDebounceTime = 0;
2 long debounceDelay = 50;
3
4 void loop () {
5 int reading = digitalRead ( buttonPin );
6 if ( reading != lastButtonState ) {
7 lastDebounceTime = millis (); // ﺍ ﺇ ﺩﺓ
8 }
9 if (( millis () - lastDebounceTime ) > debounceDelay ) {
10 if ( reading != buttonState ) {
11 buttonState = reading ;
12 // ﺓ ﺍ ﺍ ً ﺍ ﺫ ﺇ ﺍﺀ ﺀ
13 }
14 }
15 lastButtonState = reading ;
16 }
Hands-On Project
Project: Pushbutton-Controlled LED
Wokwi Simulation
• 1x Pushbutton ($0.20)
• 1x LED ($0.10)
Steps:
2. Connect one side to +5V, the other to pin 2 via a 10kΩ resistor to GND.
3. Connect the LED anode to pin 13 via a 220Ω resistor; cathode to GND.
• LED stays on/off constantly: Floating pin. You forgot to connect the 10kΩ pull-
down resistor.
• Random toggling: The pin is picking up ambient noise. Ensure the input is tied to
a definitive HIGH or LOW.
Extension Ideas:
1 int buttonState = 0;
2 int lastButtonState = 0;
3 int buttonPushCounter = 0;
4
5 void loop () {
6 buttonState = digitalRead ( buttonPin );
7 if ( buttonState != lastButtonState ) {
8 if ( buttonState == HIGH) {
9 buttonPushCounter ++; // ﺯ ﺩﺓ ﺍ ﺍﺩ
10 Serial .print (" Pushes : ");
11 Serial . println ( buttonPushCounter );
12 }
13 delay (50); // debounce
14 }
15 lastButtonState = buttonState ;
16
17 if ( buttonPushCounter % 4 == 0) {
18 digitalWrite (ledPin , HIGH); // ﺭﺍ
19 } else {
20 digitalWrite (ledPin , LOW);
21 }
22 }
Insight
Installing the Keypad Library ( ﺍ :)
1. ﺍArduino IDE.
4. ﺍInstall.
Insight
Why millis() instead of delay(20)? Using delay() inside the scan loop freezes the
entire microcontroller. With millis(), the scan function checks timing non-blockingly,
allowing the main loop to handle sensors, displays, and serial communication simultane-
ously. This is a fundamental design pattern for responsive embedded systems.
Caution
For production projects, utilize the well-tested Keypad library by Mark Stanley. It handles
debouncing, multiple key presses, and events elegantly.
Exercises
1. What is the difference between a pull-up and a pull-down resistor configuration?
2. Why is using delay(20) during keypad scanning a bad engineering decision? How will
you rewrite the code using millis()?
3. Design a button that toggles an LED state on each press. How will you fix the issue of it
toggling multiple times per single press due to bouncing?
4. What if you read a button without any pull-up or pull-down resistor? What will the pin
read when the button is not pressed?
Chapter 7
Analog Input
+Vin
GND
40
7.4. USING MAP() TO CHANGE RANGES 41
Example
Example: Measuring a 9V Battery
To safely measure a 9V battery with an Arduino (5V max), use R1 = 10kΩ and R2 =
10kΩ:
10k
Vout = 9V × = 4.5V
10k + 10k
This is safely below 5V. In code:
Caution
Never connect more than 5V directly to an Arduino pin. Always use a voltage divider.
7.7 Calibration
Insight
This implements a running average (ﻙ ﺍ )ﺍ. It maintains a window of recent read-
ings and updates in O(1) time—crucial for real-time embedded applications.
7.8. SMOOTHING DATA 43
Exercises
1. What is a voltage divider and when is it necessary in an Arduino circuit?
2. Your temperature sensor readings are fluctuating wildly. How will you debug and smooth
this data using a running average?
3. You want to measure a 12V battery using Arduino (max 5V). Calculate R1 and R2, and
explain what happens if you apply 12V directly.
4. What if the resistance of your LDR changes non-linearly with light? How does this affect
the map() function output?
Chapter 8
44
8.2. DETECTING MOTION (PIR SENSOR) — WITH DEBOUNCE 45
12 void loop () {
13 int val = digitalRead ( inputPin );
14
15 // ﺭﺓ ﺍ ﺍﺀﺍﺕ ﺍ millis ﺍﻡ ﺍ
16 if (val == HIGH && ( millis () - lastMotionTime > motionCooldown )) {
17 digitalWrite (ledPin , HIGH); // ﻑ ﺍ LED ﺇ ﺀﺓ
18 Serial . println (" Motion detected !");
19 lastMotionTime = millis (); // ﻑ ﻭ ﺁ ﺍ
20 delay (100); // (stabilization) ﺍ ﺍﺀﺓ
21 } else if (val == LOW) {
22 digitalWrite (ledPin , LOW);
23 }
24 }
Caution
Why delay(100) after detection? PIR sensors like the HC-SR501 have a built-in delay
potentiometer, but the output signal can still experience brief glitches when motion starts
or stops. Adding a small delay(100) or, preferably, the millis() cooldown shown above
prevents the sensor from triggering dozens of times in quick succession. Always prefer
millis() to keep your main loop responsive.
1. Physically separated the PIR sensor from the ESP8266 antenna by 15cm.
3. Implemented a software rule: ignore motion triggers lasting less than 1500ms (real
motion sustains the signal longer than RF noise).
Wokwi Simulation: You can model the false trigger logic here: [Link]
projects/pir-noise
Insight
The HC-SR501 PIR features two potentiometers:
• Time Delay: Adjusts how long the output stays HIGH (5s–5min).
A jumper selects repeatable trigger (H) vs. single trigger (L). For most projects, set the
jumper to H and implement a software cooldown with millis().
46 CHAPTER 8. GETTING INPUT FROM SENSORS
Insight
The speed of sound is approximately 340 m/s, or 29 microseconds per centimeter. The
ultrasonic ping travels out and back, so we divide by 2. Formula: d = t×c
2 .
1 void loop () {
2 int value = analogRead ( inPin );
3 float millivolts = ( value / 1024.0) * 5000;
4 float celsius = millivolts / 10; // ﺩﺭ 10
5 float fahrenheit = ( celsius * 9) / 5 + 32;
6 Serial .print ( celsius );
7 Serial .print (" C, ");
8 Serial .print ( fahrenheit );
9 Serial . println (" F");
10 delay (1000) ;
11 }
ﺀﺍ ﺩﻱ ﺃ ﺍ ﺍ ـ ﺩisnan() ﺍﻡ ﺍ ﺍ ﺍ ﺍ ﺍ ﺇ ،ﺱ ﺍﺀﺓ ﺍ
:ﺕ ﺍ
Insight
Installing the DHT Library (Required):
1. Open Arduino IDE → Sketch > Include Library > Manage Libraries.
3. Install the one by Adafruit (also install “Adafruit Unified Sensor” if prompted).
1 # include <DHT.h>
2 # include <math.h> // isnan() ﺍ
3
4 # define DHTPIN 2 // ﺕ ﺍ
5 # define DHTTYPE DHT11 // ﺱ ﺍ DHT22 ﺃﻭ
6
7 DHT dht(DHTPIN , DHTTYPE );
8
9 void setup () {
10 Serial .begin (9600) ;
11 [Link] (); // ﺱ ﺍ
12 }
13
14 void loop () {
15 delay (2000) ; // ﺍ ﺍﺀﺍﺕ ﺭ ﺍ
16
17 float h = dht. readHumidity (); // ﺍﺀﺓ ﺍ
18 float t = dht. readTemperature (); // ﺍﺀﺓ ﺍ ﺍﺭﺓ
19
20 // ﺍ ﺍﺀﺓ ﺍ
21 if (isnan(h) || isnan (t)) {
22 Serial . println (" Failed to read from DHT sensor !");
23 return ;
24 }
25
26 Serial .print (" Humidity : ");
27 Serial .print (h);
28 Serial .print ("% Temperature : ");
29 Serial .print (t);
30 Serial . println (" C");
31 }
48 CHAPTER 8. GETTING INPUT FROM SENSORS
Caution
The DHT11 is slow—you must wait at least 1–2 seconds between readings. Reading faster
returns NaN values. The DHT22 is more accurate (±0.5◦ C vs ±2◦ C) and covers a wider
operational range.
1 const int distanceTable [] = {150 , 140, 130, 100, 60, 50, 40, 35, 30, 25, 20, 15,
10}; // ﺍ
13
2
3 int getDistance (int mV) {
4 int index = mV / 250;
5 if (index > 11) index = 11; // ﻭﺩ ﺍ ﻭﺯ
6 float frac = (mV % 250) / 250.0;
7 return distanceTable [ index] -
8 (( distanceTable [ index ] - distanceTable [index + 1]) * frac);
9 }
Insight
Installing the MFRC522 Library:
3. Install it.
Caution
The MFRC522 module operates strictly at 3.3V. Connecting VCC to 5V will destroy
the chip. The SPI logic lines (SCK, MOSI, MISO, SS) are 5V-tolerant and can connect
directly to Arduino Uno’s 5V logic.
1 # include <SPI.h>
2 # include <MFRC522 .h>
3
4 # define SS_PIN 10
5 # define RST_PIN 9
6 MFRC522 mfrc522 (SS_PIN , RST_PIN ); // ﺍ ﺭﺉ ﺇ ﺀ
7
8 void setup () {
9 Serial .begin (9600) ;
10 [Link] (); // SPI ﺀ
11 mfrc522 . PCD_Init (); // ﺍ ﺭﺉ
12 Serial . println ("Scan RFID card ...");
13 }
14
15 void loop () {
16 // ﺓ ﺍ
17 if (! mfrc522 . PICC_IsNewCardPresent ()) return ;
18 if (! mfrc522 . PICC_ReadCardSerial ()) return ;
19
20 // [Link] ﺍﻡ UID ﺍﺀﺓ
21 Serial .print ("Card UID:");
22 String content = "";
23 for (byte i = 0; i < mfrc522 .[Link]; i++) {
24 Serial .print( mfrc522 .uid. uidByte [i] < 0x10 ? " 0" : " ");
25 Serial .print( mfrc522 .uid. uidByte [i], HEX);
26 content . concat ( String ( mfrc522 .uid. uidByte [i] < 0x10
27 ? " 0" : " "));
28 content . concat ( String ( mfrc522 .uid. uidByte [i], HEX));
29 }
30 Serial . println ();
31 content . toUpperCase ();
32
33 // ﺍ
34 if ( content . substring (1) == "4D 55 AD D3 66") {
35 Serial . println (" Authorized access ");
36 } else {
50 CHAPTER 8. GETTING INPUT FROM SENSORS
Insight
For encoders in busy sketches, use hardware interrupts (attachInterrupt()) instead of
polling. Variables modified inside Interrupt Service Routines (ISRs) must be declared
volatile.
Exercises
1. What does it mean for a PIR sensor to ”bounce”, and why is debouncing necessary?
2. You connected a PIR sensor and found it triggers false alarms continuously. How will you
fix this in code using millis()?
3. Compare using DHT11 vs LM35 in a project requiring high accuracy and fast response.
What happens if you read the DHT11 every 500ms?
4. What if you power the MFRC522 RFID module with 5V instead of 3.3V? What permanent
damage occurs?
Chapter 9
Visual Output
Insight
PWM (Pulse Width Modulation) does not reduce voltage; it rapidly switches the pin on
and off. The duty cycle determines the perceived brightness. At 50% duty cycle (value
127), the LED is on half the time.
Insight
52
9.3. CONTROLLING RGB LEDS 53
Exercises
1. What is a duty cycle in the context of Pulse Width Modulation (PWM)?
2. How would you debug an RGB LED code that outputs incorrect colors? How does this
relate to the LED type (Common Anode vs Common Cathode)?
3. You need to control 16 LEDs using an Arduino Uno. How will you use a 74HC595 shift
register to minimize pin usage?
4. What if you try to drive a full 8x8 LED matrix continuously at once? How does multi-
plexing solve this visually?
Chapter 10
Physical Output
1 void loop () {
2 int val = analogRead ( potpin );
3 val = map(val , 0, 1023 , 0, 179);
4 myservo .write (val);
5 delay (15);
6 }
55
56 CHAPTER 10. PHYSICAL OUTPUT
D5 (IN1) IN1
D6 (IN2) IN2
D9 (ENA) ENA
Arduino H-Bridge (L298N) Motor
OUT1
OUT2
1 int solenoidPin = 2;
2
3 void setup () {
4 pinMode ( solenoidPin , OUTPUT );
5 }
6
7 void loop () {
8 digitalWrite ( solenoidPin , HIGH); //
9 delay (1000) ;
10 digitalWrite ( solenoidPin , LOW); // ﺇ ﺀﺍ
11 delay (3600000) ; //
12 }
Caution
When driving inductive loads (motors, solenoids, relays), always use a flyback diode (
)ﺍacross the load. Without it, back-EMF voltage spikes can destroy your transistor or
Arduino.
Exercises
1. What is a flyback diode and why is it used with inductive loads?
2. You are driving a DC motor via a transistor and notice the Arduino resets randomly. What
missing component caused this?
3. You need to move a servo while simultaneously reading a sensor. How will you design the
timing loop to prevent blocking delays?
4. What if you set both IN1 and IN2 to HIGH on an H-bridge simultaneously? What fault
occurs?
Chapter 11
Audio Output
58
11.3. CONTROLLING MIDI 59
Hands-On Project
Project: Arduino Melody
Wokwi Simulation
Steps:
Common Mistakes:
• No sound: Buzzer is polarity-sensitive. Ensure the red wire goes to the pin.
• Choppy audio: Using delay() inside the loop instead of non-blocking timers.
Extension Ideas:
Exercises
1. What is the relationship between frequency and the pitch of a tone?
2. How would you fix a melody that sounds choppy and broken? What is the relationship
between this and the delay() function used after tone()?
3. Design a door that plays a different tone when opened vs closed. How will you decouple
the audio logic so the tone plays while checking a motion sensor?
4. What if you try to play two different tones on the same pin simultaneously? What happens
in the Arduino hardware?
Part IV
61
Overview: Part IV
This part covers how Arduino communicates with other devices—your computer, peripheral
microcontrollers, and the Internet. We explore serial communication, I2C, SPI, wireless protocols
(Bluetooth, Wi-Fi), and modern IoT platforms like ThingSpeak and MQTT. These skills are
essential for building networked projects and IoT devices.
62
Chapter 12
Serial Communications
1 void setup () {
2 Serial .begin (9600) ;
3 }
4 void loop () {
5 Serial .print ("The number is ");
6 Serial . println ( number );
7 delay (500);
8 number ++;
9 }
1 void loop () {
2 if ( Serial . available ()) {
3 char ch = Serial .read ();
4 if (ch >= '0' && ch <= '9') {
5 blinkRate = (ch - '0') * 100;
6 }
7 }
8 blink ();
9 }
63
64 CHAPTER 12. SERIAL COMMUNICATIONS
Exercises
1. What is the baud rate, and why must the sender and receiver match it?
2. You are reading sensor data to send to a PC, but the text appears garbled in the Serial
Monitor. How will you fix this baud rate mismatch issue?
3. You need to send data prone to noise. Compare sending ASCII text vs Binary data, and
design a packet structure with a header and checksum.
4. What if you call [Link]() when no data is available? What value does it return,
and how does it corrupt your buffer logic?
Chapter 13
Using Displays
1 void loop () {
2 for (int pos = 0; pos < textLen ; pos ++) {
3 lcd. scrollDisplayLeft ();
4 delay (150);
5 }
6 }
65
66 CHAPTER 13. USING DISPLAYS
10
11 void loop () {
12 lcd. setCursor (0, 0);
13 [Link] (0);
14 delay (500);
15 }
Hands-On Project
Project: LCD Screen Writer
Wokwi Simulation
Steps:
• Blank screen / White boxes: Contrast too high/low. Adjust the 50kΩ potentiometer
connected to V0.
Extension Ideas:
Exercises
1. What is the purpose of the [Link]() function?
2. Your LCD screen only shows white boxes and no text. How will you debug and fix this
hardware issue? Which component needs adjustment?
3. Design an LCD menu navigated with buttons. How will you fix the screen freezing when
holding a button down due to a blocking delay() used for debouncing?
4. What if you need more than 8 custom characters on a standard 16x2 LCD? What is the
workaround?
Chapter 14
1 delay (1000) ; //
2 delayMicroseconds (10); // ﻭ 10
Caution
The delay() function halts the entire microcontroller. For projects requiring simultaneous
operations, use millis() instead.
68
14.3. MEASURING PULSE DURATION 69
14 }
Insight
This pattern—checking elapsed time with millis()—is one of the most critical techniques
in Arduino programming. It enables cooperative multitasking.
1 # include <Wire.h>
2 # include <DS1307TM `C.h>
3
4 void setup () {
5 setSyncProvider ([Link]);
6 if ( timeStatus () != timeSet )
7 Serial . println (" Unable to sync with RTC");
8 }
9
10 void loop () {
11 digitalClockDisplay ();
12 delay (1000) ;
13 }
Exercises
1. What is the difference between delay() and millis() in terms of program execution?
2. How would you debug an alarm system relying on an RTC (DS1307) that loses the correct
time when powered off? What missing component is causing this?
3. You wrote code to perform two independent tasks using delay(). How does this break
timing synchronization, and how will you optimize it using a cooperative multitasking
state machine?
4. What if you use pulseIn() to measure a very short pulse? Why might it freeze your main
loop, and what is the alternative?
Chapter 15
+3.3V/+5V
Slave 10x68
4.7k
SDA
Master
SCL
Common GND between all devices Slave 20x76
1 # include <Wire.h>
2
3 void setup () {
4 [Link] (); // master ﻡ ـ ﺍ
5 }
6
7 void loop () {
8 Wire. beginTransmission (0 x68);
9 [Link] (0 x00);
10 Wire. endTransmission ();
11
12 Wire. requestFrom (0x68 , 7);
13 while (Wire. available ()) {
14 int data = [Link] ();
15 }
16 }
70
15.2. SPI COMMUNICATION 71
1 # include <SPI.h>
2
3 void setup () {
4 [Link] ();
5 pinMode ( slaveSelect , OUTPUT );
6 }
7
8 void sendCommand (int command , int value ) {
9 digitalWrite ( slaveSelect , LOW);
10 SPI. transfer ( command );
11 SPI. transfer ( value );
12 digitalWrite ( slaveSelect , HIGH);
13 }
Slave:
72 CHAPTER 15. COMMUNICATING USING I2C AND SPI
1 void setup () {
2 [Link] (4);
3 Wire. onReceive ( receiveEvent );
4 }
5
6 void receiveEvent (int howMany ) {
7 while (Wire. available () > 0) {
8 char c = [Link] ();
9 Serial .print(c);
10 }
11 }
Exercises
1. What is the difference between I2C and SPI in terms of pin count?
2. You connected an I2C sensor, but it doesn’t show up. How will you use an I2C Scanner
to debug this, and what is the most common wiring mistake?
3. You want to connect two identical I2C sensors with the same fixed address. How will
you resolve this address conflict electrically, and when would you choose SPI over I2C for
high-speed data acquisition?
4. What if you omit the pull-up resistors on the I2C bus? How does signal integrity affect
the data?
Chapter 16
Wireless Communication
Insight
Wiring HC-05 to Arduino:
• GND → GND
Important: Use SoftwareSerial on pins 2, 3 so you can retain hardware serial for
debugging.
73
74 CHAPTER 16. WIRELESS COMMUNICATION
Hands-On Project
Project: Smartphone-Controlled LED
Wokwi Simulation
Steps:
Common Mistakes:
• Garbage characters on Serial Monitor: Baud rate mismatch. Try 9600 or 38400.
Exercises
1. What is AT mode in the context of HC-05 Bluetooth modules?
2. You connected an HC-05 module and found it receives garbage characters. How will you
debug the baud rate mismatch?
3. Why is connecting the HC-05’s RXD pin directly to Arduino’s TX a destructive decision?
How will you design a voltage divider to protect it?
4. What if you send temperature data via 433MHz RF without a checksum? How does data
loss manifest in the receiver?
Chapter 17
1 # include <SPI.h>
2 # include <Ethernet .h>
3
4 byte mac [] = {0xDE , 0xAD , 0xBE , 0xEF , 0xFE , 0xED };
5 byte ip [] = {192 , 168, 1, 177};
6
7 void setup () {
8 Ethernet .begin(mac , ip);
9 Serial .begin (9600) ;
10 }
76
17.2. WEB SERVER 77
Exercises
1. What is the role of an IP address and MAC address in networking?
2. Your web server stops responding after a few requests. How will you debug and fix the
resource leak related to [Link]()?
3. In a small web server project controlling a door lock, when do you use HTTP GET vs
POST? Design the endpoint logic to ensure the lock command is secure and not accidentally
triggered by caches.
4. What if you serve a very large HTML page via the Ethernet shield? How does buffer size
affect the transmission, and how would you chunk the data?
Chapter 18
The ESP8266 (ESP8266 )ﻭ ﺓis a low-cost Wi-Fi microcontroller that revolutionized the IoT
landscape. Boards like NodeMCU and Wemos D1 Mini cost $3–5 and integrate Wi-Fi, GPIO,
ADC, and USB programming. They can be programmed directly from the Arduino IDE.
Insight
Installing ESP8266 Board Support:
78
18.1. CONNECTING TO WI-FI 79
Insight
ThingSpeak Setup:
MQTT (MQTT ) ﻭ ﻝis a lightweight publish/subscribe messaging protocol ideal for IoT.
Devices publish data to topics, and other devices subscribe to receive that data.
OTA allows updating ESP8266 firmware over Wi-Fi without a physical USB connection. Here
is the local network method using ArduinoOTA.
82 CHAPTER 18. IOT WITH ESP8266 AND WI-FI
Insight
Exercises
1. What is the MQTT protocol and how does the pub/sub model work?
2. You connected a sensor to the D8 pin on a NodeMCU and found it fails to boot. How will
you fix this based on your understanding of boot pins?
3. You are sending data to ThingSpeak but notice intermittent HTTP errors. Design a robust
reconnect logic to handle temporary Wi-Fi drops, and explain how to prevent bricking the
board during OTA updates.
4. What if the MQTT broker goes offline? How does your reconnect() function handle the
blocking delay(5000) without freezing the main loop?
Chapter 19
Data logging (ﺍ ﺕ ) is essential for field projects like weather stations, where you must
record sensor readings over time for later analysis.
Insight
SD Card Module (SPI) Wiring:
• GND → GND
• MISO → Pin 12
• MOSI → Pin 11
• SCK → Pin 13
• CS → Pin 10
Card format: Format your microSD card as FAT16 or FAT32 before use.
1 # include <SPI.h>
2 # include <SD.h>
3
4 const int chipSelect = 10;
5
6 void setup () {
7 Serial .begin (9600) ;
8
9 Serial .print (" Initializing SD card ...");
10 if (! [Link] ( chipSelect )) {
11 Serial . println ("Card failed , or not present ");
12 return ;
13 }
14 Serial . println ("Card initialized .");
83
84 CHAPTER 19. SD CARD DATA LOGGING
15 }
16
17 void loop () {
18 // ﺕ ﺍﺀﺓ ﺍ
19 float temp = analogRead (A0) * 5.0 / 1023.0 * 100;
20
21 // ( ﺍ )ﺇ ﺍ
22 File dataFile = [Link](" datalog .txt", FILE_WRITE );
23
24 if ( dataFile ) {
25 dataFile . print ( millis ());
26 dataFile . print (",");
27 dataFile . println (temp);
28 dataFile . close (); // ﺕ ﺍ ﺍ ﺃ:
29
30 Serial .print(" Logged : ");
31 Serial . println (temp);
32 } else {
33 Serial . println ("Error opening datalog .txt");
34 }
35
36 delay (5000) ; // ﻥ
ٍ ﺍ5
37 }
Caution
SD Card Best Practices:
• Do not open/close files too rapidly; it wears out the flash memory.
• Use a separate 5V supply for the SD module if you experience voltage brownouts.
Exercises
1. What is the 8.3 filename format, and why is it required for SD cards?
2. You logged data to an SD card, but after a power loss, the file is empty. How will you fix
this file handling bug?
3. The Arduino resets when trying to write to the SD card. Identify the likely hardware cause
(Voltage Brownout) and design a power management solution to prevent flash memory
wear-out.
4. What if you open and close the file 1000 times a second? How does this affect the flash
memory lifespan?
Part V
Advanced Topics
85
Overview: Part V
In this advanced section, we go under the hood. We cover memory management (PROGMEM,
EEPROM), hardware interrupts, digital signal processing (DSP), direct register manipulation,
and best practices including version control with Git.
86
Chapter 20
3. Click Install.
Caution
Library Updates: Sensor libraries (especially RFID and DHT) receive frequent updates.
If your code breaks after an IDE update, check for library updates in the Library Manager.
Always read the library’s README for breaking changes.
87
88 CHAPTER 20. USING, MODIFYING, AND CREATING LIBRARIES
Exercises
1. What is the difference between a header (.h) file and a source (.cpp) file?
2. After updating a sensor library in the Library Manager, your code breaks. How will you fix
this without manually reverting to old versions? What must you check in the README?
3. Why do we separate interface and implementation when creating a library? Design a library
structure that abstracts hardware specifics to make the main sketch more readable.
4. What if you put all your library code in a single .h file? What multiple definition errors
occur during linking if it’s included in multiple files?
Chapter 21
Insight
The Arduino Uno has only 2KB of RAM. The memoryFree() function indicates available
RAM. If your sketch behaves erratically, suspect memory exhaustion.
89
90 CHAPTER 21. ADVANCED CODING AND MEMORY HANDLING
Example
Using the F() Macro for Serial Printing
1 Serial . println (F("This string is stored in flash memory and saves RAM!"));
1 # define DEBUG
2
3 void loop () {
4 #if defined DEBUG
5 Serial . println (val); // DEBUG ﺇﺫﺍ ُ
6 #endif
7 }
8
9 #if defined ( __AVR_ATmega1280__ )
10 numberOfSensors = 16; // Arduino Mega
11 #else
12 numberOfSensors = 6; // Arduino Uno
13 #endif
Insight
Why Git? As your projects grow, tracking changes becomes critical. Git ( ﻡﺍ
ﺍﺭﺍﺕ )ﺍlets you:
• Save snapshots of your code at any point.
Exercises
1. What is heap fragmentation and how does it affect an Arduino sketch?
2. Your project works for 2 hours then crashes and resets. How do you suspect ”Heap
Fragmentation” caused by String is the culprit, and how will you fix it using the F()
macro and PROGMEM?
3. How would you debug code that works perfectly on an Arduino Uno but gives wrong
values on an ESP8266 due to different int sizes? Design a cross-platform solution using
conditional compilation.
4. What if you track versions via Git but accidentally commit a build artifact (like the .hex
file)? How does a .gitignore file solve this?
Chapter 22
Sensors are inherently noisy. Whether dealing with a jittery ultrasonic sensor or fluctuating
temperature readings, processing raw analog or digital signals in software is crucial for stable
system behavior.
Insight
How Alpha (α) works:
92
22.3. PRACTICAL APPLICATION: SMOOTHING ULTRASONIC SENSOR 93
• If α = 0.1, the filter is highly smooth but responds slowly to sudden changes.
Exercises
1. What is the difference between a Moving Average filter and an Exponential Moving Average
(EMA)?
2. Your robot’s distance sensor gives sudden ghost spikes. How will you apply an EMA filter
to fix and smooth this data?
3. What if you set the Alpha (α) value in the EMA filter to 0.01? Analyze the engineering
trade-off between responsiveness and noise reduction in memory-constrained systems.
4. What if you use a Moving Average array of size 100 on an Arduino Uno? How does this
impact the 2KB RAM limit?
Chapter 23
Insight
The ATmega328P has 1KB of EEPROM that persists across power cycles. EEPROM
has limited write endurance (≈100,000 writes per cell). Use it for configuration data, not
rapidly changing sensor data.
Caution
Variables modified inside an ISR must be declared volatile. Keep ISRs exceptionally
short.
94
23.3. TIMER INTERRUPTS 95
Why you cannot use delay() inside an ISR: delay() relies on timer interrupts,
which are automatically disabled inside ISRs. Calling delay() inside an ISR will cause
an infinite hang.
Caution
Faster analog reads trade precision for speed. Test your application to determine if this
trade-off is acceptable.
Insight
digitalWrite() takes ≈5µs per call. Direct port manipulation takes ≈0.125µs—40x
faster! Use this only when maximum speed is required.
Exercises
1. What is the volatile keyword used for in embedded C++?
2. You placed a delay(1000) inside an ISR and found the board freezes completely. How
will you fix this design flaw? Why is delay() forbidden inside interrupts?
3. You need to write data to EEPROM that exceeds 100,000 times a day. Design a wear-
leveling algorithm, and justify when Direct Port Manipulation is preferred over digitalWrite().
4. What if you manipulate the ADC prescaler to read analog values much faster? What
trade-off in precision occurs?
Part VI
Hands-On Projects
97
Overview: Part VI
This final part applies everything you have learned. We build a variety of projects, from beginner
builds to an advanced IoT capstone project. We also cover how to design custom PCBs to make
your projects permanent.
98
Chapter 24
Beginner Projects
Wokwi Simulation
Estimated Cost: $6
Bill of Materials (BOM):
Common Mistakes: Connecting the potentiometer to a non-PWM pin. Pin 9 must be used
for analogWrite.
99
100 CHAPTER 24. BEGINNER PROJECTS
Common Mistakes: Leaving the moisture sensor constantly powered causes rapid corrosion.
Power it from a digital pin and turn it on only during reading.
Exercises
1. Add a third LED color (yellow) to the strobe light.
2. Modify the plant monitor to send data to Serial Monitor every 5 minutes.
Intermediate Projects
102
25.4. PROJECT: REMOTE CONTROL SERVO 103
16 delay (15);
17 }
1 # include <DHT.h>
2 # include <LiquidCrystal .h>
3
4 # define DHTPIN 8
5 # define DHTTYPE DHT11
6 DHT dht(DHTPIN , DHTTYPE );
7 LiquidCrystal lcd (12 , 11, 5, 4, 3, 2);
8
9 void setup () {
10 [Link] ();
11 [Link] (16 , 2);
12 }
13
14 void loop () {
15 delay (2000) ; // ﺍ ﺍﺀﺍﺕ ﺍ:
16 float h = dht. readHumidity ();
17 float t = dht. readTemperature ();
18
19 if (isnan(h) || isnan (t)) {
20 [Link] (" Sensor error ");
21 return ;
22 }
23
24 lcd. setCursor (0, 0);
25 [Link]("Hum: ");
26 [Link](h);
27 [Link]("%");
28 lcd. setCursor (0, 1);
29 [Link]("Temp: ");
30 [Link](t);
104 CHAPTER 25. INTERMEDIATE PROJECTS
31 [Link]("C");
32 }
Common Mistakes: Reading DHT11 faster than every 2 seconds causes NaN errors.
Exercises
1. Add sound effects to the memory game.
Security Projects
1 void loop () {
2 val = digitalRead ( inputPin );
3 if (val == HIGH) {
4 digitalWrite (ledPin , HIGH);
5 playTone (300 , 160);
6 delay (150); // ﺍ ﺍﺀﺓ
7 } else {
8 digitalWrite (ledPin , LOW);
9 playTone (0, 0);
10 delay (300);
11 }
12 }
105
106 CHAPTER 26. SECURITY PROJECTS
1 # include <SPI.h>
2 # include <MFRC522 .h>
3 # include <Servo .h>
4
5 # define SS_PIN 10
6 # define RST_PIN 9
7 MFRC522 mfrc522 (SS_PIN , RST_PIN );
8 Servo doorLock ;
9
33 if ( cardMatch ) {
34 digitalWrite (LED_access , HIGH);
35 doorLock . write (180); // ﺍ ﺏ
36 delay (5000) ;
37 doorLock . write (0);
38 digitalWrite (LED_access , LOW);
39 } else {
40 digitalWrite ( LED_intruder , HIGH);
41 tone(buzzerPin , 200, 1000);
42 delay (1000) ;
43 digitalWrite ( LED_intruder , LOW);
44 }
45
46 mfrc522 . PICC_HaltA ();
47 mfrc522 . PCD_StopCrypto1 ();
48 }
Common Mistakes: Forgetting to share GND between Arduino and the external power supply
driving the lock. Connecting MFRC522 to 5V destroys it instantly.
Exercises
1. Add a 3-attempt lockout to the keypad entry system.
Advanced Projects
Insight
Building a standalone Arduino is the ultimate demonstration of understanding the plat-
form. The ATmega328P chip is the Arduino—everything else is support circuitry.
108
Chapter 28
Once your breadboard prototype works, the next step is making it permanent. While you can
use perfboard, designing a custom Printed Circuit Board (PCB) provides a professional, reliable
finish.
3. Place components (symbols) from the libraries: microcontrollers, resistors, capacitors, con-
nectors.
4. Route the traces (wires) connecting the pads. Green lines indicate ratsnest connections.
5. Add a ground pour (copper fill) to reduce noise and save etching material.
6. Run the Design Rule Checker (DRC) to ensure no overlaps or unconnected nets.
109
110 CHAPTER 28. DESIGNING CUSTOM PCBS WITH KICAD
• Keep trace widths at least 0.25mm (10mil) for signals, and 0.5mm+ for power lines.
• Silkscreen labels (pin names, component values) will save you hours of debugging
later.
• 1x DHT22 ($3)
• I2C LCD not showing text: NodeMCU I2C pins are D1 (SCL) and D2 (SDA). Wiring
them backward is a common error.
• NaN readings from DHT22: The DHT22 requires a minimum 2-second interval. Using
delay() inside the web server handler will cause the server to crash. Use the millis()
timer as shown.
Exercises
1. Add SD card logging to the capstone project.
Reference
113
Overview: Reference
This final part contains quick references, troubleshooting guides, and solutions to all exercises
presented in the book.
114
Chapter 29
Troubleshooting Flowchart
Insight
What to do when your project doesn’t work. Follow this flowchart systematically
before asking for help.
115
116 CHAPTER 29. TROUBLESHOOTING FLOWCHART
Power No
Check USB cable, battery, barrel jack
LED on?
Yes
Yes
Uploads No
Check COM port, board type, drivers
successfully?
Yes
Serial No
Monitor Check baud rate, [Link](), wiring
shows data?
Yes
Components
No Check wiring, polarity, re-
respond
sistor values, voltage levels
correctly?
Yes
Caution
Common Pitfalls Checklist:
• Forgot [Link](9600)
Quick Reference
118
30.3. TYPICAL VOLTAGE AND CURRENT VALUES 119
Caution
Arduino Uno max current per pin: 40 mA (absolute max 20 mA recom-
mended).
Never draw more than 200 mA total from all pins combined. For higher current devices
(motors, relays, long LED strips), always use a transistor, MOSFET, or relay driver.
120 CHAPTER 29. TROUBLESHOOTING FLOWCHART
From To Formula
Celsius Fahrenheit F = C × 9/5 + 32
Fahrenheit Celsius C = (F − 32) × 5/9
Celsius Kelvin K = C + 273.15
Inches cm cm = inches × 2.54
cm Inches inches = cm/2.54
Feet cm cm = f eet × 30.48
Table 30.4: Temperature and Length Conversion
Troubleshooting Guide
123
Chapter 32
Caution
Simulators are excellent for testing logic, but they cannot perfectly model real-world
physics (noisy sensors, voltage drops, transient currents). Always verify your design on
physical hardware.
124
Chapter 33
• ThingSpeak: [Link]
• ThingSpeak by MathWorks
125
Chapter 34
Glossary
126
Chapter 35
Exercise Solutions
1. [Direct] The setup() function runs only once when the board is powered on or reset. It
is used to initialize pin modes, configure serial communication, and set up libraries. The
loop() function runs continuously immediately after setup() finishes, executing the main
logic of the sketch over and over.
2. [Debug] The LED appears continuously on because removing the delays causes the pin to
toggle thousands of times per second. The human eye cannot process such rapid flashing
(persistence of vision), so it merges into a dim glow. To fix this without blocking delays,
use the millis() function to track time and toggle the LED only when a specific interval
has passed:
3. [Design] Design the traffic light as a state machine. Use a variable to track the current
state (RED, GREEN, YELLOW, EMERGENCY). In the loop(), check the button state.
If pressed, switch to EMERGENCY mode. To avoid blocking the button read while
the yellow light flashes, use millis() to toggle the yellow LED, allowing the code to
continuously monitor the button for a second press to exit emergency mode.
4. [What If] From my experience, applying 12V directly to the 5V pin completely bypasses
the voltage regulator. The ATmega328P chip is rated for an absolute maximum of 5.5V.
Applying 12V will cause a massive current surge through the silicon, permanently frying
the microcontroller and likely producing a distinct burning smell. Always use the Vin pin
or barrel jack for voltages above 5V.
1. [Direct] Integer overflow occurs when a variable exceeds its maximum storage capacity.
For an Uno, a 16-bit signed int maxes at 32,767. Adding 1 makes it ”roll over” to -32,768,
causing catastrophic logic failures in calculations.
2. [Debug] The String class dynamically allocates memory on the heap. Over an hour,
repeated concatenation and manipulation create ”holes” in the RAM (heap fragmentation),
127
128 CHAPTER 35. EXERCISE SOLUTIONS
eventually causing the system to run out of memory and crash. The fix is to replace
String with C-style character arrays (char[]) and use strcpy() and strcat(), which
do not fragment memory.
3. [Design] A standard int (max 32,767) will fail and roll over to negative numbers. The
appropriate data type is unsigned long, which occupies 4 bytes and can track values up
to 4,294,967,295. This provides a safe margin for a 100,000-event counter without risking
overflow.
4. [What If] Using a float for currency is a bad engineering practice. Floating-point math
on Arduino is not perfectly precise (e.g., 0.1 + 0.2 might equal 0.1999999). Over thousands
of transactions, these microscopic rounding errors accumulate into significant financial
discrepancies. The correct design is to use unsigned long to track currency in cents (e.g.,
$10.50 stored as 1050) and only convert to decimals during display.
2. [Debug] The local variable is being re-initialized to 0 on every function call. To fix
this, declare the variable as static (e.g., static int counter = 0;). A static variable
maintains its value between function calls while keeping its scope local, preventing it from
polluting the global namespace.
3. [Design] You must pass the array by reference. In C/C++, passing an array by its name
actually passes a pointer to its first element. If you pass by value, the compiler attempts to
copy the entire array into the stack, consuming massive amounts of scarce RAM. Passing
by reference (int processArray(int* arr) or int processArray(int arr[])) simply
passes the memory address, taking only 2 bytes.
4. [What If] If you declare a variable inside loop() without static, the compiler allocates
memory for it on the stack every single time the loop iterates, and destroys it when the
loop ends. While this is safe, it is inefficient if the variable needs to retain its state. It also
increases the CPU overhead slightly due to repeated stack frame creation.
3. [Design] switch-case is highly efficient for discrete integer values (like 5 specific robot
modes) because it uses jump tables. However, it cannot evaluate ranges (e.g., if (temp
> 30 && temp < 50)) or floats. If your robot modes depend on continuous sensor ranges,
you must use if-else if chains.
129
4. [What If] A while loop that never becomes false creates an infinite loop inside loop().
This completely blocks the Arduino from reading new sensors, updating outputs, or com-
municating. The board appears frozen. The solution is to ensure the loop condition is
updated inside the block, or use a break statement based on a timeout.
1. [Direct] Integer division truncates the decimal completely (3 / 2 yields 1). Floating-point
division preserves the fractional part (3.0 / 2 yields 1.5).
2. [Debug] The expression 5 / 1023 evaluates as integers, yielding 0. Multiplying the sensor
value by 0 always results in 0. The fix is to force floating-point math by making at least
one operand a float: float voltage = sensorValue * (5.0 / 1023.0);.
3. [Design] First, use constrain(sensorValue, 0, 1023) to ensure the input never ex-
ceeds expected ADC bounds. Then, apply map(constrainedValue, 0, 1023, 0, 180)
to scale it to the servo angle. This protects the servo from receiving out-of-bounds signals
that could damage its gears if the sensor shorts out.
4. [What If] If you use a constant value like randomSeed(42), the pseudo-random number
generator starts from the exact same mathematical state on every boot. Your project will
generate the exact same sequence of ”random” numbers every time it is powered on. To fix
this, seed it with electrical noise from an unconnected analog pin: randomSeed(analogRead(A0));.
1. [Direct] In a Pull-up configuration, the pin reads HIGH when the button is open and
LOW when pressed. In a Pull-down configuration, the pin reads LOW when open and
HIGH when pressed.
2. [Debug] Using delay(20) freezes the entire microcontroller for 20 milliseconds per column
scan, making the system unresponsive to other critical tasks. The fix is to implement a
non-blocking state machine using millis() to track when a key was first pressed, and only
register the press if 20ms have passed, allowing the rest of the loop() to run concurrently.
3. [Design] The bouncing causes multiple rapid state changes. Design an edge-detection
algorithm: store the lastButtonState. Only register a toggle when the current state
differs from the last state AND a millis() debounce timer has expired. This ensures only
one toggle event per physical press.
4. [What If] The pin becomes a ”floating” input. Without a pull-up or pull-down resistor,
the pin acts as an antenna, picking up ambient electromagnetic noise. The digitalRead()
value will rapidly fluctuate between HIGH and LOW unpredictably, causing your logic to
trigger randomly even when the button isn’t touched.
1. [Direct] A voltage divider is a simple resistive circuit that scales down a high input voltage
to a lower, safe output voltage. It is necessary when reading sensors that operate above
5V or resistive sensors (like LDRs) that change resistance rather than voltage.
130 CHAPTER 35. EXERCISE SOLUTIONS
2. [Debug] To smooth the data, implement a Running Average filter using an array of recent
readings. Every loop, subtract the oldest reading from a running total, add the new reading,
and divide by the array size. It is an O(1) operation because the math complexity does
not increase regardless of how many samples are in the array.
3. [Design] To drop 12V to a safe level (under 5V), use R1 = 10kΩ and R2 = 4.7kΩ. This
yields an output of 12 × (4.7/14.7) ≈ 3.8V . If you apply 12V directly, you will exceed the
ATmega328P’s absolute maximum rating, permanently destroying the microcontroller pin
or the entire chip.
4. [What If] The map() function assumes a linear relationship. An LDR’s resistance changes
logarithmically with light intensity. Using map() will result in uneven, jerky brightness
steps at one end of the scale. The solution is to use a logarithmic lookup table or implement
a mathematical log transformation in software.
2. [Debug] The PIR sensor outputs a sustained HIGH signal that briefly glitches. Implement
a software cooldown using millis(). When motion is detected, record the current time.
Ignore subsequent HIGH readings until millis() - lastMotionTime > 2000 (2 seconds)
has passed. This prevents false spam to your logs or alarms.
3. [Design] The DHT11 is a digital sensor with a slow internal processor; reading it faster
than every 2 seconds returns NaN (Not a Number) errors. The LM35 is an analog sensor
providing instant readings. For a fast-response project, use the LM35. If using DHT11,
you must architect the system to update temperature in a background millis() timer
without blocking the main loop.
4. [What If] The MFRC522 operates strictly at 3.3V. Supplying 5V to its VCC pin will
instantly fry the chip’s internal logic, rendering it permanently dead. The SPI logic lines,
however, are 5V tolerant, so they can connect directly to the Arduino.
1. [Direct] The duty cycle is the percentage of time a PWM signal is HIGH during a single
cycle. A 50% duty cycle means the pin is HIGH half the time, resulting in half the
perceived brightness for an LED.
2. [Debug] If an RGB LED outputs incorrect colors (e.g., sending 255 for Red yields noth-
ing, but 0 yields full Red), you are likely using a Common Anode LED. In a Common
Anode LED, the common pin goes to 5V, so writing analogWrite(pin, 255) turns it
OFF, and 0 turns it ON. Fix the code by inverting the values: analogWrite(pin, 255 -
brightness);.
3. [Design] Daisy-chain two 74HC595 shift registers. You connect the Serial Output (Q7’)
of the first register to the Data Input (DS) of the second. They share the Latch and Clock
pins. This allows you to control 16 LEDs using only 3 Arduino pins, saving valuable GPIO
for other sensors.
131
4. [What If] Driving an 8x8 matrix continuously at once would require 64 pins, which is
impossible. Even if possible, the current draw would exceed the microcontroller’s limits.
Multiplexing solves this by turning on only one row at a time, extremely fast. The human
eye’s persistence of vision blends the rows together, making it appear as a stable image
while keeping current draw low.
2. [Debug] The missing component is the flyback diode. When the motor turns off, its
magnetic field collapses, generating a massive voltage spike that hits the Arduino’s power
rail, causing the microcontroller to brown out and reset. Fix the circuit by adding a diode
across the motor terminals.
3. [Design] Using delay(15) blocks the CPU, freezing sensor reads while the servo moves.
Design the timing using a non-blocking millis() state machine. Track the servo’s target
angle and move it one degree every few milliseconds based on elapsed time, allowing the
main loop to continuously read the sensor in between servo steps.
4. [What If] Setting both IN1 and IN2 to HIGH creates a ”shoot-through” fault. This
essentially short-circuits the power supply directly across the transistors, bypassing the
motor. Massive current flows, generating heat and permanently destroying the H-bridge
chip. The code must guarantee IN1 and IN2 are never HIGH simultaneously.
2. [Debug] The tone() function operates asynchronously in the background, but if you
immediately call delay(duration) and then play the next note, the timing might overlap
or cut off abruptly. The choppy sound is due to poor sequencing. Fix it by using millis()
to track when a note should start and stop, ensuring a brief pause (inter-note gap) between
notes for clarity.
3. [Design] Decouple the audio logic using a state machine. Define an array of notes and
durations. In the loop(), use millis() to check if it is time to play the next note.
This allows the main loop to continuously check the motion sensor between note changes,
playing the melody without freezing the sensor monitoring.
4. What If] The Arduino’s hardware timer can only generate one square wave frequency per
pin at a time. If you call tone() a second time, it simply overrides the first frequency.
You cannot play polyphonic chords on a single pin without external audio hardware or
complex software PWM.
2. [Debug] Garbled text almost always indicates a baud rate mismatch. If the Arduino is
programmed for 9600 baud, but the Serial Monitor is set to 115200, the receiver samples
the bits at the wrong intervals, producing random characters. Fix it by ensuring the value
in [Link](9600) exactly matches the dropdown menu in the Serial Monitor.
3. [Design] ASCII text is human-readable but consumes 1 byte per character (e.g., sending
”-45.2” takes 5 bytes). Binary data is compact (a float takes 4 bytes) but is not human-
readable. To ensure data integrity over a noisy channel, design a packet structure: a
Header byte (e.g., 0xAA), the Payload (binary data), and a Checksum (XOR of all payload
bytes). The receiver verifies the checksum before accepting the data.
4. [What If] If you call [Link]() when no data is available, it returns -1. If you store
this in a char array and process it, you are injecting garbage data into your logic. This is
why you must always check if ([Link]() > 0) before reading.
1. [Direct] [Link](col, row) moves the invisible text cursor to a specific column
and row on the LCD so the next printed character appears exactly there.
2. [Debug] White boxes indicate the LCD controller is powered but receiving no data, or
the contrast is too high. The component needing adjustment is the 10kΩ potentiometer
connected to the V0 (Contrast) pin. Turn the pot until the boxes disappear and text
becomes visible.
3. [Design] If a button uses delay(200) for debouncing, the entire screen freezes during
that 200ms, making the menu feel unresponsive. Replace the blocking delay with a non-
blocking millis() timer. Check the button state, record the time, and update the LCD
immediately if the state is stable, allowing the screen to refresh continuously.
4. [What If] The HD44780 LCD controller only has 8 bytes of Custom Character RAM
(CGRAM). You cannot store more than 8 custom characters at once. The workaround is
to dynamically overwrite a CGRAM slot with new character data on the fly when that
specific character needs to be displayed, swapping them in and out of memory as needed.
1. [Direct] delay() halts the entire CPU, preventing any other code from running. millis()
tracks elapsed time since boot, allowing the code to check timers and execute tasks con-
currently (cooperative multitasking).
2. [Debug] The RTC is losing time when powered off because the CR2032 backup battery is
missing or dead. Without backup power, the RTC resets to 00:00:00 on every power loss.
Fix it by inserting a fresh CR2032 coin cell.
3. [Design] Using delay() for two independent tasks breaks synchronization because the
delays stack up. Design a cooperative multitasking state machine. Maintain two sepa-
rate unsigned long variables (e.g., timer1, timer2) tracking the last execution time for
each task. In the loop(), check if millis() - timer1 > interval1 to run task 1, and
similarly for task 2, allowing them to run completely independently.
133
4. [What If] pulseIn() is a blocking function. It halts the loop waiting for the pulse to start
and finish. If the pulse never arrives (e.g., a broken wire), the program hangs indefinitely.
The alternative is to use a hardware interrupt (attachInterrupt) on the pin to trigger
an ISR when the pin changes, capturing the time non-blockingly.
2. [Debug] Run an I2C Scanner sketch (which loops through addresses 1-127 and pings
them). If nothing appears, the most common wiring mistake is swapping the SDA and
SCL wires, or forgetting to connect the common Ground between the Arduino and the
sensor.
3. [Design] If two sensors have a fixed address, you cannot put them on the same bus.
Resolve this by using an I2C Multiplexer (like the TCA9548A), which acts as a traffic cop,
allowing you to switch the bus to one sensor at a time. Alternatively, if extreme speed
is required for data acquisition, switch to SPI, which requires a separate SS pin for each
device but avoids address conflicts entirely.
4. [What If] I2C lines are open-drain, meaning they rely entirely on pull-up resistors to
drive the line HIGH. Omitting them causes the signal to never go HIGH, resulting in a
locked bus where the SCL/SDA lines float at 0V. Data transmission fails completely. Add
4.7kΩ pull-up resistors to both SDA and SCL.
2. [Debug] Garbage characters indicate a baud rate mismatch between the Arduino’s SoftwareSerial
and the HC-05. The default HC-05 baud rate is usually 9600 or 38400. Adjust the
[Link](xxxx) baud rate in the code until readable text is received. Always use the
SoftwareSerial example sketch to echo characters to the Serial Monitor for debugging.
3. [Design] Connecting Arduino’s 5V TX directly to the HC-05’s 3.3V RX pin forces 5V logic
into a 3.3V tolerant input, which degrades the chip and eventually destroys it. Design a
voltage divider using two resistors (e.g., 1kΩ and 2kΩ) between the Arduino TX and HC-05
RX to step the 5V signal down to a safe 3.3V.
4. [What If] Without a checksum, RF noise or dropped packets will manifest as corrupted
data (e.g., receiving ”2!.5” instead of ”25.5”). The receiver will parse garbage and crash.
You must implement a payload structure with a checksum byte, and the receiver must
discard any packet where the calculated checksum doesn’t match the received checksum.
2. [Debug] The server stops responding because of a resource leak. If [Link]() is not
called after serving the HTTP response, the socket remains open. The Ethernet shield has
a limited number of sockets (usually 4). Once all are stuck open, it refuses new connections.
Ensure [Link]() is always executed before the loop ends.
3. [Design] GET appends parameters to the URL (e.g., /?lock=1), making it cacheable by
browsers and proxies—dangerous for a lock system, as a cached URL could unlock the door
repeatedly. POST sends data in the HTTP body, which is not cached or logged in browser
history. Design the endpoint to accept POST requests for the lock action, verifying the
HTTP method in code before acting.
4. [What If] The Ethernet library buffer is small. Serving a massive HTML page in a
single [Link]() call can overflow the buffer, crashing the Arduino or dropping
data. The solution is to chunk the data: print the HTML in small segments, checking
[Link]() and using [Link]() to stream the data safely in a loop.
4. [What If] Flash memory has limited write cycles (often around 100,000 per sector). Open-
ing and closing a file 1000 times a second forces the FAT table to update constantly, wearing
out the flash memory’s sectors in a matter of hours. The SD card will permanently brick.
To prevent this, buffer data in RAM and write to the SD card in large chunks every few
minutes.
1. [Direct] The .h (header) file declares the interface—function names, variable types, and
class structures. The .cpp (source) file implements the actual logic and code behind those
declarations.
2. [Debug] The update likely introduced breaking API changes (e.g., renaming a function
or changing a parameter type). Fix this by opening the Library Manager, finding the
library, and selecting ”Version 1.0.0” from the dropdown to downgrade. Then, check the
library’s [Link] on GitHub to see what changed in the new version and update your
code accordingly.
3. [Design] Separating interface from implementation abstracts the hardware. Design the
library so the .h file defines generic functions like openDoor() and closeDoor(), while
the .cpp file handles the specific pin writes and servo angles. This makes the main sketch
highly readable, and if you change hardware later, you only rewrite the .cpp file without
touching the main logic.
4. [What If] If you put all implementation code in a single .h file and include it in multiple
.cpp files in your project, the C++ linker will try to compile the functions multiple
times. This results in ”multiple definition” linker errors. The standard practice is to put
declarations in .h and implementations in .cpp to avoid this.
2. [Debug] The String class dynamically allocates and deallocates memory on the heap
every time it is modified. Over 2 hours, this fragments the 2KB RAM until it runs out.
Fix it by replacing String concatenations with C-strings (char[]), using strcpy() and
strcat(). Wrap all static text in the F() macro (e.g., [Link](F("Hello"));)
to force them into Flash memory, drastically saving RAM.
3. [Design] The issue is that int is 16-bit on Uno but 32-bit on ESP8266, causing bit-shifts
and overflows to behave differently. Design a cross-platform solution using conditional
compilation:
Better yet, use standard fixed-width types like uint32_t from <stdint.h> everywhere.
136 CHAPTER 35. EXERCISE SOLUTIONS
4. [What If] Committing a build artifact (like the compiled .hex file) bloats the Git reposi-
tory with binary data. Git struggles to diff binary files efficiently, making the repository
size grow uncontrollably and slowing down clones. Adding a .gitignore file with patterns
like *.hex and /build/ prevents these artifacts from ever entering version control.
2. [Debug] Apply an EMA filter to smooth the data. Initialize float filteredValue =
0.0;. In the loop, calculate: filteredValue = (alpha * rawSensor) + ((1.0 - alpha)
* filteredValue);. This mathematically damps sudden spikes, providing a smooth trend
line while reacting to real changes.
3. [Design] If Alpha is 0.01, the filter is 99% reliant on history and 1% on the new reading.
This makes it extremely smooth, but the reaction time is dangerously slow. A robot might
crash into a wall before the filtered distance reading drops to the collision threshold. The
engineering trade-off is responsiveness vs. noise reduction; for a robot, use a higher alpha
(e.g., 0.3) to balance safety and smoothness.
4. [What If] An array of 100 integers consumes 200 bytes of the Arduino Uno’s 2KB RAM.
That’s 10% of total system memory dedicated solely to one filter. If you have multiple
sensors, you will quickly exhaust the RAM, causing a stack overflow and system crash.
This is why EMA is vastly preferred in memory-constrained embedded systems.
2. [Debug] delay() relies on timer interrupts to count milliseconds. When an ISR triggers,
global interrupts are disabled. Calling delay() inside the ISR waits for a timer interrupt
that can never fire, causing an infinite hang. Fix this design flaw by removing delay()
and instead setting a volatile boolean flag inside the ISR, handling the timing logic
in the main loop().
3. [Design] Distribute the writes using a wear-leveling algorithm. Divide the 1KB EEPROM
into several pages. Keep a pointer to the ”active” page. Every time you write data, move
to the next address in the page. When the page is full, erase it and move to the next. This
spreads the 100,000 write cycles across thousands of addresses, extending the EEPROM’s
life by orders of magnitude.
4. [What If] The ADC precision drops. The ADC needs a certain number of clock cycles
to charge its internal capacitor and calculate a 10-bit result accurately. By manipulating
the prescaler to speed up the ADC, you give it less time to settle, resulting in noisy, lower-
resolution readings. Use faster ADC reads only when raw speed (e.g., fast audio sampling)
is more important than precision.
Index
137
138 INDEX
LED, 52 Sensors, 44
LED Bar Graph, 53 Serial Communication, 63
LED Resistors, 120 Serial Monitor, 14
Libraries, 87, 125 Servo Motor, 55
Library Manager, 14 setup(), 24
LM35, 46 Shift Register, 54
Logical Operators, 26 Shorthand Operators, 27
loop(), 24 Simulators, 124
Low-pass Filter, 92 Sketch, 14
Sleep Mode, 95
map(), 29 Smoothing, 42
Math Functions, 29 SoftwareSerial, 64
Melody, 58 Solenoid, 57
Memory Management, 89 Sound Sensor, 48
MFRC522, 48 SPI, 71
Microcontroller, 13 Stepper Motor, 56
MIDI, 59 String Class, 20
millis(), 68 Strings, 20
Modulo Operator, 28 Switch-Case, 27
Moving Average, 92 Syntax, 15
MQTT, 81
Multiplexer, 41 ThingSpeak, 79
Multiplexing, 53 Tilt Sensor, 44
Timer Interrupts, 95
OTA, 81 tone(), 58
Over-The-Air Updates, 81 Troubleshooting, 115, 123
Passing by Reference, 25 Ultrasonic Sensor, 46
PCB Design, 109 Unit Conversion, 120
Pinout, 121
PIR Sensor, 44 Variable Scope, 25
Port Manipulation, 95 Variables, 18
Power Management, 95 Version Control, 90
Power Supply, 13 volatile, 94
PROGMEM, 89 Voltage Divider, 40
Pull-up Resistor, 35
pulseIn(), 69 Web Server, 76
PWM, 52 While Loop, 28
Wi-Fi, 78
RAM, 89 Wireless Communication, 73
Random Numbers, 30
Real-Time Clock, 69 XBee, 75
References, 125
ZigBee, 75
Relays, 57
Resistor Color Code, 120
RFID, 48
RGB LED, 53
Rotary Encoder, 50
RTC, 69
SD Card, 83
Semicolon, 15
CONNECT WITH THE AUTHOR
ﺭ ﺍﺩ ﻭﺍ ﺙﺍ ﺃ ﻝ ﺕﺍ ﺍ
Rebouh Abdallah
ﺕ ﻭﺍ ﻭ ﺍ ﺱﺍ
GitHub
Telegram