Manually assigning MAC addresses is a pain! Not only do you have to keep track of what addresses you've already used in your projects, but if you have the same sketch on a bunch of identical Arduino-based devices you have to modify the sketch for each one to set a different MAC address.

So one handy trick is to generate the MAC address automatically, by taking values from a device such as a DS18B20 1-Wire temperature sensor's unique identifier and using that to seed the MAC address. Then you can load the exact same sketch onto multiple devices, and each one will get its own unique MAC address automatically.

First, add a DS18B20 temperature sensor to your Arduino and test that it works normally. To make it easy to connect a DS18B20 to your Arduino we have a temperature sensor module with a DS18B20 mounted on it, and example code to test it. For the purpose of this example we'll assume your DS18B20 data pin is connected to digital pin D2 on your Arduino.

Once the DS18B20 is working well, connect your Arduino to your Ethernet network and load the following sketch into it.

#include <SPI.h>
#include <Ethernet.h>
#include <OneWire.h>

// Attempt to automatically configure everything. Set a default MAC
// address to be replaced later, and get the IP address from DHCP
byte mac[] = {  
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };  // Try to replace with DS MAC

// Initialise a DS18B20 temperature sensor
OneWire ds(2); // Set up DS18B20 sensor on pin D2

/**
 * Setup
 */
void setup()
{
  byte i;
  byte dsAddress[8];
  
  Serial.begin( 38400 );
  delay( 500 ); // Give the Ethernet chipset time to fully initialise

  Serial.println( "Searching for DS18B20..." );
  ds.reset_search();  // Start the search with the first device
  if( !ds.search(dsAddress) )
  {
    Serial.println( "none found. Using default MAC address." );
  } else {
    Serial.println( "success. Setting MAC address:" );
    Serial.print( " DS18B20 ROM  =" );
    for( i = 0; i < 8; i++)
    {
      Serial.write(' ');
      Serial.print( dsAddress[i], HEX );
    }
    Serial.println();
    
    // Offset array to skip DS18B20 family code, and skip mac[0]
    mac[1] = dsAddress[3];
    mac[2] = dsAddress[4];
    mac[3] = dsAddress[5];
    mac[4] = dsAddress[6];
    mac[5] = dsAddress[7];
  }
  
  Serial.print( " Ethernet MAC =" );
  for( i = 0; i < 6; i++ )
  {
    Serial.write( ' ' );
    Serial.print( mac[i], HEX );
  }
  Serial.println();

  // start the Ethernet connection:
  Serial.print( "Eth: " );
  Ethernet.begin( mac );
  Serial.print( "My IP address: " );
  Serial.println( Ethernet.localIP() );
}

void loop()
{

}

This example sketch isn't very useful by itself because it doesn't do anything much, but it's a useful skeleton to use as a starting point for your own projects.

It starts by setting a default MAC address that will be used if it can't find a 1-Wire device. It then searches for a device, and if it finds one it takes its 1-Wire bus address and stores it in the array called "dsAddress".

The 1-Wire bus address is longer than an Ethernet MAC address, and the first few bytes are used to specify the device family. We therefore ignore the first few bytes and replace the final 5 bytes of the Ethernet MAC with the end of the 1-Wire bus address.

In this tutorial we've specifically mentioned the DS18B20 1-Wire bus temperature sensor because it's so popular and easily available, but this works just as well with any 1-Wire bus device. The DS18B20 just happens to be a very common device for Arduino users.

Related Articles: