Les microcontroleurs (µC)
Unité de principale d’un système Embarqué
Un µC est principalement composé :
◦ d’une unité de calcul (CPU)
◦ de mémoires
◦ des ports d’entrée/sortie
◦ d’autres modules : Convertisseur, comparateur,
compteur/timer, interface de communication ..
Tout ça dans un petit chip (circuit intégré) avec une
consommation électrique faible (quelques milli-Watts) et
un coût peu élevé.
Les principaux fabricants de µC sont : Texas Instrument, STMicroelectronics,
Atmel, MicroChip, Intel.
Le microcontrôleur ATMega328p
C’est un µC fabriqué par ATMEL de la famille AVR 8bits et
ayant une architecture Advanced RISC à 16 MHz, composé de
FLASH : mémoire programme de 32Ko
SRAM : données (volatiles) 2Ko
EEPROM : données (non volatiles) 1Ko
3 ports digital (PortB[0..7], PortC[0..6], PortD[0..7] : 23 broches I/O
3 Timers/Counters : Timer0 et Timer2 (8 bits), Timer1 (16bits).
8 canaux analogiques multiplexées avec un CAN (10bits)
6 canaux PWM (Pulse Width Modulation): ~ sortie analogiques.
Interface sérielle TWI (Two Wire Interface) compatible I2C
Interface sérielle asynchrone (USART)
Interface sérielle synchrone (SPI Serial Peripheral Interface )
Comparateur Analogique
Watchdog Timer programmable.
Gestion d'interruptions (24 sources possibles (cf interrupt vectors)) :
- Interruptions liées aux entrées INT0 (PD2) et INT1 (PD3)
- Interruptions sur changement d'état des broches PCINT0 à PCINT23
- Interruptions liées aux Timers 0, 1 et 2 (plusieurs causes configurables)
- Interruption liée au comparateur analogique
- Interruption de fin de conversion ADC
- Interruptions du port série USART
- Interruption du bus TWI (I2C)
Configuration et Architecture
ATMega328P
Configuration mémoire ATMega328p
Trois espaces mémoire :
◦ (32 k) Mémoire Flash (Flash Program Memory)
bootloader (512 octets) dans une section séparée (adresses hautes)
organisée en 256 pages de 64 mots de 2 octets (instructions sur 1 ou 2
mots)
10 000 cycles d’écriture/effacement mini
accès via le bus SPI
◦ (registres + 2 k) Mémoire SRAM (SRAM Data Memory)
organisée en mots de 8 bits
stockage des registres : 32 + 64 + 160 = 256
le reste est dédié à l’exécution du programme
◦ (1 k) EEPROM pour stockage de long terme
I organisée en 256 pages de 4 mots de 1 octet
100 000 cycles d’écriture/effacement mini
accès via le bus SPI
Configuration de la carte Arduino Uno
Version : Revision 3 • Mémoire: (ATMega328p)
- flash: 32 KB
Microprocesseur: ATMega328 16MHz
- SRAM: 2 KB (Volatile)
Oscillateur : quartz 16Mhz - EEPROM: 1 KB (Non volatile)
Broches(PINS) multi-fonctions :
•Alimentation:
- 14 broches entrées/sorties
numériques (dont 6 utilisables en via port USB 5 volts
sorties PWM)
via port jack: 7 à 12 volts
- 6 entrées analogiques 10 bits
(utilisables en E/S numériques) tension limite: 6-20 volts
intensité max par broche
• Bus: E/S (5 volts): 40
- bus UART mA (ATTENTION : 200mA cumulé
- bus I2C pour l'ensemble des broches
- bus SPI E/S)
Connecteurs/boutons: intensité max pour la
- 1 connexion USB B (ATMega16u) pin 3,3v: 50mA
- 1 connecteur d'alimentation jack intensité max pour la pin 5v:
- 1 connecteur ICSP 500mA (Si alimenté via USB
- 1 bouton (Reset) seul)
• Dimensions:
- 74 x 53 x 15 mm
Programmation Arduino
Environnement de developpement
(Arduino) :
Editeur de source (sketch)
Compilateur AVR GCC(C/C++)
Outils de chargement du programme
via une liaison seriel USB
Moniteur série : pour suivre les traces
d’exécution
Le programme source étant constitué de :
Partie déclaration globale : bibliothèque ,
macro (#define), variables, constantes et
types.
Procédure void setup() : exécuté une
seule fois au démarrage de la carte. Doit
contenir les initialisations (configuration
des ports ER/S, timer, interrupts...)
Procédure void loop() : Traitement en
boucle infinie
Type du langage C (Arduino)
boolean : true/false (8 bits)
char = entier 8 bits signé [-128,+127] (codes ASCII)
byte / unsigned char : entiers 8 bits non signés [0,255]
int : entiers 16 bits signés [-32768,+32767]
word / unsigned int : entier 16 bits non signé [0,65535]
long : entiers 32 bits signé
unsigned long : entiers 32 bits non signés
float /double : flottant format IEEE 32 bits
Fonctions courantes fournies par ARDUINO
Constantes : HIGH, LOW, INPUT, INPUT_PULLUP, OUTPUT
Digital I/O (gestion entrées/sorties binaires)
◦ pinMode(pin,mode) : configure le pin en mode INPUT/OUTPUT/INPUT_PULLUP
◦ digitalWrite(pin,value) : Met en sortie du pin la valeur (HIGH/LOW )
◦ int digitalRead(pin) : retourne la valeur en entrée du pin;
Analog I/O (gestion entrées/sorties analogique)
◦ int analogRead (pin) : retourne la valeur (0-1023) correspondant à un connecteur
analogique (pin)
◦ void analogWrite (pin, value) : fournie une valeur (0..255) sur sortie PWM
Temporisations
◦ delay(unsigned long ms) : delai de ms milli secondes avec ms sur 32 bits
◦ delayMicroseconds(unsigned int ms) : delai de ms microsecondes avec ms sur 16 bits
◦ unsigned long micros() : nombre de micro secondes depuis démarrage. Revient à zéro
tous les 70mn environ.
◦ unsigned long millis() : nombre de milli secondes depuis démarrage. Revient à zéro tous
les 50 jours environ.
Fonction Moniteur sériel (USART) : Objet (Seriel)
◦ Serial.begin(Vitesse) : Initialisation et configuration de la liaison sériel (300, 600, 1200, 2400,
4800, 9600, 14400, 19200, 28800, 38400, 57600, 115200 bauds (Bit par seconde) )
◦ Serial.write() : écriture d’un octet ou d’une chaîne de caractères,
◦ Serial.print() : écriture de n’importe quelle valeur convertible en chaîne de caractères,
◦ Serial.println(): comme Serial.print(), mais avec un retour à la ligne à la fin.
Exemple 1 : Feu de circulation
#define LedR 5
#define LedV 4
#define LedJ 3
void setup() {
pinMode(LedR,OUTPUT);
pinMode(LedV,OUTPUT);
pinMode(LedJ,OUTPUT);
}
void loop() {
digitalWrite (LedR, HIGH);
delay (1000);
digitalWrite (LedR, LOW);
digitalWrite (LedV, HIGH);
delay (1000);
digitalWrite (LedV, LOW);
digitalWrite (LedJ, HIGH);
delay (1000);
digitalWrite (LedJ, LOW);
}
Exemple 2 : Commande LED au moyen d’un
bouton poussoir en montage PULLDOWN
#define LedR 8 // Led Rouge
#define PBtt 2 // Bouton poussoir
byte PBttV = 0 ;
void setup() {
pinMode (LedR, OUTPUT);
pinMode (PBtt, INPUT);
}
void loop() {
PBttV=digitalRead(PBtt);
digitalWrite(LedR, PBttV);
// digitalWrite(LedR, digitalRead(PBtt));
}
Exemple 3 : Commande LED au moyen d’un
bouton poussoir en montage PULLUP
#define LedR 8 // Led Rouge
#define PBtt 2 // Bouton poussoir
byte PBttV ;
void setup() {
pinMode (LedR, OUTPUT);
pinMode (PBtt, INPUT_PULLUP);
}
void loop() {
PBttV=digitalRead(PBtt);
digitalWrite(LedR, ! PBttV);
//digitalWrite(LedR, ! digitalRead(PBtt));
}
Exemple 4 : Commande LED par interruption suite
au changement d’état d’un bouton poussoir en
montage PULLUP
#define LedR 8
#define PBtt 2
byte LedState = LOW ;
void setup() {
pinMode (LedR, OUTPUT);
pinMode (PBtt, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(PBtt), Blink, CHANGE);
// LOW, CHANGE, RISING, FALLING
}
void loop() {
digitalWrite(LedR, LedState);
}
void Blink() {
LedState = ! LedState ;
}
Exemple 5 : Commande Leds en fonction de la température
mesurer à l’aide d’un capteur analogique TMP36
([0.1, 2.0]V [-40 , 150]°C)
Fonctions transferts :
#define LedR 5 (1) Capteur : Us = F(T) = 0.01 *T + 0.5
#define LedV 4
(2) CAN Arduino (10 Bits,Vref=5) : Ecan = G(Scan) = Scan * 5/1023
#define LedJ 3
#define TMP36 A0
La sortie du capteur est connecter à l’entrée du CAN Us = Ecan
void setup() {
pinMode(LedR,OUTPUT); Fonction Globale : T = 100 * (-0.5 + Scan * 5/1023 )
pinMode(LedV,OUTPUT);
pinMode(LedJ,OUTPUT); Scan analogRead(Pin)
}
void AllumerLed(byte Led) {
digitalWrite (LedR, Led==LedR);
digitalWrite (LedR, Led==LedV);
digitalWrite (LedV, Led==LedJ);
}
float CalculerTemp() {
float Res;
Res = 100 * (-0.5 + anlogRead(TMP36)*5.0/1023.0);
return Res ;
}
void loop() {
float T = CalculerTemp();
if ( T < 15.0) AllumerLed(LedJ) ;
else if ( T < 30.0) AllumerLed(LedV) ;
else AllumerLed(LedR) ;
delay(1000); }
Exemple 6 :
Liaison Série UART
// Arduino Serial Example : Remote Control
Blink - Master
byte buttonSwitch1 = 14; // A0
byte buttonSwitch2 = 15; // A1
boolean buttonState1 = false;
boolean buttonState2 = false;
boolean buttonState1_old = false;
boolean buttonState2_old = false;
void setup() {
Serial.begin(9600); // Config. Vitesse de transmission à 9600 Bit/s (Bauds)
}
void loop() {
buttonState1 = digitalRead(buttonSwitch1);
if (buttonState1 != buttonState1_old) {
buttonState1_old = buttonState1;
if (buttonState1 == HIGH) { Serial.print(1);}
else { Serial.print(0);}
}
buttonState2 = digitalRead(buttonSwitch2);
if (buttonState2!= buttonState2_old) {
buttonState2_old = buttonState1;
if (buttonState2 == HIGH) { Serial.print(3);}
else { Serial.print(2); }
}
}
// Arduino Serial Example Remote Control Blink - Slave
char c = ' ';
byte LED1 = 2;
byte LED2 = 3;
void setup() {
pinMode(LED1, OUTPUT);
pinMode(LED2, OUTPUT);
Serial.begin(9600); // Config. à la même Vitesse de transmission
// à 9600 Bit/s (Bauds)
}
void loop() {
if(Serial.available()) {
char c = Serial.read();
if (c=='0') digitalWrite(LED1, LOW);
if (c=='1') digitalWrite(LED1, HIGH);
if (c=='2') digitalWrite(LED2, LOW);
if (c=='3') digitalWrite(LED2, HIGH);
Serial.println(c);
}
}
Bus I2C: Inter Integrated Circuits
Connu sous le nom de bus TWI (Two Wire Interface)
Composé de trois fils pour fonctionner :
signal de données : SDA ;
signal d’horloge : SCL ;
une référence (masse).
Fonctionnement : maître/esclaves.
Chaque périphérique a une adresse (7 bits) sur le bus
Gestion du Bus I2C via la bibliothèque Wire Library ou les bibliothèques
associé à certains capteur/actionneurs (Ex : LiquidCrystal_I2C)
Exemple 7: Mesure et affichage température &
humidité
void loop()
{
#include <DHT.h>;
#include <LiquidCrystal_I2C.h> hum = dht.readHumidity();
temp= dht.readTemperature();
#define DHTPIN 2 // PIN SDA
#define DHTTYPE DHT22 // DHT 22 lcd.setCursor( 0, 0); lcd.print("Temperat:");
lcd.setCursor(10, 0); lcd.print(temp);
// Création et Initialisation Objet dht
DHT dht(DHTPIN, DHTTYPE); lcd.setCursor( 0, 1); lcd.print("Humidity:");
lcd.setCursor(10, 1); lcd.print(hum);
#define I2C_ADDR 0x27
#define N_COLS 16 delay(2000); //Delay 2 sec !!!.
#define N_LINES 2 }
// Création et Initialisation Objet lcd
LiquidCrystal_I2C lcd(I2C_ADDR, N_COLS, N_LINES);
//Variables
float hum; //Stores humidity value
float temp; //Stores temperature value
void setup()
{
dht.begin();
lcd.init();
lcd.backlight();
}
Programmation multitâches avec la librairie
FreeRTOS (Real Time Operating System)
FreeRTOS : est une couche du système d’exploitation
◦ Offre les services nécessaire à l’implémentation et l’exécution de
plusieurs tâches concurrentes (task) au sein d’un même processus
(programme en cours d’exécution) .
◦ Intègre un ordonnanceur (Scheduler) appliquant les algorithmes
d’ordonnancements des tâches selon plusieurs stratégie (FCFS, SJN,
RR, Priority, …)
◦ Répond aux besoins des solutions dites temps réel pour lesquelles
les réponses du programme sont soumis à des contraintes de
temporelle.
◦ Assure une meilleure flexibilité du programme.
◦ Simplifier le contrôle des périphériques (Capteurs/Actionneurs).
◦ Augmente le niveau d’efficacité, modularité et extensibilité du
programme.
Programmation multitâches avec la librairie
FreeRTOS (Real Time Operating System)
Bibliothèque : Arduino_FreeRTOS.h
A chaque tâche on associe Une fonction
déclarer selon la syntaxe :
void fncTask( void *pvParameters )
{… }
Création d’une tâche au moyen de la
primitive :
xTaskCreate(
void pvfncTask, // nom de la fonction
char * pcName, // nom de la tâche
unsigned usStackDepth, // default 128
void *pvParameters, // default NULL
UBaseType_t uxPriority, // priorité
TaskHandle_t *pxHTask //default NULL
);
Exemple 8 : Contrôle de 3 leds en multitâches
void setup() {
#include <Arduino_FreeRTOS.h> pinMode(LedR,OUTPUT);
#define LedR 5 pinMode(LedV,OUTPUT);
#define LedV 4 pinMode(LedJ,OUTPUT);
#define LedJ 3 xTaskCreate (TaskR, “Rouge", 128, NULL, 1, NULL);
xTaskCreate (TaskV, “Verte", 128, NULL, 1, NULL);
void TaskR(void *prm) { xTaskCreate (TaskR, “Jaune", 128, NULL, 1, NULL);
byte Etat= HIGH; vTaskStartScheduler();
while (1) { }
digitalWrite (LedR, Etat);
Etat=!Etat;
vTaskDelay(1000 /portTICK_PERIOD_MS);
}
}
void TaskV(void *prm) {
byte Etat= HIGH;
while (1) {
digitalWrite (LedV, Etat);
Etat=!Etat;
vTaskDelay(2000 /portTICK_PERIOD_MS);
}
}
void TaskJ(void *prm) {
byte Etat= HIGH;
while (1) {
digitalWrite (LedJ, Etat);
Etat=!Etat;
vTaskDelay(3000 /portTICK_PERIOD_MS);
}
}
Exemple 8 - bis: Contrôle de 3 leds en multitâches
#include <Arduino_FreeRTOS.h>
byte LedR=5;
byte LedV=4;
byte LedJ=3;
void TaskX(void *prm) {
byte Etat= HIGH;
while (1) {
digitalWrite (*((byte *)prm), Etat);
Etat=!Etat;
vTaskDelay(1000 /portTICK_PERIOD_MS);
}
}
void setup() {
pinMode(LedR,OUTPUT);
pinMode(LedV,OUTPUT);
pinMode(LedJ,OUTPUT);
xTaskCreate (TaskX, “Rouge", 128, (void *)&LedR, 1, NULL);
xTaskCreate (TaskX, “Verte", 128, (void *)&LedV, 1, NULL);
xTaskCreate (TaskX, “Jaune", 128, (void *)&LedJ, 1, NULL);
vTaskStartScheduler();
}
void loop() {
}