par , 27/04/2023 à 08h00 (4355 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 :
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 :
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 :
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 :
1 2
| // broches GP1, GP4 et GP8
uint32_t mask = (1 << 1) | (1 << 4) | (1 << 8); |
Pour initialiser les broches, on écrira alors :
et pour les configurer toutes en sorties numériques :
gpio_set_dir_out_masked(mask); // GP1, GP4 et GP8 = output
ou toutes en entrées numériques :
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 :
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 :
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 :
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 :
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 :
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 :
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