4. Embedded Programming¶
This weeks goal was to explore a microcontroller data sheet, develop and test an embedded program that interacts with input/output devices and communicates via wired or wireless connections. Therefore I used an Arduino Uno to control a WS2812 LED strip.
In addition we compared our different programming workflows at our Group Page
Exploring the Datasheet¶
I looked for the Datasheet.pdf and would like to present a few parts of it.
The microcontroller on the Arduino Uno is a ATmega328P. It runs at a clock speed of 16 MHz and 8-bit. It is from Microchip (formerly Atmel).
Unlike the classic von Neumann architecture, where program and data memory share the same space, the Harvard architecture separates program and data memory. This allows the microcontroller to process instructions and data at the same time, resulting in a higher efficiency.
The ATmega328P uses a modified Harvard architecture, which means that program memory can also be accessed as data in certain cases.
It has 32 KB of flash memory for programs, 2 KB of SRAM for temporary data, and 1 KB of EEPROM for permanent data storage. It offers 23 usable I/O pins. For example digital inputs and outputs, PWM outputs, analog inputs with a 10-bit ADC, and communication interfaces.
Because it is easy to program, reliable and well documented, the ATmega328P is widely used for embedded systems, prototyping and education.
Writing the code¶
First of all I had to sketch the desired functions.
Full RGB control with 3 potentiometers, an ON/OFF button and a mode switch button, where each individual LED could be addressed. For the mode control I used 2 buttons, 1 for changing the mode and 1 for changing the selection.
To address the WS2812 LED strip easily I used FastLED
To implement it open the library manager and install it.
To write the code I used the arduino programming wiki, AI, our labs tutorials, some online tutorials and of course my outstanding programming skills.
#include <FastLED.h>
#define LED_PIN 6
#define NUM_LEDS 12
#define POT_R A0
#define POT_G A1
#define POT_B A2
#define BUTTON_SELECT 3 // Button: selection
#define BUTTON_ONOFF 2 // Button: ON/OFF
#define BUTTON_MODE 4 // Button: mode control
CRGB leds[NUM_LEDS];
int selectedLED = 0;
bool ledsOn = true;
int mode = 0; // 0 = single-LED, 1 = all LEDs
bool buttonSelectPressed = false;
bool buttonOnOffPressed = false;
bool buttonModePressed = false;
void setup() {
pinMode(BUTTON_SELECT, INPUT_PULLUP);
pinMode(BUTTON_ONOFF, INPUT_PULLUP);
pinMode(BUTTON_MODE, INPUT_PULLUP);
FastLED.addLeds<WS2812B, LED_PIN, GRB>(leds, NUM_LEDS);
fill_solid(leds, NUM_LEDS, CRGB::Black);
FastLED.show();
}
void loop() {
// --- LED-selection ---
if (mode == 0 && digitalRead(BUTTON_SELECT) == LOW && !buttonSelectPressed) {
buttonSelectPressed = true;
selectedLED++;
if (selectedLED >= NUM_LEDS) selectedLED = 0;
delay(200); // simple gradient
}
if (digitalRead(BUTTON_SELECT) == HIGH) {
buttonSelectPressed = false;
}
// --- ON/OFF ---
if (digitalRead(BUTTON_ONOFF) == LOW && !buttonOnOffPressed) {
buttonOnOffPressed = true;
ledsOn = !ledsOn;
delay(200); // simple gradient
}
if (digitalRead(BUTTON_ONOFF) == HIGH) {
buttonOnOffPressed = false;
}
// --- mode control ---
if (digitalRead(BUTTON_MODE) == LOW && !buttonModePressed) {
buttonModePressed = true;
mode = (mode + 1) % 2; // toggles between 0 and 1
// --- Feedback mode-switch ---
for(int i=0; i<3; i++) { // 3 blinks
fill_solid(leds, NUM_LEDS, CRGB::White);
FastLED.show();
delay(i==0 ? 400 : 100); // first 400ms, then 100ms blink
fill_solid(leds, NUM_LEDS, CRGB::Black);
FastLED.show();
delay(100);
}
delay(200); //simple debounce
}
if (digitalRead(BUTTON_MODE) == HIGH) {
buttonModePressed = false;
}
// --- RGB potentiometer --- analog values are shifted to 8-bit (0-255) for perfect rgb control
uint8_t r = analogRead(POT_R) >> 2;
uint8_t g = analogRead(POT_G) >> 2;
uint8_t b = analogRead(POT_B) >> 2;
// --- control LEDs ---
if (!ledsOn) {
fill_solid(leds, NUM_LEDS, CRGB::Black); // all off
} else if (mode == 0) {
// single LED
leds[selectedLED] = CRGB(r, g, b);
} else {
// all LEDs
fill_solid(leds, NUM_LEDS, CRGB(r, g, b));
}
FastLED.show();
}
I first had to verify the code with the Arduino IDE software.
Then I was able to upload it to the Arduino.
Building the prototype lamp¶
I used a short WS2812 LED strip and built a tiny version of my final project.
Then I attached the strip with a hot glue gun and routed the cables threw the notch.
Wiring in KICAD¶
I downloaded the program KICAD and configured it.
I used CTRL+N to create a new project and opened the schematic editor.
First I changed the page settings.
And searched A for the Arduino Uno.
And the potentiometer.
Then I added the buttons.
Connected them with D2 D3 and D4 and the potentiometers with A0, A1 and A2.
Then I added the capacitor and resistor.
I had to edtit the WS2812. By right clicking a selection the popup menu shows up.
Then I connected the LED with D6.
And finished the wiring.
The plot function exports the schematic in different file formats.
Open the schematic.svg in an extra tab.
Wiring the microcontroller¶
I used a breadboard, jumper cables, 3 buttons and 3 potentiometers. In addition I used a 200 Ohm resistor, wich protects the data line from voltage spikes and a 0,47 µF capacitor, wich stabilizes the power supply and prevents flickering.
At full brightness the LED strip uses about 12 LEDs x 60 mA = 720 mA. The microcontroller is not made for such high currents, so I limited the brightness.
I tested the system step by step to validate inputs, readings and output signals safely. Afterwards I combined the prototype lamp and the final breadboard version.
Downloads¶
Arduino IDE - Software
Datasheet.pdf
Code.ino
schematic.zip