At work a colleague developed a custom board in the time of chip shortage™ and had to use a 20 MHz oscillator in place of a 16 MHz requiring a custom board configuration. The solution after searching the often misleading Arduino forums was to hack it into the global platform.txt.
This is neither portable nor does it interact well with updates of the Core. Fortunately, there are very good, not misleading forum posts!
A (hopefully more than just slightly) better solution is to use the hardware/ directory in the Sketchbook folder and to reference the standard Arduino configurations (using the VENDOR_ID:VARIANT_ID notation).
Let’s name the board gsino since my colleague and I work at GSI.
Then let’s create a folder structure $SKETCHBOOK/hardware/gsi/avr and …
If the created folder contains only this board.txt file, the menu entry in the IDE for this board will be “Tools/Board/gsi-avr/GSino Board”. If you want it a little prettier, create a platform.txt with
gsino.name=GSino gsino.version=1.0.0
Voilà! If you need to take this to another computer or share it with a friend, just zip the relevant parts of the $SKETCHBOOK/hardware/ folder and unpack it in its new location.
And there you have a slightly more portable and cleaner solution to writing your own hardware platform.
*) This was done on Arduino IDE version 1.8.19 and should work for quite a while (probably after version 1.5.x). AFAIK, this should work similarly with the new 2.0 IDE. But I did not test this.
My kid likes traffic lights. So I decided to quickly build one. I started off on a breadboard with a bunch of components:
3 × LEDs (red, amber, green)
3 × 470 Ω Resistors (only had two, so the third are actually 2 1 kΩ in parallel)
1 × 10 kΩ Resistor
1 × Pushbutton Switch
1 × Arduino Nano (actually a clone)
The circuitry is relatively simple. All LEDs’ cathodes point to ground (GND) through a 470 Ω resistor each to limit current and not blow anything. The anodes are connected individually to the digital port D3 through D5.
The button works such that, if open, it connects digital port D2 via a 10 kΩ resistor to the 3.3 V output of the Nano. When it closes, it’s supposed to pull D2 to GND, so it’s directly connected to it. The resistor serves to limit the current and – again – not blow anything.
That’s it. Now, for example, pulling D3 high (i.e. applying 3.3 V) will switch on the red LED. Likewise for D4 on the yellow and D5 on the green LED. Let’s introduce some human readable names instead of D2 through D5:
To control the traffic light logic, I scribbled a Moore machine on a piece of paper, starting with a pedestrian traffic light (only red and green).
The machine starts in the red-light state. It remains there, unless the button is pressed. Then, it instantly switches to green (a pedestrian’s dream) where it remains until the button is pressed again.
This behaviour can be implemented by putting a simple switch case statement in the main loop() and implementing a state variable:
// States
enum states{ ST_R,
ST_G
}
void setState(bool red, bool green) {
digitalWrite(LED_RED, red ? HIGH : LOW);
digitalWrite(LED_GREEN, green ? HIGH : LOW);
}
void setRed() { setState(true, false); }
void setGreen() { setState(false, true); }
void loop() {
switch(machineState) {
case ST_R:
// Serial.write("State: Red");
setRed();
break;
case ST_G:
// Serial.write("State: Green");
setGreen();
break;
}
Why use this enum thingy, you say? You could just use an int and call your states 0, 1, 2, etc., you say? Yes, you could also sign up for the biannual global brainfuck contest.
Now that’s a simple and pretty useless traffic light (well, I still like that I can switch it to green at will, this really should be the default pedestrian crossing light!).
But it is easy to extend. You want a yellow state? Add a yellow state ST_Y to your state machine (the switch case statement). Or you want it to show yellow before switching from green to red? Add a yellow-before-red state ST_Y_R. Or you really like to let people wait? Add a wait state. Oh, and of course you can call your states whatever you want.
Here is my full implementation of a non-pedestrian red-yellow-green traffic light as it is stated in the German traffic rules:
From red to green, with wait periods, go through
Red
Red+Yellow (yes, red+yellow, yellow meaning “get ready” and red meaning “not too fast, it’s still red, Freundchen!”)
Green
From green to red, with wait periods, go through
Green
Yellow (yes, only yellow. The meaning is disputed. Reasonable people say it means “Prepare to stop, if you can’t make it in time, it’s okay.” while idiots say it means “STEP ON THE GAS!”)
Red (This is also sometimes disputed, I won’t go into this.)
Is this the best way to write this? Hell, no! Is it even a good tutorial? You tell me. I think it’s fairly simple and shows some evenly common concepts:
Using IO pins
Wiring LEDs without burning them or the output pin
Wiring a button*
Using #define statements to make code more readable and lives more easy
Using some abstraction (setState(), setRed(), etc.)
Using a state machine as an extensible concept
Using an interrupt (Why use an interrupt? Because it interrupts your code exactly when the button is pressed. It makes your little circuit very responsive and – at least in this example – it is even easier to write.)
*) You may encounter a problem that goes by the name “bouncing” (or in the beautiful German language “prellen”). That’s when your button press toggles multiple interrupts in a row. Try putting a capacitor in parallel with the resistor, or as a bad software hack, add a 5 ms delay (delay(5);) to the end of your interrupt function.
Anyways: My girl loves it. Ha! You thought she’d be a boy because it was a traffic light. Shame on you!