Holiday Special 19

Enter Your Holiday Season Project for a Chance to Win Over $20,000 Worth of Prizes and Gifts to Give!

Back to The Project14 homepage

Project14 Home
Monthly Themes
Monthly Theme Poll


Original plan for this project, involved fitting an existing Christmas Wreath decoration with some form of LED display.

Unfortunately I couldn't find the one I had, which was a more basic version of the one below.

Christmas Wreath

You get the idea however, replace the boring mini decorations with a variety of LEDs.

However I wanted something with actual electronics in it, so considered adding an LCD and reshaping the wreath into a table center piece.


Anyway I found most of the electronics I needed (bar a colour LCD), but the wreath and the box it's stored in haven't been found.


Plan B, I have two transparent spheres, one splits in half so I can stuff most of the electronics inside.

The other sphere is a fake lightbulb that was stuffed with a cheap LED string originally, going to make a mini christmas tree out of insulated wire I can stuff inside.

The wire means it can have integral LEDs, the trick will be to wire them up so there isn't a ton of wires that need to be run.


I bought an assortment of SMD LEDs in different colours, going to start by finding those, and making a 5 pointed star by soldering them to each other.

That can go on the top of the tree.


As for the controller, I have an MKR 1010 that I've seen been experimenting with, I got CAN bus working finally.

So two versions:

A. Table/door decoration, use a lithium ion battery so you don't need to run power. Power was always a hassle with my previous microcontrolled LED decorations.

B. Car/Truck decoration, make a short loom that fits into the existing wiring to access power and CAN traffic. The lights can be setup to only work when certain activity is on/off. Detecting traffic on the bus, or particular IDs, say wire the decoration to turn on when the parking lights are on.


I'll do most of B, with another micro as the CAN traffic instead of an actual car. Will however show it working from 3.3V and the lithium cell.



Made up the LED star, which goes on the top of the tiny christmas tree. Had two failed experiments in the process.

The star consists of five 0603 SMD white LEDs, each is 1.5mm long.

Plan A

Failed led star

Idea is to use the sticky side of the kapton tape, to hold the parts in place, then melt the blob of solder paste with the hot air.

It should have worked, it doesn't. Two problems:

1. The solder melts at 350 degrees, but the glue on that tape does too. Ended up with a ball of parts stuck together.

2. I hadn't considered the need to connect a wire into the middle, attempting to solder to this later would have messed it up also.

I think the surface tension of the solder also causes the parts to pull together and thus release from the tape.


Plan B

As above, but with a thick later of kapton tape over the top also, and hole poked in the middle to allow the hot air to melt the solder paste.

The top tape started to lift, parts still moved, and after all that the solder didn't melt.

Weighing the tape down with a washer helped some, but still wasn't a workable idea.

As per earlier usage, soldering to these LEDs with a soldering iron isn't good. Too easily damaged for whatever reason.


Plan C

After much thought, and hair loss, I came up with the following.

1. Scrap PCB with a pair of 0603 pads, which run to two thru hole vias.

2. More LEDs to replace the ones I lost to the above experiments.

3. One tube of artist's acrylic paint.

4. One roll of wire wrap wire.

5. One Kapton tape covered washer from plan B.


Solder the first LED to the PCB as normal.

Place the remaining four LEDs next to a pad on the already soldered LED.

A blob of white paint applied to the PCB before placing each LED secures it in place, the paint is more to one end so the middle of the star can be soldered.

Don't worry about getting paint around the outer ends of the LEDs, any paint can be scraped off later.

Leave paint to dry for a few hours, then drop a big blob of solder paste in the middle of the 5 LEDs. Put the washer over the top to keep things down and the heat where it's needed.

Scrape the white paint around the ends of the LEDs, so you can test them electrically, also makes them ready to solder.

Strip the insulation of a length of wire wrap wire, solder one end to the original LED, then wind the wire around the outside of all 5 LEDs.

For each LED, apply a bit of solder paste between the wire and the end of the component, then cover most of the other connections/parts with the kapton washer.

When you get back to the start of the wire loop, trim it then use solder paste to get it to stick.

Test the whole thing now.

I found 400 ohms to be correct resistor to make the 5 LEDs glow enough to be bright, but still able to be seen as individual LEDs, and not a lumpy white flower shape.

Naturally the photos don't show this correctly.


score: Kapton Tape 0 : Acrylic Paint 1


Next step it to make the rest of the tree around the base (to cover the PCB).

Then stuff the whole lot into it's plastic globe.


Connections between the MKR1010 and the LEDs.

White - LED star

Green - Tree lights A

Red - Tree Lights B

Black - Common negative


Connected to Digital_IO pins 0, 2, 4

Inline resistors are, 560ohm for the star, 47ohm for the other two LEDs.


In hindsight, should have added a extra resistors for the Red LEDs on the tree, to force them to share the current with the yellow and green LEDs.


Arduino software

After working on the code a bit every few days, I finally have almost all of it working.

How it works is quite simple, it keeps track of how many signals with unique IDs are being transmitted on the CAN-bus it's connected to.


A car that is running, will transmit a lot more traffic over CAN than one that is switched off.

I've taken the assumption that 7 IDs denotes a running car, it could be more, it could be less, very easily changed.

Using the millis() function to keep track of when a specific ID was transmitted, and to keep the flash rate of the LEDs consistent.


Also had to create a second sketch for transmitting 7 unique CAN IDs.

This runs on my AT MEGA2650 with a MCP2515 board, the code would also run on a second MKR1010 with CAN shield with minor changes.

Only for testing purposes, so I don't need to wire into a car to test/demonstrate it working.


MKR1010 Light Controller / CAN Receiver code


CAN Controlled christmas light display

Will turn on when connected to an active CAN BUS with at least

Written for MKR1010 Wifi with MCP2515 CAN shield, but would worth with any Arduino with a MCP2515 connected, with minor changes.




#include <mcp_can.h>

#include <SPI.h>



// LED for testing purposes





int maxPacketIDs = 7;

int packetCount = 0;

long unsigned int packetIDs[7] = {0,0,0,0,0,0,0}; // ID of last n CAN packets

unsigned long packetMillis[7] = {0,0,0,0,0,0,0};  // time in miliseconds of last n CAN packets



long unsigned int rxId;

unsigned char len = 0;

unsigned char rxBuf[8];

#define CAN0_INT 7                              // Set MCP2515 INT to pin 7

MCP_CAN CAN0(3);                                // Set MCP2515 CS to pin 3

boolean canConnected = false;



// for twinkling star

#define BLINK_RES 150

#define MAX_DELAY_MS 12

unsigned long previousStarFlashMillis = 0;

int StarFlashBlink;

int StarFlashDelay;

int StarFlashValue;



// tree lights

const long TreeFlashInterval = 3 * 500;           // interval at which to blink 3 seconds

unsigned long previousTreeFlashMillis = 0;

const int TreeFlashPinA = 2;// the number of the LED pin

const int TreeFlashPinB = 4;// the number of the LED pin

int TreeFlashState = LOW;             // ledState used to set the LED



void setup()




  // Initialize MCP2515 running at 16MHz with a baudrate of 500kb/s and the masks and filters disabled.

  if(CAN0.begin(MCP_ANY, CAN_500KBPS, MCP_16MHZ) == CAN_OK)


    Serial.println("MCP2515 Initialized Successfully!");

    canConnected = true;




    Serial.println("Error Initializing MCP2515...");



  CAN0.setMode(MCP_NORMAL);                     // Set operation mode to normal so the MCP2515 sends acks to received data.



  pinMode(CAN0_INT, INPUT);                            // Configuring pin for /INT input



  StarFlashBlink = StarFlashDelay = StarFlashValue = 0;

  analogWrite (0, 0); // star LEDs off



  // set the 2 digital pins for the tree lights as output:

  pinMode(TreeFlashPinA, OUTPUT);

  pinMode(TreeFlashPinB, OUTPUT);

  digitalWrite(TreeFlashPinA, TreeFlashState);

  digitalWrite(TreeFlashPinB, TreeFlashState);






void loop()


  if(!digitalRead(CAN0_INT))                         // If CAN0_INT pin is low, read receive buffer


    CAN0.readMsgBuf(&rxId, &len, rxBuf);      // Read data: len = data length, buf = data byte(s)


    //if((rxId & 0x80000000) == 0x80000000)     // Determine if ID is standard (11 bits) or extended (29 bits)

    //  sprintf(msgString, "Extended ID: 0x%.8lX  DLC: %1d  Data:", (rxId & 0x1FFFFFFF), len);


    //  sprintf(msgString, "Standard ID: 0x%.3lX       DLC: %1d  Data:", rxId, len);






    if((rxId & 0x40000000) == 0x40000000){    // Determine if message is a remote request frame.


    else {

      int found = -1;

      bool skip = false;

      //TODO: find if this packet has already been logged.

      //      if so, then update it's millis

      found = findLoggedID(0);

      if (packetIDs[found] == rxId)


         packetMillis[found] = millis();

         skip = true;



      if (!skip && packetCount < maxPacketIDs)


        found = findLoggedID(0);

        if (found != -1)


          // add this CAN ID to the list

          packetIDs[found] = rxId;

          packetMillis[found] = millis();








  // so totally disconnected wiring, car shut down, etc can cause light display to power off



  //packetCount = 7; // for testing purposes, so don't need other CAN device to test lights







  if (packetCount == 7)


    if(StarFlashValue == BLINK_RES) {

      StarFlashBlink = StarFlashDelay = StarFlashValue = 0;



    unsigned long currentMillis = millis();

    if (currentMillis - previousStarFlashMillis >= MAX_DELAY_MS)


      previousStarFlashMillis = currentMillis;






    if (currentMillis - previousTreeFlashMillis >= TreeFlashInterval) {

      previousTreeFlashMillis = currentMillis;

      // if the LED is off turn it on and vice-versa:

      if (TreeFlashState == LOW) {

        TreeFlashState = HIGH;

      } else {

        TreeFlashState = LOW;




      // set the LED with the ledState of the variable:

      digitalWrite(TreeFlashPinA, TreeFlashState);

      digitalWrite(TreeFlashPinB, !TreeFlashState);



  else {

    digitalWrite(TreeFlashPinA, LOW);

    digitalWrite(TreeFlashPinB, LOW);

    analogWrite (0, 0); // star LEDs off





void treeStarFade() {

  int min_delay = -1;


  if(StarFlashDelay < min_delay || min_delay == -1) {

    min_delay = StarFlashDelay;


  StarFlashDelay -= min_delay;

  if(StarFlashDelay == 0) {


    StarFlashDelay = StarFlashBlink;


  int intensity = (BLINK_RES / 2) - abs((BLINK_RES / 2) - StarFlashValue);

  intensity = intensity * (255 / BLINK_RES);

  analogWrite (0, intensity);







int findLoggedID (int ID)


  for (int i=0; i<maxPacketIDs; i++)


    if (packetIDs[i] == ID)


      return i;



  return -1;




int removeOldIDa (unsigned long currentMillis)


  int foundID = -1;

  for (int i=0; i<maxPacketIDs; i++)


    // disgard IDs older than 10 seconds

    // so powering down the car will cause the lights to go off.

    if (packetIDs[i] != 0 && currentMillis - packetMillis[i] > (1000 * 10) ) // 10 seconds


      packetMillis[i] = 0;

      packetIDs[i] = 0;




  return foundID;




AT MEG2650 CAN traffic simulator code

// CAN traffic simulator

// Transmits CAN Packets with 7 unique IDs.

// For use with AT MEGA 2650 and MCP2515 CAN transceiver shield/module



#include <mcp_can.h>

#include <SPI.h>



long unsigned int txId = 0x100;

MCP_CAN CAN0(53);     // Set CS to pin 53 for ATMega2650.SS => MCP2515.CS



void setup()





  // Initialize MCP2515 running at 8MHz with a baudrate of 500kb/s and the masks and filters disabled.

  // change 8MHZ to 16MHZ if your module has the 16MHZ chip/crystal

  if(CAN0.begin(MCP_ANY, CAN_500KBPS, MCP_8MHZ) == CAN_OK) Serial.println("MCP2515 Initialized Successfully!");

  else Serial.println("Error Initializing MCP2515...");



  CAN0.setMode(MCP_NORMAL);   // Change to normal mode to allow messages to be transmitted




//byte data[8] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};

byte data[] = {"ABCDEFGH"};



void loop()


  // send data:  ID = 0x100, Standard CAN Frame, Data length = 8 bytes, 'data' = array of data bytes to send

  byte sndStat = CAN0.sendMsgBuf(txId, 0, 8, data);

  if(sndStat == CAN_OK){

    Serial.println("Message Sent Successfully!");

  } else {

    Serial.println("Error Sending Message...");


  txId = txId + 0x07;

  if (txId > 149)


    txId = 0x100;


  delay(100);   // send data per 1000ms