Raspberry Pi+Arduino+I²C: I dalis

Posted: 2013-07-09 in Darbeliai
Žymos:, , , ,

Iškilo realus poreikis sujungti Arduino (ar tiesiog AVR mikrovaldiklį) su Raspberry Pi kompiuteriuku. Kompiuteriukas galėtų dirbti „sunkius“ darbus: būti už interneto serverį, rinkti ir saugoti duomenis bei perduoti konfigūruojamas reikšmes mikrovaldikliui. Mikrovaldiklis tuo tarpu dirbtų palyginti nesudėtingus darbus: pagal komandą arba pagal laikmatį nuskaitinėtų duomenis ir valdytų servovarikliukus. Mikrovaldiklis su duotomis reikšmėmis turėtų sugebėti dirbti pats, be kompiuterio įsikišimo.

Kadangi tiek Raspberry Pi, tiek AVR turi I²C sąsają, tai pagalvojau, kad ją reikia ir išnaudoti. Avietinis kompiuteriukas būtų pagrindinis mazgas (master), o mikrovaldiklis — šalutinis (slave). Gerai yra tas, kad į lenciūgėlį galima sujungti daug šalutinių mazgų, tad paliekama galimybė plėtimui.

Bandysiu šį projektą sudėlioti iš kelių dalių. Dabar pati pirmų-pirmiausioji dalis: pabandyti sujungti Avietę su Arduino.

Kaip visada, truputį sunerimau dėl logikos lygių: juk Avietė dirba su 3,3 V logika, o Arduino — su 5 V. Galima į tarpą pastatyti logikos lygių keitiklį iš dviejų tranzistorių ir kelių rezistorių, maža bėda. Bet… gūgl gūgl ir randu, kad to visai nereikia. Nesigilinant į jokias smulkmenas viskas labai paprasta: galima sujungti Avietę su Arduino be jokių keitiklių. Vienintelė būtina salyga, kad Avietė būtų pagrindiniu mazgu, o Arduino — šalutiniu. Kadangi ši tinklo topologija (toks labai jau gudrus mokslinis žargonas) man tinka, tai, aišku, kam aš tą logikos keitiklį darysiu… Juk visuose projektuose reikia laikytis paprastumo principo. Čia jau kiek patyrusio programuotojo išmintis taip sako.

Toliau viską padariau copy-paste metodu, nieko pats negalvodamas, iš štai šio tinklapio su atitinkamais pavyzdžiais. Tiems, kas nenori skaityti angliškai, aš truputuką padėsiu ir į copy-paste metodą įdėsiu kiek ir savo darbo: išversiu pagrindinius žingsnius.

Pastaba. Aš visas šitas makles dariau su Raspbian OS. Dėl kitų distribucijų nieko negaliu pasakyti ir nieko apie jas nežinau.

Pirmas punktas. Faile /etc/modprobe.d/raspi-blacklist.conf reikia užkomentuoti eilutę, kuri išjungia I²C palaikymą (parašyti priekyje ženkliuką #):

#blacklist i2c-bcm2708

Antras punktas. Į /etc/modules failą reikia įrašyti tokią eilutę (failo pabaigoje):

i2c-dev

Trečias punktas. Įdiekite diagnostinius įrankius ir reikalingas bibliotekas I²C programų kūrimui:

sudo apt-get install i2c-tools
sudo apt-get install python-smbus

Ketvirtas punktas. Jeigu naudojate vartotoją pi arba kokį nors kitą, pridėkite jį prie ką tik sukurtos i2c grupės:

sudo adduser pi i2c

Penktas punktas. Laikas perkrauti Raspberry Pi ir patikrinti, ar atsirado I²C įrenginiai. Štai iškarpa iš mano komandinės eilutės:

pi@Uoga ~ $ ls -l /dev/i2*
crw-rw---T 1 root i2c 89, 0 Rgs 11 16:05 /dev/i2c-0
crw-rw---T 1 root i2c 89, 1 Rgs 11 16:05 /dev/i2c-1

Šeštas punktas. Jei turte „B“ leidimo Raspberry Pi, paleiskite I²C magistralės patikrinimo programą. Ji turėtų grąžinti tuščių eilučių krūvą:

pi@Uoga ~/Programs/RPI_I2C_ARD $ i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --

Jei turite „A“ leidimo Avietę, tai komanda turi būti su nuliuku gale:

i2cdetect -y 0

„A“ ir „B“ Aviečių I²C magistralės skiriasi.

Septintas punktas. Laikas į Arduino įkelti programėlę, kurioje mikrovaldiklis nustatomas kaip  I²C šalutinis mazgas su adresu 04. Programėlėje šiam reikalui naudojama Wiring biblioteka. Duomenų priėmimui ir siuntimui nustatomos reikalingos funkcijos. Priimančioji funkcija nustato vieno kintamojo reikšmę į gautąją, o jei gautoji reikšmė yra lygi vienetui, tai uždega arba užgesina prie 13 elektrodo prilituotą šviesos diodą. Taip pat gautą skaičiuką nusiunčia atgal į Avietę, kaip patvirtinimą, kad „viskas gerai“. Tokia žaislinė programėlė pirmam pabandymui:

#include 
#define SLAVE_ADDRESS 0x04
int number = 0;
int state = 0;

void setup() {
    pinMode(13, OUTPUT);
    Serial.begin(9600);         // start serial for output
    // i2c antrinis mazgas
    Wire.begin(SLAVE_ADDRESS);
    // i2c duomenų apsikeitimui susietos funkcijos
    Wire.onReceive(receiveData);
    Wire.onRequest(sendData);

    Serial.println("I2C pasiruose!");
}

void loop() {
    delay(100);
}

// Duomenų priėmimo funkcija
void receiveData(int byteCount){

    while(Wire.available()) {
        number = Wire.read();
        Serial.print("Gavau skaiciuka: ");
        Serial.println(number);

        if (number == 1){

            if (state == 0){
                digitalWrite(13, HIGH); // set the LED on
                state = 1;
            }
            else{
                digitalWrite(13, LOW); // set the LED off
                state = 0;
            }
         }
     }
}

// Duomenų išsiuntimo funkcija
void sendData(){
    Wire.write(number);
}

Aštuntas punktas. Avietės pusėje panaudojau su Python parašytą programėlę, kuri į Avietę nusiunčia vartotojo įvestą skaičiuką nuo 1 iki 9. Įdomu visgi, o kaip yra su nulio siuntimu? Reikės kada vėliau išsiaiškinti.

# -*- coding: utf-8 -*-
import smbus
import time

# „A“ RPI versijai rašykite "bus = smbus.SMBus(0)"
bus = smbus.SMBus(1)

# Arduino (antrinio mazgo) adresas
address = 0x04

def writeNumber(value):
    bus.write_byte(address, value)
    return -1

def readNumber():
    number = bus.read_byte(address)
    return number

while True:
    var = input("Invesk nuo 1 iki 9: ")

    if not var:
        continue

    writeNumber(var)
    print "Avietė: į Arduino pasiųstas skaičiukas ", var

    # Sekundės pauzė (kol kas nežinau, kam)
    time.sleep(1)

    number = readNumber()
    print "Arduino: į Avietę pasiųsta atgal ", number

    print

Devintas punktas. Laideliais sujungiama Avietė ir Arduino. Reikia trijų laidelių: vienas sujungia „žemę“, kiti du — I²C elektrodus SDA ir SCL. Avietėje SDA yra trečias elektrodas (arba GPIO 0), o SCL — penktas (arba GPIO 1, čia aprašytas visas Raspberry Pi elektrodų „šabakštynas“). Arduino tuo tarpu SDA yra ketvirtasis analoginis elektrodas A4, o SCL — A5. Mano junginys atrodo va maždaug šitaip:

Raspberry Pi ir Arduino sujungti per I²C magistralę | Darau, blė

Iš arčiau Arduino lizdai:

Raspberry Pi ir Arduino sujungti per I²C magistralę | Darau, blė

O čia iš arčiau Avietės elektrodai. Matyti, kad kairėje pusėje likęs vienas elektrodas, o „žemės“ elektrodas yra šeštas, tiesiai už SCL:

Raspberry Pi ir Arduino sujungti per I²C magistralę | Darau, blė

Kai jau taip viskas sujungta, vėl paleidžiam diagnostinę programėlę ir ji turi „atrasti“ Arduino su adresu 04:

pi@Uoga ~/Programs/RPI_I2C_ARD $ i2cdetect -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- 04 -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- -- --

Visa tai rodo, kad prietaisai sujungti sėkmingai. Dabar laikas paleisti minėtąją Python programėlę ir pabandyti pasiuntinėti skaičiukus į Arduino. Arduino į per nuoseklųjį prievadą taip pat šiek tiek parašinėja, ką gauna. Didysis langas yra Raspberry Pi konsolė, o sumažintas dešinėje viršuje — Arduino nuosekliojo prievado konsolė patikrinimui:

Raspberry Pi ir Arduino, bendraujančių per I²C, konsolės | Darau, blė

Ką gi, viskas veikia. Dabar reikia išsiaiškinti ir sugalvoti, kaip šį dalyką panaudoti praktiškai, kas būna, kai magistralė pagrindiniame mazge naudojama konkurenciškai bei kaip gaudyti klaidas, jei vienas iš prietaisų netyčia nustoja veikti. Python programoje tai šitas aišku, o kaip klaidas suvaldyti Arduino kode — kol kas nežinau. Taip pat reikės dar pasiieškoti kokio nors paprasto interneto serverio, pagrįsto Python programavimu. Kol kas linkstu link Flask, bet kai tą etapą prieisiu, apie jį parašysiu atskirai. O šiandienai kol kas tiek, sujungti du prietaisu pasirodė paprasta, dabar tik reikia iš to išspausti kažkokią naudą.

Komentarai
  1. […] Man taip jau pasisekė, kad Itead savo linuxuose visus reikalus jau sutvarkiusi ir iškarto matome LCD adresu 0x27 🙂 Jei jum taip nepasisekė, gali tektu I2C sąsaja pakonfigūruoti, kaip tai darė DarauBlė čia. […]

Parašykite komentarą

Įveskite savo duomenis žemiau arba prisijunkite per socialinį tinklą:

WordPress.com Logo

Jūs komentuojate naudodamiesi savo WordPress.com paskyra. Atsijungti /  Pakeisti )

Google photo

Jūs komentuojate naudodamiesi savo Google paskyra. Atsijungti /  Pakeisti )

Twitter picture

Jūs komentuojate naudodamiesi savo Twitter paskyra. Atsijungti /  Pakeisti )

Facebook photo

Jūs komentuojate naudodamiesi savo Facebook paskyra. Atsijungti /  Pakeisti )

Connecting to %s

Brukalų kiekiui sumažinti šis tinklalapis naudoja Akismet. Sužinokite, kaip apdorojami Jūsų komentarų duomenys.