Micro-contrôleur – 2/ Les périphériques

Micro-contrôleur – 2/ Les périphériques

 Convertisseur Analogique vers Numérique (A/D)

Ce dernier permet de donner une valeur numérique à une information de type analogique. Si l’alimentation de l’ADC est de 5V et qu’il s’agit d’un convertisseur 10 bits, alors un signal d’entrée variant de 0 à 5V sera converti, de façon linéaire, en une valeur numérique variant de 0 à ((2^10) -1) bits soit 1023. Attention bien sur, à vérifier la fréquence d’échantillonnage. En fonction des variations du signal d’entrée, il faudra venir lire plus ou moins rapidement la valeur de l’ADC.

Niveau débutant

Pour apprendre à utiliser une telle fonction, lançons nous dans un exemple : mesurer une température !
Objectif : lire une température de -40°C à 120°C
Matériel :

  • Arduino Mega2560 (arduino basé sur notre micro-contrôleur exemple : le ATMEGA2560) Afficher l'image d'origine
  • sonde PT1000, Un résistance qui varie en fonction de la température, elle nous servira ici de capteur (on suppose que la sonde est parfaitement linéaire, sa résistance est de 820Ω à -40°C et de 1460Ω à 120°C).

Le capteur présente donc une première conversion de la température en résistance :

temp_resistancePour utiliser toute la plage en tension de mon convertisseur ADC, je dois convertir cette plage de résistance en une plage en tension de 0 à 5V. Pour cela j’utilise un montage électronique suivant:

pt1000_arduino

En simplifié*:
V- = (R3/(R3+R1)*5V=2.5V
V+ = (R4/(R4+R2)*5V varie de 2.5V à 3.3V quand la sonde R4 (PT1000) varie de 820Ω à   1460Ω
La tension différentiel (V+ – V-) varie donc de 0 à 700mV. On utilise l’amplificateur d’instrumentation INA114 pour amplifier la différence (V+-V-) par 7.25 (soit R5=8kΩ)

*remarque montage électronique :
Il s’agit ici de faire un montage simple pour montrer que la conversion est  nécessaire.
Nous avons considéré des alimentions parfaites, mais en pratique les variations en température entrainent des variations des alimentations. Pour concevoir un design électronique plus sérieux, il faudrait :
-réaliser un montage ratio-métrique (c’est a dire prendre en compte les variations de l’alimentation 5V dans la mesure)
-protéger l’ADC d’éventuelles surtensions,
-rajouter un étage de filtrage (réduire les perturbations)…

simu_pt1000_arduino

La simulation LTSPICE ci dessus nous permet de confirmer que ce montage converti notre plage de résistance en une plage de tension de 0 à 5V.

Ce signal peut maintenant être envoyé sur la pin d’entrée Analogique du microcontrôleur !
La fonction arduino « AnalogRead » prend en entré le numéro de la pin à lire et elle renvoit la valeur numérique interprétée :

tension_numerique

Dernière étape : retrouver la valeur de la température !
Pour cela on peut utiliser la fonction arduino « map » elle permet de faire facillement le transfert linaire d’une unité à une autre :
Premier paramètre: valeur numérique lue sur l’entrée analogique
Ensuite les paramètres de la droite de conversion linéaire : x1, x2, y1, y2.
Dans notre cas : x1=0; x2= 1023; y1=-40°C;  y2=120°c
map(temperature_en_numerique , 0,1023,-40,120);
La fonction renvoie donc la valeur correspondante.

nume_temp

Au bilan, le code suivant permet d’effectuer la lecture de la température toutes les 500ms:

#define Sensor_pin=0;
int Temperature=0;

void setup() 
{
pinMode(Sensor_pin,INPUT);
}

void loop() 
{
  // put your main code here, to run repeatedly:
Temperature=map(analogRead(Sensor_pin),0,1023,-40,120);
delay(500);
}
Lecture_temperature

Niveau intermédiaire

Cette fonction « analogRead » fonctionne sur toute les cartes arduino sans même que vous n’ayez besoin d’une seule ligne de code en plus…

On peut se demander comment cela est possible alors même que les cartes Arduino embarquent des micro-contrôleur différents…

but-how

Et bien arduino vous cache des choses… Pour vous simplifier la vie, une partie du code est caché (mais pas trop quand même). La page présenté à l’ouverture d’arduino a une fonction « setup » toute prête pour vos initialisation et une fonction « loop » équivalente du habituel « main ». Sauf que derrière tout ça, d’autre code est chargé dans le micro-contrôleur.

Vous pouvez tout de même accéder aux fonctions arduino en fouillant un peu dans les dossiers arduino :
votre dossier arduino\hardware\arduino\avr\cores\arduino\wiring_analog.c
en ouvrant le fichier « wiring_analog.c », on trouve la définition de la fonction AnalogRead()

analof_read

On voit que des commandes types « #if define » sont utilisées.
Ces commandes en « # » (on évitera de prononcer « HTAG » on est pas sur twiter) sont appelées directives de préprocesseur : elles ne sont pas des commandes destinées au processeur mais bien au compilateur !
Elles sont très utiles pour gérer des configurations.
Ainsi, avec l’aide de ces directives, la fonction trouve toute seule les ressources hardware du micro-contrôleur qui correspondent à la carte Arduino que vous avez choisie. Il vous suffit de sélectionner sous Arduino « Outil/Type de carte ».

Pour aller plus loin

La datasheet nous fournit un chapitre pour chaque périphérique et nous indique comment configurer le périphérique via ses registres.La photo ci dessus montre le schémas bloc du périphérique ADC de l’ATMEGA2560.

adc_arduino
On retrouve bien en haut du schéma le DATABUS 8Bits (Direct Memory access) pour s’interfacer avec le micro-processeur.
Ce dernier contrôle 4 registres sur l’ADC le  ADCMUX , le ADCSRB le ADCSRA et le ADCH/ADCL.

admux_aduino

Les bitsREFS1 et REFS2 pilotent un multiplexer qui choisit l’alimentation de l’ADC.

vref_adc_aduino

Le Bit ADLAR permet de présenter le résultat de la conversion ajusté à droite ou à gauche (comme le résultat de la conversion fait 10bits et est stocké dans un registre de 16bits, la data est « décallé » à gauche ou à droite). On laisse la valeur par défaut. Les bits MUX0 à MUX4 permettent, via un multiplexer, de sélectionner la pin à convertir parmi  les 15 entrées analogiques. Le micro-contrôleur est ainsi capable de numériser 15 informations directement. Dans le cas on l’on a plusieurs entrées analogiques à lire, il faudra d’autant plus surveiller les temps de conversions).

adcsrb_arduino

Le bit MUX5 va avec les autres bit MUX pour définir la pin d’entrée choisie mais aussi un gain suivant la table 24-4 de la datasheet de l’ATMEGA2560.
Les bits ADTS permettent de sélectionner la source du déclenchement en mode déclenchement automatique.

adcsra_arduino

Le bit ADEN doit être mis à 1 pour activer l’ADC.
Le bit ADSC doit être mis à 1  pour commencer la conversion (Start Conversion), il retourne tout seul à 0 à la fin de la conversion.
Le bit ADATE (Auto Trigger Enabled) permet de déclencher automatiquement une conversion (source du déclenchement défini dans ADCSRB par ADTS)
Le bit ADIF (Interrupt Flag) est mis à 1 quand la conversion est terminée et que la donnée est disponible dans le registre de sortie (ADCH/ADCL). Cette fonction n’est activée que si le bit ADIE  (Interrup Enable) est activé ainsi que le bit I de SREG. Le bit ADIF repasse à 0 automatique à l’exécution de l’interruption.
Le bit ADIE (Interupt Enable) mentionné ci dessus.
Le bits ADPS permettent de choisir la valeur du prescaler (c’est a dire la fréquence de fonctionnement du périphérique ADC). Ces bits conditionnent directement le temps de conversion.On considère 13 coups d’horloge pour faire une conversion analogique/numérique (25 pour la première conversion).
Avec un prescaler de 128, la fréquence du CPU est divisé par 128 soit 16MHz/128 =125kHz soit 8us le coup d’horloge donc 13*8 =104us pour faire une conversion.
Alors on pourrait se dire  : avec un prescaler de 4, la fréquence du CPU est divisé par 4 soit 16MHz/4=4MHz soit 25ns le coup d’horloge donc 13*25 =325ns pour faire une conversion.Mais ça ne fonctionnera pas puisque la datasheet nous dit aussi que pour une résolution de 10 bit, on ne peut pas excéder les 200kHz…
Si l’on regarde nos valeurs de prescaler et notre 16MHz de freq CPU on obtient les possibilités suivantes:

  • 16 MHz / 2 = 8 MHz
  • 16 MHz / 4 = 4 MHz
  • 16 MHz / 8 = 2 MHz
  • 16 MHz / 16 = 1 MHz
  • 16 MHz / 32 = 500 kHz
  • 16 MHz / 64 = 250 kHz
  • 16 MHz / 128 = 125 kHz

Donc pour 10 bit de résolution, la seule possibilité est le prescaler à 128 et on obtient 125kH soit 125kH divisé par 13 coups d’horloge 96 mesures par milliseconde.
Si l’on a  la possibilité de changer la fréquence du CPU à 12MHz avec le prescaler 64 on obtient 187kHz divisé par 13 coups d’horloge 143 mesures par milliseconde.
On est plus rapide sur la conversion de l’ADC mais on en perd sur le reste du code puisque le CPU tourne plus lentement…Le constructeur a cependant rédigé une application note indiquant que des fréquences inférieures au Méga Hertz ne diminue pas « de façon significative » la résolution de l’ADC.
On le voit donc, il s’agit d’un compromis entre rapidité et précision.
On pourra choisir un prescaleur entre 16 et 128 pour une fréquence entre 125kH et 1MHz donc entre 93 et 769 mesures par milliseconde.Dans le cas ou la mesure est lente (prescaler fort), il sera plus judicieux d’utiliser l’interruption sur le bit ADIF. Le processeur peut ainsi, lancer l’ordre de conversion, exécuter d’autres commandes pendant la durée de conversion, il est ensuite alerté par le BIT ADIF que la data est disponible, il vient alors la lire et retourne au reste du code.
Dans l’exemple de code donnée avec le analogRead de la température on estime que l’instruction analogRead prend 100us  (elle est « bloquante » pendant les 100us, puisque le pocesseur « attend » la fin de la conversion).

On peut donc passer de analogRead avec ses 10 mesures par milliseconde à une configuration jusqu’à 769 mesures par milliseconde.

Ce qu’il faut retenir : tout dépend de vos besoins, il est évident que pour mesurer l’évolution d’une température, la gestion du temps processeur n’est pas critique et la fonction analogRead toute prête convient très bien. En revanche, si vous voulez surveiller des signaux rapides, il va falloir étudier le fonctionnement du périphérique dans la datasheet du constructeur pour optimiser le temps de conversion et l’activité du processeur.

Les Timers/Compteurs

Niveau débutant

Les timers/counter sont des éléments essentiel dans la gestion d’une application embarquée.

Pour comprendre le rôle d’un timer, lançons nous dans une analogie !

Pour faire une recette de cuisine, vous exécutez les instructions de la recette, de la même façon, le processeur exécute les lignes de code. Dans votre recette on vous demande de mettre le gâteaux au four et de le laisser la 40 minutes. Dans ces cas la, nous humain, nous ne restons pas « plantés » devant le four à ne rien faire pendant 40 minutes… Nous vaquons à nos occupations en attendant que le minuteur du four sonne. Et bien c’est pareil pour le processeur, vous devez « gérer son planning » si vous ne voulez pas qu’il se retrouve à attendre bêtement sans rien faire d’autre.
Vous allez donc demander à votre processeur de lancer un minuteur et de faire le reste de ses occupations en attendent le signal de fin du minuteur. Ici Il faudra donc commander le périphérique de Timer Counter.

 

Niveau intermédiaire

Nous allons voir une application simple d’un timer.
On souhaite réaliser un programme qui fait clignoter une LED toute les 500 millisecondes et qui, en même temps, fait tourner un servo-moteur.

Voici un code très basique pour faire clignoté une LED :

void setup() 
{
  // initialize digital pin LED_BUILTIN as an output.
pinMode(LED_BUILTIN, OUTPUT);
}

// the loop function runs over and over again forever
void loop() 
{
 digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
 delay(1000);                       // wait for a second

 digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
delay(1000);                       // wait for a second
}
LED_Blink

 

Aucun soucis, la led va clinoter toute les 500ms. Maintenant rajoutons l’action de déplacement du servo moteur : (on utilise la library Servo.h et on affecte le pilotage du servo-moteur à la pin 9)

Sans Timer :

#include <Servo.h>
Servo myservo;  // create servo object to control a servo
// twelve servo objects can be created on most boards
int pos = 0;    // variable to store the servo position
void setup() {
  myservo.attach(9);  // attaches the servo on pin 9 to the servo object
   pinMode(LED_BUILTIN, OUTPUT);
}
void loop() {
  for (pos = 0; pos <= 180; pos += 1) { // goes from 0 degrees to 180 degrees
    // in steps of 1 degree
    myservo.write(pos);              // tell servo to go to position in variable 'pos'
    delay(15);                       // waits 15ms for the servo to reach the position
  }
  for (pos = 180; pos >= 0; pos -= 1) { // goes from 180 degrees to 0 degrees
    myservo.write(pos);              // tell servo to go to position in variable 'pos'
    delay(15);                       // waits 15ms for the servo to reach the position
  }
  digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
  delay(1000);                       // wait for a second
  digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
  delay(1000);                       // wait for a second
}

Résultat de ce programme :
La led s’allume pendant 500ms (le servomoteur est immobile).
La led s’éteint pendant 500ms  (le servomoteur est immobile).
Le servomoteur bouge de 0° à 180 ° (la LED reste éteinte).
Le servomoteur bouge de 180° à 0° (la LED reste éteinte).
Le programme ne fait pas les deux « en même temps » il attend dans la fonction « delays » sans rien faire d’autre.

C’est la q’intervient le Timer/counter ! Nous allons le programmer pour nous dire de faire une action toute les 500ms.
Comme tous les périphériques, le Timer/counter sera configuré via ses registres (présentés dans la datasheet du micro-contrôleur).

Pour aller plus loin

Implémentation du Timer :

  • Etape 1 : Choisir un le Timer/Counter

Les termes timer et counter sont associés parce que ces instruments permettent de compter le temps.
En fait, par « compter le temps » on veut dire compter les impulsions de l’horloge du microcontrôleur.

Prenons l’exemple de notre ATMEGA2560 cadencé à 16MHz : cela signifie que le signal généré par le quartz sur la carte électronique possède une fréquence de 16MHz soit une pulsation toute les 62,5 nanosecondes….
Si je veux compter un temps de 1 milliseconde je devrait compter (1 ms/ 62.5ns) soit 16000 « tick ». Or les timers possèdent une limitation. On peut par exemple trouver des timers 8bits ou 10bits capables de compter respectivement jusqu’à 255 et 1023 (donc insuffisant pour compter 16000 « tick »).
C’est pourquoi on a recours à un « prescaler ». Le « prescaler » permet justement de diviser l’horloge d’entrée d’un facteur choisi (en général 1,2,4,8 ou 16).
Reprenons notre comptage de 1 milliseconde, cette fois ci j’applique un prescaler de 16. Ma fréquence d’entré dans mon compteur est donc de 16MHz/16 soit
1 MHz, soit une période de 1 microseconde. J’ai donc besoin d’en compter 1000 pour atteindre une milliseconde. C’est possible avec un timer 10bits (qui va jusqu’à 1023).

Nous avons vu que pour utiliser un Timer il faut veiller à choisir un des Timer/Counter qui convient avec le bon prescaler (suivant le besoin de comptage et l’horloge de votre cible).

Il y a un autre élément à prendre en compte : la gestion des ressources.
Lorsqu’on utilise des librairies on gagne énormément de temps mais il faut aussi regarder quelles sont les ressources matérielles utilisées par ces librairies. Dans notre exemple nous utilisons la Library « Servo.h » qui nous permet facilement de piloter des servo-moteurs.
Il se trouve que cette librarie utilise des timer/counter pour générer les signaux de commande des servo-moteur. Si nous utilisons le même Timer que celui de la librairie, le code ne pourra pas fonctionner comme nous le voulons. En fait le code que l’on écrit nous même et le code de la Library risquent de configurer à différents moments le même timer ce qui entraînerai  un comportement aléatoire.
Maintenant que les contraintes sont identifiées, choisissons un Timer : le ATMEGA2560 nous propose en tout 5 périphériques de Timer/Counter numérotés de 0 à 5.

Le Timer/Counter 0 est un timer 8 bits donc pas intéressant pour nous, et en plus, il est utilisé pour les fonctions arduino  :__delay()__, __millis()__ et__micros()__.
Le Timer/Counter 5 est utilisé par la Library « Servo.h ».
Le Timer/Counter 2 est un timer 8 bits un peu particulier avec des fonctions supplémentaires.

 On peut choisir les Timer/Counter 1,3 ou 4 qui sont 16bits. Allons y pour le Timer/Counter 1  !

  • Etape 2 : Configuration du Timer Counter

Prenons donc la documentation technique de notre Timer/Counter1 sur ATMEGA2560.

Le constructeur nous propose la vu suivante du périphérique TIMER1.
Nous, utilisateur, avons accès aux registres via le databus à gauche du schéma. Ces registres sont les suivants : TCNT1, OCR1A, OCR1B, OCR1C,TCCR1A, TCCR1B,TCCR1C.
En sortie du périphérique Timer on trouve 3 signaux OC1A, OC1B, OC1C.
Dans notre cas, nous n’avons besoin que d’un signal qui changera d’état toute les millisecondes :OC1A.

Passons à la configuration :

A) Le Prescaler  

Il faut assigner la valeur correspondante aux bits CS12;CS11,CS10.

Ce qui donne : 

TCCR1B |=(1<<CS11)|(1<<CS10); //Prescaler 64
Prescaler_timer_arduino

Si cette écriture condensé ne vous parle pas voici une explication détaillée étape par étape :

B) Le mode de fonctionnement

Les Timers possèdent deux principaux modes :

  • Mode PWM pour (Pulse With Modulation) dans ce mode-là, on peut utiliser les timers pour générer des signaux PWM sans monopoliser le processeur. Les PWM sont très utilisés en électronique. Par exemple la Library « Servo.h » utilise ce mode la sur le Timer5 afin de contrôler un servomoteur. Ce n’est pas le mode qui nous intéresse ici.
  • Mode CTC pour « Clear Timer on Compare match ». On vient remettre à 0 le compteur du timer quand celui-ci a atteint la valeur spécifiée

Il faut assigner la valeur correspondante aux bits CS12;CS11,CS10.

Ce qui donne :

TCCR1B |= (1<<WGM12); //Mode CTC Clear Timer on Compare Match
Timer_Mode_Arduino
C) Registre de comparaison

A ce stade, nous avons configuré notre Timer avec une horloge de 16MHz divisée par un prescaler de 64 ce qui nous donne 250kHz. Nous devons donc compter 250 pulsations pour atteindre 1 milliseconde. On charge la valeur 250 dans le registre OCR1A.

OCR1A=250; //Comparator Value
Timer_Compar_Arduino
D) Activer l’interruption sur le Timer

Maintenant que nous avons réglé notre minuteur, la sortie OC1A va changer d’état chaque milliseconde. Il nous faut maintenant s’assurer que l’événement sera géré par le processeur.
Pour ce faire, nous allons associer une interruption à la sortie OC1A du Timer. C’est à dire que, quoi que fasse le processeur, si OC1A change d’état, le processeur met pause son activité et va immédiatement exécuter la fonction de gestion de cette interruption (« interrupt Handler ») avant de revenir à son activité initiale.
On configure le registre de gestion des interruptions du timer1 :

Ce qui donne :

TIMSK1 |= (1<<OCIEA);//Enable Timer Interrupt
Timer_Interrupt_Arduino
E) Bilan config Timer

Voici donc le code de configuration du timer, on veillera à désactiver les interruptions avant de commencer la configuration et à les réactiver ensuite. Cela nous permet de ne pas déclencher d’interruptions de façon intempestive.

  /*CONFIG TIMER*/
  noInterrupts();//First disable interrupt to avoid unpredicted interrupt trig
  TCCR1A=0;
  TCCR1B=0;
  TCNT1=0;
  TCCR1B|=(1<<WGM12); // MODE CTC Clear Timer on Compare match
  TCCR1B|=(1<<CS11)|(1<<CS10);//Pre-Scaler at 64 so 16MHz/64=250KHz
  OCR1A=250; // Set compare value to 250 ( on millisecond timer duration)
  TIMSK1|=(1<<OCIE1A);// Enable Interrupt on compare match (OC1A output)
  interrupts(); //Global interrupt enable
Arduino_Timer_config

Programme final : nous allons nous servir de cette interruption pour décharger le processeur de ces « delay() ».

#include <Servo.h>
#include <avr/sleep.h>
#define PIN_LED 13
#define PIN_SERVO 2
Servo myservo;  // create servo object to control a servo
int pos = 0;    // variable to store the servo position
int CPT_LED_ms=0;  //Millisecond counter
int CPT_servo_ms=0;//Millisecond counter
bool sens=true;
void setup() 
{
  /*INOPUT/OUTPUT Configuration */
  myservo.attach(PIN_SERVO);  // attaches the servo on pin 9 to the servo object
  pinMode(LED_BUILTIN, OUTPUT);
  
  /*CONFIG TIMER*/
  noInterrupts();//First disable interrupt to avoid unpredicted interrupt trig
  TCCR1A=0;
  TCCR1B=0;
  TCNT1=0;
  TCCR1B|=(1<<WGM12); // MODE CTC Clear Timer on Compare match
  TCCR1B|=(1<<CS11)|(1<<CS10);//Pre-Scaler at 64 so 16MHz/64=250KHz
  OCR1A=250; // Set compare value to 250 ( on millisecond timer duration)
  TIMSK1|=(1<<OCIE1A);// Enable Interrupt on compare match (OC1A output)
  interrupts(); //Global interrupt enable
}
//Timer 1 Interrupt Handler
ISR(TIMER1_COMPA_vect) //select the TIMER1_COMPA_vect interrupt from the interrupt manager
{
CPT_LED_ms++;
CPT_servo_ms++;
  //GESTION LED
  if(CPT_LED_ms>=500)
  {
  digitalWrite(PIN_LED,!digitalRead(PIN_LED));
  CPT_LED_ms=0;//reset millisecond counter
  }
  
  //GESTION Servo
  if(CPT_servo_ms>=15)
  {
    if(sens==true)//sens is true
    {
      if(pos<=176) // position is under 176
      {
       pos++;
       myservo.write(pos);
      }
      else //pos is above180
      {
       sens=false; // change sens
      }
    }
    else //sens is false
    {
      if(pos>0) // position is above 0
      {
       pos--;
       myservo.write(pos);
      }
      else //pos is 0
      {
       sens=true; //change sens
      }
    } 
  CPT_servo_ms=0;//reset millisecond counter  
  }
 }
void loop() 
{
set_sleep_mode(SLEEP_MODE_IDLE);
sleep_mode();// This fonction set the sleep enable to 1, then sleep the CPU and set back the sleep enable to 0 (before sleeping). This means the CPU is sleeping but the sleep enable is 0, so next interrupt event will "wake up" the CPU
}
Arduino_Timer_LED_SERVO

Remarque : si vous avez une erreur à la compilation due à une double utilisation d’un timer, c’est peut être que la Library Servo.h utilise également un des timers que vous cherchez à configurer. Pour contrer ce problème, il vous faut ouvrir le fichier ServoTimers.h sous C:\Program Files (x86)\Arduino\libraries\Servo\src\avr  et commenter la ligne correspondante. Par exemple, si vous ne voulez pas que Servo.h utilise le Timer 1 vous devez commenter la ligne « #define Timer1 ».

Ici aucun problème, la LED clignote comme il faut et le servomoteur tourne en continue en même temps (sourire)

Mais ce n’est pas le seul avantage de ce code.
Pour rappel le CPU reçoit une horloge de 16 millions de « tick » par secondes, hors dans notre cas, on lui demande seulement d’exécuter une action toutes les 1milliéme de seconde.Il travaille donc 0.006% du temps (un peu plus en réalité mais c’est de cet ordre là).
Rapportons ça à « l’échelle de temps humaine », si on vous demande de travailler 1 jour sur 16 000 jours, autant se reposer pendant 15 999 jours…
La boucle infinie « loop » étant déchargée de toute activités, on peut demander au microcontrôleur de se mettre en veille (comme un PC !) et celui-ci sera automatiquement réveillé par l’interruption pour exécuter ses taches périodiques.

Ceci nous permet de :
-baisser grandement la consommation de courant du microcontrôleur
-réduire  la température du microcontrôleur (puisqu’il consomme moins)
-augmenter la durée de vie du microcontrôleur (puisqu’il chauffe moins)

Les USART (Universal Synchronus/Asynchronus Receiver Transmiter)

Niveau débutant

En électronique, on diffère deux types de communications, série et parallèle.
Avec une communication parallèle, chaque fil représente un bit. Alors que sur une communication série, on envoie les bits « les un à la suite des autres » sur un seul fil.
Dans la communication série, l’horloge permet de connaître la cadence à laquelle les bits s’enchaînent (et donc de les lire correctement).
Cette horloge peut être transmise par un fil (communication série synchrone).
Ou alors elle n’est pas transmise mais les émetteurs et récepteurs sont préalablement réglés sur la même cadence, un bit de START et de STOP permettent de synchroniser la lecture des bits (communication série asynchrone).

Les USART (Universal Synchronus/Asynchronous Receiver Transmiter) sont les périphériques utilisés pour les communication série. Ils permettent de décharger le processeur de ses taches de communication.
Le processeur n’a pas besoin de venir écrire chaque bit sur la ligne le communication).
Le périphérique communiquera avec le processeur uniquement pour lui dire que des données ont été reçues et sont disponibles en lecture ou qu’il a terminé d’envoyer son message…

Pour aller plus loin

On commence à avoir l’habitude, nous allons attaquer le schémas bloc de l’USART du ATMEGA2560.

On distingue bien 3 parties :
-Génération de la clock (communication assynchrone)
-Transmitter (contrôle la pin TX)
-Receiver (contrôle la pin RX)

Les commentaires sont clos.
Scroll Up