IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Voir le flux RSS

Le blog de f-leb

[Actualité] [Raspberry Pi Pico][SDK C/C++] Après le 'Hello World', apprendre à piloter simultanément plusieurs GPIO

Note : 2 votes pour une moyenne de 3,00.
par , 27/04/2023 à 08h00 (4099 Affichages)
Après avoir découvert la carte Raspberry Pi Pico et réalisé votre premier "Hello World !" (un blink, quoi !) avec le SDK C/C++ (voir le billet précédent), je vous propose de découvrir des fonctions plus avancées pour piloter simultanément plusieurs broches GPIO.

À titre de démonstration, je vous présenterai une petite application de pilotage d'un afficheur 7-segments à cathode commune :

Nom : 20230423_111147.jpg
Affichages : 4077
Taille : 161,9 Ko

Parenthèse... Arduino : avec le « langage Arduino », si l'on considère une broche configurée en sortie avec pinMode(pin, OUTPUT), vous passerez par un digitalWrite(pin, HIGH) ou digitalWrite(pin, LOW) pour mettre la broche (pin) respectivement à l'état haut ou à l'état bas. Mais si vous devez piloter plusieurs broches, vous ne pouvez le faire que séquentiellement, broche par broche, en multipliant les pinMode() et digitalWrite().
De façon plus astucieuse, vous parcourrez un tableau dans une boucle for, par exemple :
Code arduino : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
int pins[] = {2, 3, 4, 5, 6, 7, 8, 9}; // tableau des broches
// ...
for (int i=0; i<8; i++) {
  pinMode(pins[i], OUTPUT); // les broches du tableau configurées en sortie numérique...
  digitalWrite(pins[i], HIGH); // ... initialement à l'état haut.
}
Mais que se passe-t-il lorsque vous devez synchroniser deux signaux qui basculent d'état en écrivant :
Code arduino : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
digitalWrite(8, LOW);
digitalWrite(9, HIGH);
// ...
digitalWrite(8, HIGH);
digitalWrite(9, LOW);
Quand la broche 8 passe à l'état haut, 9 doit passer à l'état bas... Mais dans des instructions séparées, il y aura une période de chevauchement (négligeable ?) où 8 et 9 sont tous les deux à l'état haut ! Cela n'a aucune importance en pratique si vous jouez avec des LED, mais en est-il pareil si vous manipulez les signaux de ponts pour contrôler des moteurs ?

Note : si l'API Arduino ne permet pas d'agir sur plusieurs broches simultanément, vous pouvez toujours le faire en attaquant directement les registres des ports d'E/S du microcontrôleur. Consultez le manuel pour l'ATmega328P de l'Arduino Uno.

... fin de la parenthèse.

Avec le SDK C/C++ de la Raspberry Pi Pico, vous pouvez agir simultanément sur plusieurs broches de la carte, en définissant un masque.
Sur la Raspberry Pi Pico, vous pouvez jouer avec 30 broches GPIO numérotées GP0 à GP29.
Le masque est donc une valeur entière définie sur 32 bits (uint32_t) où le bit 0 de poids faible concerne la broche GP0, le bit 1 pour la broche GP1, le bit 2 pour la broche GP2, etc. Tout simplement.

Si vous voulez par exemple attaquer les broches GP1, GP4 et GP8, on définira le masque :
Code C : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
// broches GP1, GP4 et GP8
uint32_t mask = (1 << 1) | (1 << 4) | (1 << 8);

Pour initialiser les broches, on écrira alors :
Code C : Sélectionner tout - Visualiser dans une fenêtre à part
gpio_init_mask(mask);

et pour les configurer toutes en sorties numériques :
Code C : Sélectionner tout - Visualiser dans une fenêtre à part
gpio_set_dir_out_masked(mask); // GP1, GP4 et GP8 = output

ou toutes en entrées numériques :
Code C : Sélectionner tout - Visualiser dans une fenêtre à part
gpio_set_dir_in_masked(mask); // GP1, GP4 et GP8 = input

En renseignant une valeur supplémentaire, on peut même choisir entre certaines broches configurées en entrées et d'autres en sorties :
Code C : Sélectionner tout - Visualiser dans une fenêtre à part
gpio_set_dir_masked(mask, value);
value est aussi un entier 32 bits, avec le bit de la broche à 0 (input) ou à 1 (output).

Pour des sorties numériques, vous pouvez mettre toutes les broches définies dans le masque à l'état haut (set) ou à l'état bas (clr) en une seule opération :
Code C : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
gpio_set_mask(mask); // GP1, GP4 et GP8 à l'état haut 
gpio_clr_mask(mask); // GP1, GP4 et GP8 à l'état bas

Mais on peut aussi définir certaines broches à l'état haut et d'autres à l'état bas, toujours simultanément. Par exemple :
Code C : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
uint32_t mask =  (1 << 1) | (1 << 4) | (1 << 8); // broches GP1, GP4 et GP8
gpio_init_mask(mask);
gpio_set_dir_out_masked(mask); // GP1, GP4 et GP8 = output
 
uint32_t value = (1 << 1) | (1 << 4);  
gpio_put_masked(mask, value); // GP1 et GP4 à l'état haut, GP8 à l'état bas.

Ainsi, pour s'assurer que les états de deux signaux basculent simultanément, on écrira :
Code C : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
uint32_t mask =  (1 << 4) | (1 << 8); // broches GP4 et GP8
gpio_init_mask(mask);
gpio_set_dir_out_masked(mask); // GP4 et GP8 = output
 
uint32_t state1 = (1 << 4);
uint32_t state2 = (1 << 8);
 
gpio_put_masked(mask, state1); // GP4=1, GP8=0
 
// ...autre action
 
gpio_put_masked(mask, state2); // GP4=0, GP8=1, les signaux sur GP4 et GP8 basculent simultanément
 
// ...

______________________________
Dans l'exemple d'application ci-dessous, on montre comment piloter un afficheur 7-segments (à cathode commune) avec un compteur qui évolue entre 0 et 9 (voir photo du montage plus haut).

Les anodes des segments (7 segments + point décimal) sont reliées aux broches GP08 à GP15 (n'oubliez pas les résistances 330Ω) et seront donc pilotées simultanément grâce à gpio_put_masked.

Fichier source digit7seg.c :
Code C : Sélectionner tout - Visualiser dans une fenêtre à part
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
36
37
38
39
40
41
42
43
44
/**
 * Démonstration pilotage digit 7-segments
 */
 
#include "pico/stdlib.h"
 
int main() {    
    /*
     * seg a  --> GP15
     * seg b  --> GP14
     * seg c  --> GP13
     * seg d  --> GP12
     * seg e  --> GP11
     * seg f  --> GP10
     * seg g  --> GP09
     * seg dp --> GP08 
     */
 
    //                            abcdefgp
    const uint8_t digit[] = {   0b11111100, // 0
                                0b01100000, // 1
                                0b11011010, // 2
                                0b11110010, // 3
                                0b01100110, // 4
                                0b10110110, // 5
                                0b10111110, // 6
                                0b11100000, // 7
                                0b11111110, // 8
                                0b11110110  // 9
                            };      
 
    const uint32_t mask = 0x0000FF00; // masque GP08 à GP15
    gpio_init_mask(mask); // GPO8 à GP15 = I/O
    gpio_set_dir_out_masked(mask); // GPIO8 à GPI15 = sorties
 
    while (true) {
        for (uint8_t counter=0; counter<10; counter++) { // compteur 0 à 9
            uint32_t value = digit[counter] << 8;
            gpio_put_masked(mask, value);
            sleep_ms(1000);
        }
    }
 
}

Fichier CMakeLists.txt :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
cmake_minimum_required(VERSION 3.13)

# initialize the SDK based on PICO_SDK_PATH
# note: this must happen before project()
include(pico_sdk_import.cmake)

project(digit7seg C CXX ASM) 

set(CMAKE_C_STANDARD 11)  
set(CMAKE_CXX_STANDARD 17) 

# initialize the Raspberry Pi Pico SDK
pico_sdk_init()

# rest of your project
add_executable(digit7seg
    digit7seg.c
)

# Add pico_stdlib library which aggregates commonly used features
target_link_libraries(digit7seg pico_stdlib)

# create map/bin/hex/uf2 file in addition to ELF.
pico_add_extra_outputs(digit7seg)
Voir le billet précédent pour la construction du projet.

Pour plus de détails Pico C SDK : hardware_gpio

Envoyer le billet « [Raspberry Pi Pico][SDK C/C++] Après le 'Hello World', apprendre à piloter simultanément plusieurs GPIO » dans le blog Viadeo Envoyer le billet « [Raspberry Pi Pico][SDK C/C++] Après le 'Hello World', apprendre à piloter simultanément plusieurs GPIO » dans le blog Twitter Envoyer le billet « [Raspberry Pi Pico][SDK C/C++] Après le 'Hello World', apprendre à piloter simultanément plusieurs GPIO » dans le blog Google Envoyer le billet « [Raspberry Pi Pico][SDK C/C++] Après le 'Hello World', apprendre à piloter simultanément plusieurs GPIO » dans le blog Facebook Envoyer le billet « [Raspberry Pi Pico][SDK C/C++] Après le 'Hello World', apprendre à piloter simultanément plusieurs GPIO » dans le blog Digg Envoyer le billet « [Raspberry Pi Pico][SDK C/C++] Après le 'Hello World', apprendre à piloter simultanément plusieurs GPIO » dans le blog Delicious Envoyer le billet « [Raspberry Pi Pico][SDK C/C++] Après le 'Hello World', apprendre à piloter simultanément plusieurs GPIO » dans le blog MySpace Envoyer le billet « [Raspberry Pi Pico][SDK C/C++] Après le 'Hello World', apprendre à piloter simultanément plusieurs GPIO » dans le blog Yahoo

Mis à jour 29/04/2023 à 17h57 par f-leb

Catégories
Raspberry Pi , Programmation , C , C++ , Raspberry Pi Pico

Commentaires

  1. Avatar de Artemus24
    • |
    • permalink
    Salut à tous.

    Je ne sais pas pourquoi, mais ton sujet n'a aucun succès.
    Et pourtant, tu donnes toutes les explications nécessaire à son bon déroulement.

    Encore bravo et merci de te donner la peine d'écrire pour les débutants, ainsi que les autres.

    Cordialement.
    Artemus24.
    @+