Mémo Arduino
Michel Llibre - Janvier 2023
Le compilateur C/C++ de l'IDE Arduino n'est pas parfait. Certaines fonctions standard genre sprintf(), scanf() ne sont pas complètement bien implantées et sont à tester lors de l'utilisation. Il en est de même du switch. Les éléments d'un case doivent être mis entre { } si on ne veut pas avoir de surprise (les "case" qui suivent le premier sont parfois ignorés !).
En fonctionnement autonome, l'Arduino est alimenté par son jack d'alimentation en 9V. La tension peut varier de 7 à 12V.
En mode programmation, il est alimenté par le port USB qui le relie au PC.
Télécharger l'IDE (92.6 Mo) sur www.arduino.org et l'installer.
Les applications ou projets Arduino sont appelés sketch dans la version anglaise ce qui est traduit par croquis (!!) dans la version française.
Le menu fichier/New permet de démarrer un nouveau projet avec un nom par défaut du genre sketch_moisjj que l'on changera lors de sa sauvegarde.
Sauvegarde d'un fichier : Menu Fichier/Enregistrer ou CTRL+S. Avec la boite de dialogue, sélectionner un répertoire et donner un nom au fichier, par exemple toto. L'IDE crée, dans le répertoire sélectionné, un sous-répertoire nommé toto et dans ce répertoire il crée le fichier toto.ino.
Le contenu minimal du fichier initial est constitué des 2 lignes suivantes :
void setup() {}
void loop() {}
Ce programme est exécutable. L'Arduino ne fera rien.
Pour vérifier la validité d'un programme : menu Sketch/Verify-Compile ou CTRL+R ou clic sur bouton V.
Pour charger un programme dans la carte Arduino :
•Brancher la carte Arduino au pc par le cordon USB. Dans le menu Tools/Board doit détecter la carte. Dans le menu Tools/Port cliquer le port COMx avec la bonne valeur de x (voir dans le gestionnaire des périphériques).
•Chargement : menu Sketch/Upload ou CTRL+U ou clic sur bouton =>. Sur la carte Arduino la led jaune (marquée de la lettre L, à coté du pin GND du connecteur digital) doit s'allumer, après un chargement réussi. Le programme reste en place dans la mémoire flash, même après avoir débranché le cordon USB.
•Mise en fonctionnement autonome : Brancher la pile 9V à la prise jack de la carte. Le programme chargé démarre dès le branchement.
Le menu Tools/Serial Monitor ouvre une fenêtre dans laquelle l'Arduino peut écrire via la liaison USB (émulation port série COMx).
Plusieurs IDE peuvent tourner en parallèle sur le pc. Ils partagent la fenêtre Serial Monitor. Quand avec un IDE on charge le projet en cours de cet IDE dans l'Arduino, il remplace le programme qui était en cours d'exécution. Ainsi pour arrêter un programme, il surfit d'ouvrir un autre IDE et d'envoyer le programme menu Files/Examples/01.Basics/Blink qui ne fait que faire clignoter la led interne de la carte.
Référence du langage : En local par menu Aide/Réfrence ou en ligne à : https://www.arduino.cc/en/Reference/HomePage
Libraires
L'installation a enregistré des librairies dans le répertoire C:\Users\Utilisateur\Documents\Arduino\libraries
Une librairie arduino "toto" est composée d'un couple de fichiers sources toto.cpp et toto.h. réunis dans un fichier *.zip que l'on importe à l'aide du gestionnaire de librairies de l'IDE. Il les placera dans le répertoire des librairies.
int compte = 0;
// Routine d'initialisation
void setup() {
// Initialise la liaison avec le PC pour écrire des résultats
Serial.begin(9600); // 9600 bauds, cad bits/s en standard
// L'Arduino envoi un texte au PC
Serial.println("Bonjour Michel !");
// On conditionne la led interne à la carte en sortie.
pinMode(LED_BUILTIN, OUTPUT);
// Impressions pour voir ce que valent ces 2 constantes
int val1 = LED_BUILTIN;
Serial.print("LED_BUILTIN = ");
Serial.println(val1);
int val2 = OUTPUT;
Serial.print("OUTPUT = ");
Serial.println(val2);
}
// La routine loop() qui recommence sans fin
void loop()
{
Serial.print("compte = ");
Serial.println(++compte);
digitalWrite(LED_BUILTIN, HIGH); // Allume la led
delay(1000); // Attente une seconde
digitalWrite(LED_BUILTIN, LOW); // Eteint la led
delay(1000); // Attente une seconde
}
Ouvrir la console de réception des messages qu'enverra l'Arduino au PC : menu Outils/Moniteur série, puis charger le programme dans l'Arduino par le bouton -> (téléverser). Il s'exécute dans la foulée, s'il n'y a pas d'erreur dans le programme. Voici ce qu'on doit recevoir :
Bonjour Michel !
LED_BUILTIN = 13
compte = 1
compte = 2
compte = 3
...
Les int Arduino ne sont que sur 16 bits :
char : -128 à +127
byte: 0 à +255
int: -32768 à +32767
unsigned int: 0 à +65535
long : -2147483648 à +2147483647
unsigned long: 0 à +4294967295
float et double (32 bits) : 3.e-38 à 3e+38 à environ 1,5e-7 de précision
Pour spécifier une constante unsigned long utiliser le postfixe UL : exemple :
const unsigned long secondesparjour = 60UL * 60 * 24;
Attention : Aussi bien sur le Uno que sur le Mega les double sont sur 4 octets seulement (comme les float). Pour avoir des double sur 8 octets, il faut une carte Arduino Due.
La classe String permet de concaténer des chaînes, y ajouter des chaînes, rechercher et remplacer des sous-chaînes, etc. Noter que les chaînes constantes, spécifiées entre "guillemets doubles" sont traitées comme des tableaux de caractères et non comme des instances de la classe String.
Membres : String(), charAt(), compareTo(), concat(), c_str(), endsWith(), equals(), equalsIgnoreCase(), getBytes(), indexOf(), lastIndexOf(), length(), remove(), replace(), reserve(), setCharAt(), startsWith(), substring(), toCharArray(), toInt(), toFloat(), toLowerCase(), toUpperCase(), trim()
Operateurs : [ ], +, += , == , >, >=, <, <=, !=
Les tableaux strings littéraux (string avec un s minuscule = tableau de caractères) comme "Bonjour !" sont créés dans la RAM qui n'est que 2 Ko dans l'UNO. Si on encadre le string par F(), comme ceci F("Bonjour !") on utilise une macro qui va déplacer ce string dans la mémoire flash qui est atteint 32 Ko pour l'UNO. Faire son choix en fonction des places disponibles.
La routine void setup(){…} est exécuté une seule fois au démarrage de l'application, puis la routine loop() {…} est exécutée en boucle, sans fin. Si on veut faire faire une simple séquence d'opérations à l'Arduino, il suffit de la programmer entièrement dans la fonction setup(), et elle s'exécutera une fois. A contrario, on programmera dans loop() une séquence d'opérations à répéter indéfiniment.
Les liaisons séries communiquent par 2 broches RX et TX, avec un câble croisé : le Rx d'un appareil est connecté au TX et l'autre et réciproquement. On peut programmer des broches de données numériques en TX et RX pour effectuer une liaison série logicielle quand on n'a pas assez des liaisons matérielles existantes.
Arduino Uno : 1 seule liaison matérielle (Serial) par le connecteur USB qui est lié aux broches Rx = d0, TX = d1.
Arduino Mega : 4 liaisons matérielles
•Serial : RX=0, TX=1
•Serial1 : RX=19, TX=18
•Serial2 : RX=17, TX=16
•Serial3 : RX=15, TX=14
Broches utilisables en RX logiciel : 10, 11, 12, 13, 50, 51, 52, 53, A8 (62), A9 ( 63), A10 (64), A11 (65), A12 (66), A13 (67), A14 (68), A15 (69).
Pour le Leonardo, seuls les éléments suivants peuvent être utilisés en RX logiciel : 8, 9, 10, 11, 14 (MISO), 15 (SCK), 16 (MOSI).
Initialisation du port série USB (dans le setup en général) :
Serial.begin(9600); // 9600 bauds, cad bits/s en standard
while (!Serial) delay(1000); // Attendre la disponibilité de la connexion USB.
Sur le Uno, la liaison USB accapare les broches RX et TX (d0 et d1) qui ne sont plus disponibles pour un autre usage.
L'Arduino Mega a 4 ports séries :
void setup()
{
Serial.begin(9600);
Serial1.begin(38400);
Serial2.begin(19200);
Serial3.begin(4800);
Serial.println("Hello Computer");
Serial1.println("Hello Serial 1");
Serial2.println("Hello Serial 2");
Serial3.println("Hello Serial 3");
}
Sur le Uno la fonction Serial.end() arrête la liaison et rend disponibles les broches RX et TX pour des E/S générales.
Serial.print("Bonjour Michel !");
Serial.print(val);
Serial.print(val, format);
Le print ne prend qu'un argument, nombre ou string. Dans le cas d'un nombre entier on peut mettre une 2ème argument qui spécifie le format parmi les suivants : BIN, DEC, OCT ou HEX.
Dans le cas d'un nombre flottant le nombre entier spécifie le nombre de décimales.
Idem avec insertion d'un retour à la ligne :
Serial.println("Bonjour Michel!");
Serial.print et Serial.println retournent le nombre de caractères écrits.
Serial.write : Ecriture octet par octet :
Attention :
char c = 65; byte b = 65; int i = 65;
Serial.print(c) → A, Serial.write(c) → A,
Serial.print(b) → 65, Serial.write(b) → A,
Serial.print(i) → 65, Serial.write(i) → A.
Serial.print et Serial.write ne sont pas bloquant. Si on désire attendre la fin d'une sortie avant de passer à la suite, on utilise Serial.flush()qui met le programme en attente pendant le vidage du buffer sortant. Attention Serial.flush()n'a aucun effet sur les entrées !!! comme ce fut peut-être le cas sur les versions préliminaires. Pour vider le tampom d'entrée il suffit de faire : while(Serial.available()) Serial.read();
Le menu Outils/Moniteur série ouvre une console qui reçoit les messages envoyés par l'Arduino sur le liaison et permet, dans l'autre sens d'envoyer des messages à l'Arduino.
La fonction n = Serial.available() renvoi le nombre de caractères disponibles dans le buffer de réception et -1 quand il n'y a rien à lire. Les caractères présents dans ce buffer sont lus un par un en mode FIF0 (1er entré, 1er sorti) par la fonction c = Serial.read(). Exemple :
char c;
While(Serial.avalable() > 0) { c = Serial.read(); ... }
Plutôt que de boucler pour tester Serial.available() pour réceptionner les caractères, on peut utiliser une routine evènementielle qui est lancée avant chaque début de la routine loop() {..}, c'est la routine serialEvent(){..}. Exemple :
void serialEvent()
{
int c;
while((c = Serial.read()) != -1) { ... }
}
Pour vider le buffer de réception avant un autre read : while (Serial.read() ≥ 0);
Il existe des fonctions spécialisées pour la lecture des nombres, string et chaines :
int i = Serial.parsInt();
float f = Serial.parseFloat();
Serial.readBytes(buffer, length);
Serial.readBytesUntil(character, buffer, length);
String s1 = Serial.readString();
qui lisent jusqu'au return ou au timeout qui est fixé par :
Serial.setTimeout(time_ms)
Attention :
Sur Arduino la fonction sscanf ne sait pas lire les flottants. Utiliser atof(). De même sprintf ne sait pas écrire les flottants. Utiliser dtostrf().
dtostrf (f, 10, 4, buf); // number, width, decimal places, buffer
La librairie SoftwareSerial (#include <SoftwareSerial.h>) permet de configurer une paire de broches en broches RX/TX d'une liaison série, définie par le constructeur SoftwareSerial(Rx, Tx). Par exemple, si on utilise la broche d2 en Rx (réception) et la broche d3 en Tx (transmission), on initialisera une liaison nommée ss (par exemple) par :
SoftwareSerial ss(2, 3);
placé avant le Setup(); Un troisième argument booleen (false par défaut) permet d'inverser les niveaux logiques sur les lignes (le haut devient 0 et le bas devient 1).
puis on l'initialisera dans le Setup(), par :
ss.begin(9600); // par exemple,
puis on communiquera sur cette liaison par ss.available(), ss.read(), ss.print()... tout comme sur la liaison Serial.
Si on utilise plusieurs liaisons série logicielles, une seule peut recevoir des données à la fois. C'est la liaison active. A l'origine c'est celle dont le begin() a été appelé le plus récemment. On rend la liaison xyz active en appelant sa méthode xyz.listen().
Lorsqu'on renvoie automatiquement une réponse sur une même ligne après réception d'un message, il faut laisser un petit délai avant de répondre sinon, ça ne marche pas très bien.
Le temps écoulé en millisecondes depuis le démarrage s'obtient par nbms = millis(); Cette fonction utilise un des timers de la carte : le timer0.
Il y a aussi l'instructions nmus = micros(); qui renvoi le même temps en microsecondes.
Une pause avant l'exécution de l'instruction suivante est obtenue par la fonction delay(n) où n est en millisecondes.
Voir : https://passionelectronique.fr/introduction-timer-arduino/
Les timers sont des registres du microprocesseur qui s’incrémente en fonction des impulsions d’horloge ou d’impulsions extérieures. Il est possible de les configurer pour modifier leur comportement. Le microprocesseur de l’Arduino UNO (ATmega328P) possède 3 timers:
1.timer0 (8 bits) compte de 0 à 255 et commande la PWM des broches 5 et 6. Il est aussi utilisé par les fonctions delay(), millis() et micros().
2. timer1 (16 bits) compte de 0 à 65535 et est utilisé pour la commande PWM des broches 9 et 10. Il est utilisé également par la libriaire Servo.h
3.timer2 (8 bits) compte de 0 à 255. Il est utilisé par la fonction Tone() et la génération de la PWM sur les broches 3 et 11 du Uno.
Le Mega en possède 8. Tous ces timers sont alimentés par l'horloge du microprocesseur qui tourne, de base à 16 Mhz.
On peut lire ou forcer le contenu des compteurs avec les variables TCNT0, TCNT1 et TCNT2. On peut également accéder aux poids forts et faibles de TCNT1 avec TCNT1H et TCNT1L.
On peut à tout moment diviser la fréquence de base à l'aide du registre prescaler CLKPR (clock PRescaler), en founissant la valeur de division dans ses 4 bits de poids faible (CLKPS0 à CLKPS3), division par 1 à 256..
Pour modifier ce diviseur, il faut désactiver les interruptions, puis tout d’abord mettre à 1 le bit CLKPCE et tous les autres bits à 0 (en envoyant par exemple le nombre 0b10000000 dans le registre CLKPR) et ensuite, dans un délai maximal de 4 cycles d’horloge, de mettre à 0 le bit CLKPE, tout en spécifiant dans les 4 derniers bits le rapport de division de fréquence souhaitée (pour cela, il suffira donc d’envoyer le nombre 0b0000xxxx dans le registre CLKPR, en remplaçant xxxx par des valeurs 1 ou 0, selon le rapport de division que vous voulez, comme visible dans le tableau ci-dessus), puis réactiver les interruptions. Exemple :
cli();
CLKPR = 0b1000 0000; // on souhaite changer de rapport de fréquence
CLKPR = 0b0000 0101; // rapport voulu (ici 0101 => division par 32)
sei();
Remarque : Il vaut mieux ne pas toucher à cette fréquence car cela peut impacter le baudrate de la liaison série, etc...
Chaque timer a en plus son propre prédiviseur. Le facteur de division est à indiquer dans les 3 bits de poids faible des registres TCCRxB avec x= 0,1 ou 2 pour le Uno (jusqu'à 8 pour le Mega).
On peut soit positionner d'un seul coup tous les bits d'un registre comme dans :
CLKPR = 0b1000 0000;
ou bien positionner bit par bit, comme par Exemple pour mettre CS10 à 1 dans le registre TCCR1B :
Solution 1 : bitSet(TCCR1B, CS10);
Solution 2 : TCCR1B |= (1<<CS10);
ou pour mettre CS12 à 0 dans le registre TCCR1B :
Solution 1 : bitClear(TCCR1B, CS12);
Solution 2 : TCCR1B &= ~(1<<CS12);
Nous avons déja vu l'utilisation des 3 bits de poids faible des registres TCCR0B, TCCR1B et TCCR2B pour fixer la valeur des prédiviseurs.
Les bits WGMxz permettent de définir le mode de comptage des timers :
•Normal : le timer visé compte jusqu’à atteindre sa valeur maximale possible, puis envoie un signal de débordement (overflow), avant de revenir à zéro (et continuer à compter).
•CTC : le timer compte normalement et déclenche une alerte (levée de drapeau) lorsque sa valeur courant sera égale à une valeur de référence préalablement définie (spécifiée dans le registre de comparaison ). À ce moment-là, une interruption pourrait être générée, si souhaité. Et dans tous les cas, le timer, quant à lui, aura repris son comptage depuis zéro !
WGM00, WGM01 dans TCCR0A et WGM02 dans TCCR0B
WGM10, WGM11 dans TCCR1A, et WGM12, WGM13 dans TCCR1B
WGM20, WGM21 dans TCCR2A et WGM22 dans TCCR2B
Pour le timer 1 :
•le mode normal est obtenu avec tous les WGMxz à 0.
•le mode CTC est obtenu avec tous les WGMxz à 0 sauf WGM12 à 1.
Leurs bits alertent sur le fait qu'un débordement est atteint (valeur max ) ou qu'une valeur de comparaison est atteinte. L'overflow est indiqué par le bit b0 : TOVx (x = 0, 1, 2) et l'égalité est indiquée par les bits b1 et b2 OCFxy
Attention : Si un drapeau est levé (valeur 1) pour le baisser il faut envoyer 1 à ce bit pour qu'il repasse à 0.
Chacun de ces registres contient des bits, qui, s’ils sont mis à 1, définissent dans quelle condition une interruption est déclenchée :
•Si TOIEx est mis à 1, alors une interruption sera levée quand le timerx atteindra sa valeur maximale (en fait, le drapeau est levé en même temps que le timer repasse à zéro, après avoir essayé de dépasser son maximum)
•Si OCIExA est mis à 1, alors une interruption sera levée quand le timerx aura atteint une valeur égale à celle qu’on aura préalablement renseigné, et stocké dans le registre OCRxA
•Si OCIExB est mis à 1, alors une interruption sera levée quand le timerX aura atteint une valeur égale à celle qu’on aura préalablement renseigné, et stocké dans le registre OCRxB
Ils permettent de stocker des valeurs qui serviront à effectuer des tests d’égalité avec la valeur courant des timer. Ces valeurs sont stockées dans les registres suivants :
OCR0A et OCR0B, pour le masque d’interruption TIMSK0 (timer0 donc)
OCR1A et OCR1B, pour le masque d’interruption TIMSK1 (timer1 donc)
OCR2A et OCR2B, pour le masque d’interruption TIMSK2 (timer2 donc)
À noter que le timer1 est sur 16 bits au lieu de 8. Du coup, les registres huit bits de comparaison sont en fait OCR1AL, OCR1AH, OCR1BL, et OCR1BH. Par contre, au niveau de votre programme arduino, on peut directement entrer un nombre de 16 bits dans la variable OCR1x du code arduino, et le compilateur se chargera de répartir ces valeurs dans les deux registres 8 bits correspondants !
Exemple de configuration du timer2 :
cli(); // disable interrupts
TCCR2A = (1<<WGM21)|(0<<WGM20); // Mode CTC
TIMSK2 = (1<<OCIE2A); // Local interruption OCIE2A
TCCR2B = (0<<WGM22)|(1<<CS22)|(1<<CS21); // Frequence 16Mhz/ 256 = 62500
OCR2A = 250; //250*125 = 31250 = 16Mhz/256/2
sei(); // enable interrupts
Elles sont réalisées via le connecteur DIGITAL (PWM~) équipé des broches 0, 1, 2, ~3, 4, ~5, ~6, 7, 8, ~9, ~10, ~11, 12, 13, GND, AREF.
Comme les broches 0 à 13 fonctionnent dans les deux sens, ce denier doit être choisi avant l'utilisation de la broche.
Configuration de la broche d'E/S digitale numéro n, en entrée ou en sortie:
•en sortie : pinMode(n, OUTPUT);
•en entrée standard : pinMode (n, INPUT);
•en entrée pull_up : pinMode(n, INPUT_PULL_UP);
Constantes prédéfinies :
OUTPUT : Pour configurer l'E/S numérique en mode sortie (1 dans le cas de l'UNO).
INPUT : Pour configurer l'E/S numérique en mode entrée (0 dans le cas de l'UNO)
INPUT_PULLUP : Pour configurer l'E/S numérique en mode entrée avec une résistance de tirage interné reliée à l'alimentation (2 dans le cas de l'UNO).
LED_BUILTIN : Numéro de l'E/S numérique connectée à la LED interne (13 sur la plupart des cartes dont l'UNO).
La lecture d'un niveau sur une broche configurée en entrée se fait par digitalRead(n); ou n est le numéro de la broche lue. Cette fonction retourne les valeurs LOW ou HIGH.
En mode entrée pull_up une résistance interne de valeur comprise entre 20 et 50 k relie la patte au +5 V, ce qui fait qu'on peut la relier à un interrupteur poussoir dont l'autre patte est relié au 0V. A la lecture digitalRead(n); LOW correspond au circuit fermé (consommation environ 0.15 mA) et HIGH au circuit ouvert (consommation négligeable).
En mode entrée standard, pour détecter l'état d'un poussoir, on relie l'autre patte du poussoir au 5 V et on ajoute une résistance dite pull-down d'environ 5 à 10 k entre la patte d'E/S reliée au poussoir et le 0 V. Quand le poussoir est fermé on lit HIGH (consommation environ 0.7 mA) et quand il est ouvert on lit LOW ( consommation négligeable).
L'entrée pull_up est donc préférable.
Constantes prédéfinies :
LOW : (0 dans le cas de l'UNO)
en entrée : tension < 1.0 (carte 3.3V) ou < 1.5V (carte 5V) lue par digitalRead().
en sortie : tension = 0V.
HIGH : (1 dans le cas de l'UNO)
en entrée : tension > 2.0 (carte 3.3V) ou > 3.0V (carte 5V) lue par digitalRead().
en sortie : tension = 3.3 (carte 3.3V) ou = 5V (carte 5V)
Elles se font sur les broches d'E/S préalablement configurées en OUTPUT par les fonctions :
digitalWrite(pin, LOW);
ou
digitalWrite(pin, HIGH);
Les broches digitales du connecteur d'E/S numérique précédées d'un ~, à savoir les broches 3, 5, 6, 9, 10 et 11, peuvent être programmées en PWM (Pulse Width Modulation) en faisant varier le rapport cyclique (duty cycle en anglais) entre les états de sortie HIGH et LOW, ce qui fournit l'équivalent d'un niveau analogique. Exemple :
analogWrite(11, val); ou val est le rapport cyclique compris entre 0 et 255. La valeur 0 fournit la tension LOW en permanence et la valeur 255 fournit la tension HIGH en continu.
La fréquence du cycle dépend du modèle d'Arduino et également des broches, mais seulement 2 fréquences sont utilisées : 490 ou 980 Hz.
Ne pas oublier de conditionner la broche en sortie : pinMode(11, OUTPUT);
On peut modifier la fréquence du cycle par programmation avec le code suivant :
// on définit une variable de type byte
// qui contiendra l'octet à donner au registre pour diviser la fréquence de la PWM
// division par : 1, 8, 64, 256, 1024
byte division_frequence=0x01;
// fréquence : 62500Hz, 7692Hz, ...
// temps de la période : 16µs, 130µs, ...
void setup()
{
pinMode(6, OUTPUT); // broche de sortie
// TCCR0B c'est le registre, on opère un masquage sur lui même
TCCR0B = TCCR0B & 0b11111000 | division_frequence;
// ce qui permet de modifier la fréquence de la PWM
}
void loop ()
{
// on écrit simplement la valeur de 0 à 255 du rapport cyclique du signal
analogWrite(6, 128);
// qui est à la nouvelle fréquence choisit
}
TCCR0B est le nom du registre utilisé. Pour la variable division_frequence , on utilisera les valeurs hexadécimales suivantes :
0x01 // f = 62500Hz, f. max. possible (f. quartz / 256) divisée par 1
0x02 // f = 7692Hz, division par 8 de la fréquence maximale
0x03 // f = 976Hz, division par 64
0x04 // f = 244Hz, division par 256
0x05 // f = 61Hz, division par 1024
Génération d'une tension analogique à partir de la PWM
Avec les valeurs suivantes :
U=5V (ou 0 : sortie PWM
C=1000μF
Rcharge=1kΩ
Rdecharge=1kΩ
Constante de temps de charge et décharge : τ=R×C . Plus grand est τ, meilleure est l'approximation, mais cela augment le temps d'établissement de la valeur. Si la fréquence de coupure 1/2πτ du filtre est 20 fois plus faible que la fréquence du cycle de la PWM, l'ondulation sera quasiment supprimée.
Les broches digitales du connecteur d'E/S numérique peuvent être programmées en tonalité à l'aide de la fonction : tone(pin, freq, nbms);
qui génère sur la broche pin, un signal carré à la fréquence freq, pendant une durée nbms millisecondes. C'est en fait un signal entre LOW et HIGH de rapport cyclique 50% à la fréquence freq. Si nbms est absent, la durée est permanente jusqu'à un nouvel appel de la fonction ou jusqu'à l'appel de la fonction noTone(pin).
Les fréquences sont comprises entre 31 Hz et 65535 Hz
Remarque : si plusieurs notes sont jouées l'une après l'autre, il faut utiliser la fonction delay pour leur laisser le temps d’être exécutées :
tone(8, 440, 1000); delay(1000);
tone(8, 880, 2000); delay(2000);
tone(8, 220, 1000); delay(1000);
Pour tester cette fonction mettre une patte du buzzer à la terre et relier l'autre à la sortie numérique.
Les librairies PWM et tone utilisent des timers pour générer les sorties, sans coordination entre elles, et comme ces timers sont en nombre limités il peut y avoir conflit, en particulier dans le cas du UNO l'utilisation de tone interfère avec analogWrite des broches 3 et 11.
Le connecteur ANALOG_IN comporte 6 entrées marquées A0, A1, … A5.
Lecture de la broche A0 : int v = analogRead(A0); tens = 5.*(v/1024.);
donne une valeur comprise entre 0 et 1023, image de la tension comprise entre 0 et 5 volts.
Remarque : Pour envoyer directement cette lecture vers une sortie pseudo-analogique (numérique en PWM), il suffit de diviser la valeur lue par 4 (pour la ramener entre 0 et 255).
Constantes prédéfinies : A0, A1, …, A5 = 14, 15, … 19 dans le cas de l'UNO.
Seules certaines broches peuvent être utilisées pour envoyer des interruptions :
Uno, Nano, (chipset328) : d2, d3
Mega : d2, d3, d18 à d21
Due : Tous les dX
Micro, Leonardo (chipset 32u4) : d0 à d3 et d7
Zero : tous les dX sauf d4
MKR : d0, d1, d4 à d9, A1 et A2.
On attache une interruption par la fonction :
attachInterrupt(interrupt, callback, mode)
avec pour mode :
•LOW : Passage à état bas du pin
•FALLING : Detection d’un front descendant (passage de l’état haut à l’état bas)
•RISING : Detection d’un front montant (passage de l’état bas à l’état haut)
•CHANGE : Changement d’état du pin
pour callback le nom de la fonction de rappel void callback();.
interrupt est le numéro de l'interruption donné par la fonction :
interrupt = digitalPinToInterrupt(pin);
en fonction du numero pin de la broche.
Attention, dans la callback, les fonctions delay() et millis() ne fonctionnent pas.
Les variables globales modifiées dans la callback doit être déclarée volatile (pour être sur que la modification soit effective).
On détache l'interruption par :
detachInterrupt(interrupt);
avec interrupt = digitalPinToInterrupt(pin);
L'écran LCD du starter kit Arduino à 2 lignes de 16 caractères. D'un point de vue logiciel il est régit par la bibliothèque LiquidCrystal à l'aide d'une classe LiquidCrystal dont les fonctions sont prototypées dans le fichier LiquidCrystal.h.
On doit connecter les broches suivantes du LCD :
•n°1 : masse
•n°2 Vcc +5v
•n°3 Luminosité : À la masse pour une luminosité maximale. Éventuellement à la sortie d'un potentiomètre 10 kΩ entre 5v et la masse si on veut diminuer la luminosité on augmentant le voltage sur cette broche.
•n°4 rs: Register Select
•n°5 rw : Read/Write : mettre à la masse en mode standard (lecture)
•n°6 en : Enable
•n°7 à 10 : d0 à d3 : connection facultative
•n°11 à 14 : d4 à d7 : à connecter
•n°15 Led+ : au +5V à travers résistance de 220 Ω
•n°16 Led- : à la masse
soit 12 broches à brancher en tout et 4 (d0 à d3) facultatives.
Une instance de l'écran est créée par l'appel du constructeur :
LiquidCrystal(rs, en, d4, d5, d6, d7)
LiquidCrystal(rs, rw, en, d4, d5, d6, d7)
LiquidCrystal(rs, en, d0, d1, d2, d3, d4, d5, d6, d7)
LiquidCrystal(rs, rw, en, d0, d1, d2, d3, d4, d5, d6, d7)
Arguments :
rs: numéro de la broche Arduino connectée à la broche rS (n° 4) de l'écran LCD
rw: numéro de la broche Arduino connectée à la broche rw (n° 5) de l'écran LCD (optionnel, mettre à la masse en mode standard (lecture))
en: numéro de la broche Arduino connectée à la broche enable (n° 6) de l'écran LCD
d0, d1, d2, d3, d4, d5, d6, d7: les numéros des broches Arduino connectées aux broches de données correspondantes d0 (n°7) à d7 (n°14) de l'écran LCD (d0 à d3 sont facultatifs). Si on les omet, l'écran LCD sera contrôlé en utilisant uniquement les quatre lignes de données d4 à d7).
Exemple : LiquidCrystal lcd(12,11,5,4,3,2);
crée une instance nommée lcd avec : rs = 12, en = 11, d4 = 5, .., d7 = 2.
Puis on doit initialiser l'écran par :
lcd.begin(nc, nl); // où nl est le nombre de lignes de l'écran et nc le nombre de caractères par ligne.
Les méthodes les plus utiles sont :
lcd.clear(); // pour effacer
lcd.setCursor(c,l); pour positionner le curseur au caractère n°c de la ligne l.
lcd.home() ≡ lcd.setCursor(0,0);
lcd.print("Bonjour."); pour écrire à partir de la position du curseur, imprime un seul argument à la fois de type char, byte, int, long ou string. Dans le cas d'un nombre, un deuxième argument, pris parmi BIN, DEC, OCT ou HEX permet de spécifier la base (DEC par défaut).
Exemple de programme :
// include the library code:
#include <LiquidCrystal.h>
// Pour générations aléatoires
int aleat;
// description des branchements
LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
void setup()
{
// Nombre de colonnes et lignes du LCD
lcd.begin(16, 2);
// Message de bienvenue.
lcd.print("Bonjour Michel");
lcd.setCursor(0, 1); // curseur colonne 0, ligne 1
lcd.print("Comment vas-tu ?");
}
void loop()
{
delay(2000);
aleat = random(32767);
lcd.clear(); lcd.setCursor(0, 0);
lcd.print("Tirage de "); lcd.print(aleat);
lcd.setCursor(0, 1);
switch (aleat%4) {
case 0: lcd.print("0 modulo 4"); break;
case 1: lcd.print("1 modulo 4"); break;
case 2: lcd.print("2 modulo 4"); break;
case 3: lcd.print("3 modulo 4"); break;
}
}
Branchements pour Arduino Uno, Nano, Mega et Leonardo : informations tirées de https://randomnerdtutorials.com/guide-for-oled-display-with-arduino/
L'écran OLED (organic light-emitting diode) SSD1306 0.96 inch I2C of128×64 pixels. Il n'utilise que 4 broches :
|
|
Il faut télécharger les bibliothèques adafruit_SSD1306.h et adafruit_GFX.h (dans l'éditeur Arduino taper SSD1306 dans la fenêtre ouverte par le menu Sketch > Inclure la bibliothèque > Gérer les bibliothèques).
Documentation : https://learn.adafruit.com/adafruit-gfx-graphics-library/graphics-primitives
Fonctions utiles :
display.clearDisplay() – tous les pixels sont éteints
display.drawPixel(x,y, couleur) – tracer un pixel dans les coordonnées x,y
display.setTextSize(n) – définir la taille de la police, prend en charge les tailles de 1 à 8
display.setCursor(x,y) – définir les coordonnées pour commencer à écrire du texte
display.print ("message") – imprimer les caractères à l'emplacement x,y
display.display() – appelez cette méthode pour que les modifications prennent effet
Pour tester l'écran essayer l'exemple de la bibliothèque : menu Files/Examples/Adafruit SSD 1306/ ssd1306_128x64_i2c.
Si l'Oled n'a pas de broche RESET, il faut définir le OLED_RESET variable à -1 comme indiqué ci-dessous :
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit Display(128, 64, &wire, OLED_RESET);
Le paramètre (-1) signifie que lécran OLED n'a pas de broche RESET. Si l'écran OLED a une broche RESET, il doit être connecté à un GPIO. Dans ce cas, il faut passer le numéro de la broche GPIO en paramètre.
Pour que ça marche j'ai modifié :
#define OLED_RESET 4 => -1
#define SCREEN_ADDRESS 0x3D => 0x3C
Si l'écran n'affiche rien, exécuter ce code :
/*********
Rui Santos :Complete project details at https://randomnerdtutorials.com
*********/
#include <Wire.h>
void setup() {
Wire.begin();
Serial.begin(115200);
Serial.println("\nI2C Scanner");
}
void loop() {
byte error, address;
int nDevices;
Serial.println("Scanning...");
nDevices = 0;
for(address = 1; address < 127; address++ ) {
Wire.beginTransmission(address);
error = Wire.endTransmission();
if (error == 0) {
Serial.print("I2C device found at address 0x");
if (address<16) {
Serial.print("0");
}
Serial.println(address,HEX);
nDevices++;
}
else if (error==4) {
Serial.print("Unknow error at address 0x");
if (address<16) {
Serial.print("0");
}
Serial.println(address,HEX);
}
}
if (nDevices == 0) {
Serial.println("No I2C devices found\n");
}
else {
Serial.println("done\n");
}
delay(5000);
}
Vérifier l'adresse dans le moniteur série / résultat :
Scanning...
I2C device found at address 0x3C
done
et modifiez l'adresse en conséquence dans la ligne suivante :
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
adresse qui dans le cas présenté ci-dessus était 0x3C.
Exemple "Hello world" :
/*********
Rui Santos : Complete project details at https://randomnerdtutorials.com
*********/
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1);
void setup() {
Serial.begin(115200);
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address 0x3D for 128x64
Serial.println(F("SSD1306 allocation failed"));
for(;;);
}
delay(2000);
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0, 10);
// Display static text
display.println("Hello, world!");
display.display();
}
void loop() {}
Les caractères s'écrivent sous la ligne x de setCursor(x,y).
La police de caractère par défaut en setTextSize(0 ou 1) a des caractères de 5x7 pixels avec en plus 1 pixel d'espacement en largeur (à droite) et en hauteur en dessous le caractère complet occupe 6x8 pixels ce qui fait qu'on peut écrire 8 lignes de 21 caractères en commençant en (0,0), (0,8), (0,16), (0,24), (0,32), (0,40), (0,48), et (0,56). Avec cette police display.println décale automatiquement de 8 pixels en hauteur.
On peut espacer les lignes davantage en gérant le nombre de pixels par ligne de caractères mais on ne pourra faire contenir que 7 lignes de 9 pixels de haut ou 6 de 10 ou 11 pixels de haut, etc.
On peut écrire avec des fontes plus élaborées, mais en perdant en nombre de caractères. Il faut à chaque fois inclure le .h correspondant, par exemple #include <Fonts/FreeSerif12pt7b.h> et charger la fonte par display.setFont(&FreeSerif9pt7b);
Les fontes suivantes sont disponibles :
FreeMono12pt7b.h FreeSansBoldOblique12pt7b.h
FreeMono18pt7b.h FreeSansBoldOblique18pt7b.h
FreeMono24pt7b.h FreeSansBoldOblique24pt7b.h
FreeMono9pt7b.h FreeSansBoldOblique9pt7b.h
FreeMonoBold12pt7b.h FreeSansOblique12pt7b.h
FreeMonoBold18pt7b.h FreeSansOblique18pt7b.h
FreeMonoBold24pt7b.h FreeSansOblique24pt7b.h
FreeMonoBold9pt7b.h FreeSansOblique9pt7b.h
FreeMonoBoldOblique12pt7b.h FreeSerif12pt7b.h
FreeMonoBoldOblique18pt7b.h FreeSerif18pt7b.h
FreeMonoBoldOblique24pt7b.h FreeSerif24pt7b.h
FreeMonoBoldOblique9pt7b.h FreeSerif9pt7b.h
FreeMonoOblique12pt7b.h FreeSerifBold12pt7b.h
FreeMonoOblique18pt7b.h FreeSerifBold18pt7b.h
FreeMonoOblique24pt7b.h FreeSerifBold24pt7b.h
FreeMonoOblique9pt7b.h FreeSerifBold9pt7b.h
FreeSans12pt7b.h FreeSerifBoldItalic12pt7b.h
FreeSans18pt7b.h FreeSerifBoldItalic18pt7b.h
FreeSans24pt7b.h FreeSerifBoldItalic24pt7b.h
FreeSans9pt7b.h FreeSerifBoldItalic9pt7b.h
FreeSansBold12pt7b.h FreeSerifItalic12pt7b.h
FreeSansBold18pt7b.h FreeSerifItalic18pt7b.h
FreeSansBold24pt7b.h FreeSerifItalic24pt7b.h
FreeSansBold9pt7b.h FreeSerifItalic9pt7b.h
Les 9 pt sont suffisamment grandes.
(Voir paragraphe suivant nouvelle librairie)
Liste des fonctions de la librairie Keypad ()
Keypad((char *)userKeymap, row[], col[], rows, cols)
begin()
getKey()
getState()
setHoldTime(unsigned int time)
setDebounceTime(unsigned int time)
addEventListener(keypadEvent)
Création d'un "objet clavier"
Pour créer un "objet clavier", il faut utiliser le constructeur suivant :
Keypad((char *) userKeymap, row[], col[], rows, cols)
avec :
userKeymap : tableau à 2 dimensions définissant les symboles des touches
row[] : tableau correspondant aux numéros des broches utilisées pour les lignes
col[] : tableau correspondant aux numéros dex broches utilisées pour les colonnes
rows : nombre de lignes
cols : nombre de colonnes
Exemple de création pour un clavier 4x3 (sans A,B,C,D)
const byte rows = 4; //four rows
const byte cols = 3; //three columns
char keys[rows][cols] = {
{'1','2','3'},
{'4','5','6'},
{'7','8','9'},
{'#','0','*'}
};
byte rowPins[rows] = {5, 4, 3, 2}; //connect to the row pinouts of the keypad
byte colPins[cols] = {8, 7, 6}; //connect to the column pinouts of the keypad
Keypad keypad = Keypad((char *) keys, rowPins, colPins, rows, cols );
Ce code crée un objet de type Keypad, appelé keypad, qui utilise les broches 5,4,3,2 pour les lignes et les broches 8,7,6 pour les colonnes. Ce clavier a 4 lignes et 3 colonnes , et a donc 12 touches.
Description des fonctions
void begin((char *)userKeymap)
Initialise toutes les variables. En fait le constructeur le fait déjà.
char getKey()
Renvoie la touche (sous forme caractère ASCII) qui est appuyée, si une l'a été.
KeypadState getState()
Renvoie l'état courant du clavier.
Les 4 états possibles sont IDLE, PRESSED, RELEASED et HOLD.
setHoldTime(unsigned int time)
Définit le nombre de millisecondes que l'utilisateur doit appuyer sur un bouton pour activer l'état HOLD.
setDebounceTime(unsigned int time)
Définit le nombre de millisecondes entre 2 appuis de touches. C'est une pause anti-rebond.
addEventListener(keypadEvent)
Crée un évènement si le clavier est utilisé. Vous pouvez regarder un exemple dans le logiciel Arduino dans "File -> Sketchbook -> Examples -> Library-Keypad -> EventSerialKeypad"
Nouvelle librairie du même clavier. Ci-après un exemple de mise en oeuvre.
#include "Adafruit_Keypad.h"
const byte ROWS = 4; // rows
const byte COLS = 4; // columns
//define the symbols on the buttons of the keypads
char keys[ROWS][COLS] = {
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}
};
byte rowPins[ROWS] = {9, 8, 7, 6}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {5, 4, 3, 2}; //connect to the column pinouts of the keypad
//initialize an instance of class NewKeypad
Adafruit_Keypad customKeypad = Adafruit_Keypad( makeKeymap(keys), rowPins, colPins, ROWS, COLS);
void setup() {
Serial.begin(9600);
customKeypad.begin();
long n = getKBlong();
Serial.print("Reçu la valeur "); Serial.println(n);
}
void loop() {
// put your main code here, to run repeatedly:
long n = getKBlong();
Serial.print("Reçu la valeur "); Serial.println(n);
delay(10);
}
// Lecture d'un caractère avec attente maximale d'un certain delai.
char getKBcar(int attente_ms)
{
long tdeb = millis();
while (millis()-tdeb < attente_ms)
{
customKeypad.tick();
while(customKeypad.available())
{
keypadEvent e = customKeypad.read();
if(e.bit.EVENT == KEY_JUST_RELEASED) return (char) e.bit.KEY;
}
delay(10);
}
return '\0';
}
// Lecture d'un entier jusqu'au caractère non chiffre
char ligne[8];
long getKBlong()
{
int i, n, c;
ligne[0] = '0'; // Si on ne reçoit rien cette valeur est utilisée
for (i = n = 0; i < 8; i++)
{
c = getKBcar(20000); if (c < 48 || c > 57) break;
ligne[i] = c; n = i;
}
long dix = 1, v = 0;
for (i = n; i >= 0; i--)
{ v += (ligne[i] - 48)*dix; dix *= 10;}
return v;
}
Les modules les plus utilisés sont le HC-05 et le HC-06.
Le HC-05 peut fonctionner en maitre et esclave. Il est compatible +5V.
Le HC-06 ne fonctionne qu'en mode esclave et il vaut mieux limiter le voltage sur l'entrée RX à 3.3V par un pont diviseur 1kOhm--2kOhm.
Le HC-06 a 4 broches en commun avec le HC-05 :
Vcc : entrée +5V, Gnd : masse, Tx ( Transmit Data ou TXD) et Rx (Receive Data ou RXD), à brancher à 2 broches Rx-Tx (en croisant) de l'Arduino.
Cette configuration interne n'est à faire que si on veut modifier le baudrate, parité, etc, le nom ou le mot de passe.
Quand il n'est pas encore appairé, la led du HC-06 est clignotante et les données que lui envoie l'Arduino sont interprétées comme des commandes AT (tableau de commandes non vérifié)
Commande AT HC-06 |
Signification |
Réponse |
AT |
Test |
OK |
AT+VERSION |
Version du module |
linvorV1.5 |
AT+BAUDx |
Changer la vitesse (1) |
OKy |
AT+NAMEnom |
Changer le nom en nom |
OKsetname |
AT+PINnnnn |
Changer le mot de passe |
OKsetPIN |
AT+PN, AT+PO, AT+PE |
Changer la parité |
OK None, OK Odd, OK Even |
(1) x est l'index de la vitesse :1->1200, 2->2400, 3->4800, 4->9600, 5->19200, 6->38400, 7->57600 , 8->115200 et y est la valeur de la vitesse.
Le HC-05 a 2 broches supplémentaires :
- En ou Key que l'on n'utilise qu'en mode commande AT
- State que l'on ne connecte pas. State est connecté en interne à la LED du module :
•clignotement bref 1 fois toutes les 2s : module en mode AT command
•clignotement continu : module en mode data, attend une connexion
• clignotement 2 fois par seconde : module en mode data, connexion établie
Pour modifier la configuration du HC-05 il faut le mettre en mode commande AT, ce qui est assez délicat : Il faut programmer la communication série interne entre l'Arduino et le HC-05 en 9600 ou 38400 exclusivement (pour cette com interne en mode AT). Par défaut elle se fait en 38400 (et je n'ai pas réussi en 9600). Suivant cette vitesse (9600 ou 38400) la broche Enable doit être portée à HIGH avant ou après la broche VCC (problématique). Le bouton poussoir du HC-05 simulerait la mise à HIGH de la broche Enable. Ce qui a marché en 38400, c'est programmer la broche En à High, et si la led ne clignotait pas lentement : débrancher la broche VCC du +5V, appuyer sur sur poussoir, puis rebrancher la broche VCC au +5V ce qui correspond au fait que la broche En est à HIGH (car toujours connectée) avant la broche VCC (que l'on rebranche).
HC-05 paramètres par défaut :
•nom Bluetooth : “DSD TECH HC-05”
•mot de passe : 1234
•mode : Data par défaut ;
•9 600 bauds, 8 bits de données, pas de bit de parité, un bit de stop (9600,0,0)
Commande AT HC05.
Question |
Commande |
Réponse |
AT |
|
OK |
AT+VERSION |
|
+VERSION:2.0-20100601 |
AT+NAME |
AT+NAME=nom |
+NAME:DSD TECH HC-05 |
AT+PSWD |
AT+PSWD=1234 |
+PSWD:1234 |
AT+ROLE |
AT+ROLE=1 (maitre ou 0 slave) |
+ROLE:0 |
AT+UART |
AT+UART=57600,0,0 |
+UART:9600,0,0 |
Source du code testé :
/*
* Lecture des paramètres du HC-05 en mode AT. La led doit clignoter très lentement, 1 fois
* toutes les deux secondes environ. Si ce n'est pas le cas débrancher la broche d'alimentation
* à Vcc (+5v), appuyer 1 à 2 secondes sur le bouton poussoir du HC-05 et rebrancher la broche.
* Eventuellement débrancher aussi la broche Enable. Enfin, faites divers pour arriver à
* obtenir ce clignotement LENT.
* La vitesse de communication en modes Commande AT n'a rien à voir avec celle du mode données
* qui est renseigné par la commande AT+UART. La vitesse en mode commande AT est soit de 9600
* bauds, soit de 38400 bauds, suivant la séquence de tension au niveau des broches VCC et Enable.
* Je n'ai pas réussi à le faire marcher en 9600. Ce fichier fonctionne bien en 38400. Et je
* répète, cette vitesse n'a rien à voir avec celle qui sera utilisée pour la communication
* bluetooth, renseignée ou fixée par la commande AT+UART.
*/
#include <SoftwareSerial.h> //Software Serial Port
#define RxArduino 3 // Tx HC-05
#define TxArduino 2 // Rx HC-05
#define EnHC05 4 // Enable Hc-05
SoftwareSerial ss(RxArduino,TxArduino);
void setup()
{
Serial.begin(9600);
delay(500);
// Configuration du bluetooth
pinMode(RxArduino, INPUT);
pinMode(TxArduino, OUTPUT);
pinMode(EnHC05, OUTPUT);
digitalWrite(EnHC05, HIGH); // Pour mode AT 9600
ss.begin(38400);
Serial.println("\n1:AT\n2:AT+VERSION\n3:AT+NAME\n4:AT+UART\n5:AT+ROLE\n6:AT+PSWD\n7:AT+NAME=HC-05-B");
}
void loop()
{
int cde = Serial.parseInt(); // Renvoi 0 si erreur => 0 n'est pris comme index de cde
switch (cde)
{
case 1 :
{ Serial.println("Envoi commande AT"); ss.print("AT\r\n"); break;}
case 2 :
{ Serial.println("Envoi commande AT+VERSION"); ss.print("AT+VERSION\r\n"); break;}
case 3 :
{ Serial.println("Envoi commande AT+NAME"); ss.print("AT+NAME\r\n"); break;}
case 4 :
{ Serial.println("Envoi commande AT+UART"); ss.print("AT+UART\r\n"); break;}
case 5 :
{ Serial.println("Envoi commande AT+ROLE"); ss.print("AT+ROLE\r\n"); break;}
case 6 :
{ Serial.println("Envoi commande AT+PSWD"); ss.print("AT+PSWD\r\n"); break;}
case 7 :
{ Serial.print("Envoi commande AT+NAME=HC-05-B"); ss.print("AT+NAME=HC-05-B\r\n"); break;}
}
while(ss.available()) {Serial.print((char) (ss.read()));}
}
/* RESULTAT :
1:AT
2:AT+VERSION
3:AT+NAME
4:AT+UART
5:AT+ROLE
6:AT+PSWD
7:AT+NAME=HC-05-B
Envoi commande AT
OK
Envoi commande AT+VERSION
+VERSION:2.0-20100601
OK
Envoi commande AT+NAME
+NAME:DSD TECH HC-05
OK
Envoi commande AT+UART
+UART:9600,0,0
OK
Envoi commande AT+ROLE
+ROLE:0
OK
Envoi commande AT+PSWD
+PSWD:1234
OK
Envoi commande AT+NAME=HC-05-BOK
Envoi commande AT+NAME
+NAME:HC-05-B
OK
*/
En utilisation normale bluetooth le circuit doit être en mode data. Pour cela il faut procéder à l'appariement entre ce circuit et l'organe éloigné avec lequel il va communiquer. Avant l'appariement la lumière du HC-05 clignote rapidement.
Pour faire l'appariement avec Windows 10 :
•Ouvrir les Paramètres périphériques de Windows.
•Cliquer sur Ajouter un appareil Bluetooth ou autre appareil.
•Dans la fenêtre qui s'ouvre, cliquer sur la ligne Bluetooth.
•Le périphérique Bluetooth doit être branché, sa LED rouge doit clignoter rapidement (en continu), signe qu'il est en attente de connexion.
•Dans la fenêtre Ajouter un appareil commence une phase de recherche (lumière bleue circulante). Les appareils trouvés sont affichés : par exemple "Appareil inconnu" et "DSD TECH HC-05". Cliquer sur cette dernière ligne.
•Entrer le code PIN : 1234, puis cliquer sur Connecter. Lorsque la connexion réussit, la led du bluetooth clignote une fois par seconde.
Dans le Gestionnaire de périphériques 2 nouvelles lignes apparaissent, intitulées Lien Série sur Bluetooth Standard. Un seul numéro de port COM va fonctionner avec Stellarium. Il faut l'identifier. Par un clic droit sur une des lignes on accède à la fenêtre des Propriétés.
Dans la fenêtre Propriétés, sélectionner l'onglet Détails et dans la liste déroulante Propriété chercher la rubrique Adresse du périphérique Bluetooth qui contient 00140305EF32 dans le cas du HC-05-B. Si cette rubrique n'est pas présente ce n'est pas le bon port COM.
Exemple de commmunication :
/* Test d'une liaison bluetooth avec le HC-05 ou HC-06 monté en SoftwareSerial sur le Uno
Apparier le bluetooth - Trouver son port COM - Ouvrir Termite en 9600 bauds sur ce port COM
Avec Termite envoyer taper une ligne de caratères se terminant par # puis l'envoyer
A sa réception l'Arduino l'affiche sur sa liaison série vers le moniteur série et
la renvoie par bluetooth vers Termite qui doit l'afficher également.
Envoyer une nouvelle ligne ....
*/
#include <SoftwareSerial.h>
#define NBMAXCHAR 80
char bufinput[NBMAXCHAR+1];
#define MITAD (NBMAXCHAR/2)
static int idx = 0;
SoftwareSerial ssBT(3, 2); // (Rx, Tx) coté Arduino, inverse cote Bluetooth
void setup() { Serial.begin(9600); while (!Serial) ; ssBT.begin(9600);}
void loop()
{
bool isComplet = false;
char c;
int n = 0;
// lecture bluetooth jusqu'à réception du #
while (ssBT.available() && !isComplet)
{
c = (char) ssBT.read(); if (idx == 0 && c == '\n') continue;
bufinput[idx ++] = c;
if (c == '#') {isComplet = true; break;}
// Si buffeur plein, on vidange la première moitié et on continue
if (idx == NBMAXCHAR)
{ for (int i = 0; i < MITAD; i++){bufinput[i] = bufinput[i+MITAD];} idx = MITAD;}
}
if (isComplet) // Reçu un message terminé par #
{
bufinput[idx] = 0;
// On le renvoie en bluetooth pour l'afficher dans Termite
ssBT.print("HC-05 a recu : <"); ssBT.print(bufinput); ssBT.println(">");
delay(100);
// On le renvoie vers le Moniteur Série
Serial.print("HC-05 a recu : <"); Serial.print(bufinput);Serial.println(">");
idx = 0;
}
}
Les modules GPS les plus utilisés sont basés sur les puces neo-6 series de u-blox (https://www.u-blox.com/en/product/neo-6-series). Ils coûtent moins de 10€.
Le câblage standard (sans prise en compte du PPS) se limite à 4 fils de liaison entre le module GPS et la carte MEGA 2560 : a masse, le +5V et (à titre d'exemple) on relie RX/TX GPS à Serial2 du Mega :
- TX du module GPS à relier à RX2 broche 17 du Mega,
- RX à relier à TX2 broche 16 du Mega.
La LED du module GPS se met à clignoter, lorsqu'elle a réussi à acquérir la position. Cette led reflète le signal One PPS (un pulse par seconde) que certaines puces offrent sur une sortie. Le front de ce signal montant toute les secondes à quelques nanosecondes près, peut-être utilisé pour des mises à l'heur extrêment précises. L'heure TU de l'instant du front montant est fourni dans les trames envoyées à la suite de ce front.
Les trames envoyées commencent par $ et se terminennt par CR LF (Ox0D Ox0A).
Ensuite vient l'identifiant de l'équipement générateur de la trame :
•GB ou BD : Beidou (ou COMPASS : chine)
•GA : Galileo (européen)
•GP : GPS (américain)
•GL : GLONASS (russe)
•GN : mix GPS + GLONASS
Ensuite viennent les 3 caractères indiquant le type de la trame :
•GGA (Heure, position et altitude)
•RMC (Heure position et date)
•VTG (Vitesse, route, cap)
•GSA (Satellites actifs/utilisés)
•GSV (Satellites visibles)
Exemple de sortie des trames fournies après chaque seconde entière par le Neo-6M, lorsque l'acquisition est bien établie
$GPRMC,104508.00,A,4331.52048,N,00134.38575,E,0.414,,081221,,,A*75
$GPVTG,,T,,M,0.414,N,0.768,K,A*2B
$GPGGA,104508.00,4331.52048,N,00134.38575,E,1,08,1.29,207.4,M,48.5,M,,*5A
$GPGSA,A,3,07,20,30,09,13,06,14,02,,,,,2.13,1.29,1.70*02
$GPGSV,3,1,11,02,35,241,29,05,39,308,16,06,14,193,27,07,61,063,17*7E
$GPGSV,3,2,11,09,28,076,27,11,38,226,31,13,26,268,17,14,11,153,26*7A
$GPGSV,3,3,11,16,00,021,,20,69,287,28,30,75,159,29*40
$GPGLL,4331.52048,N,00134.38575,E,104508.00,A,A*65
C'était le 8/12/21, date donnée par la trame $GPRMC. Il était 11h45mn08.00s TU, valeur donnée en premier par la trame $GPRMC, puis par les trames $GPGGA et $GPGLL. Longitude 43°31.52048'N et Latitude 1°34.38575'E donnée par la trame $GPRMC, puis par les trames $GPGGA et $GPGLL.
La trame $GPVTG donne des indications sur la route suivie (vitesse, angle de route, cap...).
La trame $GPGGA donne en plus le nombre de satellites utilisés : 08 et l'altitude : 207.4m.
Les trames $GPGSV redonnent ces numéros pour 11 satellites, les 8 utilisés (pas dans le même ordre) et 3 autres (soulignés), suivis de leur élévation, azimut et rapport signal/bruit.
On remarquera que seuls les satellites GPS sont utilisés.
Autre exemple de sortie fournie par un neo-M8N :
$GNRMC,093206.00,A,4331.51798,N,00134.36985,E,0.271,,081221,,,A*6C
$GNVTG,,T,,M,0.271,N,0.503,K,A*3F
$GNGGA,093206.00,4331.51798,N,00134.36985,E,1,04,4.50,209.9,M,48.5,M,,*42
$GNGSA,A,3,07,06,02,30,,,,,,,,,12.71,4.50,11.89*19
$GNGSA,A,3,,,,,,,,,,,,,12.71,4.50,11.89*19
$GPGSV,4,1,13,02,45,284,23,03,00,118,08,04,20,064,23,05,10,303,*70
$GPGSV,4,2,13,06,47,206,34,07,63,140,27,09,56,054,,11,54,273,*75
$GPGSV,4,3,13,13,02,247,,16,09,049,,20,39,306,19,29,04,326,*73
$GPGSV,4,4,13,30,41,183,34*40
$GLGSV,1,1,00*65
$GNGLL,4331.51798,N,00134.36985,E,093206.00,A,A*79
Le 8/12/21 à 9h32mn06.00s TU. Ici seuls 4 satellites sont utilisés sur les 13 satellites suivis. Ce sont des satellites du mix GPS+GLONASS. Il semblerait que ce soient des GPS car 13 sont indiqués dans la trame $GPGSV et 0 dans la trame $GLGSV.
Trouvé de guide (non exploité cette trouvaille) : https://randomnerdtutorials.com/arduino-mpu-6050-accelerometer-gyroscope/
J'ai mis la doc et les programmes dans ces dossiers :
D:\MesProgs\arduino\documentation\MPU-6050
D:\MesProgs\arduino\libraries\MPU6050
Cette carte comporte 3 gyromètres et 3 accéléromètres. Sa liaison avec l'Arduino utilise le protocole I2C (bus informatique Inter-Integrated Circuit élaboré par Philips) qui passe par deux lignes :
•SDA (Serial Data Line) : ligne de données bidirectionnelle,
•SCL (Serial Clock Line) : ligne d'horloge de synchronisation bidirectionnelle.
sans oublier la masse commune aux équipements.
Ainis la connexion avec l'Arduino se fait par seulement par 5 fils :
•Vcc relié au +5v de l'Arduino
•GND relié au GND de l'Arduino
•SCL et SDA relié aux entrées analogiques (ANALOG IN), par exemple A5 et A4
•INT l'entrée interruption relié par exemple à la broche digitale numéro 2.
Les 3 broches de la carte MPU6050 marquées XDA, XCL et AD0 ne sont pas utilisée dans l'exemple MPU6050_DMP6 décrit ci-après.
Pour communiquer avec le protocole I2C, Arduino utilise la librairie Wire qui dans le cas de la carte UNO suppose que les broches SCL et SDA de la carte MPU sont reliées au broches A5 et A4 de l'UNO.
En premier lieu, il faut inclure la définition :
#include "I2Cdev.h"
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
#include "Wire.h"
#endif
Ensuite si on utilise le processeur de mouvement 3D interne au circuit MPU6050, on inclut :
#include "MPU6050_6Axis_MotionApps20.h"
sinon, on inclut seulement :
#include "MPU6050.h"
Attention : Le fichier MPU6050_6Axis_MotionApps20.h inclut le fichier helper_3dmath.h qui est une petite bibliothèque c++ d'outils géométriques et quaternion. Elle définit une classe VectorInt16 très mal conçue car sa méthode magnitude() est fausse si la longueur est > 256 et sa méthode normalize() n'a aucun sens car les composantes étant a priori inférieures à zéro, elle serait sensée rencvyer 0 sur toutes les composantes.
Puis on crée un objet MPU6050 :
MPU6050 mpu;
Le protocole I2C est initialisée par :
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
Wire.begin();
#elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
Fastwire::setup(400, true);
#endif
On initialise la communication série entre l'Arduino et l'usager :
Serial.begin(38400); while (!Serial); // jusqu'à 115200 ou + ?
On initialise la carte MPU :
mpu.initialize();
et on teste la réussite (ou l'échec) de l'initialisation.
bool ok = mpu.testConnection();
Serial.println(ok ? "MPU6050 connection successful" : "MPU6050 connection failed");
Fonctions brutes (n'utilisant pas le Processeur de Mouvement Digital : DMP) :
On peut lire les offset des gyros et accéléros par les fonctions suivantes :
int16_t mpu.getXAccelOffset());
int16_t mpu.getYAccelOffset());
int16_t mpu.getZAccelOffset());
int8_t mpu.getXGyroOffset());
int8_t mpu.getYGyroOffset());
int8_t mpu.getZGyroOffset());
et les écrire par les suivantes
mpu.setXAccelOffset(int16_t);
mpu.setYAccelOffset(int16_t);
mpu.setZAccelOffset(int16_t);
mpu.setXGyroOffset(int8_t);
mpu.setYGyroOffset(int8_t);
mpu.setZGyroOffset(-nt8_t);
On peut lire les valeurs des accéléros et gyros de plusieurs manières :
int16_t getAccelerationX ()
int16_t getAccelerationY ()
int16_t getAccelerationZ ()
void getAcceleration (int16_t *x, int16_t *y, int16_t *z)
int16_t getRotationX ()
int16_t getRotationY ()
int16_t getRotationZ ()
void getRotation (int16_t *x, int16_t *y, int16_t *z)
void getMotion6 (int16_t *ax, int16_t *ay, int16_t *az, int16_t *gx, int16_t *gy, int16_t *gz)
Fonctions utilisant le DMP (Processeur Nuumérique de Mouvement).
Initialisation de l'utilisation du DMP dans le setup() :
devStatus = mpu.dmpInitialize();
// 0 : ok; 1 = initial memory load failed; 2 = DMP configuration updates failed
if (devStatus == 0) {
mpu.setDMPEnabled(true);
// enable Arduino interrupt detection : Arduino ext_interrupt 0
attachInterrupt(0, dmpDataReady, RISING); // définit la callback
mpuIntStatus = mpu.getIntStatus();
dmpReady = true;
packetSize = mpu.dmpGetFIFOPacketSize();
} else dmpReady = false; // Panique !!
La fonction attachInterrup déclare le nom de la callback dmpDataReady qui ne fait que positionner un booléen qui sera testé dans la loop() :
volatile bool mpuInterrupt = false;
void dmpDataReady() {
mpuInterrupt = true;
}
Signification des bits du Status qui est lu par mpu.getIntStatus():
#define MPU6050_INTERRUPT_FF_BIT 7
#define MPU6050_INTERRUPT_MOT_BIT 6
#define MPU6050_INTERRUPT_ZMOT_BIT 5
#define MPU6050_INTERRUPT_FIFO_OFLOW_BIT 4 // 0x10 : Overflow de la pile
#define MPU6050_INTERRUPT_I2C_MST_INT_BIT 3
#define MPU6050_INTERRUPT_PLL_RDY_INT_BIT 2
#define MPU6050_INTERRUPT_DMP_INT_BIT 1 // 0x02 : Données DMP pretes
#define MPU6050_INTERRUPT_DATA_RDY_BIT 0 // Données brutes pretes
Il y a intérêt à lire les bits de status tous à la fois plutôt que un par un avec les fonctions spécifiques car chaque lecture remet tous les bits à zéro.
Utilisation dans loop() :
if (!dmpReady) return; // On ne fait rien s'il y a eu échec de l' ini du DMP
// Si des paquets pas deja prets dans la fifo, on attend l'interruption
while (fifoCount < packetSize && !mpuInterrupt) {;}
// Reset de cette interruption et lecture infos pour savoir où on en est
mpuInterrupt = false;
mpuIntStatus = mpu.getIntStatus();
fifoCount = mpu.getFIFOCount();
// Vidange de la pile si overflow
if((mpuIntStatus & 0x10) || fifoCount == 1024) mpu.resetFIFO();
// Traitement des données si données DMP pretes
else if (mpuIntStatus & 0x02) {
// Attente assez de données dans la pile
while(fifoCount < packetSize) fifoCount = mpu.getFIFOCount();
// Lecture données Fifo et MAJour fifoCount
mpu.getFIFOBytes(fifoBuffer, packetSize); fifoCount -= packetSize;
// Transformation des données
mpu.dmpGetQuaternion(&q, fifoBuffer); // fifo => quat
mpu.dmpGetEuler(euler, &q); // quat => Euler
mpu.dmpGetGravity(&gravity, &q); // quat => grav
mpu.dmpGetYawPitchRoll(ypr, &q, &gravity); // quat,grav => ypr
mpu.dmpGetAccel(&aa, fifoBuffer); // fifo => gam
mpu.dmpGetLinearAccel(&aaReal, &aa, &gravity); // grav, gam = acl
}
REMARQUES : Voir sur MPU6050_6Axis_MotionApps20.h car il y a des version 16 et 32 bits qui sont différenciées par le type des arguments !!
•Même convention que moi pour le quaternion qui représente l'attitude du corps mobile par rapport au corps fixe.
•Le vecteur qu'ils appellent gravity est le vecteur unitaire des cosinus directeurs de la direction de l'axe Zo fixe en composante dans le repère mobile.
•Les angles qu'ils appellent Euler correspondent aux 3 rotations successives rx, ry et rz successivement autour des axes X0, Y1, Z2. Euler[0] est -rz, Euler[1] est -ry et Euler[2] est -rx.
•Les angles qu'ils appellent yaw, pitch, roll sont des angles bâtards :
◦yaw est l'azimut de la projection du Xcapteur sur le plan horizontale, azimut par rapport à une direction horizontale fixe Xo arbitraire,
◦pitch est l'angle que fait l'axe Z capteur avec sa projection dans le plan vertical contenant Xo,
◦roll est l'angle que fait l'axe Z capteur avec sa projection dans le plan vertical contenant Yo.
•Ces 2 systèmes (éventuellement utilisables en infographie) n'ont rien d'intéressant pour des applications physiques. Par ailleurs leurs méthodes de calculs méconnaissent totalement la signification des objets qu'ils manipulent. A titre d'exemple les angles pitch et roll sont calculés par les formules suivantes : pitch = atan(u/sqrt(v*v+w*w) et roll = atan(v/sqrt(u*u+w*w), or comme u*u+v*v+w*w=1, on a plus simplement pitch = asin(u) et roll = asin(v).
Filtre Passe-bas :
set : mpu.setDLPFMode(uint8_t val); get : uint8_t mpu.getDLPFMode();
| ACCELEROMETER | GYROSCOPE
DLPF_CFG | Bandwidth | Delay | Bandwidth | Delay | Sample Rate
---------+-----------+--------+-----------+--------+-------------
0 | 260Hz | 0ms | 256Hz | 0.98ms | 8kHz
1 | 184Hz | 2.0ms | 188Hz | 1.9ms | 1kHz
2 | 94Hz | 3.0ms | 98Hz | 2.8ms | 1kHz
3 | 44Hz | 4.9ms | 42Hz | 4.8ms | 1kHz
4 | 21Hz | 8.5ms | 20Hz | 8.3ms | 1kHz
5 | 10Hz | 13.8ms | 10Hz | 13.4ms | 1kHz
6 | 5Hz | 19.0ms | 5Hz | 18.6ms | 1kHz
7 | -- Reserved -- | -- Reserved -- | Reserved
Par défaut DLPF_CFG est sur 3 : bande passante ≈ 43 Hz, (retard 5 ms) et freq. Ech. Gyro = 1 kHz
Filtre passe-haut :
set : mpu.setDHPFMode(uint8_t val); get : uint8_t mpu.getDHPFMode();
ACCEL_HPF | Filter Mode | Cut-off Frequency
----------+-------------+------------------
0 | Reset | None
1 | On | 5Hz
2 | On | 2.5Hz
3 | On | 1.25Hz
4 | On | 0.63Hz
7 | Hold | None
Par défaut c'est sur 0 : pas de coupure du continu.
Fréquence d'échantillonage d'accès aux mesures :
set : mpu.setRate(uint8_t val); get : uint8_t getRate();
La fréquence d'échantillonnage interne des gyros vaut 8 kHz quand le filtre passe-bas (DLPF) est inactif, et 1 kHz quand il est actif. La fréquences d'accès aux sorties est égale à celle des gyros divisée par (1 + SMPLRT_DIV) ou SMPLRT_DIV est positionné ou lu par setRate et getRate.
Toutefois, la fréquence maximale de génération des mesures accéléros est limitée à 1 kHz. Si on règle à une valeur plus élevée, les mêmes mesures sont repétées plusieurs fois.
Par défaut SMPLRT_DIV = 0 => freq. Ech. Mesures = freq. Ech. Gyros = 1 kHz
Domaines de mesure des accéléros :
Les valeurs mesurées en entier sont sur 16 bits signés.
set : mpu.getFullScaleAccelRange(uint8_t val); get : uint8_t getFullScaleAccelRange();
AFS_SEL | Full Scale Range | LSB Sensitivity
--------+------------------+----------------
0 | +/- 2g | 8192 LSB/mg
1 | +/- 4g | 4096 LSB/mg
2 | +/- 8g | 2048 LSB/mg
3 | +/- 16g | 1024 LSB/mg
Par défaut +/- 2g = +/-32756 => g = 16384
Domaines de mesure des gyros :
Les valeurs mesurées en entier sont sur 16 bits signés.
set : mpu.getFullScaleGyroRange(uint8_t val); get : uint8_t getFullScaleGyroRange();
FS_SEL | Full Scale Range | LSB Sensitivity
-------+--------------------+----------------
0 | +/- 250 degrees/s | 131 LSB/deg/s
1 | +/- 500 degrees/s | 65.5 LSB/deg/s
2 | +/- 1000 degrees/s | 32.8 LSB/deg/s
3 | +/- 2000 degrees/s | 16.4 LSB/deg/s
Par défaut
https://www.az-delivery.de/fr/products/ftdi-adapter-ft232rl
Permet d'envoyer sur un port usb les signaux de type série RS232 (RxD, TxD, CTS, DTR) directement avec les broches et certains des autres signaux (DCD, RSD,... ) en soudant aux points prévus à cet effet. Utilisé avec succès pour relier des composants GPS-Neo-6M et Neo-M8N dotés de la sortie One-PPS à un PC par USB.
Un câble pour ce circuit ? :
https://www.amazon.com.au/Converter-Terminated-Galileo-BeagleBone-Minnowboard/dp/B06ZYPLFNB
Circuit permettant de ramener les signaux série RS232 (qui peuvent atteindre ±12V et parfois ±24V) d'un fiche DB9 aux niveaux TTL et réciproquement. A l'arrière les broches marquées GND, TxD, RxD et VCC sont à brancher telles que à L'Arduino, sans croisement : Le RxD au Rx Arduino et le TxD au Tx Arduino.
Voir ce guide : https://randomnerdtutorials.com/arduino-mpu-6050-accelerometer-gyroscope/
Voir ce guide : https://randomnerdtutorials.com/arduino-ir-remote-control/
Ceux qui sont livrés avec l'Arduino sont doubles avec un interrupteur de chaque coté, mais commandés simultanément par un seul bouton poussoir.
Pour lire l'état de ce poussoir, relier une patte à une entrée numérique et à la masse via une résistance de 10 kW, et l'autre patte au +5V. La lecture de l'entrée numérique par un digitalRead(pin) fournira LOW si le poussoir est ouvert et HIGH s'il est fermé.
Pour se servir de ce poussoir en inverseur, on pourra utiliser le code suivant, qui commute l'inverseur uniquement à l'instant d'appui :
valeur = digitalRead(pin);
if (valeur == HIGH && oldvaleur != HIGH) sortie = !sortie;
oldvaleur = valeur;
Ce code est utilsé dans la classe Rupteur présentée ci-après.
Les boutons poussoirs présentant de très mauvais contacts, il est conseillé de lire leur état par le biais de la fonction debounce de la classe poussoir suivante :
// La classe Poussoir donne, à l'aide de la fonction "debounce()", la valeur de lecture de l'état du poussoir
// (HIGH ou LOW) qui ne change que lorsque la valeur est restée stable pendant au moins une certaine durée
class Poussoir
{
int derniereMesure;
unsigned long instantFront;
unsigned long dureeCalme;
int etatStabilise;
int pinoche;
public :
// Constructeur
// pin : numéro broche de lecture du poussoir
// duree : durée minimale (en ms) de stabilité de la valeur pour qu'elle soit prise en compte
Poussoir(int pin, unsigned long duree)
{
pinoche = pin;
derniereMesure = LOW;
instantFront = 0;
dureeCalme = duree;
etatStabilise = LOW;
}
// Lecture valeur stabilisée
int debounce()
{
int mesure = digitalRead(pinoche);
int instantCourant = millis();
if (mesure != derniereMesure) instantFront = instantCourant;
if (instantCourant > instantFront + dureeCalme) etatStabilise = mesure;;
derniereMesure = mesure;
return etatStabilise;
}
};
La classe Rupteur, ci-dessous étend la classe Poussoir pour en faire un télérupteur fiable :
// La classe Rupteur donne à l'aide de la fonction "comut()" un bool qui est vrai si le pousoir a changé
// de valeur stabilisée. L'état du Rupteur est donnée accessible via la fonction etat().
class Rupteur : Poussoir
{
int oldLecture;
int etatCom;
public :
// Constructeur (voir celui de Poussoir pou pin et duree)
// etatIni : etat initial du Rupteur (LOW ou HIGH, au choix
Rupteur(int pin, unsigned long duree, int etatIni) : Poussoir(pin, duree)
{
etatCom = etatIni;
oldLecture = etatIni;
}
// Interrogation du rupteur : Retourne
// vrai si l'état à commuté depuis le dernier appel et faux sinon
bool comut()
{
bool sw = false;
int lecture = debounce();
if (lecture == HIGH && oldLecture != HIGH) { etatCom = !etatCom; sw = true;}
oldLecture = lecture;
return sw;
}
int etat() {return etatCom;}
};
Exemple de commutation de la led 13 de l'Uno avec l'entrée du poussoir sur pin n°2.
#include "poussoir.h" // Classes Poussoir et Rupteur
#define valIni LOW
Rupteur p(2, 20, valIni);
void setup() {
pinMode(2, INPUT);
pinMode(13, OUTPUT); // ledin
digitalWrite(13, valIni);
}
void loop() {
if (p.comut()) {digitalWrite(13, p.etat());}
}
Ce sont des diodes qui éclairent quand elles sonr parcourues (dans le bon sens) par un courant. Brancher la cathode (patte courte) via une résistance de 220 ohm à la masse, et pour l'allumer envoyer sur l'anode (patte longue représentée tordue) une tension positive, par exemple via un digitalWrite(pin, HIGH).
Pattes 1,2,3 de gauche à droite en regardant le coté plat qui est vers nous, le bombé étant de l'autre coté dans la direction du regard. Patte 1 au +5V, patte 3 à la masse et patte 2 (milieu) vers une entrée analogique (A0 à A5)
Il est allongé et a 4 pattes sur une des 2 petites faces. Quand il est disposé grandes faces horizontales, une bille est en équilibre et va se déplacer d'un coté ou de l'autre dès qu'une des 2 petite face est plus haute que l'autre. Sur la petite face opposée aux pattes , une flèche et un UP inscrit indique le haut et les bas. La grande face que l'on met en bas est rainurée. Les deux broches coté bas sont en circuit ouvert ou fermé suivant dès qu'on monte ou descend une petite face par rapport à l'autre. Pour lire son état, procéder comme pour un bouton poussoir (+5V sur une patte, l'autre vers une entrée numérique, reliée à la masse via 10 kW.
Une broche à la masse et l'autre alimentée par une sortie digitale sur laquelle on envoie des commandes tone(pin, frqq, duree);
Une broche au +5v et l'autre reliée à la masse via une résistance de 1 MW. La tension variable (à priori faible de l'ordre de 0.1v à 1v) au niveau de cette dernière, envoyée sur une entrée analogique permet de détecter via un analogRead(pin) le niveau des vibrations subies par le buzzer.
Type : Encoder 600 P / R Photoelectric Incremental Rotary 5-24V AB Two Phases 6mm Shaft
Source de puissance: DC 5-24V
Arbre: 6*13mm
Dimension: 38*35.5mm
Sortie :circuit pulse orthogonaux rectangulaires 2 phases AB, type NPN collecteur ouvert.
Vitesse maximale : 5000 tours / min
Réponse en fréquence : 0-20KHz
Longueur câble: 1.5 m
Note: La sortie 2 phases AB ne doit pas être directement connecté au VCC, cela brulerait la triode de sortie.
Connexions :
Vert : phase A
Blanc : B phase,
Rouge :Vcc power +,
Noir = 0 V.
Modèle SM-S2309S. Trois fils : Masse noire, 5V rouge et commande blanche. Mettre un condensateur de découplage de 100 μF entre le 5 Volts et la masse pour atténuer les appels de courants.
#include <Servo.h>
Servo myServo; // déclaré en global par exemple
myServo.attach(9); // Dans le setup(), on déclare le numéro de la broche PWM (9 par exemple) qui commande le servo.
myServo.write(angle); // Dans loop() on commande un angle compris entre les entiers 0 à 179 au servo.
Le moteurs à courant continu fourni avec l'Arduino UNO est alimenté par 2 fils rouge et noir. L'Arduino n'ayant pas la puissance nécessaire pour alimenter ce moteur, le montage fait appel à une batterie supplémentaire pour apporter tension et puissance et à un transistor à effet de champ à grille isolée appelé MOSFET pour délivrer le courant. Ce mosfet (IRF520 Y56K BC ) est de type NPN dans la cas de l'exercice 9 du Arduino starter kit. Le fil rouge du moteur est directement relié au + 9V fourni par la batterie et le noir est relié à la masse par l'intermédiaire du mosfet qui va servir de robinet. Ainsi le fil noir du moteur est relié à la broche D (pour Drain) du mosfet, dont la broche S (pour Source) est reliée à la masse. La commande est effectuée par broche G (pour grille) du mosfet qui est reliée à une sortie numérique, sur laquelle on enverra digitalWrite(pin, LOW) pour bloquer le moteur et digitalWrite(pin, HIGH) pour le faire tourner.
Source à gauche, drain à droite et grille à droite. (Attention la grille n'est pas au milieu !)
Remarque : Quand on envoie la commande arrêt, l'inertie de la charge fait que le moteur continue de tourner se comportant alors en génératrice qui à tendance à perpétuer le courant qui la traversait auparavant, courant qui peut abimer le mosfet. Pour éviter cela on met une diode en parallèle du moteur, dans un sens tel que le courant produit par le mosfet (qui fait débiter la batterie) ne traverse pas la diode (elle est donc mise avec la cathode vers le plus de la batterie). Par contre le courant produit par le moteur, au lieu de descendre vers le mosfet pourra passer par cette diode.
Pour fournir la puissance on utilise une pile de 9v dont la masse est reliée à celle de l'Arduino. Le circuit intégré réalisant le pont en H est mis en oeuvre dans l'exercice 09.
Ce circuit permet de faire tourner un moteur à courant continu dans les deux sens, à vitesse variable (en fait ce serait plutot à couple tension de commande variable). Il gère 4 canaux (1,2,3 et 4). Dans l'exercice seul les canaux 1 et 2 sont utilisés (pour faire tourner le moteur dans les 2 sens).
Le pont en H comporte (numéro des broches entre parenthèses) :
•2 broches Vcc : Vcc1 (16) est reliée ua +5v de l'Arduino et Vcc2 (8) qui est reliée au +9v de la pile.
•4 broches masse et dissation de chaleur (4, 5, 12, 13). Dans l'exemple seules les broches 4 et 5 sont reliées à la masse, les broches 12 et 13 sont inutilsées.
•Une broche notée 1,2Enable (1) d'activation des canaux 1 et 2 (reliée à une sortie numérique pour gérer cette activation)
•Une broche notée 1,2Enable (9) d'activation des canaux 3 et 4, inutilisée.
•Deux broches de gestion du sens de rotation du moteur par les canaux 1 et 2 notées 1A (2) et 2A (7), reliées à des sorties digitales. L'envoi de 00 et 11 sur ces broches mettent le moteur à l'arrêt, 01 indique un sens et 10 l'autre.
•Deux broches de gestion du sens de rotation du moteur par les canaux 3 et 4 notées 3A (10) et 4A (15) inutilisées.
•Deux broches pour les sorties des commandes du moteur canaux 1 et 2 notées 1Y (3) et 2Y(6) sont reliées aux 2 poles du moteur.
•Deux broches pour les sorties des commandes du moteur canaux 3 et 4 notées 3Y (11) et 4Y(14) sont inutilisées.
Principe du pont en H :
Si VA = 0 et VB = 5v, Q2 et Q4 sont bloqués et Q1 et Q3 conduisent. Le +5v traverse le moteur en passant par Q1, le moteur puis Q3, + coté A.
Si VA = 5v et VB = 0, Q1 et Q3 sont bloqués et Q2 et Q4 conduisent. Le +5v traverse le moteur en passant par Q4, le moteur puis Q2, + coté B.
Si VA = 0 et VB = 0, Q2 et Q3 sont bloqués et Q1 et Q4 conduisent. Le +5v arrive aux 2 bornes. Pas de ddp. Aucun courant ne passe.
Si VA = 5v et VB = 5v, Q1 et Q4 sont bloqués et Q2 et Q3 conduisent. Les 2 bornes sont à la masse. Pas de ddp. Aucun courant ne passe.
Un transistor est un composant à 3 connexions qui s'appellent (standard / effet de champ):
•l'émetteur (E) / la source (S) qui est traversée par l'ensemble du courant, et qui est symbolisé avec une flèche dans le sens du courant,
•la base (B) / la grille (G) qui commande le passage du courant,
•le collecteur (C) / le drain (D).
Un transistor à deux jonction PN et NP consécutives (le courant conventionnel circule de P vers N). Il y a deux types :
•le type NPN avec la zone P au centre. Le collecteur a une tension supérieure à celle de l'émetteur (Vc >> Ve). La flèche sort par l'émetteur, car le courant conventionnel va du collecteur vers l'émetteur. Le transistor conduit si Vb > Ve + 0.6V et la faible chute de tension totale Vce est de l'ordre de 0.1 à 2v suivant les modèles
•Le type PNP avec la zone N au centre. L'émetteur a une tension supérieure à celle du collecteur (Ve >> Vc). La flèche entre par l'émetteur, car le courant conventionnel va du collecteur vers l'émetteur. Le transistor conduit si Vb < Ve – 0.6V et la faible chute de tension totale Vec est de l'ordre de 0.1 à 2v suivant les modèles (Vce de l'ordre de -0.1 à -2V).
Dans les deux cas le transistor conduit quand la tension de la base se rapproche de celle du collecteur et se bloque quand la tension de la base se rapproche de celle de l'émetteur.
Le 1er schéma à gauche est utilisé lorsque les tensions sont plus grandes en haut qu'en bas. Il implique d'inverser la position des broches collecteur et émetteur.
Dans le 2ème schéma à droite, les collecteurs sont en haut et les émetteurs en bas. Dans ce cas la tension est plus grande en haut qu'en bas dans le cas du NPN (comme pour le 1er schéma), mais c'est l'inverse dans le cas du NPN.
Le transistor est un robinet fermé quand la tension de la base est voisine de celle de l'émetteur, et il s'ouvre quand elle se rapproche de celle du collecteur.
- Redémarrage logiciel par un jump à l'adresse 0, en appelant la routine suivante :
// Redémarre le programme depuis le début
void software_Reset()
{
asm volatile (" jmp 0");
}
mais ne remet pas à zéro les registres : les états des pins (HIGH, LOW…) sont conservés et les shields externes ne sont pas redémarrés.
Pour utiliser le watchdog, il faut d'inclure le fichier avr/wdt.h et appeler ensuite la fonction wdt_enable().
La fonction wdt_enable accepte le temps à attendre avant de lancer un Reset automatique de la carte s'il n'y a pas d'autre appel au watchdog.
Constantes pour durées prédéfinies prédéfinies :
15mS WDTO_15MS
30mS WDTO_30MS
60mS WDTO_60MS
120mS WDTO_120MS
250mS WDTO_250MS
500mS WDTO_500MS
1S WDTO_1S
2S WDTO_2S
4S WDTO_4S
8S WDTO_8S
Pour forcer le reset de la carte, il suffit alors d'implémenter une courte boucle, le système reboot lorsque le temps choisi expire (timeout).
L'exemple suivant utilise la plus petite valeur pour le timeout. Il suffit d'appeler la fonction software_Reboot pour rebooter la carte.
#include <avr/wdt.h>
void software_Reboot()
{
wdt_enable(WDTO_15MS); while(1){}
}
L'arduino possède une broche "Reset" (à coté du +3,3V sur le Uno"). Il suffit de raccorder une résistance de 1K entre la broche Reset et une broche digitale (ex: la pin 12).
Ensuite, il suffit d'utiliser la fonction suivante qui simule la pression du bouton Reset
void pushReset()
{
int pin=12; pinMode(pin, OUTPUT);
digitalWrite(pin, LOW);
}
random(n) → entier aléatoire compris entre 0 et n.
iy = map(ix, ix1, ix2, iy1, iy2);
•Arduino Uno : La plus simple
•Arduino Leonardo : Evolution de l'Uno qui n'a pas eu de succès.
•Arduino Mega : La plus diffussée après la Uno. Mieux équipée et plus puissante.
•Arduino Mega ADK : idem Mega mais ouverte sur le monde Android.
•Arduino Due : La plus performante au niveau algorithmes (doubles en 64 bits)
•Arduino Nano : Une Uno miniaturisée.
•Arduino Yun : Orientée Linux dotée nativement d’un wifi intégré.
|
Uno |
Mega 2560 |
Due |
Nano |
µcontroleur |
ATmega328P |
ATmega2560 |
AT SAM3X8E |
ATmega328 |
Flash |
32 ko |
256 ko |
512 ko |
32 ko |
EEPROM |
1 ko |
4 ko |
0 |
1 ko |
SRAM |
2 ko |
8 ko |
96 ko |
2 ko |
E/S Num |
14 |
54 |
54 |
14 |
dont PWM |
6 |
15 |
12 |
6 |
SPI |
1 |
1 |
1 |
1 |
LED |
1 |
1 |
1 |
1 |
TWI (I2C) |
1:(A4-5) |
1:(d20-21) + ?? |
2 |
1:(A4-5) |
Entrées Analogiques |
6 |
16 |
12 |
8 |
Série (mat.) |
1 |
4 |
4 |
1 |
Interrup. ext. |
2 |
6 |
54 |
2 |
#if defined(TEENSYDUINO)
// --------------- Teensy -----------------
#if defined(__AVR_ATmega32U4__)
#define BOARD "Teensy 2.0"
#elif defined(__AVR_AT90USB1286__)
#define BOARD "Teensy++ 2.0"
#elif defined(__MK20DX128__)
#define BOARD "Teensy 3.0"
#elif defined(__MK20DX256__)
#define BOARD "Teensy 3.2" // and Teensy 3.1 (obsolete)
#elif defined(__MKL26Z64__)
#define BOARD "Teensy LC"
#elif defined(__MK64FX512__)
#define BOARD "Teensy 3.5"
#elif defined(__MK66FX1M0__)
#define BOARD "Teensy 3.6"
#else
#error "Unknown board"
#endif
#else // --------------- Arduino ------------------
#if defined(ARDUINO_AVR_ADK)
#define BOARD "Mega Adk"
#elif defined(ARDUINO_AVR_BT) // Bluetooth
#define BOARD "Bt"
#elif defined(ARDUINO_AVR_DUEMILANOVE)
#define BOARD "Duemilanove"
#elif defined(ARDUINO_AVR_ESPLORA)
#define BOARD "Esplora"
#elif defined(ARDUINO_AVR_ETHERNET)
#define BOARD "Ethernet"
#elif defined(ARDUINO_AVR_FIO)
#define BOARD "Fio"
#elif defined(ARDUINO_AVR_GEMMA)
#define BOARD "Gemma"
#elif defined(ARDUINO_AVR_LEONARDO)
#define BOARD "Leonardo"
#elif defined(ARDUINO_AVR_LILYPAD)
#define BOARD "Lilypad"
#elif defined(ARDUINO_AVR_LILYPAD_USB)
#define BOARD "Lilypad Usb"
#elif defined(ARDUINO_AVR_MEGA)
#define BOARD "Mega"
#elif defined(ARDUINO_AVR_MEGA2560)
#define BOARD "Mega 2560"
#elif defined(ARDUINO_AVR_MICRO)
#define BOARD "Micro"
#elif defined(ARDUINO_AVR_MINI)
#define BOARD "Mini"
#elif defined(ARDUINO_AVR_NANO)
#define BOARD "Nano"
#elif defined(ARDUINO_AVR_NG)
#define BOARD "NG"
#elif defined(ARDUINO_AVR_PRO)
#define BOARD "Pro"
#elif defined(ARDUINO_AVR_ROBOT_CONTROL)
#define BOARD "Robot Ctrl"
#elif defined(ARDUINO_AVR_ROBOT_MOTOR)
#define BOARD "Robot Motor"
#elif defined(ARDUINO_AVR_UNO)
#define BOARD "Uno"
#elif defined(ARDUINO_AVR_YUN)
#define BOARD "Yun"
// These boards must be installed separately:
#elif defined(ARDUINO_SAM_DUE)
#define BOARD "Due"
#elif defined(ARDUINO_SAMD_ZERO)
#define BOARD "Zero"
#elif defined(ARDUINO_ARC32_TOOLS)
#define BOARD "101"
#else
#error "Unknown board"
#endif
Alimentation :
La carte peut être alimentée soit par le jack d'alimentation CC (7 - 12 V), le connecteur USB (5 V) ou la broche VIN de la carte (7-12 V) .
Les broches sortie d'alimentation sont les suivantes :
•5V : sortie 5V régulé du régulateur sur la carte.
•3V3. sortie 3,3 volts régulé du régulateur sur la carte. Consommation maximale de 50 mA.
•GND. Broches de terre.
•IOREF. Cette broche sur la carte Arduino fournit la référence de tension avec laquelle fonctionne le microcontrôleur. Un blindage correctement configuré peut lire la tension de la broche IOREF..
Mémoire :
L'ATmega328 dispose de 32 Ko (dont 0,5 Ko occupé par le bootloader). Il possède également 2 Ko de SRAM et 1 Ko d'EEPROM (qui peuvent être lus et écrits avec la bibliothèque EEPROM ).
Entrée-Sortie numériques :
- 14 broches numériques de l'Uno peut être utilisée comme entrée ou sortie, à l'aide des fonctions pinMode() , digitalWrite() et digitalRead() . Elles fonctionnent sous 5 volts. Chaque broche peut fournir ou recevoir 20 mA selon les conditions de fonctionnement recommandées et possède une résistance de rappel interne (déconnectée par défaut) de 20 à 50 kohms. Un maximum de 40 mA est la valeur qui ne doit être dépassée sur aucune broche d'E/S .
- Fonstions spécialisées :
•Série : 0 (RX) et 1 (TX). E/S série TTL. Ces broches sont connectées aux broches correspondantes de la puce série ATmega8U2 USB-to-TTL.
•Interruptions externes : 2 et 3. Ces broches peuvent être configurées par la fonction attachInterrupt().
•PWM : 3, 5, 6, 9, 10 et 11. Fournissez une sortie PWM 8 bits avec la fonction analogWrite().
•SPI : 10 (SS), 11 (MOSI), 12 (MISO), 13 (SCK). Ces broches prennent en charge la communication SPI à l'aide de la bibliothèque SPI.
•LED : 13. Il y a une LED intégrée pilotée par la broche numérique 13 (allumée si HIGH et éteinte si LOW).
•TWI : broche A4 ou SDA et broche A5 ou SCL. Prise en charge de la communication TWI à l'aide de la bibliothèque Wire.
Entrées analogiques :
- 6 entrées analogiques, étiquetées A0 à A5, chacune fournissant 10 bits de résolution de 0 à 5 volts, mais il est possible de modifier l'extrémité supérieure de la plage à l'aide de la broche AREF et de la fonction analogReference().
- AREF. Tension de référence pour les entrées analogiques. Utilisé avec analogReference().
Autres :
- Reset. Mettre à LOW pour réinitialiser le microcontrôleur. Généralement utilisé lorsque le bouton de reset est rendu inaccessible par un montage annexe.
Communication
L'ATmega328 fournit une communication série UART TTL (5V), disponible sur les broches numériques 0 (RX) et 1 (TX). Un ATmega16U2 sur la carte canalise cette communication série via USB et apparaît comme un port de communication virtuel pour le logiciel sur l'ordinateur. Le micrologiciel 16U2 utilise les pilotes COM USB standard et aucun pilote externe n'est nécessaire. Cependant, sous Windows, un fichier .inf est requis . Le logiciel Arduino (IDE) comprend un moniteur série qui permet d'envoyer des données textuelles simples vers et depuis la carte. Les LED RX et TX de la carte clignotent lorsque les données sont transmises via la puce USB-série et la connexion USB à l'ordinateur (mais pas pour la communication série sur les broches 0 et 1).
Une bibliothèque SoftwareSerial permet la communication série sur n'importe laquelle des broches numériques de l'Uno.
L'ATmega328 prend également en charge les communications I2C (TWI) et SPI. Le logiciel Arduino (IDE) comprend une bibliothèque Wire pour simplifier l'utilisation du bus I2C ; Pour la communication SPI, utilisez la bibliothèque SPI .
Reset Logiciel :
Une des lignes de contrôle de flux matériel (DTR) de l'ATmega8U2/16U2 est connectée à la ligne de réinitialisation de l'ATmega328 via un condensateur de 100 nanofarads ce qui permet à l'IDE de télécharger du code en appuyant simplement sur le bouton de téléchargement dans la barre d'outils de l'interface sans avoir à appyer sur le bouton reste de l'Arduino.
Cette configuration a d'autres implications. Lorsque l'Uno est connecté à un ordinateur exécutant Mac OS X ou Linux, il se réinitialise à chaque fois qu'une connexion est établie à partir d'un logiciel (via USB). Pendant environ la demi-seconde suivante, le chargeur de démarrage (bootloader) s'exécute sur l'Uno. Bien qu'il soit programmé pour ignorer les données malformées (c'est-à-dire tout autre chose qu'un téléchargement de nouveau code), il interceptera les premiers octets de données envoyés à la carte après l'ouverture d'une connexion. Si un sketch exécuté sur la carte reçoit une configuration unique ou d'autres données lors de son premier démarrage, assurez-vous que le logiciel avec lequel il communique attend une seconde après l'ouverture de la connexion et avant d'envoyer ces données.
•Serial : RX=0, TX=1
•Serial1 : RX=19, TX=18
•Serial2 : RX=17, TX=16
•Serial3 : RX=15, TX=14
- 6 interruptions externes accessibles via l'instruction attachInterrupt(). Broches :
•2 (interrupt 0),
•3 (interrupt 1),
•18 (interrupt 5),
•19 (interrupt 4),
•20 (interrupt 3),
•21 (interrupt 2).
- PWM (largeur d'impulsion modulée) accessibles via l'instruction analogWrite():
•Broches 0 à 13
- SPI (Interface Série Périphérique): Broches 50 (MISO), 51 (MOSI), 52 (SCK), 53 (SS).
- I2C: Broches 20 (SDA) et 21 (SCL).
- LED incluse: Broche 13.
- Broches analogiques accessibles via l'instruction analoganalogRead()
•16 entrées analogiques (10 bits cad 0 à 1023) entre le 0V (valeur 0) et le 5V (valeur 1023)
Note : les broches analogiques peuvent être utilisées en tant que broches numériques.
- AREF : Tension de référence pour les entrées analogiques (si différent du 5V). Utilisée avec l'instruction analogReference().
- Reset : Mettre cette broche au niveau BAS entraîne le redémarrage du microcontrôleur.
Attention :
Les port série/USB des cartes officielles utilise le chip FTDI qui est bien pris en charge par Windows 10 et des copies chinoises utilisent parfois le chip CH340 qui n'est pas pris en charge nativement et qui nécessite l'installation d'un driver (à télécharger où ?).
Alimentation via port USB, ou 5 Vcc régulée sur broche 27, ou 6 à 20 V non régulée sur broche 30.
Mémoire
•Atmega168 : flash: 16 ko, SRAM: 1 ko, EEPROM: 512 ko
•Atmega328 : flash: 32 ko, SRAM: 2 ko, EEPROM: 1 ko
Cadencement: 16 MHz
01 TX1 D1 (E/S) Broche série TX
02 RX0 D0 (E/S) Broche série RX
03 RST Reset
04 GND Masse d’alimentation
05 D2 D2 (E/S) et Envoi Int.
06 D3 D3 (E/S) et Envoi Int. et PWM
07 D4 D4 (E/S)
08 D5 D5 (E/S) et PWM
09 D6 D6 (E/S) et PWM
10 D7 D7 (E/S)
11 D8 D8 (E/S)
12 D9 D9 (E/S) et PWM
13 D10 D10 (E/S) et PWM
14 D11 D11 (E/S) et PWM
15 D12 D12 (E/S)
16 D13 D13 (E/S) – LED intégrée
17 3V3 Sortie 3.3V
18 REF AREF Entrée AREF
19 A0 A0 Entrée analogique 0
20 A1 A1 Entrée analogique 1
21 A2 A2 Entrée analogique 2
22 A3 A3 Entrée analogique 3
23 A4 A4 Entrée analogique 4
24 A5 A5 Entrée analogique 5
25 A6 A6 Entrée analogique 6
26 A7 A7 Entrée analogique 7
27 5V Entrée/Sortie 5V
28 RST Reset
29 GND Masse d’alimentation
30 VIN Alimentation
AREF : Tension de référence pour les entrées analogiques (si différent du 5V). Utilisée avec l'instruction analogReference().
Reset : Mettre cette broche au niveau BAS entraîne le redémarrage du microcontrôleur.
Les 6 broches à l'opposé du port USB constituent un port ICSP (In Circuit Serial Programming, parfois noté ISCP) qui peut être utilisé pour flasher l'ATmega (méthode ??)
Liste par catégories (il y a des recoupements)
•14 broches digitales I/0 : broches 1 ,2,5,6,7,8,9,10,11,12,13,14,15,16. Voltage bas 0V, haut +5V, courant 40 mA.
•6 broches PWM : broches 6 (D3), 8 (D5), 9 (D6), 12 (D9), 13 (D10), 14 (D11)
•8 broches entrées analogiques : broches 18 à 26
•Communication série : broches 1(TX1 = D1), 0 (RX0 = D0)
•Seules les broches 5 (D2) et 6 (D3) peuvent être utilisées pour envoyer des interruptions.
Alimentation de la carte : 3 solutions :
1.Via le port USB
2.Alim régulée 5V sur broche 5V (n° 27)
3.Alim entre 7 et 12 v sur broche Vin (n° 30)
Contrairement aux autres cartes Arduino, l'Arduino Due fonctionne à 3.3 V au lieu des 5 V des autres cartes, de plus les réels "double" sont en 64 bits et toutes les broches numériques D peuvent envoyer des interruptions. La prise usb pour la programmation est celle qui est proche du jack d'alimentation.
•Microcontrôleur: Atmel SAM3X8E ARM Cortex-M3 32 bits 84 Mhz
•Mémoires RAM: 96 Ko (répartis dans 2 banques de 64 Ko + 1 banque de 32 Ko)
•2 microUSB: il en a 2 : Un pour la programmation (la plus proche de la prise d'alimentation) sélectionnée dans l'IDE par "ProgrammingPort" et un autre qui peut être utilisé en sélectionnant "NativeUSBPort".
•Flash: 512 Ko, tous disponibles au programme,
•Tension de fonctionnement: 3.3v (il y a une broche 5v pour les projets)
•Tension d'entrée (recommandée): 7-12v
•Tension d'entrée (limite maximale): 6-16v
•54 Broches d'E/S numériques dont 12 PWM.
•12 Broches d'entrée analogiques
•2 Broches de sortie analogique (CNA)
•Intensité du courant par broche d'E / S: 130mAI
•Intensité du courant pour la broche 3.3v: 800mA
•Intensité du courant pour la broche 5v: 800mA
Il y a un port USB OTG haute vitesse, 4 UART, un connecteur JTAG, un bouton de réinitialisation, un bouton de suppression, un connecteur SPI et 2 TWI avec broches SDA et SCL
•Instruction IOREF qui permet à un bouclier d'adapter sa tension à celle de la plaque.
•Une broche non connectée Réservé pour une utilisation future.
Arribution des broches :
•Série 0: sur la broche 0 (RX) et la broche 1 (TX)
•Série 1: broche 19 (RX) et broche 18 (TX)
•Série 2: broche 17 (RX) et broche 16 (TX)
•Série 3: broche 15 (RX) et broche 14 (TX)
•PWM: passez des broches 2 à 13 pour fournir un PWM 8 bits.
•E/S numériques: de la broche 0 à 53
•Sorties analogiques: de la broche A0 à A11
•SPI: Tête SPI
•CAN: CANRX et CANTX pour la communication CAN
•DEL intégré inclus et connecté à la broche 13
•TWI 1: broche 20 (SDA) et broche 21 (SCL)
•TWI 2: marqué comme SDA1 SCL1
•DAC1 et DAC2 avec une résolution dans sa sortie de 12 bits (4096 niveaux) avec analogWrite () avec des tensions de 0.55v à 2.75v.
•AREF: une entrée analogique comme référence de tension. Utilisé avec la fonction analogReference ()
•Réinit: si vous réglez cette ligne sur un niveau de tension bas ou bas, le microcontrôleur se réinitialise.
Brochage :
Pour la programmation avec l'IDE, il faut choisir la carte Arduino Due, dans les cartes ARM (32 bits) et non pas dans les cartes AVR (8 bits), celle via "Programming port" (celui qui est du coté du jack d'alimentation) et non l'autre (Native USB Port).
Réinitialisation automatique (logicielle)
Le microcontrôleur SAM3X diffère des microcontrôleurs AVR car la mémoire flash doit être effacée avant d'être reprogrammée. Une procédure manuelle impliquerait de maintenir enfoncé le bouton d'effacement pendant une seconde, d'appuyer sur le bouton de téléchargement dans l'IDE, puis sur le bouton de réinitialisation.
La procédure manuelle d'effacement-flash étant répétitive, elle est gérée automatiquement par les deux ports USB, de deux manières différentes :
Port natif
L'ouverture et la fermeture du port ''Natif' au débit en bauds de 1200bps déclenchent une procédure de "soft erase" : la mémoire flash est effacée et la carte est redémarrée avec le bootloader. Si, pour une raison quelconque, le MCU devait planter au cours de ce processus, il est probable que la procédure d'effacement en douceur ne fonctionnerait pas comme c'est le cas dans le logiciel du MCU lui-même.
L'ouverture et la fermeture du port natif à un débit en bauds autre que 1200bps ne réinitialisera pas le SAM3X. Pour utiliser le moniteur série et voir ce que fait votre sketch depuis le début, vous devrez ajouter quelques lignes de code dans le setup(). Cela garantira que le SAM3X attendra que le port SerialUSB s'ouvre avant d'exécuter l'esquisse :
while (!Serial) ; [Obtenir le code]
L'Appui sur le bouton Reset du Due provoque la réinitialisation du SAM3X ainsi que la communication USB. Cette interruption signifie que si le moniteur série est ouvert, il est nécessaire de le fermer et de le rouvrir pour redémarrer la communication.
Port de programmation
Le port de programmation utilise une puce USB-série connectée au premier UART du MCU (RX0 et TX0). La puce USB-série a deux broches connectées aux broches de réinitialisation et d'effacement du SAM3X. Lorsque vous ouvrez ce port série, l' USB-série active la séquence d'effacement et de réinitialisation avant de commencer à communiquer avec l'UART du SAM3X. Cette procédure est beaucoup plus fiable et devrait fonctionner même si le MCU principal est tombé en panne.
Pour communiquer en série avec le port de programmation, utilisez l'objet "Serial" dans l'IDE. Tous les croquis existants qui utilisent une communication série basée sur la carte Uno devraient fonctionner de la même manière. Le port de programmation se comporte comme le port série de l'Uno en ce sens que la puce USB-série réinitialise la carte chaque fois que vous ouvrez le moniteur série (ou toute autre communication série).
Le fait d'appuyer sur le bouton de réinitialisation pendant la communication via le port de programmation ne ferme pas la connexion USB avec l'ordinateur car seul le SAM3X est réinitialisé.
Dans un Arduino c'est de la SRAM (pour Static Random Access Memory), qui est plus rapide mais aussi plus consommatrice en énergie que la RAM dynamique de ordinateurs. Elle est entièrement effacée lorsque l’alimentation de l’Arduino cesse.
L’EEPROM (Electrically Erasable Programmable Read-Only Memory) est capable de stocker des informations même lorsqu’elle n’est plus alimentée. La vitesse d’accès est moins élevée que la RAM et sa durée de vie (nombre de cycle d’écritures possible) est également plus faible.
Pour pouvoir manipuler l’EEPROM, il faut dans un premier temps inclure la bibliothèque EEPROM.h. Une case mémoire qui n’a jamais été utilisée possède une valeur initiale de 255.
Enregistrer des données
La mémoire EEPROM est donc divisée en 1024 blocs de 8 bits. Pour écrire une donnée, il préciser dans quel bloc on veut l’enregistrer au moyen de la fonction EEPROM.write() qui prend comme arguments l’adresse (int entre 0 et 1023) et l’octet à enregistrer (unsigned char).
EEPROM.write(600, 42); //adresse = 600, valeur = 42
Lire des données
unsigned char donnee = EEPROM.read(600); //adresse = 600
//Ecriture d'un type int en mémoire EEPROM
void sauverInt(int adresse, int val)
{
unsigned char faible = val & 0x00FF;
unsigned char fort = (val >> 8) & 0x00FF;
EEPROM.write(adresse, fort) ;
EEPROM.write(adresse+1, faible);
}
//lecture de l'int enregistrée par la fonction précédente
int lireInt(int adresse)
{
int val = 0 ;
unsigned char fort = EEPROM.read(adresse);
unsigned char faible = EEPROM.read(adresse+1);
val = fort ;
val = val << 8 ;
val = val | faible ;
return val ;
}
Elle sert à stocker le programme téléchargé dans le microcontrôleur même lorsque l’alimentation est coupée et le bootloader. Ce dernier détecte au démarrage de l’Arduino si on tente de programmer la carte via la liaison série et le cas échéant il copie les données dans la mémoire FLASH. On n’y stocke pas de données pendant l’exécution du programme. En revanche, on peut y stocker des constantes afin de gagner un peu de place dans la RAM.
Avec la DUE il est en théorie possible d’écrire dans la mémoire Flash pendant l’exécution du programme, mais aucune bibliothèque dédiée n’existe pour le moment.
La "mémoire de programme" (ou encore "Progmem") sert d’ordinaire à stocker le code créé puis compilé. On ne peut enregistrer des données dedans qu’au moment du téléchargement du programme. Une fois le programme chargé, elle agit en lecture seule, si bien qu'on ne peut que récupérer des données injectées plus tôt.
Enregister des données dans la mémoir Flash
Les données que l'on peut enregistrer dans la mémoire Flash sont de char, int, long (unsigned ou signed).
On utilise la librairie avr/pgmspace.h et le modificateur PROGMEM lors de sa déclaration (tout en majuscule) :
#include <avr/pgmspace.h>
const int myint1 PROGMEM = 42; //ce int est enregistré en mémoire flash
const PROGMEM int myint2 = 42 ; //ce int est enregistré en mémoire flash
Le mot-clé PROGMEM ne doit pas être situé entre le type et le nom de la variable.
La lecture se fait à partir de l'adresse par
pgm_read_byte() -> pour lire un char
pgm_read_word() -> pour lire un int
pgm_read_dword() -> pour lire un long
Exemple :
#include <avr/pgmspace.h>
const unsigned char unChar PROGMEM = 42;
const unsigned int unInt PROGMEM = 1324;
const unsigned long unLong PROGMEM = 987654;
const char message[] PROGMEM = "Salut les gens !";
void setup()
{
Serial.begin(9600);
Serial.print("Mon char : ");
Serial.println(pgm_read_byte(&unChar));
Serial.print("Mon int : ");
Serial.println(pgm_read_word(&unInt));
Serial.print("Mon long : ");
Serial.println(pgm_read_dword(&unLong));
char temp = pgm_read_byte(message); //on récupère le premier caractère
char i=0;
while(temp != '\0')
{
Serial.print(temp);
i++;
temp = pgm_read_byte(message + i);
}
Serial.println();
Serial.println(F("Encore plus simple !"));
}
Pour les chaines de caractères il y a plus simple avec la fonction F().
F("Chaine completement en flash !")
1le code PRN (Pseudo ramdom noise) est un numéro qui caractérise la fonction occupée par un satellite dans sa constellation