← Back to home

CAN Bus Mini-Workshop — ESP32 + Arduino UNO + MCP2515

Educational Workshop ESP32 • Arduino UNO • MCP2515 • DS18B20 Hardware • Embedded • CAN Bus

What is it?

A hands-on, beginner-friendly workshop to learn CAN bus basics through three short tasks and a final game. Teams program ESP32 nodes while a facilitator runs the CAN master (Arduino UNO).

This workshop is designed for learning through doing. You'll split into 3 teams (up to 4 people each), where each team programs an ESP32 node equipped with a DS18B20 temperature sensor. The facilitator runs the CAN master (Arduino UNO with MCP2515) that sniffs and coordinates the network. Through four progressive tasks, you'll understand CAN IDs, payload encoding, priority arbitration, and mailbox messaging.

What makes it engaging? It's not just theory—it's a game. Teams compete to have the highest average temperature over 60 seconds, with the winner receiving a private CAN message revealing the prize location. The workshop blends education with friendly competition, making CAN bus concepts tangible and memorable.

CAN Bus Mini-Workshop Guide

Learn CAN bus fundamentals through hands-on tasks and a temperature-based competition.

Introduction

Welcome to the CAN Bus Mini-Workshop! This workshop is designed to teach CAN bus fundamentals through hands-on practice. You'll work in teams to program ESP32 nodes that communicate over a CAN bus network, learning about IDs, payload encoding, priority arbitration, and messaging along the way.

The workshop is structured as four progressive tasks, culminating in a competitive game where teams compete to have the highest average temperature. It's beginner-friendly—no prior CAN bus experience required—and emphasizes learning through doing.

Hardware Overview

Nodes (ESP32)

Each team programs one ESP32 node with a DS18B20 temperature sensor. The nodes are positioned at different points along the CAN bus:

ESP32 Node Configuration
Team MCU DS18B20 Data Pin CAN Position
1 ESP32 D32 Bus end
2 ESP32 D21 Middle
3 ESP32 D25 Middle

Master (Arduino UNO + MCP2515)

The facilitator runs the CAN master using an Arduino UNO with an MCP2515 CAN controller module. This acts as a sniffer and referee for the network.

UNO ↔ MCP2515 Connections
Pin / Signal Connects to Notes
CS Pin 10 Chip select
SI (MOSI) Pin 11 SPI data out
SO (MISO) Pin 12 SPI data in
SCK Pin 13 SPI clock
INT Pin A2 Interrupt

⚠️ Important: Put 120 Ω termination resistors at both ends of the bus (Team 1 node end + Master end).

Software Setup

On all 4 computers (3 teams + facilitator), install the following via Arduino Library Manager:

  • mcp_can (MCP2515 CAN) — e.g., "mcp_can by Cory J. Fowler"
  • OneWire
  • DallasTemperature

Board Manager: Install "esp32 by Espressif" for ESP32 boards.

Workshop Flow

You'll switch tasks by toggling simple flags on the Master. Teams adjust their IDs on the Node code as instructed.

Task A — ID Chaos

Goal: Show that when all nodes share the same ID, you can't tell who's who.

Master (UNO):

  • Use the master with task toggles and set:
    ENABLE_TASK_A 1
    ENABLE_TASK_B 0
    ENABLE_TASK_C 0
    ENABLE_TASK_D 0
  • Open Serial Monitor at 115200.

Teams (ESP32 Nodes):

  • Set all teams to the same ID, e.g. #define NODE_ID 0x100.
  • Set all teams' temperature data bus (ONE_WIRE_BUS) and mailbox (MAILBOX_ID) to the correct ones. The data bus must correspond to the physical connection and the mailbox can be arbitrary, as long as it matches the ones in CAN Master code.
  • Upload node code and let it run (sends temp once per second).

You'll see:

CAN init ok
ID: 0x100  len=2  data: 0x09 0xF6
ID: 0x100  len=2  data: 0x09 0x4A
...

Three sensors, one ID — you can't tell which is which. The teams need to figure out why and change their IDs to see the difference.

Task B — Payload Mystery (Decode to °C)

Goal: Decode the 2-byte payload into real degrees Celsius and give each team a unique ID. Ask the teams what are you seeing. Is it actual temperature data or are the frames corrupted? Why does it look like that and how do I decode it?

Master (UNO):

  • Toggle: ENABLE_TASK_A 0, ENABLE_TASK_B 1, ENABLE_TASK_C 0, ENABLE_TASK_D 0
  • The decode block prints human-readable temps.

Teams (ESP32 Nodes):

  • Assign unique IDs (example):
    • Team 1 → 0x100
    • Team 2 → 0x101
    • Team 3 → 0x102
  • You may need to change these in your code for master CAN (const unsigned long NODE_IDS[3] = {0x103, 0x101, 0x102};) based on what the teams set up in the previous Task.

Concept: Payload is big-endian int16 * 100.

Example: bytes [0x09, 0xF6](0x09<<8 | 0xF6) = 255025.50 °C.

You'll see:

ID: 0x101  Temp: 24.50 °C
ID: 0x100  Temp: 21.30 °C
ID: 0x102  Temp: 26.10 °C

Task C — Priority & Filtering

Goal: Show that lower CAN ID = higher priority (wins arbitration when simultaneous).

Master (UNO):

  • Toggle: ENABLE_TASK_A 0, ENABLE_TASK_B 1 (optional), ENABLE_TASK_C 1, ENABLE_TASK_D 0
  • The master sends a periodic TICK (ID 0x7FF), then prints which node arrives first.

Teams (ESP32 Nodes):

  • Comment out the periodic sender and uncomment Task C: TICK Reply so nodes send only when TICK arrives.

Note: Without perfect sync, you'll see different winners. CAN priority (lower ID wins) only shows up when frames start at the exact same instant. Our nodes aren't perfectly synchronized to the microsecond, so often the 'winner' is just whoever hits the bus first. That's why you'll see different winners — it's timing jitter, not CAN breaking. In real systems you'd align timing with shared clocks/interrupts or hardware timers.

Task D — Final Game: 1-Minute Average (Hottest Team Wins)

Goal: For 60 seconds, the master averages each team's reported temperature. The highest average wins. The winner gets a private CAN DM to its mailbox telling them where the beer is!!! (or other non-alcoholic prize)

Master (UNO):

  • Toggle: ENABLE_TASK_A 0, ENABLE_TASK_B 0/1 (your choice), ENABLE_TASK_C 0, ENABLE_TASK_D 1
  • Optional knobs at top:
    • START_DELAY_MS — pre-start countdown (e.g., 10000 for 10s)
    • WINDOW_MS — averaging window (default 60000 = 1 min)

Teams (ESP32 Nodes):

  • Set IDs and mailboxes:
    • Team 1 → NODE_ID 0x100 (or 0x101), MAILBOX_ID 0x210
    • Team 2 → NODE_ID 0x101 (or 0x102), MAILBOX_ID 0x211
    • Team 3 → NODE_ID 0x102 (or 0x103), MAILBOX_ID 0x212
    These simply need to match with whatever is listed in CAN Master code.
  • Keep the winner-only mailbox listener (prints any text sent to your mailbox). No spoilers about rules printed by the node.

End of round:

  • Master prints each team's final average.
  • Winner chosen (highest average; tie-break = lowest node ID).
  • Master sends DM only to the winner:
    go get the beer in the fridge! you won

Installation & Build Notes

  • Baud: 115200 for Serial Monitors.
  • Bitrate: 500 kbps on MCP2515.
  • Crystal define: #define MCP_CLOCK_IS_8MHZ 1 (set to 0 if your MCP2515 is 16 MHz).
  • ESP32 DS18B20 tip: sensors.setResolution(9); for faster updates (~93 ms).

Troubleshooting

  • DS18B20 reads 85.00 °C or −127.00 °C: Check wiring and 4.7 kΩ pull-up from data to 3.3 V.
  • CAN is silent: Verify termination, shared GND, correct CS pins, matching bitrate/crystal.
  • Winner message not seen: Ensure each team's MAILBOX_ID matches the master's mapping (0x210/0x211/0x212).

Quick FAQ (for teams)

  • How do we recognize the end of the bus?
    The physical ends have 120 Ω termination resistors. In this workshop: Team 1 node and the Master are the ends.
  • Why do we sometimes see different "winners" in priority?
    CAN arbitration (lower ID wins) only shows when frames start at the exact same instant. Our software timing isn't microsecond-perfect, so "first to speak" can win—this is expected.

Code & Resources

📦 All code is available on GitHub:

View on GitHub →

Repo Structure:

CAN-workshop/
├─ Master/               # UNO master sketches (task toggles version)
├─ Nodes/                 # ESP32 node sketch (workshop format)
├─ wiring/               # images or diagrams (optional)
└─ README.md             # this file

Credits / License

Based on MCP2515 library mcp_can by Cory J. Fowler and DallasTemperature/OneWire. Use/modify freely for educational workshops.

Appendix: What the Master Prints (examples)

Task A (raw):

ID: 0x100  len=2  data: 0x09 0xF6

Task B (decoded):

ID: 0x101  Temp: 25.50 °C

Task C (priority demo):

--- TICK --- (all nodes send NOW)
Winner this tick: 0x050

Task D (final):

=== FINAL AVERAGES (1 minute) ===
Node 0x100: 26.12 °C
Node 0x101: 25.47 °C
Node 0x102: 24.98 °C
Winner: 0x100  avg=26.12 °C
📣 Announced to mailbox 0x210