Kan du ikke det her da? Link to heading
Vel, jo, kanskje egentlig? Jeg burde kunne grunnleggende elektronikk og mikrokontrollere, og jeg kan skrive litt Python uten at jeg er noen ekspert. Jeg har kunnet både litt C og litt ASM en gang. Det burde kunne bety at jeg kan skyndte meg gjennom litt grunnleggende Arduino.
Hello World.. Link to heading
Når det kommer til mikrokontrollere så har visst «Blink» erstattet Hello World. Altså, få en LED til å blinke. Arduino-en jeg fant frem er en Arduino Uno R3, som kommer med en LED allerede på kortet.
Så den enkleste Blink-koden er vel noe sånt her:
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
}
void loop() {
digitalWrite(LED_BUILTIN, HIGH);
delay(1000);
digitalWrite(LED_BUILTIN, LOW);
delay(1000);
}
loop()
og setup()
er Arduino-spesifike funksjoner som blir kjørt ved oppstart og i… loop. delay()
fryser loopen, så det er ikke noe lurt å bruke hvis mikrokontrolleren skal gjøre flere ting «samtidig».
Men det er ikke veldig spennende med «Hello World». Ett vanlig problemen med prosjekter er jo gjerne å definere prosjektet… «Hva skal det bli?», eller hva i all verden tenkte jeg egentlig? Vel. Jeg fant frem noen flere deler i skuffene. Så langt så har jeg funnet frem:
- Arduino Uno R3
- Arduino Nano
- WS2812 LED Stick 1x8
- FS1000A (evt. XD-FST & XD-RF-5V)
- Trykkbryter
- 10kΩ motstand
- Rød LED
- 220Ω motstand
pluss to koblingsbrett (jeg måtte google «breadboard»…) og noen kabler.
Dagens “prosjekt” Link to heading
Jeg skal styre en WS2812 LED Stick tilkoblet Arduino Nano-en, fra Arduino Uno-en. Det vil si trådløs kommunikasjon mellom Uno-en og Nano-en, ved hjelp av FS1000A (eller hva de egentlig heter for noe). FS1000A er ett sett med sender og mottaker for 433MHz, ISM-bånd, nærmere spesifikt 433,920MHz. Ser ut til å være godt støttet i RadioHead-biblioteket.
-
På Nano-en skal jeg:
- Bruke RadioHead-biblioteket (RH_ASK.h) til å ta i mot kommandoer fra Uno-en
- Bruke FastLED-biblioteket til å lage tilfeldig mønster e.l. på LED Stick-en på kommando
-
På Uno-en skal jeg:
- Bruke RadioHead-biblioteket (RH_ASK.h) til å sende kommandoer til Nano-en
- Bruke en trykknapp til å styre Nano-en
- Blinke en LED når den sender kommandoer, sånn at jeg vet den virker

FS1000A, evt. XD-FST
Koblingsskjemaet er laget i Fritzing. Jeg kunne sikker brukt KiCad også, men jeg prøvde de alfabetisk. Begge er open source, men Fritzing tar betalt for ferdigbygde binærfiler.
Enkelt koblingsskjema for TX-siden Enkelt koblingsskjema for RX-siden
Koden Link to heading
Arduino har sitt eget IDE, som heter Arduino IDE. Det er ikke noe helt galt med det, men jeg trives bedre i vim og på kommandolinja. vim har tydeligvis syntax highlighting for… hva er egentlig programmeringsspråket her? Ah, det er visst en C++-dialekt. Arduino har også ett kommandolinjeverktøy, som heter arduino-cli
(…), som kan ta seg av kompilering og opplasting, samt biblioteker.
Her får jeg bare unnskylde for alle som faktisk kan C++. Hvis jeg kunne det en gang, så er det i alle fall lenge siden.
Først TX Link to heading
#include <RH_ASK.h>
#include <SPI.h>
#define BUTTONPIN 2
#define LEDPIN 12
#define RFTXPIN 8
#define RFRXPIN 19 // modulen har bare TX, men...
RH_ASK rf_driver(2000, RFRXPIN, RFTXPIN);
// For å slippe å bruke delay(), så bruker jeg millis() i loop-en, og sjekker om vi har passert intervallet
unsigned long blinkPrevMillis = 0UL;
unsigned blinkInterval = 500UL;
unsigned long pressedPrevMillis = 0UL;
unsigned pressedDebounce = 200UL;
int ledState = LOW;
bool shouldSendAndBlink = false;
// Det var lettere å lage en struct enn å forstå hvordan få sendt chars/strings...
// Dvs. jeg har glemt alt som man burde kunne om typer og casting.
struct RFData
{
bool firstCommand;
};
struct RFData data;
void setup()
{
Serial.begin(9600);
pinMode(BUTTONPIN, INPUT);
pinMode(LEDPIN, OUTPUT);
attachInterrupt(digitalPinToInterrupt(BUTTONPIN), buttonPressed, RISING);
rf_driver.init();
}
void buttonPressed()
{
unsigned long currentMillis = millis();
if (currentMillis - pressedPrevMillis > pressedDebounce)
{
pressedPrevMillis = currentMillis;
shouldSendAndBlink = !shouldSendAndBlink;
if (!shouldSendAndBlink)
{
ledState = LOW;
digitalWrite(LEDPIN, ledState);
}
}
}
void runSendAndBlink()
{
unsigned long currentMillis = millis();
if (currentMillis - blinkPrevMillis > blinkInterval)
{
blinkPrevMillis = currentMillis;
ledState = !ledState;
digitalWrite(LEDPIN, ledState);
if(ledState)
{
data.firstCommand = true;
}
else
{
data.firstCommand = false;
}
rf_driver.send((uint8_t *)&data, sizeof(struct RFData));
rf_driver.waitPacketSent();
}
}
void loop()
{
if (shouldSendAndBlink)
{
runSendAndBlink();
}
}
Og så RX Link to heading
#include <RH_ASK.h>
#include <SPI.h>
#include <FastLED.h>
#define PIXELPIN 2
#define PIXELNUM 8
#define RFRXPIN 4
#define RFTXPIN 9
CRGB leds[PIXELNUM];
RH_ASK rf_driver(2000, RFRXPIN, RFTXPIN);
void setup() {
FastLED.addLeds<WS2812, PIXELPIN, GRB>(leds, PIXELNUM);
FastLED.clear();
FastLED.setBrightness(20);
FastLED.show();
randomSeed(analogRead(0));
rf_driver.init();
}
struct RFData {
bool firstCommand;
};
struct RFData *data;
void loop() {
uint8_t buf[RH_ASK_MAX_MESSAGE_LEN];
uint8_t buflen = sizeof(buf);
if (rf_driver.recv(buf, &buflen))
{
data = (struct RFData *)buf;
if (data->firstCommand)
{
pixelSetRandom();
}
}
}
// Litt ekstra kode i pixelSetRandom() og getColor() for å gjøre noe "nyttig" med LED Stick-en.
// Den setter random farge og antall LEDs/piksler for hver gang den får beskjed.
CRGB getColor(int newColor)
{
switch (newColor)
{
case 0:
return CRGB::Red;
case 1:
return CRGB::Yellow;
case 2:
return CRGB::Green;
}
}
void pixelSetRandom()
{
int newColor = random(3);
int newValue = random(8);
for (int i = 0; i < PIXELNUM; i++)
{
if (newValue > i)
{
leds[i] = CRGB::Black;
}
else
{
leds[i] = getColor(newColor);
}
FastLED.show();
}
}
Oppsummering Link to heading
Så. Hva har jeg egentlig lært? Jeg har vel fått til det jeg prøvde på, selv om jeg kanskje ikke burde prøve å leve av C++-kunnskapen min. I tillegg oppdaget jeg Fritzing og KiCad som kan være nyttig senere.
Det er forresten svært mulig at jeg overvurderte antenna jeg lodda på FS1000A-modulene. Med en 5cm lang kabel på TX og på RX, så er rekkevidden… maks 10cm. Maks 5cm hvis du skal ta i mot alle pakkene. Jeg gjetter på at det kan gjøres bedre om man legger litt innsats i det, men på Internett er det flere som ikke er veldig imponert. Det virket for en test i alle fall!