tiistai 20. maaliskuuta 2018

Leikkiminen Arduinojen ja micro:bitien kanssa jatkuu...

Tänään paneuduin pitkästä aikaa virtapiirien kytkentäkuvien piirtämiseen ja huomasin, että aikaisemmin käyttämäni circuits.io:n Electronics Lab olikin vaihtunut Tinkercad:ksi. No, hyvin näytti tämänkin toimivan. Koodi oli helppoa tehdä blokkieditorilla ja simulointi toimi mainiosti. Uutta oli myös se, että johtimet sai piirrettyä hienosti kaareviksi. Simuloinnin lisäksi koodin saa myös ladattua omalle koneelle ArduinoCC-tiedostona! Eipä hullumpaa.

Tässä ensimmäinen kokeiluni, servomoottorin ohjaaminen potentiometrillä. Simulaation käynnistämisen jälkeen tartu hiirellä potentiometriin ja liikuttele sitä niin saat servon kääntymään. Jos haluat tutkia koodia, sen saa näkyviin valitsemalla "Code".


Tinkercadillä piirretty kytkentäkuva servomoottorin ohjaamisesta potentiometrillä 

Tinkercadillä voi myös ohjelmoida ja ladata koodin ArduinoCC-tiedostona
Tämän näköistä koodia tästä generoitui:

#include <Servo.h>

Servo servo_3;

void setup()
{
  pinMode(A0, INPUT);
  servo_3.attach(3);

}

void loop()
{
  servo_3.write(map(analogRead(A0), 0, 1023, 0, 180));
  delay(100); // Wait for 100 millisecond(s)
}

Tässä vielä kuva kytkennästä:

Arduino kytkettynä potentiometriin ja servomoottorin
Vastaava toiminta micro:bit:illä ei toiminut aivan näin hyvin. Simulaatioon ei voi itse lisätä komponentteja, servo kyllä ilmestyy siihen automaattisesti kun koodiin valitsee servoblokin, potentiometriä ei voi lisätä mutta sitä voi mallintaa klikkailemalla P1-pinniä. Ensimmäinen versio koodista ei toiminut. Ilmeisesti vika on siinä, että koska JSBlocks ei tue liukulukuja jakolasku pyöristyy nollaksi... 

Hyvältä näyttää mutta ei toimi...

Kun laskujärjestyksen muuttaa niin, että kertolasku suoritetaan ensin, homma lähtee toimimaan. Aika kinkkistä...

Tämä versio koodista toimii 

Tässä linkki projektiin. Microbit:iin ladattuna koodi ei kuitenkaan toimi yhtä hyvin kuin Arduino:ssa, servo pörisi ja nyki epäilyttävästi. Tämä johtuu micro:bit:in alemmasta käyttöjännitteestä (Arduino 5V, micro:bit 3,3V). 

Tässä vielä vertailun vuoksi sama koodi ohjelmoituna C++:lla ja mbed:llä:

#include "MicroBit.h"

MicroBit uBit;

int main()
{
    uBit.init();
    
    while(1){
    int potikka = uBit.io.P1.getAnalogValue(); //P1: 0-1024 
    int moottori = (int(potikka/1024.0*180));
    uBit.io.P0.setAnalogValue(moottori);  //P0: 0-180    
    uBit.sleep(10);
    }
}

Myös mbed:llä ohjelmoidessa kokonaislukujen jakolaskun kanssa pitää olla tarkkana ja muistaa muuttaa ainakin toinen liukuluvuksi (vrt. 1024.0 yllä olevassa koodissa) ettei tulos pyöristy tässäkin nollaan. 

Tämän kytkennän sai toimimaan ilman kondensaattoria Arduinon kanssa mutta micro:bit:illä ei (moottori jämähti välillä paikoilleen). Kondensaattorin tarkoitus on tässä tasailla moottorin käynnistämisen aiheuttamia virtapiikkejä, ja ilmeisesti alemmalla käyttöjännitteellä tasaaminen auttaa pitämään moottorin käynnissä paremmin. micro:bit:in kanssa pitäisi ilmeisestikin käyttää ulkoista jännitelähdettä servolle, ja se taas johtaisi paljon monimutkaisempaan kytkentään...

micro:bit kytkettynä potentiometriin ja servomoottoriin

perjantai 2. maaliskuuta 2018

Buzzer-ongelman ratkaisu eli jälleen kerran lisää micro:bit:in ohjelmointia C++:lla mbed:in kautta

Ja pienen mutkan jälkeen sain summerinkin (piezo buzzer) soittamaan melodioita C++:lla mbedin kautta. Tähän tarvittiin PWM_tone_library. Kirjaston asentaminen mbed-ympäristössä on helppoa, riittää että menee kirjaston sivulle ja painaa esimerkkiohjelman kohdalla "import program". Tämä tekee uuden projektin mbed-ympäristöön ja imaisee mukaansa kaikki esimerkkiohjelman vaatimat kirjastot (tässä mukaan tulee siis PWM_tone_library sekä mbed-kirjasto).

Piezo buzzer -kirjaston asennus mbed:issä
Jotta tämän saa toimimaan micro:bit:in kanssa, projektiin pitää kopioida myös MicroBit - kirjasto (sen voi hakea jostain vanhasta projektista copy-paste:lla). 

Projektissa pitää olla microbit, mbed ja PWM_Tone_Library
Malliohjelmaa pitää muokata kahdesta kohtaa:
  1. lisää MicroBit - kirjasto #include "MicroBit.h"
  2. Vaihda "D5":n (pinnin nimi) tilalle käyttämäsi analogiapinni esim.  MICROBIT_PIN_P1
Ja sitten vain kiinnittämään summeria pinnin P1 ja GND:n väliin ja lataamaan ohjelmaa micro:bit:iin. Jos haluaa samalla tutkia ledinäytöllä missä mennään lisäsin tähän koodiin pieniä tulosteita (jotka asynkronisen toiminnan ansiosta toimivat samaan aikaan kuin melodia):

#include "mbed.h"
#include "MicroBit.h"
#include "pwm_tone.h"

MicroBit uBit;

PwmOut Buzzer(MICROBIT_PIN_P1);

float C_3 = 1000000/Do3,
       Cs_3 = 1000000/Do3s,
       D_3 = 1000000/Re3,
       Ds_3 = 1000000/Re3s,
       E_3 = 1000000/Mi3,
       F_3 = 1000000/Fa3,
       Fs_3 = 1000000/Fa3s,
       G_3 = 1000000/So3,
       Gs_3 = 1000000/So3s,
       A_3 = 1000000/La3,
       As_3 = 1000000/La3s,
       B_3 = 1000000/Ti3,
       C_4 = 1000000/Do4,
       Cs_4 = 1000000/Do4s,
       D_4 = 1000000/Re4,
       Ds_4 = 1000000/Re4s,
       E_4 = 1000000/Mi4,
       F_4 = 1000000/Fa4,
       Fs_4 = 1000000/Fa4s,
       G_4 = 1000000/So4,
       Gs_4 = 1000000/So4s,
       A_4 = 1000000/La4,
       As_4 = 1000000/La4s,
       B_4 = 1000000/Ti4,
       C_5 = 1000000/Do5,
       Cs_5 = 1000000/Do5s,
       D_5 = 1000000/Re5,
       Ds_5 = 1000000/Re5s,
       E_5 = 1000000/Mi5,
       F_5 = 1000000/Fa5,
       Fs_5 = 1000000/Fa5s,
       G_5 = 1000000/So5,
       Gs_5 = 1000000/So5s,
       A_5 = 1000000/La5,
       As_5 = 1000000/La5s,
       B_5 = 1000000/Ti5;

int tones[] = {E_4, D_4, C_4, D_4, E_4, E_4, E_4, 0, D_4, D_4, D_4, 0, E_4, G_4, G_4, 0, 
                             E_4, D_4, C_4, D_4, E_4, E_4, E_4, 0, D_4, D_4, E_4, D_4, C_4, 0, 0, 0};
int tones_num = 32;

int main(void)
{
    uBit.init();
    uBit.display.printAsync('C');
    Tune(Buzzer, C_4, 4);  //4 Octave C beat 4/16
    wait_ms(250);
    uBit.display.printAsync('D');
    Tune(Buzzer, D_4, 4);  //4 Octave D beat 4/16
    wait_ms(250);
    uBit.display.printAsync('E');
    Tune(Buzzer, E_4, 4);  //4 Octave E beat 4/16
    wait_ms(250);
    
    int i;
    
    uBit.display.scrollAsync("melody");
    
    for(i=0; i<tones_num; i++)
    {
        Auto_tunes(Buzzer, tones[i], 4); // Auto performance
        Stop_tunes(Buzzer);
    }
}

Eihän tämä lopulta vaikeaa ollut mutta sitäkin palkitsevampaa kun tuo pieni melodia lopulta tuli ulos :-) Se mitä tässä tarvittiin oli kirjasto, joka osaa tehdä PWM:ää (Pulse Width Modulation) analogiapinnille (PwmOut-rajapinta mbed-kirjastossa), tietoa eri sävelten taajuuksista (pwm_tone.h-tiedostossa). Esimerkkikoodissa muunnettiin sävelen taajuus värähdysajaksi (värähdysaika on taajuuden käänteisluku) mikrosekunneissa (µs). Esim. PWM värähdysaika 440Hz sävelelle on 1000000/440. Ja tuolla jaksonajalla vaihteleva jännite saa pietsoelementin sisällä olevan metallilevyn tuottamaan jotakuinkin yksiviivaista a:ta vastaavaa ääntä. Kaikkea sitä oppii kun näiden kanssa pelaa... 

Ja tilanne mbed-ArduinoCC micro:bit:in osalta on nyt virallisesti 2-0.

micro:bit:in ohjelmointia ArduinoCC:llä

Koska seinä nousi pystyyn summerin soitossa mbed:in kanssa, päätin kokeilla toista C/C++ tyylistä ohjelmointiympäristöä ArduinoCC:tä micro:bit:in ohjelmointiin. micro:bit ei ole suoraan tuettu ArduinoCC:ssä (korttivalikosta ei löydy heti heittämällä micro:bit:iä), mutta sen voi ladata helposti. Valitse Tiedosto -> Asetukset ja lisää kohtaan "Additional Boards Managers URL"-kohtaan: https://sandeepmistry.github.io/arduino-nRF5/package_nRF5_boards_index.json ja valitse ok. Tämän jälkeen avaa Työkalut -> Kortti -> Boards manager ja kirjoita hakukentään nRF5, valitse Nordic Semiconductors by Sandeep Mistry ja paina "asenna". Nyt voit käydä valitsemassa Työkalut -> Kortti -listasta micro:bit:in, muista myös valita oikea COM-portti kuten Arduinonkin kanssa. Valitse vielä Työkalut -> Softdevice valikosta "S110". Nyt sinulla on yhteys micro:bit:iin ja voit ohjelmoida sitä kuin Arduino:a. Koodi latautuu suoraan micro:bit:iin, eli sitä ei tarvitse erikseen siirtää kuten mbed:in tai JS Blocks:in kanssa.

micro:bit - tuen lisääminen ArduinoCC:hen (ensimmäinen vaihe)
micro:bit - tuen lisääminen ArduinoCC:hen (toinen vaihe)
Tässä pieni koodin pätkä, jossa ohjataan ledinäytön vasemman yläkulman lediä. Kun A-napista painetaan ledi alkaa vilkkua, kun napista B painetaan se pimenee ja kun mitään ei paineta, se palaa koko ajan.

const int COL1 = 3;
const int LED = 26;
const int buttonA = 5;     // the number of the pushbutton pin
const int buttonB = 11;    // the number of the pushbutton pin

void setup() {
  pinMode(COL1, OUTPUT);
  digitalWrite(COL1, LOW);
  pinMode(LED, OUTPUT);
  pinMode(buttonA, INPUT);  
  pinMode(buttonB, INPUT);   
}

void loop() {
  if (! digitalRead(buttonA)) {
    digitalWrite(LED, HIGH);
    delay(500);
    digitalWrite(LED, LOW);
    delay(500);
  } else if (! digitalRead(buttonB)) {
    digitalWrite(LED, LOW);
  } else {
    digitalWrite(LED, HIGH);
    }

  delay(10);
} 

Koska ledi näytön 25 lediä ohjataan 12 pinnillä oman logiikkansa mukaisesti (ledit multipleksattu, katso lisätietoa), sen käyttäminen ilman apukirjastoa on hieman sekavaa ja työlästä. Onneksi näytön ohjaamiseen on tarjolla kirjasto ja sen asentaminen onnistuu yhtä vaivattomasti kuin edellinenkin laajennos. Lataa github:ista seuraava zip-tietosto:  https://github.com/ht-deko/microbit_Screen/archive/master.zip ja avaa valikosta Sketsi -> Sisällytä kirjasto -> Tuo .ZIP kirjasto.

Kirjaston asentaminen ArduinoCC:hen
Valitse lataamasi .ZIP - tiedosto, jonka jälkeen voit lisätä sen koodiisi valikosta Sketsi -> Sisällytä kirjasto -> microbit_Screen-master. Tämän jälkeen koodiisi ilmestyy seuraava rivi koodia, joka ottaa kirjaston käytöön:

#include <microbit_Screen.h>

Tämän kirjaston avulla ledinäytölle saa vaivattomasti tekstiä, esimerkkinä se kuuluisa "Hello World!":

#include <microbit_Screen.h>

void setup() {
  SCREEN.begin();
}

void loop() {
  SCREEN.showString("Hello,World!");    
}

Vielä täytyy testata miten sen potentiometrillä ohjattavan RGB:n ledin ja summerin koodi oikein ArduinoCC:llä taittuisi... ja eihän se sitten lopulta toiminut. tone - funktiota ei löytynyt micro:bit:ille ja muutenkin koodin toiminta "pätki" eli ledi ei reagoinut reaaliajassa potentiometrin pyöritykseen kuten mbed:in kanssa. 1-0 mbed:ille ja 0-0 summerin käytössä :-)

Tässä kuitenkin koodi:

#include <microbit_Screen.h>

const int POTIKKA = 0;
const int SUMMERI = 1;
const int RGB_R = 8;
const int RGB_B = 3;
const int RGB_G = 16;

void setup() {
  SCREEN.begin();
  pinMode(RGB_R, OUTPUT);
  pinMode(RGB_B, OUTPUT); 
  pinMode(RGB_G, OUTPUT); 
  pinMode(SUMMERI, OUTPUT);
  pinMode(POTIKKA, INPUT);
}

void loop() {
    int sensorvalue = analogRead(POTIKKA);   // P1: 0 - 1024 
    SCREEN.showString(String(sensorvalue));
  //    tone(SUMMERI, sensorvalue);
    if(sensorvalue <= 340){
        digitalWrite(RGB_R, HIGH);
        digitalWrite(RGB_B, LOW);
        digitalWrite(RGB_G, LOW);        
        } else if(sensorvalue > 340 && sensorvalue <=680){
          digitalWrite(RGB_R, LOW);
          digitalWrite(RGB_B, HIGH);
          digitalWrite(RGB_G, LOW);
          } else {
            digitalWrite(RGB_R, LOW);
            digitalWrite(RGB_B, LOW);
            digitalWrite(RGB_G, HIGH);
            }
  delay(10);
}

Testikytkentä: potentiometri, RGB-ledi, summeri ja ledinäyttö

torstai 1. maaliskuuta 2018

Vieläkin lisää micro:bit:in ohjelmointia C++:llä mbed:in kautta

Kuten aika usein, nälkä kasvaa syödessä. Kolmas päivä putkeen micro:bit:in ja C++:n kanssa (no onneksi on loma).

Tänään otin esille Kitronik breakout boardin, jonka avulla pääsee eroon hauenleukajohdoista ja samalla saa käyttöönsä myös ne pienemmät pinnit, joihin hauenleukaa ei edes saa kiinni.

Ensimmäiseksi tein digitaalisen lämpömittarin, joka näyttää lämpötilalukemaa ledinäytöllä. micro:bit:issä on myös sisäinen lämpömittari, mutta sen lämpötila kuvaa lähinnä piirilevyn lämpötilaa, ei huoneen lämpötilaa. Testauksessa myön paristokotelo, jonka avulla laitteen voi irrottaa tietokoneesta. Tällainen kytkentä siitä tuli:

Kitronik breakout board, lämpötilasensori LM35 ja paristokotelo
Ja koodina tällainen:

#include "MicroBit.h"

MicroBit uBit;

float rawToTemp(int x){
  float temp = 0;
  temp = (3.0*x*100)/1024;
  return temp;
}    

int main()
{
    uBit.init();
    
    while(1){
    int sensorvalue = uBit.io.P0.getAnalogValue();   
    int t = static_cast<int>(rawToTemp(sensorvalue));
    uBit.display.scrollAsync(t);
    uBit.sleep(2);
    }
}

Aluksi idea oli kytkeä mukaan myös summeri (buzzer) mutta käytetyssä rajapinnassa ei ollutkaan tukea äänille, ja digitaalinen on/off sai aikaan vain napsumista ja analoginen jännitteen säätö vaimeaa pörinää. Lämpötilan vaihtuminen oli myös hyvin jähmeää, puhaltelemalla se ei meinannut nousta ollenkaan ja pakkasessakin lämpötila laski hyvin hitaasti (ei alle +6 asteen, vaikka ulkona oli -15 astetta). Ei kovin optimaalinen mittari siis.

Seuraava kokeilu toimikin jo paremmin: RGB-ledin ohjaaminen potentiometrillä. Kytkin potentiometrin pinniin P0 ja RGB-ledin pinneihin P1, P2 ja P16. Koska halusin näyttää  potentiometrin antaman lukeman ledinäyttöä, käyttööni ei jäänyt yhtään vapaata analogiapinniä (ovat ledinäytön kanssa yhteisiä), joten jouduin tyytymään digitaaliseen toimintaan (pinni P16 on vain digitaalinen), ja tämä rajoitti hieman RGB-ledin käyttöä. Ohjelma toimii niin, että pienillä potentiometrin arvoilla ledi näyttää punaista, keskivälillä vihreä ja suurilla arvoilla sinistä valoa.

Tässä koodi:

#include "MicroBit.h"

MicroBit uBit;

int main()
{
    uBit.init();
    
    while(1){
    int sensorvalue = uBit.io.P0.getAnalogValue();
    uBit.display.scrollAsync(sensorvalue);
    if(sensorvalue <= 340){
        uBit.io.P1.setDigitalValue(1);
        uBit.io.P2.setDigitalValue(0);
        uBit.io.P16.setDigitalValue(0);
        } else if(sensorvalue > 340 && sensorvalue <=680){
            uBit.io.P1.setDigitalValue(0);
            uBit.io.P2.setDigitalValue(1);  
            uBit.io.P16.setDigitalValue(0);
            } else {
                uBit.io.P1.setDigitalValue(0);
                uBit.io.P2.setDigitalValue(0);   
                uBit.io.P16.setDigitalValue(1);
                }
        }
}

RGB-ledi punainen

RGB-ledi vihreä

RGB-ledi sininen

Breakout board on kyllä kätevä verrattuna hauenleukoihin mutta varsinaisesti sitä tarvitsee vasta sitten kun GPIO-pinnejä tarvitaan enemmän kuin kolme. micro:bit:in pinnien käyttö on hieman sekavampaa kuin Arduinossa mutta tämän kuvan ja taulukon avulla siitäkin saa tolkkua.

PS: Ja sen summerin saa soimaan JS Blocks micro:bit:in avulla 440Hz:n taajuudella tällä koodilla (ääni on niin hiljainen, että mikään varashälytin tämä ei ole :-)):


keskiviikko 28. helmikuuta 2018

Lisää micro:bit:in ohjelmointia C++:lla mbed:in kautta

Jatkoin tänään tutustumista micro:bit:in ohjelmointiin C++:lla. Nyt kokeilulistalla oli ulkoiset GPIO-pinnit. micro:bit:in leveät pinnit P0, P1 ja P2 ovat yleispinnejä, eli ne voivat toimia sekä digitaali- että analogiapinneinä niin input kuin output -moodeissa ja pinnin toimintamoodia voi jopa vaihtaa lennossa! Tein tallaisen perinteisen ledin himmentimen, jossa valovastukselta luettu analoginen arvo (0-1024) syötetään sellaisenaan ledille. Kun valon määrä kasvaa, ledi himmenee.

Valovastus ja ledi kytkettynä micro:bit:iin koekytkentälevyn avulla
Koodi on lyhyt:

#include "MicroBit.h"

MicroBit uBit;

int main()
{
    uBit.init();
    
    while(1){
    int valo = uBit.io.P1.getAnalogValue();    
    uBit.io.P0.setAnalogValue(valo);          
    uBit.display.scrollAsync(valo);
    uBit.sleep(10);
    }
}

Valosensorin antamaa arvoa oli kätevä tutkia tulostamalla se ledinäytölle (uBit.display.scroll), mutta tämä aiheutti ohjelmaan hitautta, koska säie jäi odottamaan metodin paluuta. Pienen tutkimisen jälkeen löysin asynkronisen scroll-metodin, joka palaa heti ja jää suorittamaan scrollausta taustalla (uBit.display.scrollAsync). Näin sen homman pitää toimia :-)

Toinen kokeilu liittyi ledin vilkutteluun digitaalimoodissa (on/off) ja kuvioiden tulostamiseen ledinäytölle. A-nappia painamalla ledi alkaa vilkkumaan päälle ja pois sekunnin välein, B-napista tulostuu risti keskelle näyttöä, ja P1-pinnin yhdistäminen GND:n kanssa saa aikaan ristikuvion liikkumisen ledinäytön vasemmasta yläkulmasta oikeaan alakulmaan.

Kuvan saaminen ledinäytölle vaikuttaa helpolta, MicroBitImage-objekti luodaan antamalla ledien valaistusarvot (0-255) merkkijonona vaakariveittäin pilkulla erotettuna (rivin loppussa rivinvaihto \n).

Ledin vilkuttelua ja ristin liikuttelua näytöllä

#include "MicroBit.h"


MicroBit uBit;
MicroBitImage cross("0,255,0\n255,255,255\n0,255,0\n");

void printCross(int x, int y){
        MicroBitImage image(5,5);
        image.paste(cross, x, y);
        uBit.display.print(image);
}

void onButton(MicroBitEvent e)
{
    if (e.source == MICROBIT_ID_BUTTON_A){
       for(int i=0; i<3; i++){
            uBit.io.P0.setDigitalValue(1);
            uBit.sleep(1000);
            uBit.io.P0.setDigitalValue(0);
            uBit.sleep(1000);
            }
        }

    if (e.source == MICROBIT_ID_BUTTON_B)
        printCross(1, 1);

    if (e.source == MICROBIT_ID_IO_P1){
        for(int i=0; i<3; i++){
            printCross(i, i);
            uBit.sleep(1000);
        }
    }
}

int main()
{
    uBit.init();

    uBit.messageBus.listen(MICROBIT_ID_BUTTON_A, MICROBIT_EVT_ANY, onButton);
    uBit.messageBus.listen(MICROBIT_ID_BUTTON_B, MICROBIT_EVT_ANY, onButton);
    uBit.messageBus.listen(MICROBIT_ID_IO_P1, MICROBIT_EVT_ANY, onButton);
    uBit.io.P1.isTouched();
     
    while (1)
        uBit.sleep(10000);
}  

Ainakin näiden kokeilujen perusteella dokumentaatio on selkeää ja koodin saa toimimaan vaivattomasti. Mainio systeemi tämä mbed micro:bit! 

Ainoa ihmettelyn aihe tänään on se, miksi micro:bit tekee kaiken kolmeen kertaan (teksti skrollaa ruudulla kolme kertaa, ledit vilkkuvat kolme kertaa enemmän kuin koodin mukaan pitäisi). Ehkä tällekin löytyy vielä jokin selitys :-)  

micro:bit:in ohjelmointia C++:lla mbed:in kautta

BBC micro:bit:in ohjelmointi onnistuu monella eri välineellä: graafisesti JS Blocks:in kautta tai Micropython:illa. Näissä on kuitenkin omat rajoitteensa. Jos haluaa päästä katsomaan mitä konepellin alle on piilotettu, kannattaa tarttua kiinni hieman alemman tason rajapintaan ja ohjelmoida suoraan käyttäen microbit-dal:ia (Device Abstraction Layer). Se onnistuu näppärästi nettiselaimessa toimivan mbed - ympäristön avulla. mbed vaatii kirjautumisen ja sen jälkeen voit jo aloittaa lataamalla demokoodeja. Kääntäminen ja hex-tiedoston siirtäminen micro:bit:iin toimii samalla tavalla kuin muissakin selainpohjaisissa ympäristöissä: hex - tiedosto siirretään ladatuista tiedostoista USB-portissa näkyvälle micro:bit-levylle.

mbed-ohjelmointiympäristö toimii nettiselaimessa (tarvittavat microbit-kirjastot latautuivat siihen itsestään)
Yksinkertaisin esimerkki on Hello World, joka saa tekstin skrollaamaan micro:bitin näytöllä:

#include "MicroBit.h"
MicroBit uBit;

int main()
{
    uBit.init();
    uBit.display.scroll("Hello World!");
    release_fiber();
}

Huomattavaa koodissa on se, että Microbit-objektin instanssi (uBit) pitää luoda ennen main():iä, jotta se on globaalimuuttuja. Main:in sisällä se ensin alustetaan init-metodilla ja sen jälkeen sitä käytetään ledimatriisin (display) ohjaamiseen. fiber tarkoittanee lähinnä säiettä, joka lopuksi vapautetaan. 

Tässä esimerkissä reagoidaan nappeihin A, B sekä P0-pinnin kosketukseen GND:n kanssa (laita jotakin sähköäjohtavaa P0:n ja GND:n väliin).

#include "MicroBit.h"
MicroBit uBit;

void onButton(MicroBitEvent e)
{
    if (e.source == MICROBIT_ID_BUTTON_A)
        uBit.display.printChar('A');

    if (e.source == MICROBIT_ID_BUTTON_B)
        uBit.display.printChar('B');

    if (e.source == MICROBIT_ID_IO_P0)
        uBit.display.printChar('0');
}

int main()
{
    uBit.init();
    uBit.messageBus.listen(MICROBIT_ID_BUTTON_A, MICROBIT_EVT_ANY, onButton);
    uBit.messageBus.listen(MICROBIT_ID_BUTTON_B, MICROBIT_EVT_ANY, onButton);
    uBit.messageBus.listen(MICROBIT_ID_IO_P0, MICROBIT_EVT_ANY, onButton);
    uBit.io.P0.isTouched();

    while (1)
        uBit.sleep(10000);
}

Tässä esimerkissä käytetään erilaisia eventtejä. Jotta ohjelma saa ne, niiden kuunteluun pitää ensin rekisteröityä messageBus.listen - metodilla. Samalla kerrotaan eventhandler-funktion nimi (onButton). Ennen kun koodi laitetaan odottamaan eventtejä (sleep) alustetaan P0 - pinni toimimaan "on/off" moodissa eli reagoimaan kosketukseen kuin painonappi.  Eventhandler-funktiossa tutkitaan eventin tyyppiä ehtolauseiden avulla ja näytetään eri merkkejä näytöllä. 

Sormi johtaa sen verran sähköä, että P0-pinni yhdistyy GND:hen ja syntyy virtapiiri
 Dokumentti tämän kirjaston käyttöön löytyy täältä. Vaikka itse en ole graafisten ympäristöjen ystävä, oppilaiden kanssa niistä on aloitettava. Jää nähtäväksi kuinka monelle se jää yläkoulun aikana liian pieneksi pääsemme kiinni C++:aan...   

tiistai 20. helmikuuta 2018

Ohjelmoinnin valinnaiskurssi: Arduino-ohjelmointia (osa 3)

Jatkoimme sensoreihin tutustumista tekemällä kytkennän Project 7: Temperature Alarm. Tässä lämpötilasensorin antama jännitearvo muunnetaan ensin celsiusasteiksi, jota sitten käytetään ehtolauseessa. Ledin tilalle otetaan summeri, joka laitetaan soimaan kun lämpötila nousee riittävän korkeaksi. Rakensimme kytkennän tämän ohjeen mukaisesti:

Project 7: Temperature Alarm
image source: http://image.dfrobot.com/image//Blog/
Tätäkin kytkentää lähdimme tutkimaan sensori edellä, eli katsoimme ensin sarjamonitorin avulla, millaisia arvoja lämpötilasensori syöttää meille.

int SUMMERI = 8;
int SENSORI = 0;
int arvo = 0;

void setup() {
    pinMode(SUMMERI, OUTPUT);        
    Serial.begin(9600);        
}

void loop() {
    arvo = analogRead(SENSORI);  
    Serial.println(arvo);              
}

Lämpötilan sensorin raaka-arvot liikkuivat 50 (huoneen lämpötila) ja 60 välillä (uloshengitys). 
LM-35 lämpötilasensori on toimii lineaarisesti, eli kun lämpötila kasvaa asteella, sensorin jännite kasvaa 10mV. Sen yhtälö on siis:

Vout = 10mV/°C * T    (LM35 datasheet)

Koska käytämme 5.0V jännitettä ja analogRead muuntaa jännitearvot kokonaisluvuiksi välille 0-1024, sensorin antama raaka-arvo (x) voidaan muuttaa celsiusasteiksi seuraavan kaavan avulla:

T(x) = (5.0 * x * 100.0) / 1024   (Arduino Playground)

Seuraavaksi teimme apufunktion (arvoLampotilaksi), joka muuttaa raaka-arvon lämpötilaksi.

int SUMMERI = 8;
int SENSORI = 0;
int arvo = 0;
double lampotila = 0;

void setup() {
    pinMode(SUMMERI, OUTPUT);        
    Serial.begin(9600);        
}

double arvoLampotilaksi(int x){
  double temp = 0;
  temp = (5.0*x*100)/1024;
  return temp;
}

void loop() {
    arvo = analogRead(SENSORI);  
    lampotila = arvoLampotilaksi(arvo);
    Serial.println(lampotila);
}

Seuraavaksi otimme käytöön ehtolauseen ja summerin. Jos lämpötila nousee riittävän suureksi, summeri alkaa soida.

int SUMMERI = 8;
int SENSORI = 0;
int arvo = 0;
double lampotila = 0;

void setup() {
    pinMode(SUMMERI, OUTPUT);        
    Serial.begin(9600);        
}

double arvoLampotilaksi(int x){
  double temp = 0;
  temp = (5.0*x*100)/1024;
  return temp;
}

void loop() {
    arvo = analogRead(SENSORI);  
    lampotila = arvoLampotilaksi(arvo);
    Serial.println(lampotila);

    if(lampotila > 27){
      tone(SUMMERI, 2000);
      delay(2); 
    } else {
      noTone(SUMMERI);
    }
}

Summerin ääni ei järin korvia huumaa, joten kokeilimme myös mallikoodin mukaista hienompaa hälyytysääntä. Tosin tämän koodaaminen olikin jo hieman haastavampaa monelle ja koodin aukiselittäminenkin jäi tasolla "summerin sisääntuloa vaihdellaan for-loopin avulla"...

int SUMMERI = 8;
int SENSORI = 0;
int arvo = 0;
double lampotila = 0;
float sinVal = 0;
int toneVal = 0;

void setup() {
    pinMode(SUMMERI, OUTPUT);        
    Serial.begin(9600);        
}

double arvoLampotilaksi(int x){
  double temp = 0;
  temp = (5.0*x*100)/1024;
  return temp;
}

void loop() {
    arvo = analogRead(SENSORI);  
    lampotila = arvoLampotilaksi(arvo);
    Serial.println(lampotila);

    if(lampotila > 27){
      for(int x = 0; x < 180; x++){
            sinVal = (sin(x*(3.1412/180)));
            toneVal = 2000+(int(sinVal*1000));
            tone(SUMMERI, toneVal);
            delay(2); 
     }   
    } else {
      noTone(SUMMERI);
    }
}
Temperature Alarm - kytkentä näyttää tältä

NOTE: Tämän projektin kanssa hämmennystä aiheutti summerin + merkki, joka näytti olevan väärällä puolella summeria ja tästä johtui se, että alkuun ääntä ei tullut lainkaan.