howto:processing:processingraspberry

Raspberry Pi & électronique: les GPIO

GPIO


Le plus important, peut être, est d'avoir sous les yeux la répartition des pin du raspberry. Certaines nous sont inaccessibles, car réservées à d'autres usages.

D'autres sont utilisées pour l'alimentation. 2 pins 5V et 1 pin 3.3V, et une poignées de GND sont réparties et pourront nous servir à alimenter quelques composants. On peut compter sur environ 1.5A de la part du 5V, avec une bonne alimentation. A priori, la pin 3.3V doit pouvoir fournir environ 500 mA. Mais il reste préférable de convertir le 5V en 3.3V, si on veut alimenter autre chose qu'une poignée de Leds un microcontrôleur (type ESP).

Toutes les autres pin sont appelées GPIO (General Purpose Input Output). Elles peuvent donc indifféremment être utilisées en entrée ou en sortie digitale). Attention, néanmoins, certaines sont utilisées par certains protocoles de communication: i2C, SPI, Uart. Ces broches sont parfois légèrement différentes des autres (résistance en Pull Up par exemple). Le courant maximum (en entrée ou en sortie) par broche est de 16mA et le courant total pour l’ensemble du GPIO ne peut pas dépasser 50mA.

Une bible très pratique peut être trouvée ici: https://fr.pinout.xyz/# mais une simple recherche “raspberry pinout” vous montrera de nombreuses versions graphiques de l'implantation des pin du raspi.

Le site pinout.xyz nous autorise à publier leur image:

Il est possible d'utiliser des nappes pour déporter les connections facilement sur une plaque de prototypage, et souvent les références sont rappelées sur la PCB. Le fablab en possède deux ou trois, pour vos montages chez nous. Un exemple chez mchobby.be:

Moins coûteux et plus simple, il existe des “leafs”, des images à imprimer et venir poser directrement sur les gpio du raspberry, ex: https://github.com/splitbrain/rpibplusleaf (merci Emmanuel).

Enfin, il est possible de retrouver toutes ces infos directement dans le terminal de Rapbian, via la commande pinout tapée dans un terminal. Cette commande dépend du paquet gpiozero installé par défaut dans Raspbian. Si le paquet n'est pas installé de base sur votre distribution, les instructions d'install sont ici: https://gpiozero.readthedocs.io/en/stable/installing.html .

Numérotation


On touche ici à la partie la moins drôle de cette affaire. Chaque Pin GPIO peut avoir une numérotation différente suivant le langage que l'on utilise. La numérotation physique est la plus simple: On compte les pin dans l'ordre, de haut en bas, de gauche à droite. La numérotation Broadcom (BCM) est celle utilisée par Processing par exemple, et correspond au branchement interne du processeur. Mais il existe d'autre manière de les numéroter, (WiringPi par exemple). Avant de commencer à programmer, il est important de savoir quelle numérotation utilise le langage choisi. De nouveau, il suffit de se référer à un site comme pinout.xyz pour s'y retrouver par la suite.

Capacités


Toutes les GPIO peuvent: → générer du PWM software → lire ne entrée tout ou rien entre 0 et 3.3V → écrire une sortie en tout ou rien entre 0 et 3.3V

Toutes sauf GPIO02 et GPIO03, ont des résistances internes en pullup ou pulldown qui peuvent être activées par une commande logicielle. GPIO02 et GPIO03 ont une résistance fixe en pullup.

ATTENTION Puisque les niveaux logiques sont 3.3V, il est donc important de prendre ses précautions lorsque l'on travaille avec des composants ou des microcontrôleurs qui travaillent en 5V. Par exemple, un capteur qui travaillerait passerait une sortie à 5V lorsqu'il détecterait un mouvement pourrait endommager la pin sur laquelle il serait branchée. Il faut envisager un pont diviseur de tension à l'aide de résistances appropriées. Idem, un arduino UNO travaille avec des niveaux logiques de 5V.

Entrées analogiques


Aucune entrée GPIO ne peut lire directement d'entrée analogique. Pour lire un potentiomètre ou un capteur de force, par exemple, il faudra un convertisseur analogique vers digital (ADC).(on parle de ce genre de bestiole).

Un tuto en ligne: http://nagashur.com/blog/2013/01/13/lire-des-entrees-analogiques-sur-un-raspberry-avec-un-circuit-adc-le-mcp3008/

Branchement i2c et SPI


A noter, il faudra aller activer ces protocoles en tapant sudo raspi-config dans un terminal pour que cela soit opérationnel. Aller ensuite dans interfacing options.

i2C Pour utiliser ce protocole, une petite recherche sur le net permet de lever les doutes, mais après avoir vérifié la tension d'alimentation de votre composant et branché VCC sur 3.3V ou 5V et GND sur Ground, il faudra relier SDA et SCL du composant aux pin 2 et 5 du Raspi (numérotation physique, ce sont GPIO02 et GPI03 en BCM).

SPI Le SPI nécessite plus de fil, voici la liste des connections: SPI0: MOSI (GPIO10); MISO (GPIO9); SCLK (GPIO11); CE0 (GPIO8), CE1 (GPIO7) SPI1: MOSI (GPIO20); MISO (GPIO19); SCLK (GPIO21); CE0 (GPIO18); CE1 (GPIO17); CE2 (GPIO16)

Exemples


Voici quelques exemples, pour ne pas commencer de zéro. Tous peuvent être mis en place avec un bouton, une led et une résistance. Mais une fois que l'on sait faire cela, on sait presque tout faire !

Avec Processing

Une librairie (hardware I/O) a été développée pour utiliser les GPIO du Raspberry Pi. De même, une version spécifique de Processing a été développée pour tourner sous Arm. Il y a un sous-site dédié: https://pi.processing.org/, sur lequel vous trouverez des tutos et de la documentation.

  1. pour faire clignoter des leds, tourner des servos, etc… https://processing.org/reference/libraries/io/index.html ou explorer les exemples de la librairie: Fichier>Exemples>Librairies>HardwareI/O
Avec Python

Il faut le reconnaître, c'est la manière de faire la plus usuelle. Les exemples disponibles sur le site de la fondation RaspberryPi sont très accessibles, en plus d'être ludiques: https://projects.raspberrypi.org/en/projects?hardware%5B%5D=electronic-components

En ligne de commande

Il est intéressant de noter que les états des GPIO peuvent être lus ou modifiés directement depuis la ligne de commande! Cette méthode est à privilégier pour les utilisateurs avec le terminal, mais elle est très puissante. Les deux liens ci-dessous vous offriront une bonne introduction à cette méthode: https://raspberry-projects.com/pi/command-line/io-pins-command-line/io-pin-control-from-the-command-line http://wiringpi.com/the-gpio-utility/

i2c —

Un petit résumé des informations de base, tirées de https://fr.wikipedia.org/wiki/I2C .

Le bus de communication i2c a été inventé en 1982 par le constructeur Philips, dans le but de faire communiquer des composants électroniques, des capteurs, des circuits à l'intérieur d'un appareil. Il est très courant et très facilement utilisable dans un microcontrôleur. Plusieurs équipements, maîtres ou esclaves, peuvent être connectés au bus (jusqu'à 255). Les échanges ont toujours lieu entre un seul maître et un (ou tous les) esclave(s), toujours à l'initiative du maître (jamais de maître à maître ou d'esclave à esclave). Cependant, rien n'empêche un composant de passer du statut de maître à esclave et réciproquement.

La connexion est réalisée par l'intermédiaire de deux lignes :

  • SDA (Serial Data Line) : ligne de données bidirectionnelle,
  • SCL (Serial Clock Line) : ligne d'horloge de synchronisation bidirectionnelle.

Il ne faut également pas oublier la masse qui doit être commune aux équipements.

Pour mémoire, il faut bien penser à activer l'i2c dans raspi-config. La différence de tension ne va poser de problème dans notre cas, le raspberry étant le maître, les échanges se feront bien 3.3V.

Voici le tuto qui nous servira de base: https://www.pihomeserver.fr/2013/08/13/raspberry-pi-home-server-arduino-lier-les-deux-via-bus-i2c/

Pour connecter un ou plusieurs Arduino au Raspberry, il faut relier SDA → Pin3 et SDL → Pin5. Dans Raspbian, si besoin, installer le paquet i2c-tools s'il n'est pas déjà présent.

En tapant i2cdetect -y 1, on va pouvoir lister les périphériques i2c visibles.

Le code de base à injecter dans l'arduino, selon le modèle de notre tuto. Il est particulièrement simple mais intéressant, il illustre parfaitement le mécanisme de question/réponse.

#include <Wire.h>

#define SLAVE_ADDRESS 0x12
int dataReceived = 0;

void setup() {
    Serial.begin(9600);
    Wire.begin(SLAVE_ADDRESS);
    Wire.onReceive(receiveData);
    Wire.onRequest(sendData);
}

void loop() {
    delay(100);
}

void receiveData(int byteCount){
    while(Wire.available()) {
        dataReceived = Wire.read();
        Serial.print("Donnee recue : ");
        Serial.println(dataReceived);
    }
}

void sendData(){
    int envoi = dataReceived + 1;
    Wire.write(envoi);
}

Plusieurs solutions pour discuter avec notre arduino, depuis notre raspberry:

En Processing
import processing.io.*;
I2C i2c;

void setup() {
  printArray(I2C.list());
  i2c = new I2C(I2C.list()[0]);
}

void draw() {
  background(0);
}

void mousePressed()
{
  i2c.beginTransmission(0x12);
  int nberSent = int(random(127));
  println("Numero envoyé:"+nberSent);
  i2c.write(nberSent);
  i2c.endTransmission();
  delay(250);
  i2c.beginTransmission(0x12);
  byte[] in = i2c.read(1);
  i2c.endTransmission();
  println(in);
  
  //
  delay(250);

  i2c.beginTransmission(0x15);
  i2c.write(nberSent);
  i2c.endTransmission();
  delay(250);
  i2c.beginTransmission(0x15);
  byte[] in2 = i2c.read(1);
  i2c.endTransmission();
  println(in2);
  
}
En Python
import smbus
from time import sleep

# Remplacer 0 par 1 si nouveau Raspberry
bus = smbus.SMBus(1)
address = 0x15

while True :
    valeur = int(input("valeur à envoyer : "))
    print ("Envoi de la valeur",valeur,"...")
    bus.write_byte(address, valeur)
    
    # Pause de 1 seconde pour laisser le temps au traitement de se faire
    sleep(1)
    
    reponse = bus.read_byte(address)
    print ("La reponse de l'arduino : ", reponse)
    print("-----------\n")      
Connection UART

Raspi → raspi-config, désactiver console. Branchement RX TX GND→ ESP32 TX RX GND

Python

from time import sleep
import serial
               
ser = serial.Serial(            
    port='/dev/serial0',
    baudrate = 9600,
    parity=serial.PARITY_NONE,
    stopbits=serial.STOPBITS_ONE,
    bytesize=serial.EIGHTBITS,
    timeout=1
)
         
while True :
    ser.write(str.encode('hello\n'))
    sleep(1)

Processing

Serial myPort;  // Create object from Serial class
int val;        // Data received from the serial port

void setup() 
{
  size(200, 200);
  // I know that the first port in the serial list on my mac
  // is always my  FTDI adaptor, so I open Serial.list()[0].
  // On Windows machines, this generally opens COM1.
  // Open whatever port is the one you're using.
  printArray(Serial.list());
  String portName = Serial.list()[0];
  myPort = new Serial(this, portName, 9600);
}

void draw() {
  background(255);
  if (mouseOverRect() == true) {  // If mouse is over square,
    fill(204);                    // change color and
    myPort.write('H');              // send an H to indicate mouse is over square
  } 
  else {                        // If mouse is not over square,
    fill(0);                      // change color and
    myPort.write('L');              // send an L otherwise
  }
  rect(50, 50, 100, 100);         // Draw a square
}

boolean mouseOverRect() { // Test if mouse is over square
  return ((mouseX >= 50) && (mouseX <= 150) && (mouseY >= 50) && (mouseY <= 150));
}

ARDUINO Code pour ESP32, avec connexion sur RX2 et TX2

/*
 * There are three serial ports on the ESP known as U0UXD, U1UXD and U2UXD.
 * 
 * U0UXD is used to communicate with the ESP32 for programming and during reset/boot.
 * U1UXD is unused and can be used for your projects. Some boards use this port for SPI Flash access though
 * U2UXD is unused and can be used for your projects.
 * 
*/
 
#define RXD2 16
#define TXD2 17
 
void setup() {
  // Note the format for setting a serial port is as follows: Serial2.begin(baud-rate, protocol, RX pin, TX pin);
  Serial.begin(115200);
  //Serial1.begin(9600, SERIAL_8N1, RXD2, TXD2);
  Serial2.begin(9600, SERIAL_8N1, RXD2, TXD2);
  Serial.println("Serial Txd is on pin: "+String(TX));
  Serial.println("Serial Rxd is on pin: "+String(RX));
}
 
void loop() { //Choose Serial1 or Serial2 as required
  while (Serial2.available()) {
    Serial.print(char(Serial2.read()));
  }
}
  • howto/processing/processingraspberry.txt
  • Dernière modification: 2020/11/26 11:24
  • (modification externe)