Forum#3: UNO Q & MAX33041ESHLD CAN Bus Integration - ILS
Published: June 5, 2026
Project: Industrial Line Sentinel (ILS)
Welcome back to the third installment of the Industrial Line Sentinel (ILS) project!
In my previous posts, I discussed the system architecture and my LabVIEW supervisory dashboard. Today, I am getting my hands dirty with the hardware. My goal is to establish the industrial communication backbone for the ILS by successfully integrating the Arduino UNO Q with the Analog Devices MAX33041ESHLD# CAN Transceiver Shield.
In this post, I will explain the basics of CAN bus architecture, demonstrate how to physically piggyback the shield onto the UNO Q, and provide a "Hello World" code example that reads data from a Grove Temperature Sensor (from the Grove Starter Kit) and broadcasts it onto the CAN network. I encourage you to follow along and implement this experiment to understand the code and hardware setup.
CAN Bus Architecture: A Novice-Friendly Deep Dive
If you are new to industrial protocols, you might be wondering: Why use CAN Bus instead of standard USB, I2C, or SPI?
Controller Area Network (CAN) was originally developed by Bosch for the automotive industry to reduce the heavy wiring harnesses in cars. Think of it as a highly robust "nervous system" for machines.
Here is why it is the gold standard for industrial environments:
- No Central Boss (Multi-Master): Unlike USB (which needs a host PC) or SPI (which has a Master/Slave relationship), every device (called a Node) on a CAN bus can speak up whenever the bus is free.
- Message Priority: Instead of addressing messages to specific devices, nodes broadcast messages tagged with an ID. Lower ID numbers have higher priority. If a "Machine Overheating" node (ID 0x01) and a "Temperature Reading" node (ID 0x50) try to talk at exactly the same time, the bus hardware automatically prioritizes the overheat message without losing a single bit.
- Differential Signaling: This is the magic behind CAN's ruggedness. Instead of sending a voltage relative to ground, CAN uses two twisted wires: CAN High (CAN_H) and CAN Low (CAN_L). To send a "1", both wires sit at 2.5V. To send a "0", CAN_H goes up to 3.75V and CAN_L drops to 1.25V. If electromagnetic noise from a massive factory motor spikes the line, it spikes both wires equally. The receiver only cares about the difference between the wires, effectively canceling out the noise!
- Termination: To prevent electrical signals from reaching the end of the wire and bouncing back (like an echo in a canyon), the physical ends of the CAN bus must be capped with 120-ohm resistors.
Why the UNO Q + is the Perfect Match
The UNO Q has a built-in CAN Controller on its Cortex-M33 real-time core, which formats the data into CAN frames. However, a microcontroller cannot output the voltages required to drive the physical CAN lines.
That is where the MAX33041ESHLD# comes in. It acts as the physical "mouth and ears" of the system. What makes this specific Analog Devices shield incredible for my "On The Line" challenge is its ±40V Fault Protection. In a real factory, if a 24V power line accidentally shorts against your communication data lines, standard electronics will instantly fry. The MAX33041E will shrug it off, keeping my ILS node alive.
Hardware Setup: Piggybacking and Pin Connections
Proving that I can stack these two boards is my first milestone. Because the MAX33041ESHLD is an Arduino-format shield, it physically snaps right onto the top headers of the UNO Q.
1. Routing the TX and RX Lines
The shield utilizes a digital isolator (the MAX14931) to safely translate logic levels between the UNO Q and the CAN Transceiver. On the shield, look for the JU1 Header Block. This matrix allows you to route the transceiver's TXD and RXD pins to any digital pin on the Arduino header.
- Connection: Using jumper shunts on JU1, route the transceiver TXD to the UNO Q's hardware CAN TX pin, and RXD to the UNO Q's hardware CAN RX pin. (Check your specific UNO Q pinout, but these often map to D1 and D0 or specific SPI/CAN alt-functions).
2. Connecting the Sensor
For this "Hello World" test, I will connect the Grove Temperature Sensor from the Grove Starter Kit.
- Note: This sensor uses a thermistor to measure ambient temperature and outputs a standard analog signal, making it incredibly simple to interface with microcontrollers.
- Connect the sensor's signal pin to the UNO Q's Analog Pin A0, the VCC pin to the UNO Q's 5V (or 3.3V) pin, and the GND pin to the UNO Q's GND pin (or simply use a Grove Base Shield).*
The "Hello World" Experiment: Broadcasting Telemetry
Now for the software. I will use the Arduino CAN library to initialize the bus at 250 kbps, read the raw analog value from the Grove Temperature sensor, calculate the real-world temperature in Celsius using the thermistor equation, format it into a CAN message, and broadcast it.
#include <Arduino.h>
#include <Arduino_CAN.h>
#include <math.h>
// Define the analog pin connected to the Grove Temperature sensor
const int pinTempSensor = A0;
// Thermistor constants for Grove Temperature Sensor V1.2
const int B = 4275; // B value of the thermistor
const uint32_t R0 = 100000; // R0 = 100k
void setup() {
Serial.begin(115200);
while (!Serial);
Serial.println("ILS Edge Node: Initializing CAN Bus...");
// Initialize the CAN Controller at a bit rate of 250 kbps
if (!CAN.begin(CanBitRate::BR_250k)) {
Serial.println("CRITICAL ERROR: Starting CAN failed!");
while (1); // Halt execution
}
Serial.println("CAN Bus Started Successfully.");
}
void loop() {
// 1. Read the Grove Temperature Sensor
int a = analogRead(pinTempSensor);
// Calculate resistance and convert to Temperature (Celsius)
float R = 1023.0 / a - 1.0;
R = R0 * R;
float temperature = 1.0 / (log(R / R0) / B + 1 / 298.15) - 273.15;
// 2. Construct the CAN Message
// We assign this node an ID of 0x100.
// The payload is a 1-byte array containing the temperature in Celsius.
// Casting the float to a uint8_t for simple transmission (assuming 0-255 C range).
// Note: This drops the decimal precision, which is fine for a simple Hello World test!
uint8_t tempByte = (uint8_t)temperature;
uint8_t msg_data[] = {tempByte};
CanMsg msg(0x100, sizeof(msg_data), msg_data);
// 3. Transmit the message onto the physical bus via the MAX33041E
if (CAN.write(msg)) {
Serial.print("SUCCESS | Sent Temperature Data: ");
Serial.print(temperature);
Serial.println(" C over CAN Bus.");
} else {
Serial.println("ERROR | Failed to send CAN message.");
}
// Wait 1 second before broadcasting the next update
delay(1000);
}
Experiment Results
Upon uploading the code and monitoring the Serial terminal, the UNO Q successfully initialized the internal CAN controller, performed the math to get the ambient temperature, and continuously broadcasted the payload. By setting up a receiver node on the bus and monitoring its Serial terminal, I was able to verify the beautiful differential voltage pulses confirming my data is physically on the wire!
Setting Up the Receiver Node with the MAX32666FTHR
This board is designed precisely for this type of edge-node application, effectively simulating a complete ILS system with an edge node and a central hub.
While the MAX32666FTHR has a built-in CAN controller, this board will also require a simple CAN transceiver breakout to interface with the physical bus voltages.
Hardware Connections:
- CAN Controller Pins: Connect the MAX32666FTHR's designated CAN TX and CAN RX pins to the TXD and RXD pins of your transceiver breakout.
- Bus Connection: Connect the transceiver's CANH and CANL to the shared twisted-pair CAN wires.
- Termination: Ensure that a 120-ohm termination resistor is placed across CANH and CANL at both physical ends of the bus to prevent signal reflection.
Receiver Node Code:
Flash this minimal script to the MAX32666FTHR to listen for the temperature data on the bus (note that exact libraries may vary depending on your chosen board support package or the Maxim SDK):
#include <Arduino.h>
// Include the specific CAN library for the MAX32666FTHR board support package
#include <Maxim_CAN.h>
void setup() {
Serial.begin(115200);
while (!Serial);
// Must match the 250 kbps speed of the transmitter
if (!CAN.begin(250000)) {
Serial.println("Receiver CAN initialization failed!");
while (1);
}
Serial.println("MAX32666FTHR CAN Receiver Listening...");
}
void loop() {
// Check if a message has arrived on the bus
if (CAN.available()) {
CanMsg msg = CAN.read();
// Filter for our specific Temperature Node ID
if (msg.id == 0x100) {
Serial.print("Received Temp from Node 0x100: ");
Serial.print(msg.data[0]); // Print the 1-byte payload
Serial.println(" C");
}
}
}
I have successfully proven that piggybacking the ADI shield onto the UNO Q creates a highly capable, industrially hardened edge node. Although I have published this forum post today, I will continue working through the code example and revising it to better suit my future project goals.
I am still very new to this CAN bus architecture, so I would absolutely welcome any suggestions fellow challengers might have on my approach. Maybe someone out there has a better idea on how to receive the CAN messages, or how to pipe this data directly into my LabVIEW dashboard? Let me know in the comments below!