Fun Festive PCB for 2024

by TomGoff in Circuits > Arduino

206 Views, 1 Favorites, 0 Comments

Fun Festive PCB for 2024

main.jpg
Xmas Bauble PCB - Demo

So with the festive season upon us it's the time of year for the eagerly anticipated Norwich Hackspace annual festive PCB soldering social.

Last year we soldered custom PCB Christmas trees, see the link here Fun Festive Custom PCB : 7 Steps (with Pictures) - Instructables

This year I wanted to design something with sound as well as blinking LEDs so I designed a bauble shaped PCB with blinking LEDs and a piezo buzzer. Check out the video to see it work.

Once again I used the venerable ATMega328p microcontroller as the heart of the project. This little microcontroller maybe getting a little old but it's simple, relatively cheap and widely understood and supported. I learned a lesson from last years project whereby I used the internal clock which required installing a specialised board on the Arduino IDE. This year I kept things simple and integrated a 16MHz external crystal so that the completed PCB can be treated as an Arduino UNO or NANO.

The project has been designed to be simple and fun. I have included a very basic sketch with it but I hope the more experienced can use it as a platform to to something far more interesting.

Supplies

MAterials.jpg

Here's a list of the materials that I used:

  1. 1 x PCB x 1 (See Note*)
  2. 1 x 16MHz Crystal x 1
  3. 8 x 1k ohm 0.25W Resistors
  4. 8 x 3mm LEDs (colours of your choice)
  5. 1 x 10k ohm Resistor (for reset pullup)
  6. 1 x 100uF Electrolytic Capacitor
  7. 1 x 100nF Ceramic Disc Capacitor (marked 104)
  8. 2 x Momentary tactile switches
  9. 1 x 2-Way Screw Terminal Connector.
  10. 1 x 2 Coin cell (CR2032) battery Holder
  11. 2 x CR2032 coin cell batteries
  12. 1 x 2x3Pin 2.54mm Pin Straight Male Double Row Header Pins
  13. Solder

Note* I designed the PCB so that it includes ATMega328p SMD and SMD crystal capacitors pre-soldered by the PCB manufacturer.

Here's a list of the tools that I used:

  1. Laptop computer with Arduino IDE (should work with all versions)
  2. Soldering Iron
  3. Electronics Cutters
  4. USBtinyISP AVR Programmer (you could also use another Arduino as a programmer).

PCB Design

baublePCB.png
BaublePCBdes.png
BaubleSch.png

To design the PCB I used two software packages, Fusion360 and KiCAD. Fusion360 was used to design the custom shape of the PCB and KiCAD was used add the components and connecting wire traces.

There are multiple PCB design tutorials online for Fusion360 and KiCAD and other PCB design software packages.

I have tried to keep the design very simple and easy to understand. The schematic features an ATmega328P microcontroller powered directly by two CR2032 coin cell batteries (3V each in series, providing ~6V). The microcontroller operates at 16MHz, stabilized by an external 16MHz crystal oscillator and two 22pF capacitors connected in parallel to ground for proper clock operation. A piezo buzzer, connected to a GPIO pin (Arduino pin 3), outputs sound based on the code's tone generation. Eight LEDs, driven by individual GPIO pins (Arduino pins 4 to 11), provide visual effects. A push button (SW2) connected to a GPIO pin (Arduino pin 2) with an internal pull-up resistor is used for user input to start the process. Push button (SW1) is connected to the reset of the micro controller which turns all the LEDs off if pressed. This design was utilised to eliminate a voltage regulator to maximize simplicity and minimize power loss.

Please follow these links if you want the design files or to directly order a PCB.

https://drive.google.com/drive/folders/1kXIawOruwZufxn0tom7U6OJUI-TyFf7p?usp=sharing

PCB Assembly

bb1.jpg
bb2.jpg
bb3.jpg
bb4.jpg
bb5.jpg
bb6.jpg
bb7.jpg
bb8.jpg
bb9.jpg
bb10.jpg

When I solder the components to a PCB I usually start with the physically lowest components (such as the resistors) and then work up to the highest components (the LEDs) as it makes it easier. The order I soldered the components was:

  1. 8 x 1K ohm LED
  2. 1 x 10K ohm LED
  3. 8 x LEDs
  4. 1 x 16MHz Crystal (the metal component that's a silver lozenge shape)
  5. 2 x momentary push buttons
  6. 1 x 100nF ceramic disc capacitor (orange and marked 104)
  7. 1 x 2x3pin male header pins.
  8. 1 x Piezo Buzzer.
  9. 1 x 100uF Electrolytic Capacitor
  10. The Screw Connector on the back.
  11. The battery pack power leads.

On the front of the PCB all the resistors are 8 x 1K ohm resistors near the LED positions (R1 to R8) and need to be positioned in their holes. Once I've pulled the leads through I bend them outwards at 45 degrees to stop the resistor falling out of the PCB. I then solder all the leads in place and trim off the excess lead.

To solder the connection remember to heat the connection of the PCB and the lead and then feed in just enough solder to make a neat joint. Then pull the soldering iron away and let the joint cool making sure not to move it.

The resistors are there to limit the current going to the LEDs and prevent it from becoming damaged and failing. They also mean your battery can last longer. When you place the resistors on the PCB in doesn't matter which way round they go. The 10k ohm resistor on the back is to prevent the microcontroller resetting by holding pin 1 high.

The LEDs are a diode which means current can only go through them in one direction so it's very important they are put in the correct way round. An LED has two wires from it, usually called legs, and one is longer than the other. the Long leg goes to the positive and the short leg goes to the negative. If you look carefully at the PCB the LED position has two holes. One hole is surrounded by a square shape, this hole is for the negative LED lead (the short lead).

I pre-soldered the crystal onto the PCB for my hackspace members so that I could pre-program the microcontroller with the bootloader. If you solder the crystal yourself it does not matter which way round it goes but I prefer to see the writing on it the correct way up!

When soldering the capacitors it does not matter which way round you solder the small ceramic disc capacitor (C3) however it's very important that the electrolytic capacitor is soldered the correct way round. The shorter pin with the white stripe on the capacitor needs to be put in the hole for the negative terminal, this is marked with a white semi-circle.

The two momentary push buttons will only fit one way round so it's important that they are placed correctly. You may have to bend the pins a very small amount but not too much.

The Piezo Buzzer also needs to be installed the correct way round. Make sure the + terminal on the buzzer is placed in the hole marked with a + symbol.

A really useful tip for soldering components to a PCB is to place them in the correct position and then hold them there temporarily with blue tack. This enables you to turn the PCB upside-down without all the components falling out. This is how I soldered the microcontroller socket.

When you finally solder the battery pack power leads ensure the red wire goes to the positive terminal and the black wire goes to the negative terminal. I held the battery pack in-place with some Blu Tack but you could use hot glue or double sided tape.

The Code

BaubleCodeArduino.png

The code is written with the Arduino IDE and is meant to some simple code to try out the PCB. The idea is that once you have your PCB made and working you can then write you own (far more advanced) code.

Here's an explanation of each section of the code:

/* Notes frequency:
C = 523
d = 587
e = 659
f = 698
g = 784
*/

I put this comment at the beginning of the code to provide a reference for the frequencies of musical notes in Hertz (Hz). These frequencies are used later in the Jingle Bells melody for the buzzer.

// Define pin numbers
const int buttonPin = 2; // Pin for button
const int buzzerPin = 3; // Pin for buzzer

const int led1 = 4; // Pin for led
const int led2 = 5; // Pin for led
const int led3 = 6; // Pin for led
const int led4 = 7; // Pin for led
const int led5 = 8; // Pin for led
const int led6 = 9; // Pin for led
const int led7 = 10; // Pin for led
const int led8 = 11; // Pin for led

Definitions

This section assigns readable names to the pins connected to the button, buzzer, and LEDs.

Using constants like buttonPin makes the code easier to read and modify.

int ledArray [] = {led1, led2, led3, led4, led5, led6, led7, led8};

LED Array

The array above groups the LED pins into an array, allowing easy control of all LEDs using loops.

bool buttonState = HIGH;
bool lastButtonState = HIGH;
unsigned long lastDebounceTime = 0;
unsigned long debounceDelay = 50;

Button State Variables.

These purpose of these variables is to manage and debounce the button input to ensure stable readings.

The debounceDelay prevents false triggers caused by electrical noise when the button is pressed.

int melody[] = {
659, 659, 659, // E E E jingle bells
659, 659, 659, // E E E jingle bells
659, 784, 523, 587, 659, // E G C D E jingle all the way
698, 698, 698, 698, 698, // F F F F F oh what fun it is
659, 659, 659, 659, //E E E to ride on a
784, 784, 698, 587, 523 // G G F D C one horse open slay
};

The Melody Notes.

This array stores the sequence of notes (frequencies) "Jingle Bells" melody.

Each element in melody corresponds to a note frequency in Hz.

int noteDurations[] = {
8, 8, 4,
8, 8, 4,
8, 8, 8, 8, 2,
8, 8, 8, 12, 8,
8, 8, 8, 8,
8, 8, 8, 8, 2
};

The Melody Note Durations

This array stores the note durations for the "Jingle Bells" melody.

noteDurations specifies the length of each note 4 = quarter note, 8 = eighth note, etc.

void setup() {
pinMode(buttonPin, INPUT_PULLUP);
pinMode(buzzerPin, OUTPUT);

for (int i = 0; i<8; i++) {
pinMode (ledArray[i], OUTPUT);
}
}

setup() function

This function is run once and initializes the pins:

buttonPin is set as an input with an internal pull-up resistor (ensures a default HIGH state).

buzzerPin and all LED pins are set as outputs.

The for loop simplifies setting up multiple LEDs as outputs as it means you can just run the loop to set the pins as outputs rather than going through them each individually.

void loop() {
int reading = digitalRead(buttonPin);

if (reading != lastButtonState) {
lastDebounceTime = millis();
}

if ((millis() - lastDebounceTime) > debounceDelay) {
if (reading == LOW && buttonState == HIGH) {
ledChaser1();
playJingleBells();
ledChaser2();
}
buttonState = reading;
}

lastButtonState = reading;
}

loop() function

This main loop continuously checks the button state and runs actions when the button is pressed.

It has debouncing to prevent "false" button pressing. Debouncing ensures the button press is stable for at least debounceDelay (50 ms).

If the button is pressed, it triggers the following functions:

ledChaser1() - Lights chase clockwise.

playJingleBells() - Plays the melody.

ledChaser2() - Lights chase counterclockwise.

void playJingleBells() {
int totalNotes = sizeof(melody) / sizeof(melody[0]);
for (int thisNote = 0; thisNote < totalNotes; thisNote++) {
int noteDuration = 1000 / noteDurations[thisNote];
tone(buzzerPin, melody[thisNote], noteDuration);

int pauseBetweenNotes = noteDuration * 1.30;
delay(pauseBetweenNotes);

noTone(buzzerPin);
}
}

playJingleBells() function

This loop plays the "Jingle Bells" melody using the buzzer.

Loops through each note in melody.

Calculates the duration of the note and plays it using the tone() function.

It adds a pause (30% longer than the note duration) between notes for clarity (this was found through trial and error).

void ledChaser1() {
for (int i = 0; i<8; i++) digitalWrite(ledArray[i], LOW);
for (int i = 0; i<8; i++) {
digitalWrite(ledArray[i], HIGH);
delay(100);
}
}

ledChaser1() (Clockwise chase)

This function is to sequentially light up LEDs around the PCB in a clockwise pattern.

Turns off all LEDs first to ensure the chase starts cleanly.

void ledChaser2() {
for (int i = 0; i<8; i++) digitalWrite(ledArray[i], LOW);
for (int i = 8; i>=0; i--) {
digitalWrite(ledArray[i], HIGH);
delay(100);
}
}

ledChaser2() (Counterclockwise chase)

This function (similar to the last) sequentially lights up LEDs in a counterclockwise pattern.

Similar to ledChaser1(), but reverses the direction of the sequence.

I have attached the Arduino sketch if you want to use it.

Uploading the Code and Testing

Xmas Bauble PCB - Uploading Your Code

The code is uploaded to the PCB with an USBtinyISP AVR Programmer. The best way to see how to upload load the code is to take a look at the attached video.

You can also upload the code using another Arduino instead of the USBtinyISP AVR Programmer. There are multiple tutorials on how to do this on Instructables, an example of one is her: Programming Arduino With Another Arduino : 3 Steps - Instructables

Once you have uploaded your code you are ready to test the operation by pressing SW2. You get blinking lights and a "beautiful" rendition of Jingle Bells. It's now your turn to write some better code with an even more "beautiful" melody!

A quick tip! I find lots of discarded disposable vapes when I walk my dog. I have found the batteries from these vapes work very well for this type of project and is a great way of re-using something that is otherwise an environmental hazard. But make sure you dismantle the vape very carefully and only if you are competent to do so as these batteries can be dangerous if mishandled.