Risorse per il Lab. Elettronica
Home Page


CAD/CAE

LTspice

PSpice


Sistemi

Arduino

AVR

Raspberry Pi

National Instruments


Risorse

Datasheet

Link

Hardware e Software

Misc




Programmare il GPIO di Raspberry Pi in C (beta)







Licenza Creative Commons
Quest'opera è distribuita con Licenza Creative Commons Attribuzione - Non commerciale - Condividi allo stesso modo 3.0 Italia. E' dunque escluso l'utilizzo per scopi di lucro . Autore: Francesco Parisi, fparisi AT gmail DOT com



Ultima modifica: 09/08/2021

Il quarto programma: contare le pressioni di un pulsante


Il quarto programma, conta il numero di volte che viene premuto il pulsante e ne stampa il valore sul terminale.

• L'hardware



Come nel secondo esercizio, un pulsante normalmente aperto è collegato sul pin fisico 15, mediante un resistore di pull-down da 10kΩ, all'alimentazione 3.3V. Quando questo non è premuto, il livello logico applicato è 0. Premendolo si applica un livello logico 1 (3,3V).


Schema elettrico (fonte: http://telpar.altervista.org/)




Schema di montaggio (fonte: http://telpar.altervista.org/)



• Il software



Nella scrittura del programma, bisogna tenere conto che il pin fisico 15 corrisponde al pin virtuale 3 di WiringPi (vedi Panoramica del GPIO)

CONTA.C
#include <stdio.h>
#include <wiringPi.h>

#define BTN_PIN 	3	// Pulsante  (3 WiringPi, GPIO22, pin 15)
 
unsigned int n;  // Memorizza il numero di volte che viene premuto il pulsante

int main (void)
{
  // --- Init
  wiringPiSetup();  
  pinMode (BTN_PIN, INPUT);	// configura BTN_PIN come pin di ingresso
  
  // --- Loop
  while (1)
  {
    if (digitalRead (BTN_PIN) == HIGH)  	// bottone premuto?
       n++;	                                // incrementa il numero di n
	
    printf ("\r%d", n);
    fflush(stdout);

  }	 
 
  return 0 ;
}



 #include <stdio.h>
La direttiva al preprocessore #include <stdio.h> inserisce il file header della libreria dello standard I/O del C. Si rende necessaria perché verranno successivamente utilizzate due funzioni definite in questa libreria, la printf() e la fflush() (vedi avanti).

 // --- Init 
 pinMode (BTN_PIN, INPUT);
Con la funzione pinMode() si configura il pin al quale è collegato il pulsante (BTN_PIN), come di ingresso.


 unsigned int n;
Il conto del numero di volte che viene premuto il pulsante va ovviamente mantenuto da una variabile, a cui possiamo dare il nome n.


  if (digitalRead (BTN_PIN) == HIGH)  	// bottone premuto?
        n++;		            	// incrementa di uno il numero di n
Lo stato del pulsante è riconducibile alla lettura del livello logico del pin al quale questo è collegato: se il livello è 1 (HIGH) il pulsante è premuto, se invece è 0 (LOW) il pulsante non è premuto. La funzione digitalRead(pin) legge il livello logico del pin BTN_PIN e lo restituisce come un intero: 1 (HIGH) oppure 0 (LOW). La struttura if...else incrementa dunque di uno la variabile n ogni qualvolta viene premuto il pulsante


    printf ("\r%d", n);
    fflush(stdout);
Per la corretta stampa a video della variabile n vengono utilizzate le funzioni printf() e fflush(), contenute nella libreria I/O standard del C.

Compilando e mandando in esecuzione il programma, si nota che esso non funziona correttamente: ogni volta che si preme il bottone, il numero non aumenta di uno, ma di un numero indefinito:


Esecuzione del programma CONTA (non funzionante) nel terminale. Richiede Flash Player



Nell'impiego di interruttori, commutatori o pulsanti meccanici, si verifica quasi sempre un inconveniente che, nella maggioranza dei casi, costituisce causa di malfunzionamento nei circuiti digitali: l'elemento mobile che realizza il contatto, quando viene spostato da una posizione all'altra rimbalza (bouncing) diverse volte prima di stabilizzarsi al valore impostato.

Questi continui rimbalzi, che avvengono in un tempo brevissimo (generalmente fra 0,1 e 5ms), vengono percepiti dal software in esecuzione come ripetute pressioni del pulsante e quindi erroneamente conteggiati. Il problema viene aggirato impiegando soluzioni cosiddette di anti-rimbalzo (debouncing) che possono essere circuitali o software. Una delle soluzioni software più semplici è quella di far eseguire un'istruzione di attesa, di un tempo superiore a quello di rimbalzo (gerneralmente dalle 4 alle 10 volte), in modo che il programma ignori sicuramente queste innumerevoli commutazioni. Al termine di questo periodo, per sicurezza, si torna a leggere lo stato del pulsante: se è corrispondente a quello attivo (es. livello alto) il pulsante è stato dunque "de-rimbalzato" (debounced) e quindi può essere eseguito il codice previsto all'occorrenza della pressione del bottone.

Un possibile pseudocodice per l'anti-rimbalzo software applicato al nostro programma, potrebbe essere il seguente:
Ripeti per sempre:
Se livello del bottone = ALTO:     // è stato premuto il pulsante
   Aspetta 30ms                    // da 20 a 40ms
   Se livello del bottone = ALTO:  // bouncing terminato
      Incrementa n di 1            // viene eseguito il codice previsto alla pressione del pulsante
Stampa n su terminale.
Fine Ripeti per sempre.

Però, anche avendo "ripulito" dai rimbalzi la pressione del pulsante, il software continua a incrementare - erroneamente - la variabile n, durante il brevissimo tempo che l'utente mantiene ancora premuto il pulsante stesso. Ciò può essere evitato con una successiva istruzione, per esempio, che impedisca la prosecuzione del programma, finché non viene rilasciato lo stesso pulsante:
Ripeti per sempre:
Se livello del bottone = ALTO:             // è stato premuto il pulsante
   Aspetta 30ms                            // da 20 a 40ms 	 
   Se livello del bottone = ALTO:          // sono terminati i rimbalzi
      Incrementa n di 1                    // viene eseguito il codice previsto alla pressione del pulsante
      Finché livello del bottone = ALTO:   // aspetta rilascio del pulsante
        Itera a vuoto 		     
Stampa n su terminale.
Fine ripeti per sempre.


Le iterazioni a vuoto del while() di attesa del rilascio pulsante, comportano un impegno della CPU, da parte del processo, vicino al 100%. Inserendo, invece, nel corpo della struttura una semplice istruzione di attesa di 1ms, si riduce drasticamente l'uso del processore.
Il sorgente definitivo è il seguente:

CONTA.C
#include <stdio.h> 
#include <wiringPi.h>

#define BTN_PIN 	3		// Pulsante  (3 WiringPi, GPIO22, pin 15)
#define T_DEBOUNCE  	25		// Tempo di attesa per il termine del rimbalzo del pulsante

unsigned int n;				// Numero di pressioni del pulsante

int main (void)
{
  // --- Init
  wiringPiSetup();  
  pinMode (BTN_PIN, INPUT);	// configura BTN_PIN come pin di ingreso
  
  // --- Loop
  while (1)
  {
    if (digitalRead (BTN_PIN) == HIGH)       // se il pulsante viene premuto
    {
        delay(T_DEBOUNCE);                   // aspetta esaurirsi rimbalzo
        
        if (digitalRead (BTN_PIN) == HIGH)   // rimbalzo terminato
    	   n++;				     // incrementa di 1 il numero di pressioni
        
        while (digitalRead(BTN_PIN) == HIGH)   // aspetta rilascio pulsante
        {
           delay(1);                          // riduce utilizzo CPU (limita a 1000 iterazioni/s)
        }                
    }
    
    printf ("\r%d", n);
    fflush(stdout);

  }	 
 
  return 0 ;
}





Esecuzione del programma CONTA (funzionante) nel terminale. Richiede Flash Player







Informativa estesa sui Cookie | Web Statistics

Clicky

| Realizzazione a cura di Francesco Parisi (2002 ÷ 2024) | Contatti