0% found this document useful (0 votes)
2 views139 pages

Mastering_Arduino

The document is a comprehensive guide titled 'Mastering Arduino' by Rebouh Abdallah, focusing on embedded systems and IoT, covering topics from hardware foundations to advanced robotics and Wi-Fi. It includes detailed sections on the Arduino platform, programming, control flow, and mathematical operations, along with code snippets for practical use. The work is licensed under a Creative Commons license, allowing sharing with attribution but prohibiting commercial use and modifications.

Uploaded by

hmrayane1
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
2 views139 pages

Mastering_Arduino

The document is a comprehensive guide titled 'Mastering Arduino' by Rebouh Abdallah, focusing on embedded systems and IoT, covering topics from hardware foundations to advanced robotics and Wi-Fi. It includes detailed sections on the Arduino platform, programming, control flow, and mathematical operations, along with code snippets for practical use. The work is licensed under a Creative Commons license, allowing sharing with attribution but prohibiting commercial use and modifications.

Uploaded by

hmrayane1
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

MASTERING

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

Copyright © 2026 Rebouh Abdallah


All rights reserved under the following license:

This work is licensed under a


Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International
License (CC BY-NC-ND 4.0).

You are free to:


• Share — copy and redistribute the material in any medium or format.

Under the following terms:


• Attribution (BY) — You must give appropriate credit to the author (Rebouh
Abdallah), provide a link to the license, and indicate if changes were made.

• NonCommercial (NC) — You may not use the material for commercial
purposes without explicit written permission from the author.

• NoDerivatives (ND) — If you remix, transform, or build upon the material,


you may not distribute the modified material. The book must remain exactly as
originally authored.

Code Snippets Exception:


The source code examples, schematics, and scripts provided within this book are released
for free use. You may copy, modify, and implement these code snippets in your personal,
educational, and non-commercial physical projects without restriction.
Contents

Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9

I Getting Started 11

Overview: Part I . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

1 The Arduino Platform and IDE . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13


1.1 Understanding Arduino Hardware . . . . . . . . . . . . . . . . . . . . . . . . . . 13
1.1.1 Key Hardware Features . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
1.1.2 Powering the Arduino . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
1.2 The Arduino IDE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
1.2.1 IDE Interface Components . . . . . . . . . . . . . . . . . . . . . . . . . . 14
1.2.2 Installing the IDE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
1.3 Arduino Sketch Structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
1.3.1 Syntax Fundamentals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
1.4 The Blink Sketch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15

2 Variables and Data Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18


2.1 Understanding Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
2.1.1 Variable Naming Conventions . . . . . . . . . . . . . . . . . . . . . . . . . 18
2.2 Numeric Data Types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
2.2.1 Floating-Point Numbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
2.3 The const Qualifier . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
2.4 Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
2.4.1 Multi-Dimensional Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
2.5 Strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
2.5.1 Arduino String Class . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
2.5.2 C-Style Character Strings . . . . . . . . . . . . . . . . . . . . . . . . . . . 20

II Core Programming 22

Overview: Part II . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23

3 Structuring Arduino Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24


3.1 The setup() and loop() Functions . . . . . . . . . . . . . . . . . . . . . . . . . 24
3.2 Creating Custom Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
3.3 Passing by Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
3.4 Variable Scope . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25

4 Control Flow and Decision Making . . . . . . . . . . . . . . . . . . . . . . . . . . 26

3
4 CONTENTS

4.1 If-Else Statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26


4.1.1 Comparison Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
4.1.2 Logical Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
4.2 Switch-Case Statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
4.3 For Loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
4.3.1 Shorthand Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
4.4 While and Do-While Loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
4.5 The break Statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
4.6 The Modulo Operator (%) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28

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

III Input and Output 33

Overview: Part III . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34

6 Digital Input and Output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35


6.1 Digital Output: digitalWrite() . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
6.2 Digital Input: digitalRead() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
6.3 Using Internal Pull-up Resistors . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
6.4 Debouncing a Button . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
6.5 State Change Detection (Edge Detection) . . . . . . . . . . . . . . . . . . . . . . 38
6.6 Reading a Keypad (Non-Blocking with millis()) . . . . . . . . . . . . . . . . . 38

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

8 Getting Input from Sensors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44


8.1 Detecting Movement (Tilt Sensor) . . . . . . . . . . . . . . . . . . . . . . . . . . 44
8.2 Detecting Motion (PIR Sensor) — with Debounce . . . . . . . . . . . . . . . . . 44
8.3 Measuring Distance (Ultrasonic HC-SR04) . . . . . . . . . . . . . . . . . . . . . . 46
8.4 Measuring Temperature (LM35) . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
8.5 Measuring Temperature and Humidity (DHT11/DHT22) . . . . . . . . . . . . . 46
CONTENTS 5

8.6 Measuring Distance with IR Sensor . . . . . . . . . . . . . . . . . . . . . . . . . . 48


8.7 Detecting Sound . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
8.8 Reading RFID Tags (MFRC522) . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
8.9 Tracking Rotary Encoders . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
8.10 Reading GPS Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
8.11 Detecting Direction (Compass) . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
8.12 Reading Acceleration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51

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

IV Communication & IoT 61

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

14 Using Time and Dates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68


14.1 Using delay() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
14.2 Blink Without delay() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
14.3 Measuring Pulse Duration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
14.4 Real-Time Clock (DS1307) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
6 CONTENTS

15 Communicating Using I2C and SPI . . . . . . . . . . . . . . . . . . . . . . . . . . 70


15.1 I2C Communication . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
15.1.1 External EEPROM (24LC128) . . . . . . . . . . . . . . . . . . . . . . . . 70
15.2 SPI Communication . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
15.3 Communicating Between Arduino Boards . . . . . . . . . . . . . . . . . . . . . . 71

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

17 Ethernet and Networking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76


17.1 Setting Up the Ethernet Shield . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
17.2 Web Server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76

18 IoT with ESP8266 and Wi-Fi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78


18.1 Connecting to Wi-Fi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
18.2 ESP8266 Web Server . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
18.3 Sending Data to ThingSpeak . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
18.4 MQTT Protocol . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
18.5 Over-The-Air (OTA) Updates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81

19 SD Card Data Logging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83


19.1 Wiring the SD Card Module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
19.2 Writing Sensor Data to SD Card . . . . . . . . . . . . . . . . . . . . . . . . . . . 83

V Advanced Topics 85

Overview: Part V . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86

20 Using, Modifying, and Creating Libraries . . . . . . . . . . . . . . . . . . . . . . 87


20.1 Using Built-in Libraries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
20.2 Installing Third-Party Libraries . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
20.3 Creating Your Own Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87

21 Advanced Coding and Memory Handling . . . . . . . . . . . . . . . . . . . . . . 89


21.1 Determining Free RAM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
21.2 Storing Data in PROGMEM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
21.3 Storing Strings in PROGMEM . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
21.4 Conditional Compilation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
21.5 Version Control with Git and GitHub . . . . . . . . . . . . . . . . . . . . . . . . 90

22 Simple Digital Signal Processing (DSP) . . . . . . . . . . . . . . . . . . . . . . . 92


22.1 Moving Average Filter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
22.2 Exponential Low-Pass Filter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
22.3 Practical Application: Smoothing Ultrasonic Sensor . . . . . . . . . . . . . . . . 93

23 Using the Controller Chip Hardware . . . . . . . . . . . . . . . . . . . . . . . . . 94


23.1 EEPROM Storage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
23.2 Hardware Interrupts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
23.3 Timer Interrupts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
CONTENTS 7

23.4 Faster Analog Reads . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95


23.5 Reducing Battery Drain . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
23.6 Direct Port Manipulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95

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

25 Intermediate Projects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102


25.1 Project: Memory Game . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
25.2 Project: Secret Knock Lock . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
25.3 Project: Joystick-Controlled Laser . . . . . . . . . . . . . . . . . . . . . . . . . . 102
25.4 Project: Remote Control Servo . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
25.5 Project: Weather Station . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
25.6 Project: Electronic Die . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104

26 Security Projects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105


26.1 Project: Intruder Sensor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
26.2 Project: Laser Trip Wire Alarm . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
26.3 Project: Motion Sensor Alarm (PIR with Debounce) . . . . . . . . . . . . . . . . 105
26.4 Project: Keypad Entry System . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
26.5 Project: Wireless ID Card Entry System (MFRC522) . . . . . . . . . . . . . . . 106

27 Advanced Projects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108


27.1 Project: Rainbow Light Show . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108
27.2 Project: Build Your Own Arduino . . . . . . . . . . . . . . . . . . . . . . . . . . 108

28 Designing Custom PCBs with KiCad . . . . . . . . . . . . . . . . . . . . . . . . 109


28.1 Introduction to KiCad . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
28.2 Schematic Capture (Eeschema) . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
28.3 PCB Layout (Pcbnew) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
28.4 Exporting Gerber Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
28.5 Capstone Project: IoT Weather Station with Cloud Logging . . . . . . . . . . . . 110

VII Reference 113

Overview: Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114

29 Troubleshooting Flowchart . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115

30 Quick Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118


30.1 Board Compatibility Guide . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
30.2 Sensor Wiring Quick Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
30.3 Typical Voltage and Current Values . . . . . . . . . . . . . . . . . . . . . . . . . 119
8 CONTENTS

30.4 Unit Conversion Tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120


30.5 Resistor Color Code Quick Reference . . . . . . . . . . . . . . . . . . . . . . . . . 120
30.6 Common Resistor Values for LEDs . . . . . . . . . . . . . . . . . . . . . . . . . . 120
30.7 Arduino Uno Pin Reference . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
30.8 ESP8266 (NodeMCU) Pin Reference . . . . . . . . . . . . . . . . . . . . . . . . . 121
30.9 ASCII Character Set . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122

31 Troubleshooting Guide . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123


31.1 Code That Won’t Compile . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
31.2 Code Compiles but Doesn’t Work . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
31.3 Hardware Troubleshooting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123

32 Using Online Simulators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124

33 References and Resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125


33.1 Official Resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125
33.2 ESP8266 / IoT Resources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125
33.3 Recommended Libraries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125
33.4 Recommended Books . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125

34 Glossary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126

35 Exercise Solutions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127


Introduction

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.

Why This Book?


Transitioning from basic tutorials to practical, real-world applications often presents a steep
learning curve. This book bridges the gap between theoretical microcontroller concepts and
actual hardware implementation.
It consolidates essential literature with practical lessons learned from writing code, wiring cir-
cuits, and debugging hardware. The goal is to provide a clear, structured guide that transcends
simple code snippets, helping you build a robust foundation in how microcontrollers interact
with the physical world—and increasingly, with the Internet of Things (IoT).

Who This Book Is For


This book is designed for anyone seeking to master Arduino. Whether you are a beginner taking
your first steps into microcontrollers, an engineering student solidifying your C/C++ foundation,
or a maker building practical embedded systems and IoT devices, you will find substantial value
in these pages.

What You Need


• An Arduino Uno board (or compatible equivalent) and a USB cable.
• An ESP8266 (NodeMCU or Wemos D1 Mini) for IoT projects.
• A basic starter kit containing a breadboard, LEDs, resistors, jumper wires, and standard
sensors.
• A computer running the free Arduino IDE (version 2.0+ recommended).
• A willingness to experiment, make mistakes, and build.

How This Book Is Organized


• Part I: Getting Started — Hardware foundations, IDE setup, and basic sketch structure.

• 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.

• Part VI: Projects — Hands-on, real-world implementations, including a capstone IoT


weather station.

• Reference — Quick lookup guides, troubleshooting, and exercise solutions.

Conventions Used in This Book

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.

When NOT to Use This


Practical warnings on when a specific code snippet or hardware approach should not be
used in production or long-running deployments, preventing you from carrying bad habits
from the lab to the field.

Real-World Case Study


Detailed analysis of real-world failures, complete with generated measurements, debugging
steps, and links to Wokwi simulations to bridge the gap between theory and field assembly.

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

The Arduino Platform and IDE

1.1 Understanding Arduino Hardware


Arduino is an open-source electronics platform based on a microcontroller ( ‫ﺩ‬ )—a small,
low-cost computer designed to interact with physical components. The Arduino Uno R3, the
most popular board in the family, is built around the Atmel ATmega328P chip (ATmega328p ).

1.1.1 Key Hardware Features


The Arduino Uno board features:
• 14 Digital Input/Output Pins (pins 0–13).

• 6 Analog Input Pins (A0–A5).

• 6 PWM Pins (3, 5, 6, 9, 10, 11).

• USB Connection: For programming and serial communication.

• Power Jack: 7–12V via a 2.1mm barrel jack.

• Reset Button and On-board LED (connected to pin 13).


Insight
Arduino is open-source, meaning its hardware designs are publicly available. This has
spawned numerous compatible clone boards. While clones are cost-effective, official boards
support the Arduino project financially and guarantee strict adherence to electrical spec-
ifications.

1.1.2 Powering the Arduino


1. USB: 5V from your computer’s USB port.

2. Barrel Jack: 7–12V AC adapter or 9V battery.

3. Vin Pin: 7–12V directly to the Vin pin.

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.

1.2 The Arduino IDE


The Integrated Development Environment (IDE) ( ‫ﺍ‬ ‫ ) ﺍ‬is the software used to write,
compile, and upload programs (called sketches) to the Arduino board. It is freely available from
[Link] and runs on Windows, macOS, and Linux. Arduino IDE 2.0+ offers
autocompletion, integrated debugging, and an enhanced library manager.

1.2.1 IDE Interface Components


• Verify Button: Compiles the sketch and checks for errors.

• Upload Button: Compiles and uploads the sketch to the board.

• New / Open / Save: Standard sketch file management.

• Serial Monitor: Interface for serial communication.

• Serial Plotter: Visualizes analog data as real-time graphs.

• Library Manager: Installs third-party libraries.

• Board Manager: Installs support for ESP8266, ESP32, etc.

1.2.2 Installing the IDE


1. Download the IDE from [Link]

2. Follow the OS-specific installation instructions.

3. On Windows, you may need to install USB drivers manually.

4. Connect your Arduino via USB cable.

5. Select the correct board: Tools > Board > Arduino Uno.

6. Select the correct port: Tools > Port.

1.3 Arduino Sketch Structure


Every Arduino sketch ( ‫ )ﺭ‬consists of two mandatory functions:

1 void setup () {
2 // (setup) ‫ﺍﺩ‬ ‫ﺩﺍ ﺍ‬
3 // ‫ﺍ‬ ‫ﺓ ﻭﺍ ﺓ‬ ‫ﺍـ ﺩ‬
4 }
5
6 void loop () {
7 // (loop) ‫ﺍﺭ‬ ‫ﺩﺍ ﺍ‬
8 // ‫ﺭﺇ ﺍ‬ ‫ﺍـ ﺩ‬
9 }
1.4. THE BLINK SKETCH 15

1.3.1 Syntax Fundamentals


The Semicolon
Every statement must terminate with a semicolon (;).

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.

1 pinMode (13 , OUTPUT ); // ‫ ﺩﺍ‬pinMode


2 // (arguments) ‫ﺕ‬ ‫ ﺍ‬OUTPUT ‫ ﻭ‬13

1.4 The Blink Sketch

1 // ‫ﺕ ﺃﺭﺩﻭ‬ LED ‫ـ‬ 13 ‫ﺍ‬


2 int led = 13;
3
4 void setup () {
5 pinMode (led , OUTPUT ); // ‫ﺝ‬ ‫ﺍ‬
6 }
7
8 void loop () {
9 digitalWrite (led , HIGH); // ( 5 ) LED
10 delay (1000) ; // ( 1000) ‫ﺓ‬ ‫ﺭ‬ ‫ﺍ‬
11 digitalWrite (led , LOW); // ( 0 ) LED ‫ﺀ‬ ‫ﺇ‬
12 delay (1000) ; // ‫ﺓ‬ ‫ﺭ‬ ‫ﺍ‬
13 }
16 CHAPTER 1. THE ARDUINO PLATFORM AND IDE

Example
Step-by-Step Walkthrough of Blink:

1. int led = 13; — Declare and initialize the variable.

2. pinMode(led, OUTPUT); — Configure pin 13 as an output.

3. digitalWrite(led, HIGH); — Apply 5V (LED on).

4. delay(1000); — Pause execution for 1 second.

5. digitalWrite(led, LOW); — Apply 0V (LED off).

6. delay(1000); — Pause execution for 1 second.

7. The loop repeats from step 3 indefinitely.

Hands-On Project
Project: Blink Variations

Wokwi Simulation

Goal: Create three distinct LED blink patterns.


Estimated Cost: $5
Bill of Materials (BOM):

• 1x Arduino Uno ($3)

• 1x LED ($0.10)

• 1x 220Ω resistor ($0.05)

• Breadboard & jumper wires ($1.50)

Steps:

1. Connect the LED’s anode (long leg) to pin 13 via a 220Ω resistor.

2. Connect the LED’s cathode (short leg) to GND.

3. Upload a sketch that blinks in three patterns:

• Pattern 1: 1s on / 1s off.
• Pattern 2: 100ms on / 100ms off (strobe).
• Pattern 3: 2s on / 500ms off.

4. Cycle through each pattern, repeating each exactly 5 times.


1.4. THE BLINK SKETCH 17

Common Mistakes & Troubleshooting:

• 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.

• LED burns out: Forgot to use a current-limiting resistor.

• Patterns run too fast: Incorrect timing logic in the delay() functions.

Evaluation Criteria:

• Patterns are visually distinguishable.

• Code is well-commented and logically structured.

• Each pattern repeats exactly 5 times before cycling.

Extension Ideas:

• Add a pushbutton to cycle patterns manually.

• Use a potentiometer to dynamically control blink speed.

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

Variables and Data Types

2.1 Understanding Variables


A variable ( ) is a named memory location used to store data. When declaring a variable,
you must specify:

1. The data type.

2. The name.

3. Optionally, an initial value.

1 int ledPin = 13; // ‫ﺍ‬ ‫ﻭ‬


2 int sensorValue ; // ‫ﻭﻥ‬
3 sensorValue = 500; // ً ‫ﺀ‬ ‫ﺇ‬

2.1.1 Variable Naming Conventions


• Names should be descriptive (e.g., ledPin rather than x).

• Must start with a lowercase letter.

• Cannot share a name with Arduino reserved keywords.

• Use camelCase for multi-word names (e.g., sensorValue).

2.2 Numeric Data Types

Type Bytes Range Use


int 2 -32,768 to 32,767 Positive and negative integers
unsigned int 2 0 to 65,535 Only positive integers
long 4 ±2.1 × 109 Very large integers
unsigned long 4 0 to 4.3 × 109 Very large positive integers
float 4 ±3.4E + 38 Decimal numbers
double 4 Same as float Same as float on Arduino Uno

18
2.3. THE CONST QUALIFIER 19

boolean 1 true / false Logical states


char 1 -128 to 127 Single character
byte 1 0 to 255 Unsigned 8-bit value
Table 2.1: Arduino Numeric Data Types

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.

2.2.1 Floating-Point Numbers

Floating-point numbers (float, ‫ )ﺃ ﺍﺩ‬represent fractional values. On the 8-bit Arduino


Uno, floating-point math is computationally expensive and should be used judiciously.

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:

1 if (fabs(value ) < 0.0001)


2 Serial . println (" Close enough to zero"); // ‫ﺍ‬

2.3 The const Qualifier

1 const int ledPin = 13; // ً ‫ﻩﺍ‬

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

1 int ledPins [] = {2, 7, 4, 6, 5, 3}; // ‫ ﺃ ﺍﺩ‬6


2 int readings [10]; // ‫ﺓ‬

Arrays are zero-indexed: the first element resides at index 0.

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.4.1 Multi-Dimensional Arrays

1 int pinMatrix [3][3] = {


2 {2, 3, 4},
3 {5, 6, 7},
4 {8, 9, 10}
5 };
6 int val = pinMatrix [1][2]; // (2 ‫ﺩ‬ ‫ ﺍ‬،1 ‫ )ﺍ‬7 =

2.5 Strings
2.5.1 Arduino String Class

1 String text1 = "This string ";


2 String text2 = " has more text";
3 text1 . concat (text2); // text" more has string "This = ‫ﺍ ﻭﻝ ﺍ ﻥ‬ ‫ﺍ‬
4 Serial . println (text1. length ()); // 28

When NOT to Use This


When NOT to use String: The String class dynamically allocates memory at runtime.
On microcontrollers with limited RAM, this can lead to heap fragmentation and unex-
pected crashes. Do not use String in long-running production code or systems operating
24/7. It is acceptable only for quick prototyping or if you frequently call [Link]().

2.5.2 C-Style Character Strings

1 char myString [] = " Arduino "; // (null) ‫ﺃ ﻑ‬


2 int length = strlen ( myString ); // 7 =
2.5. STRINGS 21

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

Structuring Arduino Programs

3.1 The setup() and loop() Functions

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.

3.2 Creating Custom Functions

1 // ‫ﺕﻭ‬ ‫ﻭﻥ‬ ‫ﺩﺍ‬


2 void blink1 () {
3 digitalWrite (13 , HIGH);
4 delay (500);
5 digitalWrite (13 , LOW);
6 delay (500);
7 }
8

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 }

3.3 Passing by Reference

1 void swap(int &value1 , int & value2 ) {


2 int temp = value1 ;
3 value1 = value2 ;
4 value2 = temp;
5 }

3.4 Variable Scope

1 int globalVar = 10; // scope) (Global ‫ﻡ‬


2
3 void myFunction () {
4 int localVar = 5; // (Local)
5 static int counter = 0; //
6 counter ++;
7 }

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

Control Flow and Decision Making

4.1 If-Else Statements

1 if ( analogValue > threshold ) {


2 digitalWrite (ledPin , HIGH);
3 } else {
4 digitalWrite (ledPin , LOW);
5 }

4.1.1 Comparison Operators

Operator Test Example


== Equal to 2 == 3 // false
!= Not equal to 2 != 3 // true
> Greater than 2 > 3 // false
< Less than 2 < 3 // true
>= Greater/equal 2 >= 3 // false
<= Less/equal 2 <= 3 // true
Table 4.1: Comparison Operators

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.

4.1.2 Logical Operators

Symbol Function Description


&& Logical AND True if both conditions are true
|| Logical OR True if at least one condition is true

26
4.2. SWITCH-CASE STATEMENTS 27

! Logical NOT Inverts the boolean value


Table 4.2: Logical Operators

4.2 Switch-Case Statements

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.

4.3 For Loops

1 for (int thisPin = 2; thisPin < 8; thisPin ++) {


2 pinMode (thisPin , OUTPUT ); // ‫ﺭﺝ‬ 7 ‫ﺇ‬2 ‫ﺕ‬ ‫ﺍ‬
3 }

4.3.1 Shorthand Operators

Operator Example Equivalent


++ x++ x = x + 1
-- x-- x = x - 1
+= x += 5 x = x + 5
-= x -= 5 x = x - 5
*= x *= 3 x = x * 3
/= x /= 2 x = x / 2
Table 4.3: Shorthand Assignment Operators
28 CHAPTER 3. STRUCTURING ARDUINO PROGRAMS

4.4 While and Do-While Loops

1 // ‫ﺍ‬ ‫ﺍ ﻁ‬ while:
2 while ( analogRead ( sensorPin ) > 100) {
3 flashLED ();
4 }
5

6 // ‫ﺍ‬ ‫ﺓ‬ ‫ﺓ ﻭﺍ‬ do-while:


7 do {
8 flashLED ();
9 } while ( analogRead ( sensorPin ) > 100);

4.5 The break Statement

1 while ( analogRead ( sensorPin ) > 100) {


2 if ( digitalRead ( switchPin ) == HIGH) {
3 break; // ً ‫ﺭﺍ‬ ‫ﺍ‬ ‫ﺍ ﻭﺝ‬
4 }
5 flashLED ();
6 }

4.6 The Modulo Operator (%)

1 int result = 17 % 5; // (2 ‫ ﻭﺍ‬3 = 5 / 17) 2 =


2
3 if ( buttonPushCounter % 4 == 0) {
4 digitalWrite (ledPin , HIGH); // ‫ﺭﺍ‬
5 }

Exercises
1. What happens if you forget the break statement in a switch-case?

2. Why is writing if (x = 5) instead of if (x == 5) a critical logical fallacy? How would


you debug the unexpected behavior?

3. Compare using if-else vs switch-case for a robot’s 5 operational modes. When is


switch a bad choice?

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

5.1 Basic Arithmetic

1 int sum = 1 + 2; // 3= : ‫ﺍ‬


2 int diff = 3 - 2; // 1 = :‫ﺡ‬ ‫ﺍ‬
3 int product = 3 * 2; // 6 = :‫ﺏ‬ ‫ﺍ‬
4 int quotient = 3 / 2; // (!5.1 )1= : ‫ﺍ‬ ‫ﺍ‬
5 int remainder = 3 % 2; // 1= : ‫ﺍ‬

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 Useful Math Functions


5.2.1 Constrain

1 int val = constrain ( sensorValue , 100, 200);


2 // 200 ‫ ﻭ‬100 ‫ﺍ‬

5.2.2 Map

1 int ledLevel = map( sensorReading , 0, 1023 , 0, 255);


2 // (255-0) PWM ‫ﺕ‬ ‫( ﺇ‬1023-0) ‫ﺕﺍ‬ ‫ﻝﺍ‬

29
30 CHAPTER 5. MATHEMATICAL OPERATIONS

Example
Example: Converting Analog Read to Voltage

1 int sensorValue = analogRead (A0);


2 float voltage = sensorValue * (5.0 / 1023.0) ;
3 Serial . println ( voltage ); // ‫ﺍ‬ ‫ﺍ‬

5.2.3 Min, Max, Abs, Pow, Sqrt

1 int myMinValue = min(myValue , 200);


2 int myMaxValue = max(myValue , 100);
3 int absVal = abs(x - y); // ‫ﺍ‬ ‫ﺍ‬
4 float result = pow (3, 2); // 3^2 = 9.0
5 float root = sqrt (9); // = 3.0

5.2.4 Trigonometric Functions

1 float deg = 30;


2 float rad = deg * PI / 180; // ‫ﻥ‬ ‫ﺍ ﺭ ﺕ ﺇ ﺭﺍﺩ‬
3 float s = sin(rad); // = 0.50
4 float c = cos(rad); // = 0.87
5 float t = tan(rad); // = 0.58

5.3 Random Numbers

1 // ‫ﻥ ﺍﺀﺓ‬ (ً ‫ﺩﺓ‬ ) A5 ‫ﺍﻡ‬ ‫ﺍ‬


2 randomSeed ( analogRead (A5)); // ‫ﺍ‬ ‫ﺍ ﺭ ﻡﺍ‬
3 int r = random (10); // 9 ‫ ﻭ‬0 ‫ﺍ‬ ‫ﺭ‬
4 int r2 = random (2, 10); // 9‫ﻭ‬2 ‫ﺍ‬ ‫ﺭ‬

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.

5.4 Bitwise Operations

Symbol Function Example


& Bitwise AND 3 & 1 = 1
| Bitwise OR 3 | 1 = 3
^ Bitwise XOR 3 ^ 1 = 2
~ Bitwise NOT ~1 = 254 (byte)
<< Left shift 1 << 3 = 8
>> Right shift 8 >> 2 = 2
Table 5.1: Bitwise Operators

5.4.1 Bit Functions

1 bitSet (flags , 2); // flags ‫ﺍ‬ 2 ‫ﺭ‬ ‫ﺍ‬


2 bitClear (flags , 5); // 5 ‫ﺭ‬ ‫ﺍ‬
3 int val = bitRead (flags , 2); // 2 ‫ﺭ‬ ‫ﺍﺀﺓ ﺍ‬
4 bitWrite (flags , 3, 1); // 3 ‫ﺭ‬ ‫ﺍ‬ 1
5 int mask = bit (3); // = 8 (2^3)

5.5 Extracting and Combining Bytes

1 int intValue = 258; // ‫ﻱ‬ ‫ﻡﺍ‬ ‫ ﺍ‬0x102


2 byte loByte = lowByte ( intValue ); // ( ‫ﺍ‬ ‫ )ﺍ‬2 =
3 byte hiByte = highByte ( intValue ); // (‫ﺍ ﻱ‬ ‫ )ﺍ‬1 =
4 int recombined = word(hiByte , loByte ); // ( ‫ )ﺇ ﺩﺓ ﺍ‬258 =
32 CHAPTER 5. MATHEMATICAL OPERATIONS

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

Input and Output

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

Digital Input and Output

6.1 Digital Output: digitalWrite()

1 pinMode (13 , OUTPUT ); // ‫ﺝ‬ ‫ﺍ‬


2 digitalWrite (13 , HIGH); // 5
3 digitalWrite (13 , LOW); // 0

6.2 Digital Input: digitalRead()

1 pinMode (2, INPUT ); // ‫ﺍ‬


2 int val = digitalRead (2); // LOW ‫ ﺃﻭ‬HIGH :‫ﺍ ﺍﺀﺓ‬

6.3 Using Internal Pull-up Resistors

1 pinMode (2, INPUT_PULLUP ); // ‫ﺍ ﺍ‬ ‫ﺍ‬ ‫ﻭ‬

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

Pull-Up Configuration Pull-Down Configuration


+5V +5V
Switch
10kΩ
Pin Pin

10kΩ
Switch
GND
GND
Reads LOW when open
Reads HIGH when open Reads HIGH when pressed
Reads LOW when pressed

6.4 Debouncing a Button


Mechanical switches bounce (‫—)ﺍﺭ ﺍﺩ‬they rapidly make and break contact when pressed. Soft-
ware debouncing ignores transient state changes:

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

Goal: Control an LED with a pushbutton using a pull-up resistor configuration.


Estimated Cost: $7
Bill of Materials (BOM):
6.4. DEBOUNCING A BUTTON 37

• 1x Arduino Uno ($3)

• 1x Pushbutton ($0.20)

• 1x LED ($0.10)

• 1x 220Ω & 1x 10kΩ resistors ($0.10)

• Breadboard & wires ($3.50)

Steps:

1. Place the pushbutton on the breadboard straddling the center break.

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.

4. Upload the sketch:

1 const int buttonPin = 2;


2 const int ledPin = 13;
3 int buttonState = 0;
4
5 void setup () {
6 pinMode (ledPin , OUTPUT );
7 pinMode (buttonPin , INPUT);
8 }
9
10 void loop () {
11 buttonState = digitalRead ( buttonPin );
12 if ( buttonState == HIGH) { // ‫ﺇﺫﺍ ﺍ‬
13 digitalWrite (ledPin , HIGH);
14 } else {
15 digitalWrite (ledPin , LOW);
16 }
17 }

Common Mistakes & Troubleshooting:

• 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:

• Make the LED blink rapidly while the button is held.

• Add a second LED that toggles state on each press.


38 CHAPTER 6. DIGITAL INPUT AND OUTPUT

6.5 State Change Detection (Edge Detection)

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 }

6.6 Reading a Keypad (Non-Blocking with millis())


A 4×3 or 4×4 keypad is a matrix of switches. The naive approach uses delay(), which blocks
the entire program. Below is a non-blocking implementation using millis():

Insight
Installing the Keypad Library ( ‫ﺍ‬ :)

1. ‫ ﺍ‬Arduino IDE.

2. ‫ﺇ‬ ‫ ﺍﺫ‬Sketch > Include Library > Manage Libraries.

3. ‫ ﺍ‬Keypad ‫ ﺍ‬Mark Stanley.

4. ‫ ﺍ‬Install.

1 const int numRows = 4;


2 const int numCols = 3;
3 const char keymap [ numRows ][ numCols ] = {
4 {'1','2','3'},
5 {'4','5','6'},
6 {'7','8','9'},
7 {'*','0','#'}
8 };
9 const int rowPins [ numRows ] = {7, 2, 3, 6};
10 const int colPins [ numCols ] = {5, 8, 4};
11
12 // ‫ﺍ‬ millis ‫ﺍﺕ ﺍ ـ‬
6.6. READING A KEYPAD (NON-BLOCKING WITH MILLIS()) 39

13 unsigned long lastDebounceTime = 0;


14 const unsigned long debounceDelay = 20;
15 char lastKey = 0;
16
17 char getKey () {
18 char key = 0; // ‫ﻡﺍ‬ 0
19 for (int column = 0; column < numCols ; column ++) {
20 digitalWrite ( colPins [ column ], LOW); // ‫ﺍ ﺩ‬
21 for (int row = 0; row < numRows ; row ++) {
22 if ( digitalRead ( rowPins [row ]) == LOW) {
23 // delay ً millis ‫ﺍﻡ‬ ‫ﺍ‬
24 if (( millis () - lastDebounceTime ) > debounceDelay ) {
25 key = keymap [row ][ column ];
26 lastDebounceTime = millis ();
27 }
28 }
29 }
30 digitalWrite ( colPins [ column ], HIGH); // ‫ﺩ‬ ‫ﺍ‬ ‫ﺇ ﺀ‬
31 }
32 return key;
33 }

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

7.1 Reading Analog Values: analogRead()


The Arduino Uno features a 10-bit Analog-to-Digital Converter (ADC) ( ‫ﻱ ﺇ ﺭ‬ ‫) ﻝ‬, yield-
ing values from 0 to 1023:

1 int sensorValue = analogRead (A0); // 1023 ‫ﺇ‬0

7.2 Converting to Voltage

1 int sensorValue = analogRead (A0);


2 float voltage = sensorValue * (5.0 / 1023.0) ;
3 Serial . println ( voltage );

7.3 Voltage Divider Diagram


A voltage divider ( ‫ﺍ‬ ) allows you to measure voltages above 5V or read resistive sensors
(like LDRs or thermistors):

+Vin

R1 Voltage Divider Formula


R2
To Analog Pin Vout = Vin ×
R1 + R 2
R2

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:

1 int val = analogRead (A0);


2 float batteryVoltage = (val * 5.0 / 1023.0) * 2.0; // ‫ﺍ‬ 2 ‫ﺏ‬

7.4 Using map() to Change Ranges

1 int sensorValue = analogRead (A0);


2 int percent = map( sensorValue , 0, 1023 , 0, 100);

7.5 Reading More Than Six Analog Inputs


Use a multiplexer (‫ﺇﺭ ﻝ‬ ) like the 4051 to read up to 8 analog inputs using a single pin:

1 const int select [] = {2, 3, 4};


2 const int analogPin = A0;
3
4 int getValue (int channel ) {
5 for (int bit = 0; bit < 3; bit ++) {
6 int pin = select [bit ];
7 int isBitSet = bitRead (channel , bit);
8 digitalWrite (pin , isBitSet );
9 }
10 return analogRead ( analogPin );
11 }

7.6 Measuring Voltages Above 5V

1 const float R1 = 1000.0; // 10 ‫ﺃ‬ ‫ﺱ‬


2 const float R2 = 1000.0;
3 const float resistorFactor = 1023.0 * R2 / (R1 + R2); // 5.511 =
4
5 void loop () {
6 int val = analogRead ( batteryPin );
7 float volts = (val / resistorFactor ) * 5.0; // 0V.10 = volts val=1023:
8 Serial . println (volts );
9 }
42 CHAPTER 7. ANALOG INPUT

Caution
Never connect more than 5V directly to an Arduino pin. Always use a voltage divider.

7.7 Calibration

1 int sensorMin = 1023;


2 int sensorMax = 0;
3
4 void setup () {
5 // ‫ﻥ‬ٍ ‫ ﺍ‬5‫ﺓ ﺓ‬ ‫ﺍ‬
6 while ( millis () < 5000) {
7 int sensorValue = analogRead ( sensorPin );
8 if ( sensorValue > sensorMax ) sensorMax = sensorValue ;
9 if ( sensorValue < sensorMin ) sensorMin = sensorValue ;
10 }
11 }
12
13 void loop () {
14 int sensorValue = analogRead ( sensorPin );
15 sensorValue = map( sensorValue , sensorMin , sensorMax , 0, 255);
16 sensorValue = constrain ( sensorValue , 0, 255);
17 analogWrite (ledPin , sensorValue );
18 }

7.8 Smoothing Data

1 const int numReadings = 10;


2 int readings [ numReadings ];
3 int index = 0;
4 int total = 0;
5 int average = 0;
6
7 void loop () {
8 total -= readings [index ];
9 readings [index] = analogRead (A0);
10 total += readings [index ];
11 index = ( index + 1);
12 if (index >= numReadings ) index = 0;
13 average = total / numReadings ; // ‫ﻙ‬ ‫ﺍ‬ ‫ﺍ‬
14 Serial . println ( average );
15 }

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

Getting Input from Sensors

8.1 Detecting Movement (Tilt Sensor)

1 const int tiltSensorPin = 2;


2 const int firstLEDPin = 11;
3 const int secondLEDPin = 12;
4
5 void setup () {
6 pinMode ( tiltSensorPin , INPUT );
7 digitalWrite ( tiltSensorPin , HIGH); // ‫ﺍ‬ ‫ﻭ‬
8 pinMode ( firstLEDPin , OUTPUT );
9 pinMode ( secondLEDPin , OUTPUT );
10 }
11
12 void loop () {
13 if ( digitalRead ( tiltSensorPin )) {
14 digitalWrite ( firstLEDPin , HIGH);
15 digitalWrite ( secondLEDPin , LOW);
16 } else {
17 digitalWrite ( firstLEDPin , LOW);
18 digitalWrite ( secondLEDPin , HIGH);
19 }
20 }

8.2 Detecting Motion (PIR Sensor) — with Debounce


A Passive Infrared (PIR) sensor ( ‫ﺍ ﺍﺀ ﺍ‬ ‫ﺍ‬ ) detects human movement by sensing
changes in thermal radiation. PIR sensors output a sustained HIGH signal upon detection, but
reading directly without mitigation causes duplicate triggers and noisy logs.

1 const int ledPin = 13;


2 const int inputPin = 2; // PIR
3 unsigned long lastMotionTime = 0;
4 const unsigned long motionCooldown = 2000; // ‫ﺍ ﺍﺀﺍﺕ‬ 2
5
6 void setup () {
7 pinMode (ledPin , OUTPUT );
8 pinMode (inputPin , INPUT);
9 Serial .begin (9600) ;
10 }
11

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.

Real-World Case Study


The Ghosting PIR Sensor
In a remote weather station project, a PIR sensor kept logging false motion events exactly
every 55 seconds, draining the battery.
Diagnosis: The ESP8266 Wi-Fi chip was transmitting a heartbeat packet every 55 sec-
onds. The RF noise coupled into the PIR’s high-impedance FET input, triggering a false
HIGH.
Solution:

1. Physically separated the PIR sensor from the ESP8266 antenna by 15cm.

2. Added a 100µF decoupling capacitor across the PIR’s VCC/GND.

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:

• Sensitivity: Adjusts detection range (approx. 3–7 meters).

• 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

8.3 Measuring Distance (Ultrasonic HC-SR04)

1 const int trigPin = 12;


2 const int echoPin = 13;
3
4 void setup () {
5 Serial .begin (9600) ;
6 pinMode (trigPin , OUTPUT );
7 pinMode (echoPin , INPUT);
8 }
9
10 void loop () {
11 digitalWrite (trigPin , LOW);
12 delayMicroseconds (2);
13 digitalWrite (trigPin , HIGH);
14 delayMicroseconds (10);
15 digitalWrite (trigPin , LOW);
16
17 long duration = pulseIn (echoPin , HIGH);
18 long cm = duration / 29 / 2; // ‫ﺇ‬ ‫ﺍ‬
19 Serial .print (cm);
20 Serial . println (" cm");
21 delay (100);
22 }

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 .

8.4 Measuring Temperature (LM35)


The LM35 provides a linear output of 10mV per degree Celsius:

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 }

8.5 Measuring Temperature and Humidity (DHT11/DHT22)


The DHT11/DHT22 sensors use a custom single-wire digital protocol. You must install the DHT
sensor library by Adafruit.
8.5. MEASURING TEMPERATURE AND HUMIDITY (DHT11/DHT22) 47

Important Note on Error Checking

‫ﺀﺍ‬ ‫ﺩﻱ ﺃ‬ ‫ ﺍ ﺍ ـ ﺩ‬isnan() ‫ﺍﻡ ﺍ ﺍ‬ ‫ﺍ‬ ‫ﺍ‬ ‫ﺍ‬ ‫ﺇ‬ ،‫ﺱ‬ ‫ﺍﺀﺓ ﺍ‬
:‫ﺕ‬ ‫ﺍ‬

1 # include <math.h> // isnan() ‫ﺍ‬ ‫ﻭﺭﻱ‬

Insight
Installing the DHT Library (Required):

1. Open Arduino IDE → Sketch > Include Library > Manage Libraries.

2. Search for “DHT sensor library”.

3. Install the one by Adafruit (also install “Adafruit Unified Sensor” if prompted).

4. Include it in your sketch with #include <DHT.h>.

Without this library, the code below will NOT compile.

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.

8.6 Measuring Distance with IR Sensor


IR distance sensors output a voltage inversely proportional to distance. Use a lookup table:

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 }

8.7 Detecting Sound

1 const int numberOfSamples = 128;


2 const int middleValue = 512;
3
4 void loop () {
5 long sumOfSquares = 0;
6 for (int i = 0; i < numberOfSamples ; i++) {
7 int sample = analogRead (A0);
8 long signal = ( sample - middleValue );
9 signal *= signal ;
10 sumOfSquares += signal ;
11 }
12 long averageReading = sumOfSquares / numberOfSamples ;
13 if ( averageReading > threshold ) {
14 digitalWrite (ledPin , HIGH);
15 }
16 }

8.8 Reading RFID Tags (MFRC522)


The modern, officially supported library for the RFID-RC522 reader is MFRC522 (replacing the
deprecated RFID.h).

Insight
Installing the MFRC522 Library:

1. Sketch > Include Library > Manage Libraries.


8.8. READING RFID TAGS (MFRC522) 49

2. Search for “MFRC522” by GithubCommunity.

3. Install it.

Pin 10 (SS) SDA (SS)


Pin 13 (SCK) SCK
Pin 11 (MOSI) MOSI
Arduino Uno Pin 12 (MISO) MISO MFRC522
Pin 9 (RST) RST
3.3V 3.3V
GND GND

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

37 Serial . println (" Access denied ");


38 }
39
40 mfrc522 . PICC_HaltA (); // ‫ﺇ ﻑﺍ‬
41 mfrc522 . PCD_StopCrypto1 (); // ‫ﺇ ﻑﺍ‬
42 delay (1000) ;
43 }

8.9 Tracking Rotary Encoders

1 const int encoderPinA = 4;


2 const int encoderPinB = 2;
3 int encoderPos = 0;
4 boolean encoderALast = LOW;
5
6 void loop () {
7 boolean encoderA = digitalRead ( encoderPinA );
8 if (( encoderALast == HIGH) && ( encoderA == LOW)) {
9 if ( digitalRead ( encoderPinB ) == LOW) {
10 encoderPos --; // ‫ﺭﺏ ﺍ‬ ‫ﺩﻭﺭﺍﻥ‬
11 } else {
12 encoderPos ++; // ‫ﺭﺏ ﺍ‬ ‫ﺩﻭﺭﺍﻥ‬
13 }
14 Serial . println ( encoderPos );
15 }
16 encoderALast = encoderA ;
17 }

Insight
For encoders in busy sketches, use hardware interrupts (attachInterrupt()) instead of
polling. Variables modified inside Interrupt Service Routines (ISRs) must be declared
volatile.

8.10 Reading GPS Data

1 # include " TinyGPS .h"


2 TinyGPS gps;
3
4 void loop () {
5 while ( Serial . available ()) {
6 int c = Serial .read ();
7 if (gps. encode (c)) {
8 long lat , lon;
9 gps. get_position (&lat , &lon);
10 Serial .print ("Lat: "); Serial . print (lat);
11 Serial .print (" Lon: "); Serial . println (lon);
12 }
13 }
14 }
8.11. DETECTING DIRECTION (COMPASS) 51

8.11 Detecting Direction (Compass)

1 int calcAngle = atan2(-Y_Data , X_Data ) / M_PI * 180;


2 if ( calcAngle < 0)
3 calcAngle = calcAngle + 360; // ‫ ﺩﺭ‬359 ‫ ﺇ‬0 ‫ﺯﺍﻭ‬

8.12 Reading Acceleration

1 int xValue = analogRead (xPin);


2 int yValue = analogRead (yPin);
3 Serial .print("X = "); Serial . println ( xValue );
4 Serial .print("Y = "); Serial . println ( yValue );

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

9.1 Connecting and Using LEDs

1 void blinkLED (int pin , int duration ) {


2 digitalWrite (pin , HIGH);
3 delay( duration );
4 digitalWrite (pin , LOW);
5 delay( duration );
6 }

9.2 Adjusting LED Brightness (PWM)

1 analogWrite (ledPin , brightness ); // 255-0 brightness:

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

،(3,5,6,9,10,11) ‫ﺍﻑ‬ ‫ﺍ‬ PWM ‫ﺍ ـ‬ ‫ ﺍ ﻱ‬Arduino Uno :ESP8266


‫ﺍ‬ .(GPIO16) D0 ‫ﺀﺍ‬ ‫ﺍﻑ ﺍ‬ ‫ﺍ‬ analogWrite() ‫ﺍ ـ‬ ESP8266 ‫ﻥ‬
. ‫ﺍ ﻭﺍ‬ ‫ﻭ ﺃ‬

52
9.3. CONTROLLING RGB LEDS 53

9.3 Controlling RGB LEDs

1 const int redPin = 3;


2 const int greenPin = 5;
3 const int bluePin = 6;
4
5 void setColor (int r, int g, int b) {
6 analogWrite (redPin , r);
7 analogWrite (greenPin , g);
8 analogWrite (bluePin , b);
9 }

9.4 LED Bar Graph

1 const int ledPins [] = {2, 3, 4, 5, 6, 7, 8, 9, 10};


2 const int ledCount = 9;
3
4 void loop () {
5 int sensorReading = analogRead (A0);
6 int ledLevel = map( sensorReading , 0, 1023 , 0, ledCount );
7 for (int thisLed = 0; thisLed < ledCount ; thisLed ++) {
8 if ( thisLed < ledLevel ) {
9 digitalWrite ( ledPins [ thisLed ], HIGH);
10 } else {
11 digitalWrite ( ledPins [ thisLed ], LOW);
12 }
13 }
14 }

9.5 Multiplexing an LED Matrix

1 void show(byte *image , unsigned long duration ) {


2 unsigned long start = millis ();
3 while (start + duration > millis ()) {
4 for (int row = 0; row < 8; row ++) {
5 digitalWrite ( rowPins [row], HIGH);
6 for (int column = 0; column < 8; column ++) {
7 boolean pixel = bitRead ( image[row], column );
8 if (pixel == 1) {
9 digitalWrite ( columnPins [ column ], LOW);
10 }
11 delayMicroseconds (300);
12 digitalWrite ( columnPins [ column ], HIGH);
13 }
14 digitalWrite ( rowPins [row], LOW);
15 }
16 }
17 }
54 CHAPTER 9. VISUAL OUTPUT

9.6 7-Segment LED Displays

1 const byte numeral [10] = {


2 B11111100 , B01100000 , B11011010 , B11110010 , B01100110 ,
3 B10110110 , B00111110 , B11100000 , B11111110 , B11100110
4 };
5
6 void showDigit (int number ) {
7 for (int segment = 1; segment < 8; segment ++) {
8 boolean isBitSet = bitRead ( numeral [ number ], segment );
9 isBitSet = ! isBitSet ; // ‫ﺩ ﺍ ﻙ‬
10 digitalWrite ( segmentPins [ segment ], isBitSet );
11 }
12 }

9.7 Using Shift Registers (74HC595)

1 const int latchPin = 8;


2 const int clockPin = 12;
3 const int dataPin = 11;
4
5 void sendCommand (int command , int value ) {
6 digitalWrite (latchPin , LOW);
7 shiftOut (dataPin , clockPin , MSBFIRST , command );
8 shiftOut (dataPin , clockPin , MSBFIRST , value );
9 digitalWrite (latchPin , HIGH);
10 }

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

10.1 Controlling Servo Motors

1 # include <Servo .h>


2 Servo myservo ;
3
4 void setup () {
5 myservo . attach (9);
6 }
7
8 void loop () {
9 for (int angle = 0; angle < 180; angle ++) {
10 myservo . write(angle);
11 delay (20);
12 }
13 for (int angle = 180; angle >= 1; angle --) {
14 myservo . write(angle);
15 delay (20);
16 }
17 }

10.2 Controlling Servos with Sensors

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

10.3 Driving Brushed Motors with H-Bridge

D5 (IN1) IN1
D6 (IN2) IN2
D9 (ENA) ENA
Arduino H-Bridge (L298N) Motor

OUT1
OUT2

External Power (e.g., 12V)

EN IN1 IN2 Function


HIGH LOW HIGH Turn clockwise
HIGH HIGH LOW Turn counterclockwise
HIGH LOW LOW Motor stop
LOW X X Motor stop
Table 10.1: H-Bridge Truth Table

10.4 Driving Stepper Motors

1 # include <Stepper .h>


2 # define STEPS 24
3 Stepper stepper (STEPS , 2, 3, 4, 5);
4
5 void setup () {
6 stepper . setSpeed (30); // 30 RPM
7 }
8
9 void loop () {
10 if ( Serial . available ()) {
11 char ch = Serial .read ();
12 if (ch >= '0' && ch <= '9')
13 steps = steps * 10 + ch - '0';
14 else if (ch == '+')
15 stepper .step( steps);
16 else if (ch == '-')
17 stepper .step( steps * -1);
18 }
19 }
10.5. DRIVING SOLENOIDS AND RELAYS 57

10.5 Driving Solenoids and Relays

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

11.1 Playing Tones

1 tone( speakerPin , frequency , duration );


2 delay ( duration );

When NOT to Use This


When NOT to use delay() with tone(): The tone() function is non-blocking, but if
you immediately call delay(duration), you freeze the main loop. Do not use this pattern
if you need to read sensors or respond to buttons while the melody plays. Instead, track
the start time with millis() and check if the note duration has elapsed.

11.2 Playing a Melody

1 char noteNames [] = {'C','D','E','F','G','a','b'};


2 unsigned int frequencies [] = {262 , 294 , 330 , 349, 392, 440, 494};
3 char score [] = " CCGGaaGFFEEDDC ";
4
5 void playNote (char note , int duration ) {
6 for (int i = 0; i < noteCount ; i++) {
7 if ( noteNames [i] == note)
8 tone( speakerPin , frequencies [i], duration );
9 }
10 delay( duration );
11 }
12
13 void loop () {
14 for (int i = 0; i < scoreLen ; i++) {
15 int duration = 333;
16 playNote ( score [i], duration );
17 }
18 delay (4000) ;
19 }

58
11.3. CONTROLLING MIDI 59

Hands-On Project
Project: Arduino Melody

Wokwi Simulation

Goal: Play a simple melody using a piezo buzzer.


Estimated Cost: $4
Bill of Materials (BOM):

• 1x Arduino Uno ($3)

• 1x Piezo Buzzer ($1)

Steps:

1. Connect piezo red wire to pin 9, black to GND.

2. Upload melody sketch.

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:

• Add a button to trigger the melody.

• Use different note durations to create rhythm.

11.3 Controlling MIDI

1 void playMidiNote (byte channel , byte note , byte velocity ) {


2 byte midiMessage = 0x90 + ( channel - 1);
3 Serial .write ( midiMessage );
4 Serial .write (note);
5 Serial .write ( velocity );
6 }
60 CHAPTER 11. AUDIO OUTPUT

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

Communication & IoT

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

12.1 Sending Debug Information

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 }

12.2 Formatting Output

1 Serial .print(value , DEC); // ‫ﻱ‬


2 Serial .print(value , HEX); // ‫ﻱ‬
3 Serial .print(value , OCT); //
4 Serial .print(value , BIN); //

12.3 Receiving Serial Data

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

12.4 Sending Binary Data

1 void sendBinary (int value ) {


2 // Bytes) (Raw ‫ ﺭ ﻝ ﺍ ﺕ ﺍ ﻡ‬[Link] ‫ﻡ‬
3 // ‫ﺍﺭﺍﺕ ﺍ‬ ‫ ﺍ‬BYTE) [Link](val, ‫ﺍﻡ‬ ‫ﺍ‬ ‫ﺍ‬
4 Serial .write ( lowByte ( value)); // ‫ﺍ‬ ‫ﺇﺭ ﻝ ﺍ‬
5 Serial .write ( highByte (value )); // ‫ﻱ‬ ‫ﺍ‬ ‫ﺇﺭ ﻝ ﺍ‬
6 }

12.5 Sending and Receiving Multiple Fields

1 Serial .print('H'); // ‫ﺭﺃﺱ ﺍ‬


2 Serial .print(",");
3 Serial .print(value1 , DEC);
4 Serial .print(",");
5 Serial .print(value2 , DEC);
6 Serial . println ();

12.6 Software Serial

1 # include <SoftwareSerial .h>


2 const int rxpin = 2;
3 const int txpin = 3;
4 SoftwareSerial serial_lcd (txpin , rxpin);
5
6 void setup () {
7 Serial .begin (9600) ;
8 serial_lcd .begin (9600) ;
9 }
10
11 void loop () {
12 serial_lcd .print("Hello LCD");
13 Serial . println ("Hello PC");
14 delay (500);
15 }

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

13.1 Text LCD Display

1 # include <LiquidCrystal .h>


2 LiquidCrystal lcd (12 , 11, 5, 4, 3, 2);
3
4 void setup () {
5 [Link] (16 , 2);
6 [Link]("hello , world!");
7 }
8
9 void loop () {
10 lcd. setCursor (0, 1);
11 [Link]( millis () / 1000);
12 }

13.2 Scrolling Text

1 void loop () {
2 for (int pos = 0; pos < textLen ; pos ++) {
3 lcd. scrollDisplayLeft ();
4 delay (150);
5 }
6 }

13.3 Creating Custom Characters

1 byte happy [8] = {


2 B00000 , B10001 , B00000 , B00000 ,
3 B10001 , B01110 , B00000 , B00000
4 };
5
6 void setup () {
7 lcd. createChar (0, happy);
8 [Link] (16 , 2);
9 }

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

Goal: Display and scroll text on an LCD.


Estimated Cost: $10
Bill of Materials (BOM):

• 1x Arduino Uno ($3)

• 1x 16×2 LCD (HD44780) ($4)

• 1x 50kΩ potentiometer ($1)

• Breadboard & wires ($2)

Steps:

1. Solder 16 header pins to the LCD.

2. Wire: VSS→GND, VDD→+5V, VO→pot center, RS→7, R/W→GND, E→8,


D4→9, D5→10, D6→11, D7→12, A→+5V, K→GND.

3. Upload the sketch.

Common Mistakes & Troubleshooting:

• Blank screen / White boxes: Contrast too high/low. Adjust the 50kΩ potentiometer
connected to V0.

• Random characters: Wiring is incorrect on data lines D4-D7.

Extension Ideas:

• Display sensor readings on the LCD.

• Build a digital clock.


13.3. CREATING CUSTOM CHARACTERS 67

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

Using Time and Dates

14.1 Using delay()

1 delay (1000) ; //
2 delayMicroseconds (10); // ‫ﻭ‬ 10

Caution
The delay() function halts the entire microcontroller. For projects requiring simultaneous
operations, use millis() instead.

Feature delay() millis()


Execution Blocks the CPU entirely. Non-blocking.
Multitasking Impossible. Allows cooperative multitasking.
Power Consumption High (CPU stays active). Can be combined with sleep modes.
Best Use Case Quick prototypes, simple pauses. Production code, responsive UI,
reading sensors.
Table 14.1: Engineering Comparison: delay() vs millis()

14.2 Blink Without delay()

1 const int ledPin = 13;


2 int ledState = LOW;
3 unsigned long previousMillis = 0;
4 long interval = 1000;
5
6 void loop () {
7 unsigned long currentMillis = millis ();
8 if ( currentMillis - previousMillis > interval ) {
9 previousMillis = currentMillis ;
10 if ( ledState == LOW) ledState = HIGH;
11 else ledState = LOW;
12 digitalWrite (ledPin , ledState );
13 }

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.

14.3 Measuring Pulse Duration

1 long duration = pulseIn (pin , HIGH);

When NOT to Use This


When NOT to use pulseIn(): It is a blocking function. If the pulse never arrives (e.g.,
a broken ultrasonic sensor), your entire program hangs forever. Do not use it in safety-
critical or multitasking systems. Use hardware interrupts (attachInterrupt) instead.

14.4 Real-Time Clock (DS1307)

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

Communicating Using I2C and SPI

15.1 I2C Communication


I2C (I2C ) uses two wires: SDA (data) and SCL (clock). On Arduino Uno, these are mapped
to pins A4 and A5.

+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 }

15.1.1 External EEPROM (24LC128)

70
15.2. SPI COMMUNICATION 71

1 void I2CEEPROM_Write ( unsigned int address , byte data) {


2 Wire. beginTransmission ( EEPROM_ID );
3 [Link] (( int) highByte ( address ));
4 [Link] (( int) lowByte ( address ));
5 [Link] (data);
6 Wire. endTransmission ();
7 delay (5);
8 }
9
10 byte I2CEEPROM_Read ( unsigned int address ) {
11 Wire. beginTransmission ( EEPROM_ID );
12 [Link] (( int) highByte ( address ));
13 [Link] (( int) lowByte ( address ));
14 Wire. endTransmission ();
15 Wire. requestFrom (EEPROM_ID , (byte)1);
16 while (Wire. available () == 0);
17 return [Link] ();
18 }

15.2 SPI Communication


SPI ( ‫ﺍ‬ ‫ﺍ‬ ‫ )ﺍ ﺍ‬uses four wires: SCLK, MISO, MOSI, and SS.

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 }

15.3 Communicating Between Arduino Boards


Master:

1 Wire. begin ();


2 Wire. beginTransmission (4);
3 Wire. write('H');
4 Wire. endTransmission ();

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

16.1 Bluetooth (HC-05 / HC-06)


Bluetooth modules (‫ ) ﺙ‬allow wireless control from smartphones and computers. The HC-05
can act as both master and slave; the HC-06 is slave-only.

Insight
Wiring HC-05 to Arduino:

• VCC → 5V (or 3.3V–6V depending on the module)

• GND → GND

• TXD → Arduino RX (pin 0) — or use SoftwareSerial to avoid conflicts

• RXD → Arduino TX via voltage divider (HC-05 RX is strictly 3.3V!)

Important: Use SoftwareSerial on pins 2, 3 so you can retain hardware serial for
debugging.

1 # include <SoftwareSerial .h>


2 SoftwareSerial BT(2, 3); // RX , TX
3
4 void setup () {
5 Serial .begin (9600) ; //
6 [Link] (9600) ; // (38400 ‫ ﺃﻭ‬9600 ‫ﺍ‬ ‫ﺙ )ﺍ‬
7 Serial . println (" Bluetooth ready");
8 }
9
10 void loop () {
11 if (BT. available ()) {
12 char c = [Link] ();
13 Serial .print(" Received : ");
14 Serial . println (c);
15
16 // LED ‫ـ‬ ‫ﺍ‬
17 if (c == '1') digitalWrite (13, HIGH);
18 if (c == '0') digitalWrite (13, LOW);
19 }
20
21 if ( Serial . available ()) {

73
74 CHAPTER 16. WIRELESS COMMUNICATION

22 [Link] ( Serial .read ()); // ‫ﺙ‬ ‫ﺍ‬ ‫ﺇﺭ ﻝ‬


23 }
24 }

Hands-On Project
Project: Smartphone-Controlled LED

Wokwi Simulation

Goal: Control an LED from a smartphone via Bluetooth.


Estimated Cost: $8
Bill of Materials (BOM):

• 1x Arduino Uno ($3)

• 1x HC-05 module ($3)

• 1x LED & 220Ω resistor ($0.15)

• Breadboard & wires ($1.85)

Steps:

1. Wire HC-05 as described above.

2. Connect LED to pin 13.

3. Upload the sketch.

4. Download a Bluetooth Serial Terminal app on your phone.

5. Pair with HC-05 (default password: 1234 or 0000).

6. Send “1” to turn LED on, “0” to turn off.

Common Mistakes:

• Garbage characters on Serial Monitor: Baud rate mismatch. Try 9600 or 38400.

• Module burns out: Connected Arduino 5V TX directly to HC-05 3.3V RX without


a voltage divider.

Extension: Build a smartphone-controlled RGB lamp.


16.2. LOW-COST WIRELESS MODULES (433MHZ) 75

16.2 Low-Cost Wireless Modules (433MHz)

1 # include <VirtualWire .h>


2
3 void setup () {
4 vw_setup (2000) ;
5 }
6
7 void loop () {
8 send(" hello ");
9 delay (1000) ;
10 }
11
12 void send(char * message ) {
13 vw_send (( uint8_t *) message , strlen ( message ));
14 vw_wait_tx ();
15 }

16.3 XBee / ZigBee Communication

1 Serial .print("+++"); // ‫ﺍ ﻭﺍ‬ ‫ﻭ‬ ‫ﻝ‬ ‫ﺍ‬


2 Serial .print(" ATDH0013A200 \r");
3 Serial .print(" ATDL403B9E1E \r");
4 Serial .print("ATCN\r");
5 Serial .print("Hello!");

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

Ethernet and Networking

17.1 Setting Up the Ethernet Shield

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 }

17.2 Web Server

1 EthernetServer server (80);


2
3 void setup () {
4 Ethernet .begin(mac , ip);
5 server .begin ();
6 }
7
8 void loop () {
9 EthernetClient client = server . available ();
10 if ( client ) {
11 boolean current_line_is_blank = true;
12 while ( client . connected ()) {
13 if ( client . available ()) {
14 char c = client .read ();
15 if (c == '\n' && current_line_is_blank ) {
16 client . println ("HTTP /1.1 200 OK");
17 client . println ("Content -Type: text/html");
18 client . println ();
19 client . print (" Analog A0: ");
20 client . print ( analogRead (A0));
21 client . println ("<br />");
22 break ;
23 }
24 if (c == '\n') current_line_is_blank = true;

76
17.2. WEB SERVER 77

25 else if (c != '\r') current_line_is_blank = false ;


26 }
27 }
28 delay (1);
29 client .stop ();
30 }
31 }

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

IoT with ESP8266 and Wi-Fi

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:

1. Open File > Preferences.

2. Add this URL to “Additional Boards Manager URLs”:


[Link]

3. Go to Tools > Board > Boards Manager.

4. Search for “esp8266” and install.

5. Select your board (e.g., NodeMCU 1.0).

Feature ESP8266 ESP32


Library ESP8266WiFi.h WiFi.h
Architecture Single-core 32-bit (Tensilica Dual-core 32-bit (Tensilica
L106) LX6)
Bluetooth None Built-in BLE
Best For Simple IoT endpoints, low Complex IoT, heavy process-
cost. ing, BLE mesh.
Table 18.1: Engineering Comparison: ESP8266 vs ESP32

78
18.1. CONNECTING TO WI-FI 79

18.1 Connecting to Wi-Fi

1 # include <ESP8266WiFi .h>


2
3 const char* ssid = " YOUR_SSID ";
4 const char* password = " YOUR_PASSWORD ";
5
6 void setup () {
7 Serial .begin (115200) ;
8 [Link] (ssid , password );
9
10 Serial .print (" Connecting ");
11 while (WiFi. status () != WL_CONNECTED ) {
12 delay (500);
13 Serial .print(".");
14 }
15 Serial . println ();
16 Serial .print (" Connected ! IP: ");
17 Serial . println (WiFi. localIP ());
18 }
19
20 void loop () {
21 // ‫ﺩﻙ‬
22 }

18.2 ESP8266 Web Server

1 # include <ESP8266WiFi .h>


2 # include <ESP8266WebServer .h>
3
4 ESP8266WebServer server (80);
5
6 void handleRoot () {
7 server .send (200 , "text/html",
8 "<h1 >Hello from ESP8266 !</h1 >"
9 "<p> Analog : " + String ( analogRead (A0)) + " </p>");
10 }
11
12 void setup () {
13 [Link] (ssid , password );
14 while (WiFi. status () != WL_CONNECTED ) delay (500);
15
16 server .on("/", handleRoot );
17 server .begin ();
18 }
19
20 void loop () {
21 server . handleClient ();
22 }

18.3 Sending Data to ThingSpeak


ThingSpeak ( ) is a free IoT analytics platform for storing and visualizing sensor data in
the cloud.
80 CHAPTER 18. IOT WITH ESP8266 AND WI-FI

Feature ThingSpeak (HTTP) MQTT


Protocol HTTP POST/GET Publish/Subscribe
Latency High (handshake overhead) Low (persistent connection)
Best For Simple, periodic data logging. Real-time control and moni-
toring.
Overhead High (headers). Low (lightweight header).
Table 18.2: Engineering Comparison: ThingSpeak vs MQTT

Insight
ThingSpeak Setup:

1. Create a free account at [Link]

2. Create a new Channel with fields (e.g., Field 1 = Temperature).

3. Copy your Write API Key.

4. Install the ThingSpeak library via Library Manager.

1 # include <ESP8266WiFi .h>


2 # include <ThingSpeak .h>
3
4 WiFiClient client ;
5 unsigned long myChannelNumber = 123456;
6 const char * myWriteAPIKey = " YOUR_API_KEY ";
7
8 void setup () {
9 [Link] (ssid , password );
10 while (WiFi. status () != WL_CONNECTED ) delay (500);
11 ThingSpeak .begin( client );
12 }
13
14 void loop () {
15 float temp = analogRead (A0) * 5.0 / 1023.0 * 100;
16

17 // ThingSpeak ‫ﺍ ﻭﻝ‬ ‫ﺍ‬


18 ThingSpeak . setField (1, temp);
19 int x = ThingSpeak . writeFields ( myChannelNumber , myWriteAPIKey );
20
21 if (x == 200) {
22 Serial . println (" Channel update successful .");
23 } else {
24 Serial . println (" Problem updating channel . HTTP error " + String (x));
25 }
26
27 delay (20000) ; // ‫ﺕ‬ ‫ﺍ‬ 15 ThingSpeak
28 }
18.4. MQTT PROTOCOL 81

18.4 MQTT Protocol

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.

1 # include <ESP8266WiFi .h>


2 # include <PubSubClient .h>
3
4 WiFiClient espClient ;
5 PubSubClient client ( espClient );
6 const char* mqtt_server = " broker . hivemq .com";
7
8 void setup () {
9 [Link] (ssid , password );
10 while (WiFi. status () != WL_CONNECTED ) delay (500);
11
12 client . setServer ( mqtt_server , 1883);
13 client . setCallback ( callback );
14 }
15
16 void callback (char* topic , byte* payload , unsigned int length ) {
17 Serial .print (" Message arrived [");
18 Serial .print ( topic );
19 Serial .print ("] ");
20 for (int i = 0; i < length ; i++) {
21 Serial .print (( char) payload [i]);
22 }
23 Serial . println ();
24 }
25
26 void reconnect () {
27 while (! client . connected ()) {
28 if ( client . connect (" ESP8266Client ")) {
29 client . subscribe ("home/ sensor /#");
30 } else {
31 delay (5000) ;
32 }
33 }
34 }
35
36 void loop () {
37 if (! client . connected ()) reconnect ();
38 client .loop ();
39
40 // ‫ﺕ‬
41 client . publish ("home/temp", "25.5");
42 delay (5000) ;
43 }

18.5 Over-The-Air (OTA) Updates

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

:OTA (Local Network OTA) ‫ﺍ‬ ‫ﺍ‬


‫ﻭ‬ ‫ ﺃ‬ArduinoOTA ، ‫ﺭ ﺍ‬ . ‫ﺭ‬ ‫ﺩﻡ ﻭ‬ ‫ﺍ‬ ‫ﺍ‬
: ‫ﺍ‬ ‫ﺍ‬ Arduino IDE ‫ﺓ‬ ‫ـ‬ ‫ﺍ‬

1 // ArduinoOTA ‫ﺍﻡ‬ OTA ‫ﻭﺍ‬ ‫ﺍ‬ ‫ﺍ‬


2 # include <ESP8266WiFi .h>
3 # include <ArduinoOTA .h>
4
5 const char* ssid = " YOUR_SSID ";
6 const char* password = " YOUR_PASSWORD ";
7
8 void setup () {
9 Serial .begin (115200) ;
10 [Link](ssid , password );
11 while (WiFi. status () != WL_CONNECTED ) { delay (500); Serial . print ("."); }
12
13 // OTA ‫ﺇ ﺍﺩ‬
14 ArduinoOTA . onStart ([]() { Serial . println ("Start updating ..."); });
15 ArduinoOTA .onEnd ([]() { Serial . println ("\ nUpdate complete !"); });
16 ArduinoOTA . onError ([]( ota_error_t error ) { Serial . printf (" Error [%u]: ", error);
});
17 ArduinoOTA .begin (); // OTA ‫ﺀ‬
18
19 Serial . println (" Ready . IP: " + WiFi. localIP ());
20 }
21
22 void loop () {
23 ArduinoOTA . handle (); // ‫ﺕ‬ ‫ﻉ‬ ‫ﺍﺭ‬ ‫ﻩﺍ ﺍ‬ ‫ﺀ‬ ‫ﺍ‬
24 // ... ‫ﻭ‬ ‫ﺩ‬
25 }

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

SD Card Data Logging

Data logging (‫ﺍ ﺕ‬ ) is essential for field projects like weather stations, where you must
record sensor readings over time for later analysis.

19.1 Wiring the SD Card Module

Insight
SD Card Module (SPI) Wiring:

• VCC → 5V (some modules have regulators; verify yours)

• 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.

19.2 Writing Sensor Data to SD Card

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:

• Always close files after writing—unclosed data is lost on power loss.

• 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.

• Filenames must adhere to 8.3 format (e.g., [Link]).

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

Using, Modifying, and Creating


Libraries

20.1 Using Built-in Libraries

1 # include <Servo .h>


2 # include <LiquidCrystal .h>
3 # include <EEPROM .h>
4 # include <Wire.h>
5 # include <SPI.h>

20.2 Installing Third-Party Libraries


1. In IDE: Sketch > Include Library > Manage Libraries.

2. Search for the library (e.g., “MFRC522”, “DHT sensor library”).

3. Click Install.

4. For manual install: extract to Documents/Arduino/libraries/.

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.

20.3 Creating Your Own Library


Header file (blinkLED.h):

87
88 CHAPTER 20. USING, MODIFYING, AND CREATING LIBRARIES

1 void blinkLED (int pin , int duration );


2 void blinkLED (int pin , int duration , int repeats );
3
4 const int BLINK_SHORT = 250;
5 const int BLINK_MEDIUM = 500;
6 const int BLINK_LONG = 1000;

Source file ([Link]):

1 # include " blinkLED .h"


2
3 void blinkLED (int pin , int duration ) {
4 digitalWrite (pin , HIGH);
5 delay( duration );
6 digitalWrite (pin , LOW);
7 delay( duration );
8 }
9
10 void blinkLED (int pin , int duration , int repeats ) {
11 while ( repeats ) {
12 blinkLED (pin , duration );
13 repeats --;
14 }
15 }

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

Advanced Coding and Memory


Handling

21.1 Determining Free RAM

1 extern int __bss_end ;


2 extern void * __brkval ;
3
4 int memoryFree () {
5 int freeValue ;
6 if (( int) __brkval == 0)
7 freeValue = (( int)& freeValue ) - (( int)& __bss_end );
8 else
9 freeValue = (( int)& freeValue ) - (( int) __brkval );
10 return freeValue ;
11 }

Insight
The Arduino Uno has only 2KB of RAM. The memoryFree() function indicates available
RAM. If your sketch behaves erratically, suspect memory exhaustion.

21.2 Storing Data in PROGMEM

1 # include <avr/ pgmspace .h>


2
3 const byte table [] PROGMEM = {
4 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5 };
6
7 int value = pgm_read_byte (& table [index ]);

89
90 CHAPTER 21. ADVANCED CODING AND MEMORY HANDLING

21.3 Storing Strings in PROGMEM

Example
Using the F() Macro for Serial Printing

1 Serial . println (F("This string is stored in flash memory and saves RAM!"));

This is the recommended approach for printing constant strings.

21.4 Conditional Compilation

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

21.5 Version Control with Git and GitHub

Insight
Why Git? As your projects grow, tracking changes becomes critical. Git ( ‫ﻡﺍ‬
‫ﺍﺭﺍﺕ‬ ‫ )ﺍ‬lets you:
• Save snapshots of your code at any point.

• Revert to a working version if something breaks.

• Collaborate with others on the same project.

• Deploy code to remote servers or share with the community.


Getting Started:
1. Create a free account at [Link]

2. Install Git from [Link]

3. Initialize a repository: git init.

4. Add files: git add .


21.5. VERSION CONTROL WITH GIT AND GITHUB 91

5. Commit: git commit -m "Initial commit".

6. Push to GitHub: git push origin main.

Practical Guide: Freezing Library Versions


Because Arduino libraries update frequently and can break existing code, it is highly
recommended to ”freeze” your dependencies. Do not rely solely on the user having the
latest version installed via the Library Manager.

1. Vendorizing (Submodules): Place the library directly inside your


project folder (e.g., /lib/DHT_sensor_library) and commit it to your
repository. Alternatively, use Git submodules: git submodule add
[Link] lib/DHT.

2. Arduino CLI Versioning: If using Arduino CLI, specify exact versions in a


[Link] file or install via command line: arduino-cli lib install
"DHT sensor library@1.4.3".

3. Document it: Always add a .gitignore to exclude build artifacts (*.hex,


/build/), and include a [Link] explicitly listing the required library versions.

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

Simple Digital Signal Processing


(DSP)

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.

22.1 Moving Average Filter


The moving average filter (smoothing) was covered in Chapter 6. It sums the last N readings
and divides by N . While simple, it requires an array of size N , consuming RAM.

22.2 Exponential Low-Pass Filter


A far more memory-efficient method is the Exponential Moving Average (EMA). It requires only
the current reading and the previous filtered value.

1 float filteredValue = 0.0;


2 const float alpha = 0.1; // (0.1 to 0.0) ‫ﺍ‬
3
4 void loop () {
5 float rawSensor = analogRead (A0);
6

7 // Filter) Low-pass (Exponential ‫ﺍ‬ ‫ﺍ‬ ‫ﺍ‬


8 filteredValue = ( alpha * rawSensor ) + ((1.0 - alpha) * filteredValue );
9
10 Serial .print ("Raw: ");
11 Serial .print ( rawSensor );
12 Serial .print (" Filtered : ");
13 Serial . println ( filteredValue );
14 delay (50);
15 }

Insight
How Alpha (α) works:

• If α = 1.0, no filtering occurs (output equals raw input).

92
22.3. PRACTICAL APPLICATION: SMOOTHING ULTRASONIC SENSOR 93

• If α = 0.1, the filter is highly smooth but responds slowly to sudden changes.

• If α = 0.5, it balances responsiveness and noise reduction.

22.3 Practical Application: Smoothing Ultrasonic Sensor


Ultrasonic distance sensors (HC-SR04) often output “ghost” readings or sudden spikes. Applying
a low-pass filter prevents your robot or project from reacting to false triggers.

1 float smoothDistance = 0.0;


2 const float alpha = 0.3; // ‫ﻭﺍ‬ ‫ﺍ‬ ‫ﺍﺯﻥ‬
3
4 void loop () {
5 long duration = pulseIn (echoPin , HIGH);
6 float rawCm = duration / 29.0 / 2.0;
7

8 // (Outliers) ً ‫ﺍ‬ ‫ﺍ ﺍﺀﺍﺕ ﺍ‬


9 if (rawCm > 0 && rawCm < 400) {
10 smoothDistance = ( alpha * rawCm ) + ((1.0 - alpha ) * smoothDistance );
11 }
12
13 Serial . println ( smoothDistance );
14 delay (50);
15 }

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

Using the Controller Chip Hardware

23.1 EEPROM Storage

1 # include <EEPROM .h>


2
3 EEPROM .write(address , value);
4 byte value = EEPROM .read( address );

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.

23.2 Hardware Interrupts

1 volatile unsigned long microseconds ;


2 volatile byte index = 0;
3 volatile unsigned long results [64];
4
5 void setup () {
6 attachInterrupt (0, analyze , CHANGE );
7 }
8
9 void analyze () {
10 if (index > 0) {
11 results [ index] = micros () - microseconds ;
12 }
13 index ++;
14 microseconds = micros ();
15 }

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.

23.3 Timer Interrupts

1 # include <MsTimer2 .h>


2
3 void setup () {
4 MsTimer2 :: set (500 , flash);
5 MsTimer2 :: start ();
6 }
7
8 void flash () {
9 digitalWrite (13 , ! digitalRead (13));
10 }

23.4 Faster Analog Reads

1 bitClear (ADCSRA , ADPS0 );


2 bitClear (ADCSRA , ADPS1 );
3 bitSet (ADCSRA , ADPS2);

Caution
Faster analog reads trade precision for speed. Test your application to determine if this
trade-off is acceptable.

23.5 Reducing Battery Drain

1 # include <Narcoleptic .h>


2
3 void loop () {
4 Narcoleptic . delay (500); // ‫ﻙ‬ ‫ﺍ‬
5 }

23.6 Direct Port Manipulation

1 bitSet (PORTD , 2); // HIGH) digitalWrite(2, ً


2 bitClear (PORTD , 2); // LOW) digitalWrite(2, ً
96 CHAPTER 23. USING THE CONTROLLER CHIP HARDWARE

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

24.1 Project: Light Dimmer


Goal: Control LED brightness with a potentiometer.

Wokwi Simulation

Estimated Cost: $6
Bill of Materials (BOM):

• Arduino Uno ($3), Potentiometer ($1), LED & Resistor ($0.15)

1 int potPin = A0;


2 int led = 9;
3
4 void setup () {
5 pinMode (led , OUTPUT );
6 }
7
8 void loop () {
9 int potValue = analogRead ( potPin );
10 analogWrite (led , potValue / 4);
11 delay (10);
12 }

Common Mistakes: Connecting the potentiometer to a non-PWM pin. Pin 9 must be used
for analogWrite.

24.2 Project: Disco Strobe Light


Goal: Create a police-style strobe with adjustable speed.

99
100 CHAPTER 24. BEGINNER PROJECTS

1 const int analogInPin = A0;


2 int sensorValue = 0;
3 int timer = 0;
4
5 void setup () {
6 pinMode (12 , OUTPUT );
7 pinMode (11 , OUTPUT );
8 }
9
10 void loop () {
11 sensorValue = analogRead ( analogInPin );
12 timer = map( sensorValue , 0, 1023 , 10, 500);
13 digitalWrite (12 , HIGH); delay ( timer );
14 digitalWrite (12 , LOW); delay ( timer );
15 digitalWrite (11 , HIGH); delay ( timer );
16 digitalWrite (11 , LOW);
17 }

24.3 Project: Plant Monitor


Goal: Monitor soil moisture and alert when watering is needed.

1 const int moistureAO = A0;


2 int buzzPin = 11;
3 int LED = 13;
4
5 void setup () {
6 Serial .begin (9600) ;
7 pinMode (buzzPin , OUTPUT );
8 pinMode (LED , OUTPUT );
9 }
10
11 void loop () {
12 int tmp = analogRead ( moistureAO );
13 Serial .print (" Moisture : ");
14 Serial . println (tmp);
15 delay (1000) ;
16
17 if (tmp > 900) { // ‫ﺍ ﻑ‬
18 digitalWrite (buzzPin , HIGH);
19 digitalWrite (LED , HIGH);
20 delay (1000) ;
21 digitalWrite (buzzPin , LOW);
22 } else {
23 digitalWrite (LED , LOW);
24 }
25 }

Common Mistakes: Leaving the moisture sensor constantly powered causes rapid corrosion.
Power it from a digital pin and turn it on only during reading.

24.4 Project: Ghost Detector (EMF Detector)


Goal: Detect electromagnetic fields using a wire antenna.
Materials: Arduino, 10 LEDs, 10 220Ω resistors, 20cm wire, 1MΩ resistor.
24.4. PROJECT: GHOST DETECTOR (EMF DETECTOR) 101

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.

3. Calibrate the EMF detector to ignore background noise.


Chapter 25

Intermediate Projects

25.1 Project: Memory Game


Goal: Recreate the Atari “Touch Me” memory game.
Materials: Arduino, 4 pushbuttons, 4 LEDs, 4 220Ω resistors, piezo buzzer.

25.2 Project: Secret Knock Lock


Goal: Unlock a box using a secret knock pattern.

1 const int quietKnock = 10;


2 const int loudKnock = 100;
3
4 boolean checkForKnock (int value ) {
5 if (value > quietKnock && value < loudKnock ) {
6 digitalWrite (yellowLed , HIGH);
7 delay (50);
8 digitalWrite (yellowLed , LOW);
9 return true;
10 }
11 return false ;
12 }

25.3 Project: Joystick-Controlled Laser

1 # include <Servo .h>


2 Servo tilt , pan;
3 int joyX = A0;
4 int joyY = A1;
5
6 void setup () {
7 tilt. attach (9);
8 pan. attach (10);
9 }
10
11 void loop () {
12 int x = map( analogRead (joyX), 0, 1023 , 900, 2100);
13 int y = map( analogRead (joyY), 0, 1023 , 900, 2100);
14 [Link] (x);
15 [Link](y);

102
25.4. PROJECT: REMOTE CONTROL SERVO 103

16 delay (15);
17 }

25.4 Project: Remote Control Servo

1 # include <IRremote .h>


2 # include <Servo .h>
3
4 IRrecv irrecv (11);
5 decode_results results ;
6 Servo servo1 , servo2 ;
7
8 void loop () {
9 if ( irrecv . decode (& results )) {
10 if ( results .value == Value1 ) servo1 .write (160);
11 else if ( results . value == Value2 ) servo1 .write (70);
12 irrecv . resume ();
13 }
14 }

25.5 Project: Weather Station


Goal: Display temperature and humidity on an LCD screen.

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.

25.6 Project: Electronic Die

1 const int latchPin = 8;


2 const int clockPin = 12;
3 const int dataPin = 11;
4 const int buttonPin = 2;
5
6 unsigned char lookup_7seg [] = {
7 0x06 , 0x5B , 0x4F , 0x66 , 0x6D , 0x7D , 0x80
8 };
9
10 void DiceNumber ( unsigned char num) {
11 digitalWrite (latchPin , LOW);
12 shiftOut (dataPin , clockPin , MSBFIRST , lookup_7seg [num ]);
13 digitalWrite (latchPin , HIGH);
14 }

Exercises
1. Add sound effects to the memory game.

2. Increase the secret knock pattern to 5 knocks.

3. Add an SD card logger to the weather station.


Chapter 26

Security Projects

26.1 Project: Intruder Sensor

1 if ( distance <= 15) { // 15 ‫ﺍ‬


2 digitalWrite (greenLed , LOW);
3 digitalWrite (redLed , HIGH);
4 myservo .write (180) ;
5 delay (450);
6 } else {
7 digitalWrite (redLed , LOW);
8 digitalWrite (greenLed , HIGH);
9 myservo .write (90);
10 }

26.2 Project: Laser Trip Wire Alarm


1. Calibrate photoresistor readings with and without the laser.

2. Set a threshold between the two values.

3. When the beam is broken, sound the alarm.

26.3 Project: Motion Sensor Alarm (PIR with Debounce)

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

26.4 Project: Keypad Entry System

1 # include <Password .h>


2 # include <Keypad .h>
3 # include <Servo .h>
4
5 Password password = Password ("2468");
6
7 void checkPassword () {
8 if ( password . evaluate ()) {
9 myservo . write (90);
10 digitalWrite (11, HIGH); // ‫ﺃ‬
11 delay (500);
12 digitalWrite (11, LOW);
13 } else {
14 digitalWrite (12, HIGH); // ‫ﺃ‬
15 delay (500);
16 digitalWrite (12, LOW);
17 }
18 }

26.5 Project: Wireless ID Card Entry System (MFRC522)

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

10 // ( ‫) ّﻝ‬ ‫ﺡ‬ ‫ﺍ‬ ‫ﻑﺍ‬


11 byte authorizedCard [4] = {0x4D , 0x55 , 0xAD , 0xD3 };
12
13 void setup () {
14 [Link] ();
15 mfrc522 . PCD_Init ();
16 doorLock . attach (8);
17 pinMode (LED_access , OUTPUT );
18 pinMode ( LED_intruder , OUTPUT );
19 }
20
21 void loop () {
22 if (! mfrc522 . PICC_IsNewCardPresent ()) return ;
23 if (! mfrc522 . PICC_ReadCardSerial ()) return ;
24
25 boolean cardMatch = true;
26 for (int i = 0; i < 4; i++) {
27 if ( mfrc522 .uid. uidByte [i] != authorizedCard [i]) {
28 cardMatch = false;
29 break ;
30 }
31 }
32
26.5. PROJECT: WIRELESS ID CARD ENTRY SYSTEM (MFRC522) 107

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.

2. Log RFID access attempts to an SD card with timestamps.

3. Combine PIR and ultrasonic sensors for double-layer security.


Chapter 27

Advanced Projects

27.1 Project: Rainbow Light Show

1 int latchpin = 10;


2 int clockpin = 13;
3 int datapin = 11;
4
5 void allRed () {
6 digitalWrite (latchpin , LOW);
7 shiftOut (datapin , clockpin , MSBFIRST , 255);
8 shiftOut (datapin , clockpin , MSBFIRST , 0);
9 shiftOut (datapin , clockpin , MSBFIRST , 0);
10 shiftOut (datapin , clockpin , MSBFIRST , 255);
11 digitalWrite (latchpin , HIGH);
12 }

27.2 Project: Build Your Own Arduino


Goal: Build a standalone Arduino on a breadboard.
Estimated Cost: $8
Bill of Materials (BOM):

• ATmega328P (with bootloader) ($3)

• 16MHz crystal, L7805cv regulator, 9V battery ($3)

• 2 100µF caps, 2 22pF caps, pushbutton, LEDs, resistors ($2)

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

Designing Custom PCBs with KiCad

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.

28.1 Introduction to KiCad


KiCad is a free, open-source EDA (Electronic Design Automation) software. Unlike Eagle’s free
tier, KiCad has no board size limitations.

28.2 Schematic Capture (Eeschema)


1. Open KiCad and create a new project.

2. Open the Schematic Editor (Eeschema).

3. Place components (symbols) from the libraries: microcontrollers, resistors, capacitors, con-
nectors.

4. Wire them together logically.

5. Annotate components (assign R1, C1, U1, etc.).

6. Assign footprints (physical packages) to each symbol using CvPcb.

28.3 PCB Layout (Pcbnew)


1. Open the Board Editor (Pcbnew).

2. Read the netlist generated from the schematic.

3. Arrange the footprints on the board outline.

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

28.4 Exporting Gerber Files


Manufacturers (like JLCPCB, PCBWay, or Elecrow) require Gerber files.

1. In Pcbnew, go to File > Fabrication Outputs > Gerbers.

2. Select layers ([Link], [Link], [Link], [Link], [Link], etc.).

3. Generate the files and zip them.

4. Upload the ZIP to the manufacturer’s website.


Insight
Tips for Beginners:

• Keep trace widths at least 0.25mm (10mil) for signals, and 0.5mm+ for power lines.

• Always add mounting holes in the corners.

• Silkscreen labels (pin names, component values) will save you hours of debugging
later.

28.5 Capstone Project: IoT Weather Station with Cloud Logging


Goal: Build a comprehensive IoT weather station that reads temperature and humidity, displays
data on an LCD, logs to an SD card, and uploads to ThingSpeak.
Estimated Cost: $15
Bill of Materials (BOM):

• 1x ESP8266 (NodeMCU) ($4)

• 1x DHT22 ($3)

• 1x 16x2 I2C LCD ($3)

• 1x microSD module ($1)

• Breadboard & wires ($4)

1 # include <ESP8266WiFi .h>


2 # include <ESP8266WebServer .h>
3 # include <DHT.h>
4 # include <LiquidCrystal_I2C .h>
5 # include <ThingSpeak .h>
6
7 const char* ssid = " YOUR_SSID ";
8 const char* password = " YOUR_PASSWORD ";
9
10 # define DHTPIN D4
11 # define DHTTYPE DHT22
12 DHT dht(DHTPIN , DHTTYPE );
13
14 LiquidCrystal_I2C lcd (0x27 , 16, 2);
15 WiFiClient client ;
16 ESP8266WebServer server (80);
17
28.5. CAPSTONE PROJECT: IOT WEATHER STATION WITH CLOUD
LOGGING 111
18 unsigned long myChannelNumber = 123456;
19 const char * myWriteAPIKey = " YOUR_API_KEY ";
20
21 String generateHTML (float t, float h) {
22 String html = " <! DOCTYPE html ><html ><head >";
23 html += "<meta http -equiv=' refresh ' content ='5'>";
24 html += "<title >IoT Weather Station </ title ></head ><body >";
25 html += "<h1 > Weather Station Data </h1 >";
26 html += "<p> Temperature : " + String (t) + " C </p>";
27 html += "<p> Humidity : " + String (h) + " %</p>";
28 html += " </body ></html >";
29 return html;
30 }
31
32 void handleRoot () {
33 float t = dht. readTemperature ();
34 float h = dht. readHumidity ();
35
36 if (isnan(t) || isnan (h)) {
37 server .send (500 , "text/ plain", " Sensor error");
38 return ;
39 }
40
41 [Link] ();
42 lcd. setCursor (0, 0);
43 [Link]("T:" + String (t) + "C");
44 lcd. setCursor (0, 1);
45 [Link]("H:" + String (h) + "%");
46
47 server .send (200 , "text/html", generateHTML (t, h));
48 }
49
50 void setup () {
51 Serial .begin (115200) ;
52 [Link] ();
53 [Link] ();
54 lcd. backlight ();
55
56 [Link] (ssid , password );
57 while (WiFi. status () != WL_CONNECTED ) {
58 delay (500);
59 Serial .print(".");
60 }
61 Serial . println (WiFi. localIP ());
62
63 [Link] ();
64 [Link]("IP:");
65 lcd. setCursor (0, 1);
66 [Link](WiFi. localIP ());
67 delay (3000) ;
68
69 ThingSpeak .begin( client );
70 server .on("/", handleRoot );
71 server .begin ();
72 }
73
74 unsigned long lastUpload = 0;
75 void loop () {
76 server . handleClient ();
77
78 // 20 ThingSpeak ‫ﺕ ـ‬ ‫ﺍ‬ ‫ﺭ‬
79 if ( millis () - lastUpload > 20000) {
112 CHAPTER 28. DESIGNING CUSTOM PCBS WITH KICAD

80 float t = dht. readTemperature ();


81 float h = dht. readHumidity ();
82 if (! isnan(t) && ! isnan (h)) {
83 ThingSpeak . setField (1, t);
84 ThingSpeak . setField (2, h);
85 ThingSpeak . writeFields ( myChannelNumber , myWriteAPIKey );
86 }
87 lastUpload = millis ();
88 }
89 }

Common Mistakes & Troubleshooting:

• 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.

2. Add an MQTT publisher to broadcast weather data.

3. Build a mobile-responsive web interface for the weather station.


Part VII

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

Project not working

Power No
Check USB cable, battery, barrel jack
LED on?

Yes

Code No Check syntax, missing semi-


compiles? colons, library installation

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

Debug logic in code


117

Caution
Common Pitfalls Checklist:

• LED reversed (long leg = anode = positive)

• Forgot pinMode(pin, OUTPUT)

• Forgot [Link](9600)

• Wrong baud rate in Serial Monitor

• Floating input pin (no pull-up/down resistor)

• Voltage too high on analog pin (max 5V!)

• MFRC522 connected to 5V instead of 3.3V

• Forgot to install required library (DHT, MFRC522, etc.)


Chapter 30

Quick Reference

30.1 Board Compatibility Guide


When transitioning between Arduino Uno and ESP boards, consider these hardware differences
to avoid breaking your code or hardware.

Feature Arduino Uno ESP8266 ESP32


Architecture 8-bit AVR 32-bit Tensilica L106 32-bit Tensilica LX6
(Dual)
int size 2 bytes (16-bit) 4 bytes (32-bit) 4 bytes (32-bit)
ADC Range 0–5V (10-bit) 0–1V (10-bit) 0–3.3V (12-bit)
PWM Pins 3, 5, 6, 9, 10, 11 All except D0 All configurable
Boot Pins N/A D3 (GPIO0), D8 GPIO0, GPIO2,
(GPIO15) must be GPIO15 strapping
LOW/HIGH respec- pins.
tively at boot.
Library Swap Requires Shield ESP8266WiFi.h WiFi.h
(Wi-Fi)
Operating Volt- 5V 3.3V (5V tolerant I/O) 3.3V
age
Table 30.1: Microcontroller Compatibility Quick Reference

30.2 Sensor Wiring Quick Reference

Sensor VCC GND Signal


PIR (HC-SR501) 5V GND D2 (digital)
Ultrasonic (HC-SR04) 5V GND Trig: D12, Echo: D13
LM35 5V GND A0 (analog)
DHT11/DHT22 3.3–5V GND D2 (digital + 10k pull-up)
LDR (photoresistor) — GND A0 (via voltage divider)

118
30.3. TYPICAL VOLTAGE AND CURRENT VALUES 119

MFRC522 (RFID) 3.3V GND SPI: D10-D13, RST: D9


HC-05 (Bluetooth) 5V GND TX: D2, RX: D3 (via divider)
SD Card Module 5V GND SPI: D10-D13
ESP8266 (standalone) 3.3V GND USB programming
Table 30.2: Sensor Wiring Quick Reference

30.3 Typical Voltage and Current Values

Component Voltage Current


Component Voltage Current
Arduino Uno (operating) 5V 50 mA (idle)
LED (red, green) 1.8–2.2V 20 mA
LED (blue, white) 3.0–3.5V 20 mA
Servo motor (SG90) 5V 100–250 mA
DC motor (small) 3–6V 200–500 mA
Piezo buzzer 5V 10–30 mA
Relay module 5V 70–100 mA
ESP8266 (transmit) 3.3V 170–300 mA
HC-05 (Bluetooth) 3.3–5V 30–40 mA
Table 30.3: Typical Component Specifications

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

30.4 Unit Conversion Tables

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

30.5 Resistor Color Code Quick Reference

Color 1st 2nd Multiplier Tolerance


Black 0 0 1Ω —
Brown 1 1 10Ω ±1%
Red 2 2 100Ω ±2%
Orange 3 3 1KΩ —
Yellow 4 4 10KΩ —
Green 5 5 100KΩ ±0.5%
Blue 6 6 1MΩ ±0.25%
Gold — — 0.1Ω ±5%
Silver — — 0.01Ω ±10%
Table 30.5: Resistor Color Codes

30.6 Common Resistor Values for LEDs

LED Color Forward Voltage Resistor (at 5V)


Red 1.8V 220Ω – 330Ω
Yellow 2.0V 220Ω
Green 2.0V 220Ω
Blue 3.0V 100Ω – 150Ω
White 3.2V 100Ω
RGB (common cathode) varies 220Ω each channel
Table 30.6: LED Resistor Values
30.7. ARDUINO UNO PIN REFERENCE 121

30.7 Arduino Uno Pin Reference

Pin Function Notes


0 RX (serial) Used for USB; avoid in sketches
1 TX (serial) Used for USB; avoid in sketches
2 Digital I/O External interrupt 0
3 Digital I/O PWM, interrupt 1
4–6 Digital I/O 5,6 are PWM
7–8 Digital I/O —
9–11 Digital I/O PWM; 11=MOSI, 12=MISO, 13=SCK
10 Digital I/O PWM, SS (SPI)
13 Digital I/O Onboard LED
A0–A5 Analog input 10-bit ADC (0–1023)
A4 Analog SDA (I2C)
A5 Analog SCL (I2C)
Table 30.7: Arduino Uno Pin Reference

30.8 ESP8266 (NodeMCU) Pin Reference

Pin Function Notes


D0 GPIO16 No interrupt, no PWM
D1 GPIO5 SCL (I2C)
D2 GPIO4 SDA (I2C)
D3 GPIO0 Pull-up; boot fails if LOW at boot
D4 GPIO2 Connected to onboard LED; pull-up
D5 GPIO14 SCK (SPI)
D6 GPIO12 MISO (SPI)
D7 GPIO13 MOSI (SPI)
D8 GPIO15 Pull-down; boot fails if HIGH
A0 Analog input 0–1V (or 0–3.3V via divider)
Table 30.8: NodeMCU ESP8266 Pin Reference
122 CHAPTER 29. TROUBLESHOOTING FLOWCHART

30.9 ASCII Character Set

Dec Hex Char Dec Hex Char


0 0x00 NULL 65 0x41 A
9 0x09 Tab 66 0x42 B
10 0x0A LF 67 0x43 C
13 0x0D CR 97 0x61 a
32 0x20 Space 48 0x30 0
33 0x21 ! 49 0x31 1
Table 30.9: Selected ASCII Characters
Chapter 31

Troubleshooting Guide

31.1 Code That Won’t Compile


• Missing semicolon: Every statement must end with ;.
• Case sensitivity: ledPin and LedPin are distinct variables.
• Missing curly braces: Every { needs a matching }.
• Missing return type: loop() must be declared as void loop().
• Library not found: Install via Library Manager; verify #include spelling.
• Wrong board selected: ESP8266 code will not compile for Arduino Uno.

31.2 Code Compiles but Doesn’t Work


• Forgot [Link]().
• Wrong pin mode: Set as OUTPUT for LEDs/motors.
• Wrong baud rate: Serial Monitor must match [Link]().
• Floating pin: Use a pull-up/pull-down resistor.
• LED reversed: Long leg is positive (anode).
• DHT reading NaN: Wait 2 seconds between reads; check wiring.
• MFRC522 not detecting cards: Check 3.3V power; verify SPI wiring.

31.3 Hardware Troubleshooting


• Check power: Is the Arduino receiving adequate power?
• Check connections: Are wires seated properly in the breadboard?
• Check polarity: Are LEDs, capacitors, and diodes oriented correctly?
• Use a multimeter to verify voltages at component pins.
• Simplify: Remove components and test them one at a time.
• Check for short circuits using a multimeter’s continuity mode.

123
Chapter 32

Using Online Simulators

• Wokwi ([Link] Free, supports Arduino, ESP32, ESP8266. Fast, no


installation required.

• Tinkercad Circuits ([Link] Beginner-friendly, drag-


and-drop interface.

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

References and Resources

33.1 Official Resources


• Arduino Official: [Link]

• Language Reference: [Link]

• Arduino Forum: [Link]

33.2 ESP8266 / IoT Resources


• ESP8266 Arduino Core: [Link]

• ThingSpeak: [Link]

• Random Nerd Tutorials: [Link]

33.3 Recommended Libraries


• MFRC522 (RFID) by GithubCommunity

• DHT sensor library by Adafruit

• PubSubClient (MQTT) by Nick O’Leary

• ArduinoJson by Benoit Blanchon

• ThingSpeak by MathWorks

33.4 Recommended Books


• Arduino Cookbook by Michael Margolis

• Getting Started with Arduino by Massimo Banzi

• Making Things Talk by Tom Igoe

• ESP8266 Home Automation Projects by Caleb Curry

125
Chapter 34

Glossary

ADC Analog-to-Digital Converter.


Baud Rate Speed of serial communication (bits per second).
Breadboard Solderless prototyping board.
Debounce Filtering spurious readings from mechanical switches.
DSP Digital Signal Processing.
Duty Cycle Percentage of time a PWM signal is HIGH.
EEPROM Non-volatile storage.
EMA Exponential Moving Average.
ESP8266 Low-cost Wi-Fi microcontroller.
Flyback Diode Diode across inductive loads to absorb voltage spikes.
Gerber Standard file format for PCB manufacturing.
I2C Two-wire serial protocol.
IoT Internet of Things.
ISR Interrupt Service Routine.
KiCad Open-source EDA software for PCB design.
MQTT Lightweight pub/sub messaging protocol for IoT.
OTA Over-The-Air firmware update.
PCB Printed Circuit Board.
PROGMEM Flash memory storage for constants.
Pull-up Resistor Resistor that keeps a pin HIGH when not grounded.
SPI Serial Peripheral Interface (4-wire).
ThingSpeak IoT analytics platform.
Volatile Keyword for variables modified in ISRs.
Voltage Divider Circuit that reduces voltage using two resistors.

126
Chapter 35

Exercise Solutions

Chapter 1: The Arduino Platform and IDE

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:

1 if ( millis () - previousMillis >= 1000) {


2 previousMillis = millis ();
3 digitalWrite (led , ! digitalRead (led));
4 }

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.

Chapter 2: Variables and Data Types

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.

Chapter 3: Structuring Arduino Programs


1. [Direct] Global variables are declared outside functions and exist for the entire lifetime
of the program, accessible from anywhere. Local variables are declared inside functions,
created when the function is called, and destroyed when it exits, saving RAM.

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.

Chapter 4: Control Flow and Decision Making


1. [Direct] Forgetting the break statement causes ”fall-through.” Execution will continue
into the next case block regardless of whether its condition matches, leading to unintended
actions executing sequentially.

2. [Debug] Writing if (x = 5) uses the assignment operator, meaning it sets x to 5 and


evaluates to true (since 5 is non-zero). The condition will always pass. To debug, look
for unexpected variable mutations. Modern compilers warn against this; the fix is to use
the equality operator if (x == 5). A good defensive coding habit is if (5 == x), which
throws a compile error if you mistype =.

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.

Chapter 5: Mathematical Operations

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));.

Chapter 6: Digital Input and Output

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.

Chapter 7: Analog Input

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.

Chapter 8: Getting Input from Sensors

1. [Direct] ”Bouncing” refers to the rapid, mechanical make-and-break contacts inside a


switch that occur in the milliseconds after it is pressed. Debouncing is necessary to prevent
the microcontroller from registering a single physical press as dozens of digital events.

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.

Chapter 9: Visual Output

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.

Chapter 10: Physical Output


1. [Direct] A flyback diode is placed across inductive loads (like motors or relays) to safely
absorb high-voltage reverse spikes (back-EMF) generated when the load is turned off.

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.

Chapter 11: Audio Output


1. [Direct] Frequency determines the pitch. A higher frequency results in a higher musical
note, while a lower frequency results in a deeper bass note.

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.

Chapter 12: Serial Communications


1. [Direct] The baud rate is the speed of serial communication in bits per second. The
sender and receiver must match it so the receiver knows exactly how long each bit pulse
lasts to sample the data accurately.
132 CHAPTER 35. EXERCISE SOLUTIONS

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.

Chapter 13: Using Displays

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.

Chapter 14: Using Time and Dates

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.

Chapter 15: Communicating Using I2C and SPI


1. [Direct] I2C uses 2 wires (SDA for data, SCL for clock). SPI uses 4 wires (SCLK, MISO,
MOSI, and SS).

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.

Chapter 16: Wireless Communication


1. [Direct] AT mode is a configuration mode for the HC-05 Bluetooth module. In this mode,
it accepts text-based AT commands to modify its baud rate, name, pairing password, and
master/slave role.

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.

Chapter 17: Ethernet and Networking


1. [Direct] The MAC address is the permanent hardware identifier of the network interface.
The IP address is the logical network address used for routing packets to that specific
device on a local or global network.
134 CHAPTER 35. EXERCISE SOLUTIONS

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.

Chapter 18: IoT with ESP8266 and Wi-Fi


1. [Direct] MQTT is a lightweight publish/subscribe protocol. Devices publish data to topics
(e.g., home/temp), and other devices subscribe to those topics to receive the data instantly,
without needing to request it.
2. [Debug] The NodeMCU fails to boot because D8 is GPIO15, which must be LOW during
the boot sequence. A sensor holding this pin HIGH prevents the ESP8266 from entering
normal execution mode. Fix this by moving the sensor to a safe pin like D1 or D2.
3. [Design] Design a robust reconnect logic: in the loop(), check if ([Link]() !=
WL_CONNECTED). If disconnected, attempt to reconnect, but use millis() to space out
connection attempts (e.g., every 10 seconds) so it doesn’t freeze the loop. For OTA,
always implement [Link]() to log errors, and consider a dual-partition
OTA scheme so a failed update automatically rolls back to the previous working firmware.
4. [What If] If the MQTT broker goes offline, the standard reconnect() function’s delay(5000)
will block the main loop, freezing your local sensor reads and actuator controls. The fix is
to replace the delay(5000) with a non-blocking millis() timer. This allows the board
to continue operating locally, attempting reconnection in the background without halting
the main program.

Chapter 19: SD Card Data Logging


1. [Direct] The 8.3 format limits filenames to a maximum of 8 characters for the name, a dot,
and a 3-character extension (e.g., [Link]). This is a limitation of the FAT16/FAT32
file system libraries used by Arduino.
2. [Debug] Data is lost because the file wasn’t closed. When you write to a file, the data
sits in a small RAM buffer. It is only physically written to the SD card when the buffer
fills or when close() is called. If power is lost before close(), the buffer is wiped. Fix it
by ensuring [Link]() is called immediately after the write block.
3. [Design] The reset is caused by a Voltage Brownout. The SD card draws sudden spikes
of current during writes, dragging the Arduino’s 3.3V or 5V rail below its safe operating
threshold. Design a power management solution: power the SD card from a dedicated 5V
supply or a robust buck converter, and add a large bulk capacitor (e.g., 100µF) across the
SD card’s power pins to absorb current spikes.
135

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.

Chapter 20: Using, Modifying, and Creating Libraries

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.

Chapter 21: Advanced Coding and Memory Handling

1. [Direct] Heap fragmentation occurs when dynamic memory (malloc/new/String) is al-


located and freed in varying sizes, leaving unusable ”gaps” in the RAM. Eventually, the
system cannot allocate a contiguous block and crashes.

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:

1 #if defined ( ESP8266 ) || defined ( ESP32 )


2 typedef uint32_t int32_t ; // Ensure 32- bit
3 #else
4 typedef uint16_t int16_t ; // Force 16- bit
5 #endif

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.

Chapter 22: Simple Digital Signal Processing (DSP)


1. [Direct] A Moving Average filter stores the last N readings in an array and averages them,
requiring N bytes of RAM. An Exponential Moving Average (EMA) uses a mathematical
weight (alpha) requiring only the current reading and the previous filtered value, taking
only 4 bytes of RAM regardless of smoothing.

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.

Chapter 23: Using the Controller Chip Hardware


1. [Direct] The volatile keyword tells the compiler: ”This variable can change at any time
outside the current code flow.” It forces the compiler to fetch the variable from RAM on
every read, rather than caching it in a CPU register, which is critical for variables modified
inside Interrupt Service Routines (ISRs).

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

433MHz RF, 75 DHT22, 46


7-Segment Display, 54 Digital Signal Processing, 92
digitalRead(), 35
Accelerometer, 51 digitalWrite(), 35
ADC, 40 Do-While Loop, 28
ADC Prescaler, 95 DSP, 92
analogRead(), 40 Duty Cycle, 52
analogWrite(), 52
Arduino Hardware, 13 Edge Detection, 38
Arduino IDE, 14 EEPROM, 94
Arithmetic, 29 ESP8266, 78
Arrays, 19 ESP8266 Pinout, 121
ASCII, 122 Ethernet, 76
Audio Output, 58 Ethernet Shield, 76
Exercise Solutions, 127
Binary Data, 64 Exponential Moving Average, 92
Bitwise Operations, 31
Blink Sketch, 15 F() Macro, 90
Bluetooth, 73 Float, 19
Board Compatibility, 118 Flyback Diode, 57
break, 28 For Loop, 27
Functions, 15
C-String, 20
Calibration, 42 Gerber Files, 109
Comments, 15 Git, 90
Communication GitHub, 90
I2C, 70 Glossary, 126
SPI, 71 GPS, 50
Comparison Operators, 26
Compass, 51 H-Bridge, 56
Conditional Compilation, 90 Hardware Interrupts, 94
const, 19 HC-05, 73
constrain(), 29 I2C, 70
Control Flow, 26 If-Else, 26
Cooperative Multitasking, 69 Integer Overflow, 19
Curly Braces, 15 Internet of Things (IoT), 9
Custom Characters, 65 Interrupts, 94
Custom Functions, 24 IoT, 78
Data Logging, 83 IR Sensor, 48
Data Types, 18 Keypad, 38
Debouncing, 36 KiCad, 109
delay(), 68
DHT11, 46 LCD, 65

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

LinkedIn

Facebook

Instagram

Telegram

Reddit

You might also like