Aller au contenu

Exercices du chapitre "Microcontrôleur et periphériques"

Inverser l’état d’une LED

Exercice 1

Écrivez un programme en C++ qui inverse l’état d’une LED connectée à la broche PE_0 lorsqu’un bouton connecté sur la broche PA_0 est appuyé. Notez que la LED est allumée lorsqu’on écrit un 0 dans la broche et éteinte lorsqu’on écrit un 1. On aimerait qu’elle soit éteinte au démarrage. Notez aussi que le bouton a besoin d’une résistance de pull-down pour fonctionner. Faites attention à ne pas utiliser de “Magic numbers” dans votre code et définissez vos constantes avec des static constexpr.

Solution
simple_polling.cpp (solution)
#include "mbed.h"

constexpr int kLedOn  = 0;
constexpr int kLedOff = 1;

constexpr int buttonReleased = 0;
constexpr int buttonPressed  = 1;

int main()
{
    DigitalOut led(PE_0, kLedOff);
    DigitalIn button(PA_0, PullDown);

    int prevState = button;

    while (true) {
        int state = button;
        if (prevState == buttonReleased && state == buttonPressed) {
            led = !led;
        }
        prevState = state;
    }
}

Parité UART

Exercice 2

À quoi sert la “parité” dans les paramètres de communication avec un UART ?

Solution

La communication série n’est pas toujours très fiable et il arrive parfois que des bits soient mal reçus. La parité permet de détecter si un bit a été modifié pendant la transmission.

Périphériques I2C

Exercice 3

Cherchez sur Internet d’autres périphériques qui utilisent l’I2C

Solution

En plus des thermomètres et des mémoires EEPROM, on trouve encore

Débit sur un bus SPI

Exercice 4

Avec un SPI rapide (50MHz), combien de temps faut-il pour lire complètement une carte SD de 16GiB ?

Solution

\(16\,\mathsf{GiB} = 16 \cdot 8 \cdot 2^{30}\,\mathsf{bit}\). Il faut donc \((128 \cdot 2^{30}) \div (50 \cdot 10^{6}) = 2748\,\mathsf{secondes})\) ou environ \(45\,\mathsf{minutes}\).

Si vous n’avez pas de calculatrice, vous pouvez utiliser l’approximation \(2^{30} \approx 10^{9}\) et ça donne donc \((128 \cdot 10^{9}) \div (50 \cdot 10^{6}) = 2560\,\mathsf{secondes} \approx 42\,\mathsf{minutes}\).

Inversion d’une LED basée sur un état

Exercice Exercices du chapitre “Microcontrôleur et periphériques”/5

Implémentez la classe MyDevice pour que la LED soit inversée à chaque deuxième pression du bouton.

Solution
int_object_callback.cpp (solution)
class MyDevice {
   public:
    MyDevice(PinName led) : led_(led, kLedOff), counter_{0} {};
    void handler()
    {
        counter_++;
        if (counter_ >= 2) {
            led_     = !led_;
            counter_ = 0;
        }
    }

   private:
    DigitalOut led_;
    int counter_;
};

Suffixe C++ pour les unités de temps

Exercice 6

Quel(s) mécanismes(s) de C++ permet(tent) de simplement ajouter un suffixe ms à une durée pour un temps en millisecondes ?

Solution
  • La surcharge de l’opérateur ""ms (User defined literals)
  • La classe std::chrono::duration utilise aussi le concept des Templates, pour la représentation interne de la durée, mais ce n’est pas directement lié à la question du suffixe.

Utilisation des unités de temps

Soit le code :

timer_measure_kernel.cpp
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#include "mbed.h"

int main()
{
    uint64_t now = Kernel::get_ms_count();
    ThisThread::sleep_for(100ms);
    uint64_t later      = Kernel::get_ms_count();
    uint64_t elapsed_ms = later - now;
    printf("Elapsed ms: %u\n", (uint32_t)elapsed_ms);
}

La ligne 5 interroge le temps actuel du noyau (en millisecondes et sur 64 bits), la ligne 6 attend 100 millisecondes, puis la ligne 7 lit le nouveau temps actuel du noyau. Le temps écoulé est la différence entre les deux temps.

Exercice 7

Quel est le défaut de cette solution ?

Solution

Le nom de la méthode indique bien que nous mesurons des millisecondes, mais aucune unité n’est attachée au résultat.

Clignotement asymétrique d’une LED

Exercice 8

Soit le code

timer_blink.cpp
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
#include "mbed.h"

constexpr int kLedOn  = 0;
constexpr int kLedOff = 1;

void toggle(DigitalOut* led) { *led = !*led; }

int main()
{
    DigitalOut led(PE_0, kLedOff);
    Ticker flipper;
    flipper.attach(callback(&toggle, &led), 500ms);
    while (true) {
        asm("nop");
    }
}
Modifiez ce code pour garder la LED allumée pendant 250 millisecondes et éteinte pendant 750 millisecondes, en utilisant une classe afin de sauvegarder l’état du dispositif.

Solution
timer_blink.cpp (solution)
#include "mbed.h"

constexpr int kLedOn  = 0;
constexpr int kLedOff = 1;

class MyDevice {
   public:
    MyDevice(PinName led) : led_(led, kLedOff), counter_{0} {};
    void handler()
    {
        if (counter_ == 0) {
            led_ = kLedOn;
        } else if (counter_ == 1) {
            led_ = kLedOff;
        }
        if (counter_ >= 3) {
            counter_ = 0;
        } else {
            counter_++;
        }
    }

   private:
    DigitalOut led_;
    int counter_;
};

int main()
{
    MyDevice device(PE_0);
    Ticker flipper;
    flipper.attach(callback(&device, &MyDevice::handler), 250ms);
    while (true) {
        asm("nop");
    }
}

Consommation d’énergie et autonomie

Exercice Exercices du chapitre “Microcontrôleur et periphériques”/9

Nous souhaitons alimenter une station météo construite avec un microcontrôleur STM32F412 avec deux piles en série de type AA de \(1.5\,V\) et \(2800\,mAh\) chacune. En mode de veille, le microcontrôleur (avec une tension de \(3V\)) consomme \(12\,\mu{}A\). Pour faire la mesure et l’envoyer, le microcontrôleur à besoin de \(3\) secondes pendant lesquelles il consomme \(112\,\mu{}A\) par \(Mhz\) et il tourne à \(100\,Mhz\). Pendant ces 3 secondes, il faut aussi activer le module LoRa qui consomme \(100\,mA\) pendant \(100\, mS\). En travail, le circuit est aussi alimenté en \(3V\).

Avec quelle période pouvons nous faire des mesures pour que le système puisse fonctionner pendant \(5\) ans avec les mêmes piles ?

Solution

Le système doit fonctionner pendant 5 ans avec \(2800\,mAh\). Sa consommation moyenne doit donc être au maximum de \(\frac{2.8 [Ah]}{5 \cdot 356 \cdot 24 [h]}\) soit environ \(63.9\,\mu{}A\). En veille, il consomme \(12\,\mu{}A\), donc la réalisation est possible.

Pendant une période de \(p\) secondes, la moyenne de la consommation est de

\[\frac{112 [\mu{}A] \cdot 100 \cdot 3 [s] + 100'000 [\mu{}A] \cdot 0.1 [s] + 12 [\mu{}A] \cdot (p - 3) [s]}{p[s]}\]

Et cette moyenne ne dois pas dépasser \(63.9\,\mu{}A\). Nous pouvons résoudre l’équation suivante par rapport à \(p\):

\[\frac{33'600 + 10'0000 + 12 \cdot p - 36}{p} \leq 63.9\]
\[43'536 + 12 \cdot p \leq 63.9 \cdot p\]
\[p \geq \frac{43'536}{51.9} \approx 839\,s \approx 14\,min\]

On prend un peu de marge et on choisit une période d’au moins 15 minutes.