Iniziare con il Raspberry Pi (parte 3)

Raspberry-Pi-logo

Introduzione

Benvenuti alla terza e ultima parte dell’articolo. Per chi non avesse letto ancora la prima e la seconda parte, potete raggiungerla attraverso questo link:

In questa sezione tratteremo i seguenti argomenti:

  • Usare un circuito
  • Programmare in Python
  • Serie di esempi 
  • Tips’n’tricks

Aggiornamento 2017: L’ultimo modello di Raspberry Pi attualmente in commercio è il Raspberry Pi 3, con il nuovo alimentatore da 5V 2,5A. Comunque è disponibile anche un kit ufficiale che comprende già la scheda con tutti gli accessori necessari (vedi qui).

Il circuito

Il circuito che useremo per la prima prova sarà composto semplicemente da un LED di bassa potenza e la sua resistenza. Utilizzeremo il pin di 3,3V del pettine per l’alimentazione e un GPIO del Raspberry Pi per chiudere il circuito a massa.
Niente vieta di fare l’opposto, cioè di usare il GPIO per fornire l’alimentazione e il pin 0V del pettine per la massa. Nel mio caso ho scelto la prima opzione perchè uso un LED RGB ad anodo (positivo) comune.

raspberry_circuit2

Fig.1: circuito realizzato con FidoCadJ

La resistenza R1 si calcola con la formula:

R1=\frac{3.3-Vled}{Iled}

Questa formula non è altro che la Legge di Ohm[+] con la tensione ai capi della resistenza calcolata come la tensione d’alimentazione (3,3 V) a cui viene sottratta la caduta di tensione del LED.
Se ad esempio abbiamo un LED la cui c.d.t. è 1,6V e vogliamo che la sua corrente sia di 8mA, calcoleremo la resistenza in questo modo:

R1=\frac{3.3V-1.6V}{0.008A}\approx 213\Omega

Che diventa 220Ω se consideriamo i valori commerciali [+].
Se non avete a disposizione il valore della tensione di caduta del led, potete facilmente trovarlo con un multimetro (tester).

raspberry-circuit-2

Se usate tensioni più grandi per il test (ad esempio 12V) la resistenza deve anch’essa essere più grande (almeno 2kΩ).

Se non conoscete la corrente con cui deve essere alimentato il LED, generalmente 4-8mA vanno bene. Se non volete correre rischi, usate una resistenza da 1kΩ e se il LED non si accende, provate a scendere a 470Ω. Ovviamente primaverificate che il LED sia collegato nel verso giusto (il piedino più corto verso massa e quello più lungo verso il positivo).

Il secondo circuito che realizziamo serve per testare gli ingressi del Raspi ed è composto solo da un pulsante. Questo circuito lo useremo anche insieme al primo per vedere come usare input e output del Raspi contemporaneamente.

raspberry-circuit-3

Rpd è la resistenza di pull-down, che serve a dare un segnale logico di riferimento al GPIO. Se questa fosse assente quando SW1 è aperto, il GPIO sarebbe a tutti gli effetti scollegato dal circuito, cioè non avrebbe nè un riferimento positivo nè uno negativo e quindi potrebbe arrivare a “inventarsi” lo stato dell’ingresso dandoci delle false letture. La resistenza Rpd fa in modo che quando il pulsante è aperto il GPIO sia collegato verso massa, lasciandogli quindi sempre un segnale logico ben preciso.
Nello schema il ramo di Rpd è tratteggiato perchè useremo le resistenze interne al BCM2835. Comunque le resistenze di pull-down e pull-up si incontrano in molti circuiti elettronici digitali ed è importante capire il loro funzionamento. Un esperimento interessante è provare la lettura degli ingressi senza resistenze di pull-up/pull-down e vedere come in effetti il minimo disturbo elettrico causa delle false letture nel programma.

Python

Eccoci arrivati al punto in cui impariamo a comandare le uscite. Python integra già una libreria chiamata RPi.GPIO che permette di comandare le uscite e leggere gli ingressi.

L’interpreter

Vediamo subito come accendere il LED del primo circuito. Lanciamo python con il comando

sudo python

sudo è necessario per permettere all’interpreter di accedere al controllo dei GPIO.
A questo punto possiamo dare i comandi direttamente all’interpreter python.

raspberry_pythonpng

Fig.2: L’interpreter di python

I comandi che eseguiamo sono:

import RPi.GPIO as gpio
gpio.setmode(gpio.BCM)
gpio.setup(3, gpio.OUT, initial=1)
gpio.output(3, 0)
gpio.output(3, 1)
gpio.cleanup()
exit()

Ed ecco a cosa servono:
import RPi.GPIO as gpio dice a python di caricare la libreria RPi.GPIO che serve per gestire i pin del BCM2835 e che da qui in poi ci riferiremo alla libreria semplicemente con gpio.
gpio.setmode(gpio.BCM) chiama la funzione setmode della libreria, e specifica che nel corso del programma i GPIO verranno selezionati con il numero di pinout del microprocessore (modo BCM) anzichè con il numero del pin del pettine (modo BOARD). La scelta del metodo va a gusti personali e la differenza sta nel fatto che se scrivete programmi complessi e li caricate su revisioni diverse del Raspberry Pi, col metodo BCM dovete cambiare il numero del pin collegato secondo le specifiche di ogni revisione, mentre col metodo BOARD il programma funzionerà indipendentemente dalle connessioni del microprocessore[+].
gpio.setup(3, gpio.OUT, initial=1) configura il pin chiamato GPIO3 (vedi schema nella sezione Hardware dell’articolo) come uscita e setta lo stato della porta a livello logico alto (3,3V). In questo modo il LED rimane spento.
gpio.output(3, 0) cambia lo stato del GPIO3 portandolo a livello logico basso, che elettricamente corrisponde a 0V. A questo punto, se il circuito è stato fatto correttamente, il LED si accende.
gpio.output(3, 1) riporta lo stato del GPIO3 ad alto (3,3V). Il LED si spegne.
gpio.cleanup() cancella tutte le configurazioni che abbiamo fatto e riporta tutti i GPIO che abbiamo utilizzato ai valori di default.
exit() chiude l’interpreter. Al suo posto si può anche usare Ctrl+D.

Il comando gpio.output ha come argomenti canale e stato, dove stato può essere 1 o 0 ma anche True o False.

raspberry_pettine

Fig.3: Il pettine femmina ha un’aria abbastanza casalinga

Adesso proviamo anche il secondo circuito per verificare il funzionamento degli ingressi.

raspberry_python

Fig.4: The Rising Of The GPIO, al cinema

I comandi iniziali e finali sono gli stessi, mentre cambiano nella fase di lettura:

import RPi.GPIO as gpio
gpio.setmode(gpio.BCM)
gpio.setup(4, gpio.IN, pull_up_down=gpio.PUD_DOWN)
gpio.wait_for_edge(4, gpio.RISING)
gpio.cleanup()
exit()

In breve:
import RPi.GPIO as gpio e gpio.setmode(gpio.BCM) li abbiamo già visti nell’esempio sopra.
gpio.setup(4, gpio.IN, pull_up_down=gpio.PUD_DOWN) specifica che il GPIO4 deve essere configurato come ingresso e deve essere attivata la sua resistenza di pull-down.
gpio.wait_for_edge(4, gpio.RISING) mette in attesa l’interpreter e aspetta che il GPIO4 cambi stato logico, e passi da basso ad alto (RISING). Questo è il momento giusto per premere il pulsante SW1.
gpio.cleanup() e exit() chiudono il programma come nell’esempio precedente.

Durante il setup del gpio si può scegliere se usare la resistenza di pull-up, pull-down o nessuna delle due. pull_up_downpuò essere gpio.PUD_DOWN per la resistenza di pull-down o gpio.PUD_UP per la resistenza di pull-up. Per disattivare le resistenze interne si può omettere questa parte di comando, chiudendo la parentesi subito dopo gpio.IN
gpio.wait_for_edge può essere configurato per aspettare il fronte di salita (gpio.RISING), di discesa (gpio.FALLING) o entrambi (gpio.BOTH).

Per altri metodi di lettura degli ingressi leggete qui.
Ricordate che se avete dei problemi di lettura e non riuscite a passare il comando gpio.wait_for_edge potete interrompere l’esecuzione dell’interpreter con la shortcut Ctrl+D.

Il mio primo programma

Adesso che abbiamo cominciato a mettere le mani in pasta è ora di passare a qualcosa di più gustoso. Cominceremo con lo scrivere un semplice programma per accendere il LED alla pressione di SW1.

Prima di tutto ci serve un editor per scrivere il nostro programma. Il comando nano (preinstallato su Raspbian) lancia un editor grafico semplice ed intuitivo. Oggi useremo questo editor, ma se siete programmatori professionisti probabilmente apprezzerete l’editor vim. Anche se è davvero poco intuitivo, è estremamente configurabile e di solito una volta imparato ad usare non lo si lascia più.

Ma vediamo brevemente l’editor nano. Digitiamo il comando

nano

e premiamo [INVIO]. Ci apparirà una schermata vuota con un menu in basso.

raspberry_menu2

Fig.5: Una parte del menu

Il simbolo ^ indica che insieme alla lettera che lo segue deve essere premuto Ctrl. Quindi per uscire (e per salvare) dobbiamo usare la combinazione Ctrl+X.

Usciamo da nano e creiamo il file che conterrà il nostro programma, che chiameremo, in questo esempio, primo.py (dove py è l’estensione di un file python)

touch primo.py

ed apriamolo subito con nano

nano primo.py

Il programma in python possiamo pensarlo come la lista dei comandi che poco fa stavamo dando direttamente all’interpreter. E in effetti troviamo parte dei comandi che abbiamo già usato.
Per scrivere il programma inizieremo caricando le librerie necessarie (che saranno RPi.GPIO e time per la funzione di attesa), configureremo i due GPIO che usiamo nel circuito e faremo partire un ciclo infinito che altro non fa che leggere lo stato dell’ingresso e cambiare l’uscita di conseguenza.
Una cosa del genere può già funzionare:

La primissima riga è un commento speciale e serve a lanciare lo script da terminale. È un modo per spiegare al terminale che lo script deve essere interpretato con il programma che si trova in /usr/bin/python, che è poi il solito interpreter.
Nella fase di inizializzazione dei GPIO è apparso un nuovo comando: gpio.setwarnings. È possibile avere più script in funzione contemporaneamente e se python rileva che un pin che stiamo per configurare non si trova nello stato di default (input) ci avverte che potrebbe esserci un conflitto tra programmi. Disattiviamo gli avvisi mettendo tra parentesiFalse oppure attiviamoli scrivendo True.
Il comando print scrive a terminale il contenuto della parentesi e in questo caso ha la sola funzione di darci un feedback quando il programma ha terminato la fase di inizializzazione.
Il while segna l’inizio di un ciclo, che termina quando la sua condizione diventa falsa. In questo caso il ciclo che vogliamo è infinito e quindi la condizione 1 (che viene interpretata come 1=1) è sempre vera.
Dentro al ciclo while è piazzato un if…else che testa l’ingresso GPIO4. Se l’ingresso risulta vero, quindi alto, quindi pulsante premuto, viene spenta l’uscita GPIO3, accendendo il LED. Altrimenti l’uscita viene portata a livello alto, spegnendo il LED.
In coda al programma ho aggiunto la funzione sleep che blocca l’esecuzione dello script per 50ms, per permettere alla CPU di occuparsi di altri processi.

Da notare che la sintassi di python è estremamente semplice. Non ci sono punti e virgola, non ci sono comandi per chiudere il ciclo while o il test if. In questo linguaggio l’inizio e la fine dei comandi sono determinati dall’indentazione. Se la funzione time.sleep fosse stata scritta nella stessa colonna del while, python avrebbe interpretato quell’istruzione come fuori dal ciclo.

Una volta finito di scrivere lo script, premiamo Ctrl+X e successivamente Y per confermare il salvataggio delle modifiche. Ci verrà chiesta conferma anche per il nome del file, premiamo [INVIO] e nano uscirà ripresentandoci il terminale.

A questo punto non ci rimane che rendere lo script eseguibile con

chmod u+x primo.py

e lanciarlo con

sudo python primo.py

oppure con

sudo ./primo.py

Quando siamo soddisfatti della prova premiamo Ctrl+C per interrompere l’esecuzione dello script.

raspberry_python3

Fig.6: python mostra l’evento che ha causato il blocco dello script (KeyboardInterrupt)

Altri esempi

SPEGNIMENTO RITARDATO
Questo programma, molto simile al primo, aspetta che venga premuto il tasto per accendere e tenere acceso il LED per due secondi.

LAMPEGGIO CONTROLLATO COL PULSANTE (CON ANTIRIMBALZO)
In quest’altro esempio invece, facciamo lampeggiare un LED ogni 0.5s quando viene premuto il tasto e fermiamo il lampeggio quando viene ripremuto il tasto. Questo script usa gli interrupt e un controllo antirimbalzo per il pulsante.

Questo script non è così complicato come sembra: dopo le solite operazioni di inizializzazione viene dichiarata la variabile lampeggio che tiene in memoria se abbiamo attivato o disattivato il lampeggio. All’inizio il lampeggio è disattivato.
Dopo la variabile troviamo la funzione cambia_stato. Questa parte di codice viene chiamata ogni volta che il pulsante viene premuto e inverte lo stato della variabile lampeggio oltre a spegnere o accendere il LED a seconda delle condizioni.
La dichiarazione global lampeggio è necessaria per permettere alla funzione di modificare il valore della variabile lampeggio, che altrimenti sarebbe utilizzabile in sola lettura.
Qualche riga più in basso troviamo la dichiarazione dell’interrupt. Gli interrupt permettono di interrompere il programma principale (la parte dentro il while) ed eseguire dell’altro codice (in questo caso la funzione cambia_stato) per poi riprendere il programma principale da dove era stato interrotto.
La dichiarazione add_event_detect ha come argomenti il GPIO su cui effettuare il test (GPIO4), la condizione di rilevamento (gpio.RISING ossia il fronte di salita), la funzione da chiamare (cambia_stato) e il bouncetime (opzionale).
Il bouncetime si usa quando si lavora con i pulsanti meccanici ed è un piccolo timer (in questo caso di 200ms) che sopprime il rimbalzo del tasto per evitare letture di più fronti di salita durante una singola pressione del pulsante.

raspberry_graph

Fig.7: Ecco cosa succede quando si chiude un contatto meccanico

Dopo la dichiarazione dell’interrupt abbiamo la sezione principale che controlla la variabile lampeggio. Se questa è vera (quindi lampeggio attivato) si controlla lo stato dell’uscita del LED (sì, si deve usare gpio.input per questa operazione!) e la si inverte.
Se la variabile lampeggio è falsa, il LED viene lasciato spento (viene spento la prima volta durante la funzionecambia_stato).
Prima di ricominciare il ciclo, il programma viene fermato mezzo secondo per permetterci di vedere il LED lampeggiare.

Questi programmi non hanno in fondo la funzione gpio.cleanup() perchè è previsto che vengano interrotti da tastiera. Se scrivete un programma che invece prevede una fine, è sempre bene inserire questo comando.

C’È POSTA PER TE
(con un LED al posto di Maria De Filippi)
Questo programmino è solo per gli account Gmail e utilizza il modulo feedparser di python per controllare il numero di email non lette nella propria casella di posta.
Siccome dovete mettere dentro username e password, occhio a non copiare il programma in posti poco sicuri… tipo internet insomma.

Per prima cosa dobbiamo scaricare la libreria feedparser che di default non è installata. Andiamo sulla pagina del modulo, che potete trovare qui, e scarichiamo il file .tar.bz2. Però non scaricatevelo sul vostro pc che poi Windows piange perchè non sa cos’è un file tar, scaricatelo direttamente sul Raspberry Pi.

wget link

dove link va ovviamente sostituito con il link al file tar.bz2.
Una volta che wget finisce di scaricare il file, scompattiamolo con

tar -xf nome_del_file

(ricordo la funzione autocomplete: scrivete le prime lettere del file e premete due volte TAB).
A questo punto se invocate ls troverete una nuova cartella con lo stesso nome del file che avete scaricato. Spostatevici dentro (con cd) ed eseguite il comando

sudo python setup.py install

In pochi secondi avrete installato il nuovo modulo.

Mentre eseguivo queste operazioni, ho lanciato il setup del modulo e python mi ha risposto che gli mancava la libreria setuptools. Se vi succede lo stesso, ripetete il procedimento qui sopra con il file scaricabile da qui e una volta installato, riprendete l’installazione di feedparser.

Adesso vediamo il codice:

Oltre le solite cose (importazione delle librerie, setup dei GPIO) troviamo tre variabili configurabili da utente: username,password e mail_check_freq. I primi due servono ad autenticare l’utente con i dati di accesso di Gmail, mentre il terzo stabilisce ogni quanti secondi deve essere controllata la casella di posta.
Dentro al ciclo, la prima funzione che utilizza feedparser estrae il numero di email non lette dal feed RSS di Google e lo carica nella variabile newmail.
La variabile newmail viene controllata e se equivale a zero (che equivale a False, ecco perchè si usa un controllo di tipo booleano) viene spento il LED, altrimenti viene acceso.
Dopodichè lo script viene messo in pausa per il tempo stabilito dalla variabile mail_check_freq.
Il difficile in questo script è estrapolare dal feed il numero di email non lette. Per approfondimenti su come funziona feedparser cliccate qui.

Tips ‘n’ Tricks – parte 2

NON-ASCII CHARACTER
Alcune volte può capitare che copiando e incollando un testo di uno script finiscano in mezzo al file che andate a salvare dei caratteri che non vengono riconosciuti. Se succede, lanciando il programma vi verrà risposto no encoding declared.
Per ovviare al problema specifichiamo a python il tipo di encoding del testo (utf8 va benissimo) inserendo all’inizio del programma (ma comunque sotto al commento speciale #!) la riga

# coding: utf8

raspberry_python4

Fig.8: “Ma cos’è poi questo \xc3?”

RICONOSCIMENTO DELLA SINTASSI PYTHON CON NANO
Nano è tutto brutto e grigio di default, ma fortunatamente possiamo evidenziare la sintassi di alcuni linguaggi. Per sapere quali basta guardare dentro la cartella /usr/share/nano (sempre con il buon ls) e troveremo anche il file python.nanorc.
Per attivare il riconoscimento della sintassi dobbiamo creare il file nascosto .nanorc nella home e inserire il comandoinclude seguito dalla posizione del file che ci interessa.
Se vogliamo esagerare e fare tutto in un unico comando (assicuratevi di essere in home):

echo "include /usr/share/nano/python.nanorc" > .nanorc

Al prossimo riavvio di nano, vi troverete più o meno così

raspberry_python-5

Fig.9: Magic, you can’t explain that.

LANCIARE UNO SCRIPT ALL’AVVIO
E se volessimo far partire un programma non appena il Raspberry Pi viene acceso? Niente di più semplice! Assicuratevi che il vostro programma sia eseguibile (verificate con ls -l che il file sia contrassegnato con la x nella prima terna) e segnatevi il suo percorso (assoluto).
Se avete dubbi a proposito del percorso, il comando

pwd

vi restituirà il percorso assoluto della cartella in cui è contenuto lo script.
A questo punto, editiamo il file /etc/rc.local che è quella lista di comandi da eseguire all’avvio.

sudo nano /etc/rc.local

Ci troveremo dentro un sacco di commenti, una piccola funzione che ricava l’IP del Raspberry Pi e il comando exit 0. Inseriamo il percorso dello script che vogliamo lanciare preceduto da sudo tra la funzione già presente (che volendo possiamo anche togliere) e il comando exit 0 (che invece è importante e va lasciato in fondo al file).
Salvate e riavviate (sudo reboot), il programma partirà automaticamente.

raspberry_python-6

Fig.10: Editing con vim. La scelta del blu per i commenti non è stata una gran mossa

Se avete problemi all’avvio e lo script non vuole saperne di partire, potete provare a inserire il comando python tra sudoed il percorso dello script.

SERVER FTP
Se amate alla follia il vostro editor che avete sul pc e non ne volete sapere di usare nano o vim, questo è un metodo per mandare il file che avete già preparato sul vostro pc al Rasperry Pi per poi lanciarlo da terminale.
Il server FTP si installa velocemente con

sudo aptitude install ftpd

Dopo un minuto circa, il server sarà già pronto e configurato, verifichiamo che stia funzionando con il comando

netstat -lt

che ci mostra quali porte sono aperte. Se tutto è andato come previsto, troveremo che ci sono servizi in ascolto sulla porta 21 (ftp) e 22 (ssh).
A questo punto scarichiamo un FTP client, come può essere FileZilla, inseriamo utente e password del Raspberry Pi (specifichiamo la porta solo se è diversa dalla 21) e colleghiamoci cliccando su “Quickconnect“.
Adesso possiamo navigare tra le cartelle del Raspi comodamente e scambiare i file velocemente.

raspberry_editor

Fig.11: Spero che il vostro editor di fiducia non sia Blocco Note

LOGIN SENZA PASSWORD
(solo Linux)
Come dicevo qualche centinaio di righe fa, il protocollo SSH utilizza un tipo di autenticazione a chiave pubblica, che significa, tra le altre cose, che se abbiamo una coppia di chiavi (pubblica e privata) possiamo accedere al Raspi usando la nostra chiave privata.
Non starò a spiegare come funziona l’autenticazione, ma se siete interessati (e sarebbe bello che lo foste) ci sono già migliaia di articoli sparsi per internet che aspettano solo di essere trovati da una ricerca di Google.
Se ancora non avete una coppia di chiavi, generatela (sul vostro pc, non sul Raspberry Pi!) con il comando

ssh-keygen -t rsa

Salvate la chiave con il percorso di default e, quando vi viene chiesto, lasciate in bianco i campi Passphrase, altrimenti vi verrà chiesta la password che immettete, rendendo tutta l’operazione di fatto inutile.
Una volta terminata l’operazione, carichiamo la chiave pubblica sul Raspi lanciando (sempre dal pc) il comando:

ssh-copy-id -i ~/.ssh/id_rsa.pub pi@indirizzoip

Vi verrà chiesta la password dell’utente pi, per essere sicuri che la copia della chiave pubblica viene effettuata da un utente che ha già l’accesso al Raspberry Pi.
Finito questo passaggio proviamo a loggarci con il comando

ssh pi@indirizzoip

e se tutto è andato bene, entriamo direttamente.

raspberry_python-7

Fig.12: “Ai miei tempi qui era tutta campagna”

Conclusioni

Abbiamo esplorato un po’ di python e buttato le basi per lavorare con i GPIO. L’articolo è venuto lunghissimo ma spero di aver soddisfatto le necessità dei neofiti e di aver solleticato la curiosità di chi scopre per la prima volta il Raspberry Pi.
Ci sono tantissime altre cose che avrei voluto inserire, tante funzioni che sto provando con altrettanti programmi ma che purtroppo non posso scrivere qui per una questione di spazi.
Spero di avere a breve abbastanza materiale per mettere insieme un nuovo articolo di esempi pratici e vedere come sfruttare al meglio le capacità di questo piccolo computer.
La cosa che mi preme e che spero sia passata è che il Raspberry Pi ha delle potenzialità incredibili, è davvero facile da usare e si trovano migliaia di progetti su internet da cui prendere spunto.

Ho fatto del mio meglio per documentare tutto ciò che ho scritto, ma se trovate delle imprecisioni vi prego di lasciare un commento e farò in modo di aggiustare l’articolo.

Jon

Born in the '90s, I’m currently working as a sysadmin, I've been messing around with electronics since I can remember, with computers since Windows 95 and lately with huge wifi antennas. I travel whenever I can, I like red beers and I know by heart almost all Pixar's movies.

5 commenti:

  1. grazie per la guida, ma la resistenza rpd fisicamente dov’è? dove collego il cavo?

    • Ciao,
      la resistenza Rpd è fisicamente all’interno del BCM2835 e può essere abilitata durante il setup dei GPIO. Nell’esempio dell’articolo viene utilizzata su GPIO4, utilizzando questo comando:
      gpio.setup(4, gpio.IN, pull_up_down=gpio.PUD_DOWN)

  2. Salve
    sto trovando la guida passo passo, ho avuto però un problema nell’andare ad implementare il codice da riga di comando, dopo aver inserito il comando ” gpio.setup(3, gpio.OUT, initial=1)” mi restituisce l’errore visualizzabile qui sotto. A cosa può essere dovuto?

    >>> import RPi.GPIO as gpio
    >>> gpio.setmode(gpio.BCM)
    >>> gpio.setup(3, gpio.OUT, initial=1)
    Traceback (most recent call last):
    File “”, line 1, in
    RuntimeError: No access to /dev/mem. Try running as root!

    Grazie

    • Ciao, quando lanci python è importante usare il comando “sudo python”. Se non usi “sudo” l’interpreter non avrà sufficienti permessi per comunicare con l’hardware.

  3. Ciao invece di fare un ciclo infinito è possibile gestire il cambio di stato di un pin con gli aventi?
    Mi spiego meglio quando cambia lo stato di un pin vorrei far lanciare un mio scripts, in modo da non sovraccaricare la cpu.
    Grazie

Lascia un commento

Questo sito usa Akismet per ridurre lo spam. Scopri come i tuoi dati vengono elaborati.