Activité 3c - Analyse de la Gestion des LED de la Matrice 5x5

Notions de base :

Exercice résolu : Gestion d'une ligne de la matrice

Histoire de jouer avec les coordonnées des Leds, écrivons le code nécessaire pour obtenir le signe moins (-) qui devra occuper l'intégralité de l'afficheur :

Une façon simple de répondre au problème posé est d'utiliser une suite d'instructions display.set_pixel() comme celle ci-dessous :

from microbit import *
display.set_pixel(0,2,9)
display.set_pixel(1,2,9)
display.set_pixel(2,2,9)
display.set_pixel(3,2,9)
display.set_pixel(4,2,9)

C'est une façon un peu "laborieuse" et pas très "élégante" du point de vue du code.

A y regarder de plus près, on constate de ligne en ligne que x croit de 0 à 4 pendant que y reste constant à 2. Ces 5 lignes pourraient être remplacées par une seule :

display.set_pixel( i , 2 ,9)

à condition que i puisse prendre successivement les valeurs 0, 1, 2, 3 et 4. C'est possible en réalisant dans le programme une boucle While.

FondamentalLa boucle While :

while condition:

instruction 1 à réaliser dans la boucle

instruction 2 à réaliser dans la boucle

etc...

1 ère instruction à réaliser en sortant de la boucle

... qui signifie "tout le temps que la condition est vraie, exécute le code dans le bloc indenté ci-dessous"

Appliquons cette boucle à notre programme qui devient alors :

from microbit import *
i = 0
while i < 5 :
display.set_pixel(i, 2, 9) # x va varier de 0 à 4 ; y fixé à 2
i = i + 1

Explication :

On commence par déclarer une variable i à laquelle on affecte la valeur 0. (le signe = n'est pas un signe d'égalité mais d'affectation, qui signifie «on affecte la valeur qui est à droite du symbole = à la variable écrite à gauche»). On teste si i est strictement inférieur à 5 : c'est vrai, donc on rentre dans le bloc d'instructions avec i valant 0.

La ligne suivante va donc allumer la Led de coordonnées (0,2) avec la luminosité maximum (9)

La ligne d'instruction suivante i = i + 1 est déroutante lorsque l'on démarre la programmation. Il faut la comprendre de la façon suivante :

on affecte la valeur i + 1, c'est à dire 0 + 1, donc 1 à la variable située à gauche du signe = , donc à la variable i

Lorsque la ligne d'instruction i = i + 1 aura été exécutée, i ne vaudra plus 0 mais 1 : on a réalisé une incrémentation de la variable i.

C'était la dernière ligne d'instruction dans ce bloc, on remonte donc au test while i <5 qui est de nouveau vrai puisque i vaut 1.

Cela déclenche l'allumage d'une nouvelle Led de coordonnées (1,2), puis nouvelle incrémentation de la variable qui prend alors la valeur 2, etc. jusqu'à ce que i prenne la valeur 4. La boucle est parcourue une dernière fois : à la suite de l'incrément i prend la valeur 5. La condition i < 5 n'étant plus vérifiée la boucle n'est plus parcourue.

Remarque : si on a déjà fait de la programmation, on se demande sans doute pourquoi ne pas utiliser plutôt une boucle «à compteur» de type «for».

Exemple en C :

for (i = 0 ; i  4 ; i++)
    {
    }

Cette instruction comporte moins de code (une seule ligne contre 3 avec la boucle while : initialisation de la variable, test d'entrée de boucle et incrémentation dans la boucle...

Deux raisons à ce choix de présentation :

1. on va avoir besoin rapidement de réaliser des boucles infinies, et c'est mieux de découvrir la boucle while sur un exemple de boucle finie

2. L'instruction « for » existe aussi en Python (sous la forme « for...in...) », mais elle a un rôle plus puissant (elle permet de travailler sur des séquences comme par exemple des listes).

On la mettra en œuvre plus tard. Une de ses applications est de pouvoir aussi faire une boucle à compteur :

for i in range(5):

for i in range(5)

La fonction range(5) commence par créer une liste de 5 entiers de 0 à 4 , et cette liste est parcourue avec l'instruction for, donnant successivement à i la valeur des éléments de la liste.

Exercices de base

Exercice d'application 1 :

Écrire un programme pour obtenir sur l'écran le signe plus(+) qui devra occuper l'intégralité de l'afficheur.

Ce programme devra utiliser lui aussi une boucle While.

Exercice d'application 2 :

On souhaite dans un même programme :

  • afficher le signe + pendant 1 seconde

  • effacer l'écran et le voir rester ainsi pendant 0,2 seconde

  • et enfin afficher le signe -

Écrire le code nécessaire respectant le cahier des charges défini ci-dessus. Pour cela, on pourra bien sûr réutiliser du code déjà écrit mais on aura aussi besoin de savoir exploiter les informations suivantes :

Une temporisation (ou délai) se réalise dans un programme en MicroPython avec la fonction :

sleep(n)

dans laquelle n représente le nombre de milliseconde de délai

L'effaçage de l'écran se fait avec la méthode :

display.clear()

Réaliser une boucle infinie :

On veut améliorer le programme précédent pour afficher en permanence la succession des signes + et – avec le même cahier des charges que précédemment, à savoir : l'affichage des signes pendant une seconde, l'effacement de l'écran pendant 0,2 s.

Pour cela on va de nouveau utiliser une boucle While dans laquelle va être incluse le programme précédent. Ici il nous faut donc une condition qui soit toujours vraie pour que la boucle

tourne indéfiniment.

Explication : un microcontrôleur n'est pas programmé pour réaliser une suite d'actions puis s'arrêter. On inscrit donc toujours le programme écrit pour un microcontrôleur dans une boucle infinie :

Une possibilité serait de déclarer une variable booléenne comme étant Vraie (True), variable inutilisée dans le reste du programme. elle restera donc toujours Vraie. A chaque entrée dans la boucle on teste si elle est toujours vraie. Comme elle le sera le programme tournera indéfiniment dans la boucle :

tournicoti = True

while tournicoti == True :

instruction 1 à réaliser dans la boucle

instruction 2 à réaliser dans la boucle

etc...

Attention : double signe == dans le test de condition.

Python permet une écriture plus concise qui peut être néanmoins déroutante. L'idée est simple : à quoi bon déclarer et tester une variable qui ne change pas. Le plus court est alors d'écrire :

while True : #qui signifie tout le temps que Vrai est Vrai ... !!

instruction 1 à réaliser dans la boucle

instruction 2 à réaliser dans la boucle

etc...

La séquence d'instructions qui n'était exécutée qu'une seule fois est maintenant incluse dans une boucle while infinie (on a ici entouré les différentes blocs de code des boucles while).

from microbit import *
while True:
i = 0
# affichage du signe + :
while i < 5:
   display.set_pixel(i,2,9)
   display.set_pixel(2,i,9)
   i = i + 1
# réalisation du délai et de l'effaçage :
sleep(1000) #1000ms = 1 seconde !
display.clear()
sleep(200)
# affichage du signe - :
i = 0
while i < 5:
   display.set_pixel(i,2,9)
   i = i + 1
# réalisation du délai et de l'effaçage :
sleep(1000) #1000ms = 1 seconde !
display.clear()
sleep(200)

Exercice d'application 3 :

Compléter le programme pour pouvoir afficher au même rythme, la succession des symboles +, - , x et / :

L'instruction conditionnelle : IF

Fondamental

Pour savoir si un bouton a été pressé, on va utiliser une instruction conditionnelle : IF (= "Si")

Regardons ce que donnerait une version francisée des possibilités offertes :

• Pour un test unique (aucune autre alternative n'est traitée) :

Si (condition vraie):

faire ceci

• Pour un test unique (toutes les autres alternatives sont traitées) :

Si (condition vraie):

faire ceci

sinon faire celà

Pour un test multiple (ici on teste trois conditions, avec en plus le traitement de toutes les autres alternatives) :

Si (condition1 vraie):

faire ceci

sinonSi (condition2 vraie):

faire celà

sinonSi (condition3 vraie):

faire çà

sinon faire cette chose

Pour rédiger le code en Python il suffira de remplacer :

• Si par if

• Sinon par else

• SinonSi par elif (contraction de else if)

Remarques :

  • En Python, on fera attention à l'indentation des blocs de code (à réaliser avec une tabulation).

  • On peut imbriquer plusieurs tests de deux façons pour vérifier que deux conditions sont satisfaites pour déclencher une action :

  • en imbriquant deux tests

  • en liant les deux conditions dans le même if à l'aide de l'opérateur logique "and" (= "et")

  • On peut réaliser une même action lorsque l'une ou l'autre de deux conditions est réalisée à l'aide l'opérateur logique "or" (="ou") :

Exercice résolu : Affichage de lettres sur la matrice

On souhaite afficher la lettre A si on appuie sur le bouton A et la lettre B si on appuie sur le bouton B.

L'affichage d'une lettre (A par exemple) se fait simplement de la façon suivante :

display.show(‘A')

Pour savoir si le bouton A est appuyé, on utilise la méthode :

button_a.is_pressed()

qui renvoie la valeur booléenne :

• True si le bouton A est appuyé

• False dans le cas contraire

L'utilisation de l'instruction conditionnelle if, associée à cette méthode permet alors d'orienter le programme selon le bouton appuyé.

from microbit import*
display.show('?')
while True: #creation d'une boucle infinie
   if button_a_is_pressed():
     display.show('A')
   elif button_b.is_pressed():
     display.show('B')

Explication : dans la première ligne d'instruction de la boucle infinie, la condition évaluée est button_a.is_pressed() :

• Si le résultat est True (le bouton A est appuyé au moment du test) alors on rentre dans le bloc indenté qui affiche sur l'écran la lettre A.

• Si le résultat est False (le bouton A n'était pas appuyé au moment du test) alors on passe à la ligne d'instruction de même indentation c'est à dire la ligne elif button_b.is_pressed() qui traite de la même façon le bouton B.

Quel que soit le résultat de chacun de ces tests, on reviendra toujours à la ligne while True qui permet cette boucle infinie. On est typiquement ici dans de la programmation évènementielle : le

programme ne fait strictement rien d'autre qu'attendre un évènement : l'appui sur un des boutons du système, évènement auquel il réagit.

Exercice d'application 4 :

1. Écrire un programme qui affiche une image au démarrage, image qui sera changée ensuite selon le bouton appuyé.Par exemple avec les images SAD et SMILE :

2. Lire le programme. Indiquer ce qui se passe au démarrage et lors de l'appui sur le bouton A ou sur le bouton B.

from microbit import*
i=5
while True:
   display.show(i)   
   if i>0 and button_a_is_pressed():
     i=i-1
   if i<9 and button_b.is_pressed():
     i=i+1

2. Écrire ce programme et lancer son exécution. Indiquer ce qui se passe au démarrage et lors de l'appui sur le bouton A ou sur le bouton B.

Remarque : il y a une explication à ce problème. Un peu d'électronique nous permettra de le comprendre.

Un bouton poussoir (dans sa forme la plus courante), réalise un contact momentané quand on appuie dessus, contact qui est rompu dès qu'on relâche le bouton.

Voici un montage classique pour un bouton poussoir (noté BP, mis en série avec une résistance de 10 kΩ) :

La tension mesurée par le voltmètre (ou par un oscilloscope) sera :

  • soit égale à 0 V, ce qui donnera un niveau logique 0 appelé état bas

  • soit égale à la tension d'alimentation (3,3V sur cet exemple), ce qui donnera un niveau logique 1 appelé état haut.

L'oscillogramme obtenu lors d'un appui bref sur ce bouton montre qu'un appui bref sur le bouton à une durée supérieure à 100 ms (souvent entre 100 et 200 ms). Cette boucle a une durée de l'ordre de 2 ms... Pendant la durée d'appui sur un bouton (100 à 200 ms pour un appui « bref »), cette boucle est donc parcourue plusieurs dizaines de fois, ce qui explique la variation « instantanée » de la valeur affichée. Il faut donc ralentir le programme. On va donc ajouter une petite temporisation dans la boucle. Prenons 200 ms puisque c'est l'ordre de grandeur d'un appui bref sur un bouton.

Exécuter ce code et le tester par des appuis brefs ou longs sur l'un ou l'autre des boutons poussoirs A et B.

Remarque : un phénomène mécanique peut se produire avec les boutons poussoirs : celui du rebond de contact. Au lieu d'être franc, le contact donne lieu à des microcoupures qui peuvent être interprétées (selon leur intensité et leur durée) comme de «vrais» appuis sur le bouton poussoir.

Exercice de synthèse :

Écrire un programme d'obtenir le fonctionnement suivant :

  • le programme démarre avec toutes les Leds allumées avec une luminosité égale à 5

  • un appui sur le bouton A décroît la luminosité de 1

  • un appui sur le bouton B augmente la luminosité de 1

  • la luminosité reste toujours comprise entre 0 et 9