Hi Anish! Today you integrate — combine all the separately-tested modules into one big sketch. This is often the hardest day, because things that worked alone sometimes act strangely when glued together. You’ll learn the tools to debug those issues.
The good news: you’ve already done the hard parts. All the components work. All the thresholds are measured. All the wiring is in place. Today is about gluing them together cleanly.
The structure of a good integrated sketch #
Every Arduino project, once it has more than one module, should follow this shape:
|
|
Notice how tiny loop() is. Just 3 lines. Each line calls a helper that does one job. This is the shape of every serious Arduino project.
For the Smart Plant Monitor, we might structure it like this:
|
|
Five verbs. Read top-to-bottom, understand in 2 seconds.
Writing your integrated sketch #
Open a new sketch. Copy your Day 24 module code in one chunk at a time, using the structure above. Your goal: make loop() small and readable by moving logic into helpers.
Here’s a full example for the Smart Plant Monitor (adapt to your own project):
|
|
Upload. The flow:
- Read sensors.
- Read button. If pressed, set a 10-minute silence timer.
- Decide if the plant is thirsty.
- Update the LCD.
- Light the right LED and, if all conditions are met, beep every 5 seconds.
Key patterns in this code #
millis() for non-blocking timing
#
Look at the beep logic:
|
|
No delay() anywhere. Instead:
lastBeepTimeremembers when the last beep happened.- Every loop, we check: “has enough time passed since the last beep?”
- If yes, beep and update
lastBeepTime.
This pattern is called non-blocking timing. It’s how you do “every N milliseconds, do X” without freezing the rest of the code. delay() would stall the sensor reads, the button, the display — everything. millis() lets you do many timed things in parallel.
unsigned long for time
#
|
|
Notice I used unsigned long instead of int for anything holding millis(). Why? Because int on Arduino Uno is only 16 bits (holds up to ~32,000). millis() counts milliseconds — it hits 32,000 in just 32 seconds. unsigned long is 32 bits and holds over 4 billion — good for ~49 days of running.
Rule: any variable holding a millis() value must be unsigned long. Don’t use int.
Padding strings for clean LCD #
|
|
Trailing spaces to overwrite the previous (possibly longer) string. Same trick as Day 18. Critical when two status strings have different lengths.
State variables #
|
|
Global variables at the top hold the state of the system — values computed by the sensor reader, decided by the status function, and used by the display and alert functions. Each helper function only reads/writes a few of them, and the overall data flow is easy to follow.
Debugging integration issues #
Things that often go wrong when you glue everything together:
Issue 1: “Everything works alone but fails when combined” #
Usually a pin conflict you missed. Double-check that no pin is used by two things. Especially watch for A4/A5 (both I2C and regular analog), pins 0/1 (used for Serial), pin 13 (used by the built-in LED).
Issue 2: “The LCD freezes for a second every few seconds” #
You probably have a delay() somewhere that’s blocking everything. Replace it with a millis()-based check.
Issue 3: “Random garbage on the LCD” #
Likely a power issue — too many modules on 5V at once. The IR receiver, the LCD, and the sound sensor all draw a little power. If you’re running on USB power and you’ve got a bunch of modules, consider plugging in a separate 9V battery or USB wall adapter.
Issue 4: “Button sometimes registers twice” #
Bounce. Add a small delay in the button handler (delay(50) after detecting a press) or track the last-press time with millis().
Issue 5: Serial Monitor prints nothing #
Is Serial.begin(9600) in setup()? Is the Serial Monitor set to 9600 baud? Is the Arduino selected and the port correct? These are the 3 usual suspects.
The debug print trick #
When in doubt, print everything. Add Serial.println lines that say what each function is doing:
|
|
Run the Serial Monitor while interacting with the project. You’ll see exactly which functions run in what order and what values they’re working with. Most integration bugs become obvious as soon as you print the data flow.
Delete the debug prints once the sketch is stable. Or leave them in — they don’t slow anything important down and they help future-you understand the code.
Checklist before Demo Day #
Before tomorrow, go through every item on your “done” list from Day 23. Check them off as you verify:
- Does every core feature work reliably?
- Does the LCD show what I expect, with no flicker or garbage?
- Are there any weird edge cases? (What happens if I press the button during an alert?)
- Have I written down which remote button does what?
- Can I explain in 60 seconds what each part of the code does?
If something feels flaky, fix it now. Tomorrow is Demo Day — you don’t want to debug in front of an audience.
Optional polish #
- Add a splash screen in
setup()— “Smart Plant Monitor” + your name for 2 seconds before the main display starts. - Clean up the wires — shorter jumpers, tucked neatly, labeled.
- Write a tiny laminated card saying what each pin does. Pros do this.
What you learned today #
- How to integrate modules into one sketch using the “tiny
loop(), big helpers” pattern unsigned longfor time — why you can’t useintwithmillis()- Non-blocking timing with
millis()— how to do timed actions without freezing other code - Common integration bugs: pin conflicts,
delay()blocking, power issues, bouncing - The debug print trick — add Serial.println lines everywhere when stuck
- The habit of going through your “done” checklist before declaring finished
What is next #
Day 26 — Demo Day! You present your project to your family. Tomorrow is the celebration of 26 days of hard work.
Go get some rest, Anish. Tomorrow is the big day.