Bird
Raised Fist0
Arduinoprogramming~15 mins

I2C scanner sketch in Arduino - Deep Dive

Choose your learning style10 modes available
Overview - I2C scanner sketch
What is it?
An I2C scanner sketch is a small program written for Arduino boards that searches for devices connected to the I2C bus. It tries every possible address and reports which ones respond, helping you find the addresses of connected sensors or modules. This is useful because I2C devices use addresses to communicate, and knowing these addresses is essential for programming them.
Why it matters
Without an I2C scanner, you might not know the exact address of your connected devices, making it hard to communicate with them correctly. This can lead to frustration and wasted time. The scanner saves you from guesswork by quickly identifying all devices on the bus, so you can write code that talks to them properly.
Where it fits
Before using an I2C scanner, you should understand basic Arduino programming and know what I2C communication is. After learning to scan for devices, you can move on to reading and writing data to those devices using their addresses.
Mental Model
Core Idea
An I2C scanner systematically checks every possible device address on the bus and reports which ones respond, revealing all connected devices.
Think of it like...
It's like knocking on every door in an apartment building to see which apartments have someone home and can answer you.
┌───────────────┐
│ Start scanning │
└──────┬────────┘
       │
       ▼
┌───────────────┐
│ Try address 0 │
└──────┬────────┘
       │
       ▼
┌───────────────┐
│ Device responds? ──Yes──> Record address
└──────┬────────┘
       │No
       ▼
┌───────────────┐
│ Next address  │
└──────┬────────┘
       │
       ▼
┌───────────────┐
│ All addresses checked? ──No──> Repeat
└──────┬────────┘
       │Yes
       ▼
┌───────────────┐
│ Print results │
└───────────────┘
Build-Up - 7 Steps
1
FoundationUnderstanding I2C Basics
🤔
Concept: Learn what I2C communication is and how devices use addresses to talk on the bus.
I2C is a way for multiple devices to share two wires: one for clock and one for data. Each device has a unique address between 0 and 127. When the master (like Arduino) wants to talk, it sends the address. Only the device with that address responds.
Result
You know that each device listens only to its own address on the shared wires.
Understanding that devices have unique addresses on a shared bus is key to why scanning for addresses works.
2
FoundationSetting Up Arduino I2C Communication
🤔
Concept: Learn how to include the Wire library and initialize I2C on Arduino.
In Arduino, the Wire library manages I2C. You start it with Wire.begin() in setup(). This prepares the Arduino to send and receive I2C signals.
Result
Arduino is ready to communicate on the I2C bus.
Knowing how to start I2C communication is the first step before scanning or talking to devices.
3
IntermediateWriting a Loop to Test Addresses
🤔Before reading on: do you think the scanner tries addresses from 0 to 127 or just a few common ones? Commit to your answer.
Concept: Create a loop that tries every possible I2C address to see if a device responds.
The sketch uses a for loop from 1 to 127 (0 is reserved). For each address, it tries to start communication. If the device acknowledges, it means a device is present at that address.
Result
You get a list of all addresses where devices respond.
Trying every address ensures no device is missed, even if you don't know its address beforehand.
4
IntermediateDetecting Device Response
🤔Before reading on: do you think a device responds by sending data back or by acknowledging the address? Commit to your answer.
Concept: Use the Wire.endTransmission() function to check if a device acknowledges its address.
After sending the address with Wire.beginTransmission(address), calling Wire.endTransmission() returns 0 if a device responded. Any other number means no device or error.
Result
You can tell exactly which addresses have devices by checking the return value.
Understanding how acknowledgment works lets you detect devices without needing to read data.
5
IntermediatePrinting Found Addresses Nicely
🤔
Concept: Format the output to show addresses in hexadecimal and decimal for easy reading.
The sketch prints each found address in hex (like 0x3C) and decimal (like 60). It also formats output in rows for clarity.
Result
You get a clear list of device addresses to use in your programs.
Good output formatting helps you quickly identify devices and reduces errors when coding.
6
AdvancedHandling Bus Errors and Timeouts
🤔Before reading on: do you think the scanner can hang if a device misbehaves? Commit to your answer.
Concept: Add checks to avoid hanging if a device holds the bus or does not respond properly.
Some devices may cause the bus to hang if they don't respond. The sketch can include timeouts or error checks to skip these addresses and continue scanning.
Result
The scanner completes reliably even with problematic devices connected.
Knowing how to handle bus errors prevents your scanner from freezing and makes it robust.
7
ExpertUnderstanding Address Conflicts and Multiplexers
🤔Before reading on: do you think multiple devices can share the same I2C address on one bus? Commit to your answer.
Concept: Learn about address conflicts and how hardware like multiplexers help manage multiple devices with the same address.
I2C devices must have unique addresses on the same bus. If two devices share an address, communication fails. Multiplexers let you switch between buses to use devices with the same address separately. The scanner only sees devices on the active bus.
Result
You understand why some devices might not show up and how to manage complex setups.
Knowing address conflicts and multiplexers helps you design scalable I2C systems and interpret scanner results correctly.
Under the Hood
The Arduino sends a start condition followed by a 7-bit address and a read/write bit on the I2C bus. Devices listen and respond with an acknowledgment bit if their address matches. The Wire.endTransmission() function checks this acknowledgment to confirm device presence. The scanner loops through all addresses, sending these signals and checking responses.
Why designed this way?
I2C was designed as a simple, two-wire bus to connect multiple devices with minimal wiring. The acknowledgment mechanism allows the master to detect devices without complex handshakes. The scanner uses this built-in feature to find devices efficiently without needing device-specific commands.
┌───────────────┐
│ Start signal  │
└──────┬────────┘
       │
       ▼
┌───────────────┐
│ Send address  │
│ + R/W bit    │
└──────┬────────┘
       │
       ▼
┌───────────────┐
│ Device listens│
│ for address   │
└──────┬────────┘
       │
       ▼
┌───────────────┐
│ Device ACKs?  │
├─────┬─────────┤
│ Yes │ No      │
│     │         │
▼     ▼         ▼
Record address  No device
present        response
       │
       ▼
┌───────────────┐
│ Stop signal   │
└───────────────┘
Myth Busters - 4 Common Misconceptions
Quick: Does the scanner find devices that are powered off? Commit to yes or no.
Common Belief:The I2C scanner will find all devices connected to the bus regardless of power state.
Tap to reveal reality
Reality:Devices that are not powered on will not respond and thus will not be detected by the scanner.
Why it matters:Expecting to find unpowered devices leads to confusion and wasted troubleshooting time.
Quick: Can two devices share the same I2C address on one bus without problems? Commit to yes or no.
Common Belief:Multiple devices can share the same I2C address on the same bus and still work fine.
Tap to reveal reality
Reality:Devices with the same address cause conflicts and communication errors; only one device per address is allowed per bus.
Why it matters:Ignoring this causes mysterious bugs and devices not responding correctly.
Quick: Does the scanner tell you what type of device is connected at each address? Commit to yes or no.
Common Belief:The I2C scanner identifies the exact type and model of each connected device.
Tap to reveal reality
Reality:The scanner only detects if a device responds at an address; it does not identify device type or capabilities.
Why it matters:Assuming device type from the scanner output can lead to wrong code and failed communication.
Quick: Does the scanner always complete quickly regardless of bus size? Commit to yes or no.
Common Belief:The scanner runs instantly and is unaffected by the number of devices or bus speed.
Tap to reveal reality
Reality:The scanner takes longer with more devices and slower bus speeds because it tests each address sequentially.
Why it matters:Not knowing this can cause impatience or misinterpretation of scanner delays.
Expert Zone
1
Some devices only respond to certain commands after power-up and may not acknowledge during a simple scan, causing false negatives.
2
Repeated scanning can cause bus noise or interfere with sensitive devices; scanning should be done sparingly in production.
3
Certain I2C multiplexers or switches require special handling in the scanner to detect devices on different channels.
When NOT to use
Avoid using a simple I2C scanner when devices require initialization before responding or when using complex bus topologies like multiplexers without addressing them. Instead, use device-specific detection methods or bus analyzers.
Production Patterns
In real projects, the scanner is used during setup or debugging to confirm device connections. Automated tests may include scanning to verify hardware presence. For complex systems, software manages multiple buses or uses device IDs rather than just addresses.
Connections
Network Device Discovery
Similar pattern of probing addresses to find active devices on a network.
Understanding I2C scanning helps grasp how computers discover devices on networks by sending requests to IP addresses.
Telephone Directory Lookup
Both involve searching through a list of possible addresses to find a responding party.
Knowing how scanning works in I2C is like understanding how to find a phone number by checking each entry until you get a response.
Biological Neural Network Signaling
Both involve selective response to specific signals among many possible inputs.
Recognizing device addresses in I2C is like neurons responding only to certain neurotransmitters, showing selective communication in complex systems.
Common Pitfalls
#1Assuming the scanner will find devices even if wiring is incorrect.
Wrong approach:Uploading the scanner sketch without checking SDA and SCL connections or pull-up resistors.
Correct approach:Verify wiring: SDA to SDA, SCL to SCL, and ensure pull-up resistors are present before running the scanner.
Root cause:Misunderstanding that physical wiring and electrical requirements are essential for I2C communication.
#2Using address 0 in the scan loop.
Wrong approach:for (byte address = 0; address < 128; address++) { ... }
Correct approach:for (byte address = 1; address < 128; address++) { ... }
Root cause:Not knowing that address 0 is reserved and should not be scanned.
#3Expecting the scanner to identify device types automatically.
Wrong approach:Relying on scanner output alone to write device-specific code.
Correct approach:Use the scanner to find addresses, then consult device datasheets or libraries to communicate properly.
Root cause:Confusing device detection with device identification.
Key Takeaways
I2C devices communicate using unique addresses on a shared two-wire bus.
An I2C scanner tries every possible address and checks for device acknowledgment to find connected devices.
Proper wiring and pull-up resistors are essential for successful scanning.
The scanner only detects device presence, not device type or functionality.
Understanding address conflicts and bus errors helps build reliable I2C systems.

Practice

(1/5)
1. What is the main purpose of an I2C scanner sketch in Arduino programming?
easy
A. To reset the Arduino board automatically
B. To detect and list all devices connected on the I2C bus
C. To send data to all I2C devices simultaneously
D. To measure voltage levels on the I2C pins

Solution

  1. Step 1: Understand the role of I2C scanner

    An I2C scanner checks each possible address on the I2C bus to find connected devices.
  2. Step 2: Identify the main function

    The main function is to detect and list all devices so you know which addresses are in use.
  3. Final Answer:

    To detect and list all devices connected on the I2C bus -> Option B
  4. Quick Check:

    I2C scanner = device finder [OK]
Hint: I2C scanner finds devices by checking addresses [OK]
Common Mistakes:
  • Thinking it sends data to devices
  • Confusing it with board reset functions
  • Assuming it measures electrical signals
2. Which of the following is the correct way to start the I2C communication in an Arduino I2C scanner sketch?
easy
A. Wire.begin();
B. Wire.start();
C. Wire.init();
D. Wire.connect();

Solution

  1. Step 1: Recall the Wire library initialization

    The Wire library uses Wire.begin(); to start I2C communication.
  2. Step 2: Check other options

    Functions like Wire.start();, Wire.init();, and Wire.connect(); do not exist in the Wire library.
  3. Final Answer:

    Wire.begin(); -> Option A
  4. Quick Check:

    Start I2C with Wire.begin() [OK]
Hint: Use Wire.begin() to start I2C communication [OK]
Common Mistakes:
  • Using non-existent Wire functions
  • Confusing with other library methods
  • Omitting Wire.begin() causing no communication
3. Consider this snippet from an I2C scanner sketch:
for (byte address = 1; address < 127; address++) {
  Wire.beginTransmission(address);
  byte error = Wire.endTransmission();
  if (error == 0) {
    Serial.print("Device found at 0x");
    Serial.println(address, HEX);
  }
}

What will this code print if devices are found at addresses 8 and 42?
medium
A. Device found at 0x8\nDevice found at 0x2A
B. Device found at 0x08\nDevice found at 0x2A
C. Device found at 0x08\nDevice found at 0x42
D. Device found at 0x8\nDevice found at 0x42

Solution

  1. Step 1: Understand the address printing format

    The code prints the address in hexadecimal using Serial.println(address, HEX);. Hex 8 is '8', hex 42 decimal is '2A'.
  2. Step 2: Check leading zeros

    Since Serial.println() with HEX does not pad zeros, 8 prints as '8', 42 prints as '2A'.
  3. Final Answer:

    Device found at 0x8\nDevice found at 0x2A -> Option A
  4. Quick Check:

    Hex 8 = 8, Hex 42 = 2A [OK]
Hint: Hex print does not add leading zeros by default [OK]
Common Mistakes:
  • Assuming leading zeros appear automatically
  • Confusing decimal 42 with hex 42
  • Expecting uppercase letters always
4. You wrote this I2C scanner code but it never finds any devices:
for (byte address = 0; address <= 127; address++) {
  Wire.beginTransmission(address);
  byte error = Wire.endTransmission();
  if (error == 0) {
    Serial.print("Found device at ");
    Serial.println(address, HEX);
  }
}

What is the likely problem?
medium
A. Wire.endTransmission() must be called twice
B. Address 0 is reserved and should not be scanned
C. The loop should start from 1, not 0
D. Serial.print() cannot print HEX values

Solution

  1. Step 1: Check the address range in the loop

    The I2C valid addresses range from 1 to 127. Starting at 0 is invalid and may cause issues.
  2. Step 2: Understand scanning addresses

    Starting from 1 avoids reserved addresses and ensures proper scanning.
  3. Final Answer:

    The loop should start from 1, not 0 -> Option C
  4. Quick Check:

    Scan addresses 1 to 127 [OK]
Hint: Start scanning from address 1, not 0 [OK]
Common Mistakes:
  • Including address 0 which is reserved
  • Calling Wire.endTransmission() multiple times unnecessarily
  • Thinking Serial.print() can't print HEX
5. You want to modify an I2C scanner sketch to skip addresses where Wire.endTransmission() returns 4 (other error) and print a summary count of devices found at the end. Which code snippet correctly implements this?
hard
A. int count = 0; for (byte addr = 1; addr < 128; addr++) { Wire.beginTransmission(addr); byte error = Wire.endTransmission(); if (error == 0) { Serial.print("Device at 0x"); Serial.println(addr, HEX); count++; } else if (error == 4) { count--; } } Serial.print("Total devices: "); Serial.println(count);
B. int count = 0; for (byte addr = 0; addr <= 127; addr++) { Wire.beginTransmission(addr); byte error = Wire.endTransmission(); if (error == 0) { Serial.print("Device at 0x"); Serial.println(addr, HEX); count++; } else if (error == 4) { break; } } Serial.print("Total devices: "); Serial.println(count);
C. int count = 0; for (byte addr = 1; addr < 127; addr++) { Wire.beginTransmission(addr); byte error = Wire.endTransmission(); if (error == 0) { Serial.print("Device at 0x"); Serial.println(addr, HEX); count++; } else if (error == 4) { Serial.println("Error 4 at address " + addr); } } Serial.print("Total devices: "); Serial.println(count);
D. int count = 0; for (byte addr = 1; addr < 127; addr++) { Wire.beginTransmission(addr); byte error = Wire.endTransmission(); if (error == 0) { Serial.print("Device at 0x"); Serial.println(addr, HEX); count++; } else if (error == 4) { continue; } } Serial.print("Total devices: "); Serial.println(count);

Solution

  1. Step 1: Set correct address range and initialize count

    The loop must scan addresses 1 to 126 (less than 127). Initialize count to zero before loop.
  2. Step 2: Handle error 4 by skipping and count devices found

    If error is 0, print address and increment count. If error is 4, skip with continue to avoid stopping the scan.
  3. Step 3: Print total devices after loop

    After scanning, print the total count of devices found.
  4. Final Answer:

    Code snippet A correctly implements the requirements -> Option D
  5. Quick Check:

    Skip error 4 with continue, count devices [OK]
Hint: Use continue to skip error 4 and count devices found [OK]
Common Mistakes:
  • Using break instead of continue on error 4
  • Starting loop at 0 instead of 1
  • Decreasing count on error instead of skipping
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard