De façon générale :
⇒ un ordinateur !
Vocabulaire utilisé :
En 40 ans :
Que nous réservent les années à venir ?!
Comparé aux configurations actuelles :
et pourtant, cela a permis d'amener des humains sur la Lune
Un développeur logiciel embarqué fait beaucoup avec peu 🙂
Un microcontrôleur actuel équivalent :
Rôles principaux de la mémoire virtuelle :
Voir partie Développement logiciel
Voir partie Développement logiciel
Parmi les licenciés Cortex-M :
prix : US$ 13
prix : US$ 28.90
US$ 42
Bloc microcontrôleur :
Blocs analogiques :
Blocs numériques :
prix : US$ 15.00
Série ESP8266 :
Série ESP32 :
Série ESP32-S3 :
Série ESP32-C3 :
Prix (à l'unité - ajouter la Flash si nécessaire):
ESP32-C3-DevKitC-02 - environ US$ 9,00
ESP32-EYE - environ US$ 20,00
mangOH Yellow :
capteurs :
divers :
environnement logiciel :
Prix (à l'unité) : environ US$ 165
Souvent nécessaire d'ajouter :
Dans notre exemple :
Dans notre exemple :
Dans notre exemple
niveaux électriques :
Connecteurs V.28 et RS232 : D-subminiature DB9 ou DB25
Pour les ordinateurs actuels, adaptateurs série-USB
Transfert des données :
Important :
Dans notre exemple :
Dans notre exemple :
Ecriture :
Lecture :
Voir section Communications
n
bits :
-2n-1 ⇒ 2n-1 - 1
0 ⇒ 2n - 1
-128 ⇒ 127
0 ⇒ 255
-2 147 483 648 ⇒ 2 147 483 647
0 ⇒ 4 294 967 296
2/3
...) ?
...) ?e
...) ?signe x mantisse x baseexposant
2
1
et inférieure à 2
. Un 1
initial est sous-entendu et non codé ⇒ 24 ou 53 bits en fait127
ou 1024
Librairie virgule flottante :
Exemple : calculer une courte distance sur la surface de la Terre (jusqu'à quelques dizaines de km)
Mémoire minimale nécessaire :
Habituellement :
Ce type d'environnement est destiné à des cartes plus proches d'une carte-mère d'ordinateur que d'une carte microcontrôleur
Mémoire minimale nécessaire :
Services disponibles :
(services analogues à ceux d'un OS)
Différence (très importante !) par rapport à un OS : pas de mémoire virtuelle.
Fournis par le RTOS, ou fournis en tant que services additionnels, et (souvent) nécessaires à un objet connecté :
Question : que fait le microcontrôleur lorsqu'il n'y a rien à faire ?
Réponse :
Question : et quand il y a quelque chose à faire ?
Réponse : interruptions et tâche de fond (interrupts and background task)
Question : qu'est-ce qui génère une interruption ?
Entrée :
Timer :
UART :
Conversion A/N :
etc.
Question : que se passe-t-il si une interruption se produit pendant qu'un gestionnaire d'interruption est actif ?
Réponse : cela dépend 🙂
Question : pourquoi des gestionnaires d'interruptions courts ?
Réponse :
Plus détaillé :
Dans beaucoup d'applications, il y a peu d'évènements.
Question : comment économiser de l'énergie ?
Réponse : dormir, entre deux évènements
Exemple : réception d'octets sur une liaison série
bool rec_byte_event = false;
uint8_t rec_byte;
rec_byte = get_byte_from_uart();
rec_byte_event = true;
while (true) {
...
if (rec_byte_event) {
rec_byte_event = false;
// Process rec_byte.
...
}
...
}
Que se passe-t-il si la tâche de fond a parfois trop de choses à faire, et ne peut pas vérifier assez souvent si un octet a été reçu ?
Des octets peuvent être perdus.
Solution habituelle :
Attention : le tampon est modifié par la routine d'interruption (quand un octet est reçu), et par la tâche de fond (quand les octets sont extraits du tampon)
Un bon moyen de gérer cela : un tampon circulaire, avec accès atomiques (voir plus loin)
Une façon de représenter un automate fini :
Format d'un message :
Décodage :
Une implémentation :
currentState = WAIT_DOLLAR;
while (true) {
c = getCharacter();
switch (currentState) {
case WAIT_DOLLAR:
if (c == '$') {
currentState = WAIT_G;
break;
}
// Other character, stay in this state.
break;
case WAIT_G:
if (c = 'G') {
currentState = WAIT_P;
break;
}
// Other character, go back to initial state.
currentState = WAIT_DOLLAR;
break;
case WAIT_P:
if (c = 'P') {
msgLength = 0;
currentState = WAIT_CR;
break;
}
// Other character, go back to initial state.
currentState = WAIT_DOLLAR;
break;
case WAIT_CR:
if (c == CR) {
currentState = WAIT_LF;
break;
}
// Other character, store into message.
addToMessage(c);
msgLength++;
break;
case WAIT_LF:
if (c == LF) {
processMessage(msgLength);
currentState = WAIT_DOLLAR;
break;
}
// Other character, go back to initial state.
currentState = WAIT_DOLLAR;
break;
default:
signalError(UNKNOWN_STATE);
currentState = WAIT_DOLLAR;
}
}
Un exemple réel : gestion de la connexion à un AP Wi-Fi pour l'ESP32 :
Plusieurs transitions non représentées, pour simplification.
Exemple typique d'utilisation : réception d'octets depuis une liaison série.
Une implémentation :
#define BUFFER_LENGTH 64
#define BUFFER_EMPTY -1
uint16_t inIndex;
uint16_t outIndex;
uint16_t dataLength;
uint8_t ringBuffer[BUFFER_LENGTH];
void initBuffer(void) {
inIndex = 0;
outIndex = 0;
dataLength = 0;
}
void putData(uint8_t data) {
ringBuffer[inIndex] = data;
// Move inIndex forward.
inIndex++;
if (inIndex == BUFFER_LENGTH) {
inIndex = 0;
}
dataLength++;
if (dataLength == BUFFER_LENGTH + 1) {
// Overflow. Move outIndex forward.
outIndex++;
if (outIndex == BUFFER_LENGTH) {
outIndex = 0;
}
dataLength--;
}
}
int getData(void) {
if (dataLength == 0) {
return BUFFER_EMPTY;
}
uint8_t dataToReturn = ringBuffer[outIndex];
dataLength--;
// Move outIndex forward.
outIndex++;
if (outIndex == BUFFER_LENGTH) {
outIndex = 0;
}
return dataToReturn;
}
Attention : si le tampon circulaire est partagé entre un gestionnaire d'interruption et la tâche de fond, rendre atomiques les modifications du tampon.
Exemple d'utilisation : messages GNSS
Bien entendu, automates et tampons circulaires s'utilisent également avec un RTOS ou un OS.