Raspberry umożliwia sterowanie systemem przez czujniki GPIO za pomocą przerwań. Przypomniało mi się, jak na ćwiczeniach z systemów komputerowych dr Kwiatkowski kazał przejmować przerwanie zegarowe 1C w DOSie i pisać pseudowirusy (bez kodu kopiującego).

Przerwania służą do odciążenia zasobów procesora. Jeśli piszemy aplikację stojącą jako serwer i sprawdzającą co jakiś czas stan czujników – przerwania są wręcz koniecznością, jeśli chcemy by nasza malinka pozostała chłodna.

Uwaga! Niewłaściwe łączenie obwodów może spowodować uszkodzenia Raspberry Pi, albo uszczerbek na zdrowiu, układy podłączacie na własną odpowiedzialność!

Przykład zastosowania: sterowanie malinką za pomocą klaśnięć (hałasu). Podłączamy czujnik hałasu (mój to Ky-038 kupiony za kilka złotych) trzema żyłami – jeden do napięcia (u mnie 5v), drugi uziemienia, trzeci to D0 – podpinamy do GPIO – u mnie to GPIO 25 (BCM GPIO 25), czyli PIN 6 dla wiringPi, ale równie dobrze może być to inny port GPIO. Wyjścia A0 nie podłączamy, gdyż Raspberry nie posiada wejścia analogowego. Na A0 jest sygnał z mikrofonu. D0 pokazuje tylko czy zadany poziom sygnału jest przekroczony (hałas), czy nie (cisza) i tylko tyle nasza malina widzi. Klaśnięcie powoduje nagły wzrost poziomu hałasu. Śrubką regulujemy na Ky-038 poziom powyżej którego jest już hałas (trzeba się sporo nakręcić, w moim przypadku wykręcać). Ky-038 posiada dwie diody, jeśli trzymamy czujnik nóżkami w dół dioda po prawej sygnalizuje napięcie, po lewej przekroczony poziom hałasu i stan wysoki na wyjściu D0, kręcimy śrubką, aż dioda z lewej nie zgaśnie ale tylko tyle, że po klaśnięciu na chwilę się zapali.

Zamiast printf można podpiąć wysłanie żądania na inny port GPIO i sterowanie np. oświetleniem za pomocą klaśnięć.

Oto kod z przerwaniem:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <wiringPi.h>
#include <stdio.h>

#define SOUNDPIN 6
extern void exit(int);

int zgloszenie=0;

void przerwanie(void)
{
        zgloszenie=1;
}

int setup()
{       //inicjacja wiringPi i  podpięcie funkcji przerwania
        if (   wiringPiSetup()==-1
            || wiringPiISR(SOUNDPIN, INT_EDGE_BOTH, &przerwanie) <0)
                exit(1);
}

int main()
{
        int licznik=0;
        setup();
        while(1)
        {
                if (zgloszenie)
                {
                         printf("Przerwanie, wywołanie nr: %i\n", ++licznik );
                         zgloszenie = 0;
                }
                delay(200); //ominięcie delay oznacza obciążenie procesora 25%, tu spada do 2%
        }
        return 0;
}

Kompilujemy z biblioteką wiringPi:

1
gcc dzwiek.c -o dzwiek -lwiringPi

Uruchamiamy jako root (przez sudo), a tu jest mniej ekonomiczny, tradycyjny kod bez użycia przerwań bardziej obciążający procesor:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <wiringPi.h>
#include <stdio.h>

#define SOUNDPIN 6
extern void exit(int);

int setup()
{
        if (wiringPiSetup()==-1) exit(1);
        pinMode( SOUNDPIN, INPUT);
}
void loop()
{
  int licznik=1,odczyt;
  while (1)
  {
         odczyt=digitalRead(SOUNDPIN);
         if (odczyt) //przelacz
         {
                printf("Sygnal: %i\n", licznik++);
                delay(100);
        }
        //delay(1);
  }
}

int main()
{
        setup();
        loop();
        return 0;
}

Głównym problemem drugiego kodu jest stałe warowanie procesora w oczekiwaniu na sygnał wysoki, w ciągu sekundy gorączkowo milion razy sprawdza stan czujnika czy aby ktoś nie klasnął. W pierwszym kodzie można spokojnie wydłużyć delay(200) na delay (2000) i procesor sprawdzi raz na dwie sekundy, czy aby w czasie tych 2sekund nie nastąpiło przerwanie (200ms jest ok, bo to 1/5 sekundy, więc reakcja jest prawie natychmiastowa). Gdyby w drugim kodzie użyć takiego delay – program nie pamiętałby, czy było klaśnięcie. Na tym polega magia przerwań i odciążania procesora. Dobrym przykładem jest klawiatura (też ma swoje przerwanie). Procesor nie musi gorączkowo sprawdzać, czy aby nie wciśnięto klawisza.