/*
Forum: https://forum.arduino.cc/t/coding-help-requested-for-interactive-periodic-table-with-ws2812b-leds-and-phone-app-as-controller-project-for-students/1308898/2
Wokwi: https://wokwi.com/projects/411098731795952641
Date: 2024/10/07
Created: ec2021
103 elements in the Periodic Table
2 leds per element = 206 leds
led 0 and 1 -> Hydrogen (No = 1)
...
led 205 and 206 -> Lawrencium (No = 103)
Calculation of leds to illuminate for certain element
No = element number
led1 = (No-1)*2
led2 = led1+1
*/
#include <Adafruit_NeoPixel.h>
#include <FastLED.h>
const int N_PIXELS = 206; // Number of pixels in strand
const byte LED_PIN = 6; // NeoPixel LED strand is connected to this pin
const byte maxElements = 103;
// Parameter 1 = number of pixels in strip
// Parameter 2 = Arduino pin number (most are valid)
// Parameter 3 = pixel type flags, add together as needed:
// NEO_KHZ800 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
// NEO_KHZ400 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
// NEO_GRB Pixels are wired for GRB bitstream (most NeoPixel products)
// NEO_RGB Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
// NEO_RGBW Pixels are wired for RGBW bitstream (NeoPixel RGBW products)
Adafruit_NeoPixel strip = Adafruit_NeoPixel(N_PIXELS, LED_PIN, NEO_GRB + NEO_KHZ800);
// IMPORTANT: To reduce NeoPixel burnout risk, add 1000 uF capacitor across
// pixel power leads, add 300 - 500 Ohm resistor on first pixel's data input
// and minimize distance between Arduino and first pixel. Avoid connecting
// on a live circuit...if you must, connect GND first.
const byte alkaliMetals[] = {3, 11, 19, 37, 55, 87};
const byte noOfAlkaliMetals = sizeof(alkaliMetals) / sizeof(alkaliMetals[0]);
const byte alkalineEarthMetals[] = {4, 12, 20, 38, 56, 88};
const byte noOfAlkalineEarthMetals = sizeof(alkalineEarthMetals) / sizeof(alkalineEarthMetals[0]);
uint32_t cWhite, cRed, cGreen, cBlue;
void setup()
{
cWhite = strip.Color(255, 255, 255);
cRed = strip.Color(255, 0, 0);
cGreen = strip.Color(0, 255, 0);
cBlue = strip.Color(0, 0, 255);
Serial.begin(115200);
strip.begin();
strip.setBrightness(255);
clearLeds(); // Initialize all pixels to 'off'
Serial.println("Start");
showElement("Halogen", 1, cRed, false); // false does not clear leds
showElement("Lawrencium", 103, cGreen, false);
showElement("Mercury", 80, cBlue, true); // true clears leds
showGroupInRow("Actinoids", 89, 103, cBlue, true);
showGroupInRow("Lanthanoids", 57, 71, cRed, true);
showGroup("Alkali Metals", noOfAlkaliMetals, alkaliMetals, cBlue, false);
showGroup("Alkaline Earth Metals", noOfAlkalineEarthMetals, alkalineEarthMetals, cGreen, false);
Serial.println("Done");
}
void loop() {
}
void clearLeds() {
for (int i = 0; i < N_PIXELS; i++) {
strip.setPixelColor(i, 0);
}
strip.show();
}
// Set the leds of a certain element
void illuminateElement(uint8_t element, uint32_t c) {
if (element > 0 && element <= maxElements) {
int led1 = (element - 1) * 2;
int led2 = led1 + 1;
strip.setPixelColor(led1, c);
strip.setPixelColor(led2, c);
strip.show();
}
}
void showElement(char name[20], byte no, uint32_t col, boolean clear) {
if (clear) {
clearLeds();
}
Serial.print(name);
Serial.print(": ");
Serial.println(no);
illuminateElement(no, col);
delay(3000);
}
// If elements are not in a row we use an array that contains their element numbers
void showGroup(char name[20], byte len, byte *arr, uint32_t col, boolean clear) {
Serial.print(name);
Serial.print(": ");
if (clear) {
clearLeds();
}
for (int i = 0; i < len; i++) {
byte element = arr[i];
illuminateElement(element, col);
Serial.print(element);
if (i < len - 1) {
Serial.print(",");
}
}
Serial.println();
delay(3000);
}
// If the elements are "in a row" we can use a for-loop()
void showGroupInRow(char name[20], byte fromElement, byte toElement, uint32_t col, boolean clear) {
Serial.print(name);
Serial.print(" from ");
Serial.print(fromElement);
Serial.print(" to ");
Serial.println(toElement);
clearLeds();
for (int i = fromElement; i <= toElement; i++) {
illuminateElement(i, col);
}
delay(3000);
}