Arduino, debugging, et autres trucs

26/033/24

***Pour revenir à la page d’accueil** ICI


************En cas de refus  de chargement du code dans la bête  ( Esp32 , Nano33...)*******************

Pour l' IDE classique ou même la V2 :

 --Localiser le répertoire Arduino15  (C:\users\votre nom\AppData\Local\Arduino15 )
On peut le renommer par sécurité mais c'est en fait inutile, 

--Relancer l'IDE qui recrée aussitôt un nouvel Arduino15.

 --Recharger les biblis des processeurs que vous utilisez: par

Outil/Gérer les bibliothèques


Pourquoi choisir un Arduino comme microcontrôleur ?

Facilité d’emploi et relative portabilité du langage C, de plus augmenté d’appels de fonctions puissantes.

Par exemple analogRead(), qui sait exploiter le convertisseur analogique/numérique, sans plus de spécifications de la part de l’utilisateur.

Deuxième raison

Son interface USB intégrée permet de le programmer directement avec n’importe quel PC sans programmeur spécifique.

Troisième raison

Son coût ridiculement faible, autour de 3€, câble USB et port compris, pour un clone d’ Arduino-Nano, par exemple.

Pour ce prix on dispose d’une alimentation régulée, d’une puce USB, d’un quartz 16 MHz, de 4 Leds, un interrupteur de reset, une puce Atmel 328p- 32 k de mémoire et d’un bootloader préchargé et protégé.

Quatrième raison

Active depuis 2005, une large communauté internationale d’utilisateurs qui créent et partagent de nombreux logiciels, ainsi que des vidéos/tutos sur Youtube.

Par exemple https://wiki.mdl29.net/lib/exe/fetc...

Et maintenant l’inconvénient principal :

il n’existe aucun matériel d’aide à la mise au point (debugging). En effet les différentes et épaisses couches logicielles (compilateur C,C++ etc) qui nous isolent des détails complexes de la puce Atmel 328p, nous en éloignent aussi. Il existe bien du matériel spécifique dans l’environnement Atmel, comme dans le cas des Pic de Microchip par exemple, mais c’est un domaine difficile d’accès dont nous voulons rester isolés.



Source

Impression du nom d'une variable et de sa valeur


//Imprimer_une_variable et son nom
//Il suffit d'utiliser + et String()

void setup() {
Serial.begin (115200);
}
void loop() {
int INT_VAR = 32;
float FLOAT_VAR = 32.23;
bool BOOL_VAR = true;
Serial.println("Un chaine qui combine un entier " + String(INT_VAR) + ", un décimal " + String(FLOAT_VAR) + " et un bool " + String(BOOL_VAR));
//On obtient :  Un chaine qui combine un entier 32, un décimal 32.23 et un bool 1
}


Un article sur la CONVERSION de TYPES

POINT D’ARRÊT

Faute de hardware pour implémenter les points d’arrêt d’exécution du programme, indispensables dans la phase de mise au point,voici une solution logicielle, avec cette macro à copier/coller au début de tout sketch, ou mieux, utiliser la Template ci dessous.

//Macro pa(v)de debug pour imprimer le numéro de ligne, le nom d’une variable, sa valeur, puis s’arrêter et attendre un clic de souris sur le bouton ’Envoyer’en haut de l’écran sériel pour continuer.

#define pa(v) Serial.print("Ligne_") ; Serial.print(__LINE__) ; Serial.print(" ; ") ;Serial.print(#v) ;Serial.print(" = ") ; Serial.println((v)) ; Serial.println(" Clic bouton ’Envoyer’ pour continuer") ;while (Serial.available()==0) ; {int k_ = Serial.parseInt() ;}

(On notera l’utilisation de la macro système " __LINE__" valable en langage C "Serial.print (__LINE__) ;" qui imprime le numéro de ligne du code source) .

Par exemple, à la ligne 145, l’instruction pa(var2) imprimera :

"Ligne_145 var2 = 25.3 Clic bouton ’Envoyer’ pour continuer"

Durant la mise au point on parsèmera donc le sketch de "pa(var) ; ".

Une fois le sketch théoriquement au point, soit on supprimera ces lignes, soit on les commentera pour les rendre inactives, ce qui est préférable : qui peut affirmer qu’un logiciel est définitivement au point ?

Encore mieux, pour éviter d’aller commenter chaque pa(), on utilise les instructions du pré-compilateur (instructions ou macros précédées du #).

On définit une constante, par exemple DEBUG dont on teste l’existence pour compiler les pa().

Exemple :

#define DEBUG // pour générer tous les pa() , A mettre une fois en debut de sketch

***********Ensuite on insère ces triplets pour chaque pa()

#ifdef DEBUG // mode DEBUG à cet endroit dans le sketch

pa(maVar1) ;

#endif

************** #ifdef DEBUG // mode DEBUG plus loin dans le sketch

pa(maVar12) ;

#endif

******************

Une fois le code mis au point il est facile de supprimer la generation de tous les pa(). Pour cela il suffit de commenter la première ligne ou DEBUG était définie

// #define DEBUG // pour l’affichage en mode DEBUG

On économise ainsi de la mémoire et surtout évite les arrêts d’execution à chaque pa().

*************Variante pour imprimer une variable puis continuer l’execution*********

//Macro pc(v)de debug pour imprimer le numéro de ligne, le nom d’une variable, sa valeur, puis continuer l’execution

#define pc(v) Serial.print("Ligne_") ; Serial.print(__LINE__) ; Serial.print(" ; ") ;Serial.print(#v) ;Serial.print(" = ") ; Serial.println((v)) ;

Exemple :

pc(var2) ;// à la ligne 145

imprimera "Ligne_145 var2 = 25.3" et continuera l’execution

Non seulement "pc(var2) ;" est bien plus rapide à écrire que

"Serial.print("var2 = ") ;Serial.println(var2) ;"

mais en prime on a le numéro de ligne, bien pratique dans un sketch un peu long.....

************Template pour debugging************

Template pour debugging - 1.3 ko

Template pour debugging

****************Template générale Arduino*************

Pour se remémorer la syntaxe et aussi :

-  dialogue en Bluetooth avec smartphone
-  Les deux timers 1 et 2

Template_generale_Arduino220919 - 13.7 ko

Template_generale_Arduino220919


*************Cette macro  imprime le nom de la fonction qui s'exécute et la valeur de son paramètre en entrée.***************************


//Debug_macro_080123  Ceci est un sketch executable
//Macro pour imprimer le nom de la fonction, fn, qui s'exécute   et la valeur du paramètre en entrée ,p1.
//Execution controlée par debEn = 1 ou 0
//On ajoute une ligne en tête des fonctions que l'on veut tracer

#define DEBUG_FUNC1(fn, p1)      if (debEn) { Serial.print('>'); Serial.print(fn); Serial.print('('); Serial.print(p1); Serial.println(')'); }  //Macro

int debEn = 0;      //Autoriser l'impression par execution de la macro, ou non
void maFonction(int mp)   //Fonction avec 1 paramètre
{
  DEBUG_FUNC1("maFonction", mp);//Appel de la macro, à mettre en première ligne
  // suite du code de la fonction
}

void setup() {
  Serial.begin(9600);
}

void loop() {
  debEn = 1;  //Autoriser debug
  maFonction( 15);   //Appel de la fonction

  //sur le moniteur du PC on récupère
  //   ">maFonction(15) "  donc on sait que cette fonction a été exécutée et avec quel paramètre
}



BUGS SOURNOIS

D’abord un piège du matériel : les 8 broches A0...A7 entrées analogiques sont aussi des entrées/sorties numériques, reconnues comme D14...D21, MAIS les deux broches A6 et A7 ne sont que des ENTREES, pas des sorties !!!

Bugs "sournois", car non détectés ou alors mal détectés à la compilation ils entraînent des comportements bizarres :

-  oubli des parenthèses lors de l’appel de fonction, comme "maFonction ;" au lieu de" maFonction() ;" Aucun message d’erreur !

-  Oubli ou ajout d’un "{" ou "}"   :

On récupère un message d’erreur de type " function x not declared in this scope" et la fonction en question est souvent bien loin de la ligne du message d’erreur.

-  Oubli de "//" avant un commentaire suivant une instruction :

On récupère un message d’erreur de type "stray\ 303 in program", parfaitement cryptique.

-  la fonction delayMicroseconds(D) ; fonctionne parfaitement tant que D < 16 383µs puis devient non fiable, il fallait le savoir...

-  "var = ! 25 ", au lieu de" var != 25", pour "var différent de 25", est un piège.Aucun message d’erreur ! Donc bien utiliser" != "et non "= !"

-  Var_a==23 ; Aucun message d’erreur !

-  Variables dynamiques : quand on arrive vers 80% du total (2048 bytes) le comportement peut devenir imprévisible. Ce pourcentage est indiqué après chaque compilation ("Verifier" dans le jargon) mais pas un televersement.

Pour diminuer le nombres de variables, le plus simple est de supprimer du texte dans les xx.print() existants dans le sketch, ou mieux de mettre les textes fixes en mémoire par cette variante en les préfixant simplement par "F" :

Serial.print(F("toto") ;

-  pire que tout : oublier de déclarer VOLATILE toutes les variables d’une fonction d’interruption.Le compilateur "optimise" alors le code en SUPPRIMANT certaines de ces variables comme "inutilisées".

-  Le WatchDog est dangereux à utiliser car il a tendance à neutraliser le bootloader ce qui rend la puce inutilisable.Il faut alors restaurer ce bootloader en copiant celui d’un autre Arduino, comme expliqué ci dessous.

-Ne jamais réaffecter les vitesses en bps par l'instruction Begin.Serial (115200) par exemple. Donc à n'utiliser qu'une seule fois dans un sketch.


-Utiliser fréquemment le trans-typage ( Type Cast ) quand on a le moindre doute sur les conventions et conversions de format en arithmétique.

Noter déjà que ce forçage de type ne s'applique qu'à la seule variable le suivant.

Mais attention, il y a des piêges! Par exemple si l'on veut tout calculer en float pour  obtenir C en float, avec A entier on est tenté d'écrire

C = (float)(180 -A/100);

or le compilateur commence par évaluer la paire A/100 en entier donc, ce qui fait perdre les chiffres décimaux.

Ensuite il évalue 180- A/100 toujours en entier et enfin convertit l'ensemble en float...trop tard et d'ailleurs inutile car l'affectation à C effectue cette conversion!!

Ce qu'il fallait faire: rendre 100 décimale en écrivant

C = 180 - A/100.0 ;

ceci promeut  ( c'est le terme) A en flottant pour effectuer la division, et ensuite la soustraction, toujours en flottant.

Pour ce faire, le compilateur crée des copies locales de A et 180  en flottant, effectue les calculs et détruit ces copies.

Enfin le  résultat en flottant est assigné à C.


Lecture directe des ports

      Cas de l'Arduino

Et pour vraiment comprendre ce qui se passe au niveau des ports et pouvoir declarer par exemple plusieurs pins en interruption (outre les classiques 2 et 3) voir l'exemple traité dans
ce remarquable tuto.

      Cas de l’ESP32

 Pour lire Simultanément l’état des ports 0 à 39 , on dispose de deux registres de 32 bits
 -- GPIO_IN_REG registre des ports 0 à 31
 --GPIO_IN1_REG registre des ports 32 à 39

 Le registre qu'on lit contient l'état des bornes des I/O quel que soit leur affectation, entrées ou sorties.
 Il faut donc masquer les bits pour sélectionner les entrées qu'on désire traiter.
 Dans l'exemple les 16 premiers bits sont sélectionnés et leur état est affiché sous forme décimale, hexadécimale et binaire(Jacques de F6GYJ)

uint32_t jbv = (REG_READ(GPIO_IN_REG) & 0B1111111111111111); // sélectionne les 16 premiers I/O

Serial.print(jbv);                                          // affichage valeur décimale
Serial.print(" "); Serial.print(jbv,HEX);         // affichage valeur binaire
Serial.print(" "); Serial.println(jbv,BIN);        // affichage valeur binaire

 Et à l’exécution cela donne
52905 CEA9 1100111010101001
52905 CEA9 1100111010101001
52905 CEA9 1100111010101001
52905 CEA9 1100111010101001
52907 CEAB 1100111010101011 changement
52905 CEA9 1100111010101001


PWM

Le Pulse Width Modulation standard a une periode d’environ 2ms ( environ 500Hz ).Pour augmenter la frequence à 32 ou 64kHz, ce code modifie les registres de Timer 0 ou 2,

(A noter que la librairie <PWM.h> exposée ci dessous est une solution plus simple)

-  Attention, les accolades étant interdites par un ancien éditeur de texte, utiliser le fichier ci après pour compiler le code

//PWM_32_ou_64_kHz_20017

//En standard la frequence de PWM est environ 500Hz soit une periode de 2ms

//Si l’on veut augmenter cette frequence à 32 ou 64kHz

//il faut modifier les registres des timers 2 ou 0 comme ci après

void setup()

// Pour 32kHz, soit une periode de 31.3µs, sorties sur D3 et D11

TCCR2A = _BV(COM2A1) | _BV(COM2B1) | _BV(WGM20) ;//Timer 2

TCCR2B = _BV(CS20) ;//Timer 3

analogWrite(11, 50) ;//On 50 sur 255

analogWrite(3, 200) ;//On 200 sur 255

//Preserve Timer0 : par exemple delay(1000) = 1s, millis() reste OK

//Pour 64 kKz, soit une periode de 15.6µs, sorties sur D5 et D6

TCCR0B = TCCR0B & 0b11111000 | 0x01 ;//Timer 0

analogWrite(6, 100) ;// On 100 sur 255

analogWrite(5, 10) ;// On 10 sur 255

//Accelère Timer1, attention !!! delay(100000) pour qq secondes ! et oublier millis()

void loop()


Le logiciel avec les accolades qui vont bien :

PWM_32_ou_64_kHz_20017 - 862 octets

PWM_32_ou_64_kHz_20017
PWM_32_ou_64_kHz_20017

Plus simple et plus flexible, la librairie PWM jusqu'à 1MHz

#include <PWM.h>

int32_t mafrequence = 100000 ; // frequence en Hertz  Peut monter à 1MHz

byte   pwmratio ;  // de 0 à 255

void setup()

{

InitTimersSafe() ; //Initialise

bool success = SetPinFrequencySafe(9, mafrequence) ;

//Si la patte 9 oscille bien à mafrequence, allumer la Led 13

if (success) { pinMode (13, OUTPUT) ; digitalWrite(13, HIGH) ;}

pwmratio= 128;
pwmWrite(9, pwmratio);    //Oscille à 10000Hz et ratio 50% 

}

void   loop()

{}


Les deux Timers

Il suffit en general de Timer1, le plus courant.
Son unité est la microseconde.
On le declare dans setup ( ) avec la fonction à executer pour chaque declenchement.

EX: Timer1.attachInterrupt(isr_Fin_T1);
         Timer1.initialize(12000);  //  12ms

Si necessaire on peut utiliser FlexiTimer2 dont l'unité est programmable 1 ms, 100 µs ou 10µs, avec 100 µs recommandée.
A chaque execution on definit l'unité et la fonction à executer.

EX: FlexiTimer2::set(120, 0.1 / 1000, isr_Fin_T2);// Unité 100µs définie par 0.1/1000 et durée 12ms soit 120 *100µs


//Timer1_Timer2_Exemple
//Les deux timers du Nano/Uno

//Aller chercher les deux librairies sur;
//https://github.com/PaulStoffregen/TimerOne
//https://github.com/wimleers/flexitimer2
//Les mettre dans le repertoire  " libraries"
//Timr1 a pour unité les microsecondes
//L'unité de Timer2 est ajustable
//1.0/1000 pour 1 ms
//0.1/1000 pour 100µs recommandé
//0.01/1000 pour 10µs a des pbs de precision

#include"TimerOne.h"
#include <FlexiTimer2.h>

void  isr_Fin_T1()
{ Timer1.stop();//S'execute quand Timer1 overflow
  //Code ici
}

void  isr_Fin_T2 ()
{ FlexiTimer2::stop();//S'execute quand Timer2 overflow
  //Code ici
}

void setup() {
  Timer1.attachInterrupt(isr_Fin_T1); //Une fois pour toutes
  //Noter que l'isr attachée au Timer2   est déclarée à chaque appel

}

void loop() {
  //Lancer TMR1 et TMR2  pour 1200µs
  Timer1.initialize(12000);
  FlexiTimer2::set(120, 0.1 / 1000, isr_Fin_T2);
  FlexiTimer2::start();
}

y

kjkjkjk


EEPROM  Ecriture et Lecture 16 bits

On commence par inclure la bibli EEPROM.h qui permet de lire et ecrire un byte B en eeprom à l'adresse contenue dans eePc

EEPROM.write(eepC, B);    //Ecrit B  
B= EEPROM.read(eepC);   //Relit B
 
Si au lieude B on utilise un entier de 16 bits voici la méthode.

//Eeprom290320
// Lecture/Ecriture de 16 bits en EEPROM
#include <EEPROM.h>
int eepC = 0; // pointeur à l'EEPROM
int stoRe = 0; //Valeur sur 16bits à ecrire en EEPROM
int fromEep = 0;  //Valeur sur 16bits relue de l'EEPROM
int hiB = 0; //MSB lu de l'EEPROM 8 bits Most Significant Byte
int loB = 0; //LSB lu de l'EEPROM 8 bits Least Significant Byte

void ReadEep16()////////////////////////////////////////////////////
{ //Serial.print("Write_eepC__stoRe_"); Serial.println(eepC); Serial.println(stoRe); //while (1){}
  hiB = EEPROM.read(eepC);// Serial.print("hiB__");Serial.println(hiB);// Lecture de 8 bits MSByte
  eepC++;
  loB = EEPROM.read(eepC);//Serial.print("loB__");Serial.println(loB);// Lecture de 8 bits LSByte
  eepC++;                       //preparer prochaine adresse
  fromEep = (hiB << 8) + loB; // Regeneration des  16 bits, shift 8 fois à gauche du MSB et addition du LSB
}

void  WriteEep16()  /////////////////////////////////////
{ //Serial.print("Write_eepC__stoRe_"); Serial.println(eepC); Serial.println(stoRe); //while (1){}
// Noter l'utilisation des fonctions highByte() et lowByte() pour extraire MSB et LSB
  EEPROM.write(eepC, highByte (stoRe)); //MSByte
  eepC ++;
  EEPROM.write(eepC, lowByte (stoRe));  //LSByte
  eepC ++;                      //preparer prochaine adresse
}
void setup() {
//Ecriture de 2540 en 15 et 16  puis 333 en 17 et 18 de l'EEPROM
Serial.begin (9600);
eepC=15;//Modifiable ainsi que 2540 et 3333
stoRe= 2540;
WriteEep16();
stoRe= 3333;
WriteEep16();

//Relecture de ces valeurs dans fromEp et impression

eepC=15;
ReadEep16();
Serial.println( fromEep);
ReadEep16();
Serial.println( fromEep);
Serial.println( "That's all folks!");
}
void loop() {
}

d

Arduino et Bluetooth

Grace aux modules HC05/06 à 3 ou 4€, on programme facilement une liaison Bluetooth bi directionnelle avec le clavier et l’écran d’un Smartphone (Android, bien sur !).

L’avantage essentiel est de simplifier le hardware : plus de LCD à fils multiples, plus d’interrupteurs capricieux à gérer !

Avec pour consequence la possible impasse sur le circuit imprimé, en soudant point à point un nombre réduit de composants.

Ci joint le logiciel d’exemple.

LECTURE_du_clavier_du_sphone_par_Bluetooth_220919 - 1.2 ko

LECTURE_du_clavier_du_sphone_par_Bluetooth_220919


*******************Autre article sur Arduino et BlueTooth*****************  

BlueTooth et Arduino, Smartphone, modules HC05/06 et ESP 32




Carte SD

Il suffit de 6 fils connectés à un module SD (coût environ 4€) équipé d’une carte SD (se limiter à 32GB, Fat 32, Mode 10 de preference car la plus rapide) pour obtenir un "disque" de 32GB.

Les Exemples de la bibliothèque officielle "SD" sont parfaits pour se mettre en main cet outil simple et puissant.

Performances : l’écriture d’une ligne de 6 valeurs prend 1.5ms environ. Par contre la fermeture du fichier prend 20 ms.

Donc si les données arrivent rapidement, les écrire "au vol", et ne fermer le fichier que de temps en temps.

Ce logiciel de test montre que 30 000 lignes sont écrites en 45 s, vérifiant 1.5 ms par ligne.

SD_Essais_de_timing_290919 - 1.7 ko

SD_Essais_de_timing_290919

Ce logiciel contient les principales fonctions pour les cartes SD.

Template_carte_SD031019 - 2.7 ko

Template_carte_SD031019

ATELIER ARDUINO (IDE) : LES OUTILS PLUS OU MOINS CONNUS

-  FICHIER/EXEMPLES fournit des exemples de sketchs bien commentés et intéressants

-  FICHIER/PRÉFÉRENCES pour afficher les numéros de lignes et autres options

-  EDITION/COMMENTER-DECOMMENTER pour neutraliser des ensembles de ligne de code pendant la mise au point ( évite de taper "// "à chaque ligne.

Ensuite on réactive ces lignes par "Decommenter"

-  Ctrl+F pour Find c’est à dire rechercher un mot.

-  OUTIL/FORMATAGE AUTOMATIQUE pour une mise en page propre et standardisée.

-  OUTIL/GRAVER LA SÉQUENCE D’INITIALISATION pour restaurer le bootloader à partir d’un autre Arduino.

Voir les explications détaillées ci dessous.

-  Ctrl+C pour copier du texte de l’écran sériel dans le bloc-note, car le Copier habituel à la souris ne fonctionne pas.

-  Sur les versions 1.6.6 et ultérieures, dans OUTILS, ne pas ouvrir le Moniteur Serie mais Traceur Série : les valeurs envoyées par Serial.println s’affichent en vertical, l’axe horizontal est le temps.

SUGGESTIONS DE PROGRAMMATION


-  Déclarer toutes les fonctions en début de sketch, avant setup() et surtout dans l’ordre alphabétique.

-  Ne pas utiliser les arguments/paramètres dans les fonctions mais uniquement des variables globales.

Ceci fera hurler les puristes qui ( à juste titre pour les gros programmes ) conseillent exactement l’inverse ! Mais on est ici dans le domaine des sketchs de disons 100 à 300 lignes, ce qui à mon avis justifie cette solution plus simple et accessoirement, plus rapide à l’exécution

-  Même démarche pour les précédences d’opérateurs, à oublier, et utiliser systématiquement des parenthèses.

-  Ne jamais utiliser les abréviations du C ( "compound assignment operators", aberrants à mon avis, car cryptiques et alors que l’on écrit une seule fois du code, on le relit de multiples fois, et parfois beaucoup plus tard !!!...)

Ex1 : x+ = y ; signifie x = x + y ;

Ex2 : a/ = b ; signifie a = a / b ;

Ex3 : le pire !

z = ( x > y ) ? x :y ; qui signifie

if (x>y) z=x ;

else z= y ;

-  Les fonctions d’attente de type delay() ; sont très utiles mais on peut parfois préférer programmer soi même un délai.

Il est alors indispensable d’utiliser une variable VOLATILE, ici duree, qui peut être INT ou FLOAT, avec en gros un rapport de 10 .

En INT,

volatile int ct = 0 ; volatile int unsigned long duree = 1000 ; while (ct < duree) ct++ ;//1000 pour 1.25ms environ

En FLOAT,

volatile float ct = 0 ; volatile float duree = 100 ; while (ct < duree) ct++ ;//100 pour 1.25ms eviron

Exemple en forme de fonction pour une attente en ms :

Nota : les accolades sont remplacées par des parenthèse, contrainte de SPIP utilisé pour ce blog.

void monDelay_ms(int unsigned long delai) //Attente en ms

( volatile float ct = 0 ;

volatile float duree = delai*100/1.25 ; //100 pour 1.25ms environ

while (ct < duree) ct++ ;

)

Appel ;

unsigned long d= 3000 ;

monDelay_ms(d) ; //Attente de 3s

— Difference entre read et write :

CharLu=65 ;Serial.print( CharLu) ; donne 65.

alors que Serial.write( CharLu) ; donne A.

Autrement dit, write considère que la valeur transmise est le code ASCII d’un caractère et tente donc de l’imprimer.Si la valeur est >255, il prendra le modulo 256, par exemple pour Serial.write(1094) ; on obtient "F" car 1094 = 4*256 + 70 et 700 est le code ASCII pour F.

Quelques exemples :

Serial.println(78) ;// gives "78"

Serial.println(1.23456) ;// gives "1.23"

Serial.println(’N’) ;// gives "N"

Serial.println("N") ;// gives "N"

//An optional second parameter specifies the base (format) to use ; permitted values are BIN (binary, or base 2), OCT (octal, or base 8), DEC (decimal, or base 10), HEX (hexadecimal, or base 16). For floating point numbers, this parameter specifies the number of decimal places to use. For example :

Serial.println(78, BIN) ;// gives "1001110"

Serial.println(78, OCT) ;// gives "116"

Serial.println(78, DEC) ;// gives "78"

Serial.println(78, HEX) ;// gives "4E"

Serial.println(1.23456, 0) ;// gives "1" par défaut on a deux chiffre après le point

Serial.println(1.23456, 2) ;// gives "1.23"

Serial.println(1.23456, 4) ;// gives "1.2346"// put your setup code here, to run once :

-  Pour diminuer le volume des variables (limité à 2k sur un Uno/Nano), il suffit de remplacer

-  Serial.print("Mon texte") ; par

-  Serial.print(F("Mon texte")) ;

Cette chaîne de caractères ira alors en mémoire Flash(programme, 32k sur un Uno/Nano).

LES POINTEURS

Vaste sujet, terrifiant par certains aspects car generateur de bugs complexes.

Il est vrai que le langage C crée la confusion dès le début par la syntaxe de déclaration des variables de type pointeur :

int *ptA ;

crée la variable ptA comme pointeur ( c’est à dire une adresse) vers toute variable de type int (entier).

La confusion vient de l’astérisque "*" utilisée ensuite, dans un sens totalement différent, comme signe d’indirection.Par exemple :

maVal = *ptA ;

qui attribue à maVal, la valeur trouvée à l’adresse pointée par ptA.

Si le langage comportait un mot réservé, disons "ptr" pour déclarer un pointeur, on aurait alors comme déclaration

int ptr ptA ;

Variable ptA, déclarée pointeur vers toute valeur entière, puis accès à cette valeur par indirection

maVal = *ptA ; // "*" signifiant l’indirection

En résumé, un pointeur contient une adresse.De plus un pointeur sait vers quel type de données il pointe ( ici un entier ).

Exemple:

Pour  initialiser ptA en le faisant pointer vers le premier element du tableau Tab[]

int*ptA = &Tab[0];

Notons que l’on ne peut imprimer la valeur d’un pointeur par Serial.print(ptA) ; par exemple.

LE MATÉRIEL

L’Arduino Nano original est de marque Gravitech, made in USA.Il est doté d’une véritable puce FTDI pour l’interface USB et supporte jusqu’à 20 volts sur l’entrée Vin bien que les spécifications soient de 7 à 12 V.Il coûte environ 35€.

Les clones asiatiques à 3€, ont en général une puce CH340G au lieu de FTDI ( le driver se trouve sur le Net ) mais surtout sont, sauf exception, limités à 12 V sur Vin.

Pour une utilisation sur une auto par exemple, soit 14 V, il est fortement conseillé d’utiliser un régulateur de tension de 5V (7805 par exemple, < 0.3€) connecté à l’entrée +5V de l’Arduino et non Vin. Cette entrée +5V est une connexion directe au Vcc de la puce 328p.

On peut même descendre à moins de 3 V avec comme seul inconvénient une éventuelle perte de precision sur la fréquence de base de 16 MHz.

-  Sur la quasi totalité des Arduino, la patte D 13 est connectée à un ensemble Led + résistance repérée "L".Il suffit de declarer D13 en sortie pour allumer/éteindre L (Voir FICHIER/EXEMPLES/BASIC/BLINK).




******************************Annexes*******************************

-  Un readAnalog() prend environ 100µs.Pour nettement diminuer ce temps, voir cet article bien détaillé

http://www.glennsweeney.com/tutoria...

-  Pour créer une librairie, et l’inclure dans l’IDE voir : https://www.arduino.cc/en/Hacking/L...


Testeur de Nano/Uno




18 Leds sont connectées de D2 à D13 et de A0 à A5.
Leur cathode est reliée à la résistance de 220 ohms qui va à GND.
L'alimentation est fournie ici par le câble USB mais toute autre source convient.
On pendant 0.5s et Off pendant 0.5s.
Ce test détecte les pannes les plus communes mais n'est pas exhaustif bien sûr, par exemple les entrées analogiques ne sont pas testées.

//Testeur_de_Nano_Uno_040521
//http://loutrel.org/Liste_Electronique.html
int k=0; //N° de patte
void  OnOff()
{digitalWrite(k,1);
 delay(500);
 digitalWrite(k,0);
 delay(500);
}
void setup() {
pinMode(2,OUTPUT);
pinMode(3,OUTPUT);
pinMode(4,OUTPUT);
pinMode(5,OUTPUT);
pinMode(6,OUTPUT);
pinMode(7,OUTPUT);
pinMode(8,OUTPUT);
pinMode(9,OUTPUT);
pinMode(10,OUTPUT);
pinMode(11,OUTPUT);
pinMode(12,OUTPUT);
pinMode(13,OUTPUT);
pinMode(A0,OUTPUT);
pinMode(A1,OUTPUT);
pinMode(A2,OUTPUT);
pinMode(A3,OUTPUT);
pinMode(A4,OUTPUT);
pinMode(A5,OUTPUT);

}
void loop() {
 for(k==2;k<14;k++)
 {OnOff();}

 digitalWrite(A0,1);
 delay(500);
 digitalWrite(A0,0);
 delay(500);
 digitalWrite(A1,1);
 delay(500);
 digitalWrite(A1,0);
 delay(500);
  digitalWrite(A2,1);
 delay(500);
 digitalWrite(A2,0);
 delay(500);
 digitalWrite(A3,1);
 delay(500);
 digitalWrite(A3,0);
 delay(500);
  digitalWrite(A4,1);
 delay(500);
 digitalWrite(A4,0);
 delay(500);
 digitalWrite(A5,1);
 delay(500);
 digitalWrite(A5,0);
 delay(500);
 k=2;
}


Reprogrammer le bootloader

Il peut arriver de l’écraser, particulièrement si l’on joue avec le timer chien de garde.

Le connecter à un Arduino avec boot loader ( à droite) suivant le schema ci dessous :

-  Aller dans Fichier/Exemples/Arduino as ISP.

-  Téléverser ce sketch

-  Aller dans Outils/Programmateur Arduino/Arduino as an ISP

— - Tout clignote et la restitution du boot loader est effectuée en quelques secondes.

Programmer un Arduino SANS boot loader

Pourquoi supprimer un boot loader ?

-  soit pour récupérer environ 2k de mémoire

-  soit pour un démarrage immédiat du logiciel sans l’attente d’environ 2s due au boot loader qui teste si la liaison série est active.

Création d’un Arduino Nano without boot loader

Dans un premier temps, on ajoute à la liste des descriptifs de types d’Arduino un "Arduino Nano without bootloader". Pour cela il faut ajouter environ 30 lignes de texte au fichier boards.txt qui se trouve dans le repertoire ( cas de Windows 7)

c :\ProgFile X86\arduino\hardware\arduino\avr

le fichier boards.txt contient tous les types d’Arduino.

-  Faire une copie de sécurité puis l’ouvrir avec un éditeur de texte type Notepad

-  repérer le bloc d’une trentaine de lignes entre deux lignes de dièses qui commence par

.

.

###########################################################

nano.name = ArduinoNano

nano.upload.tool=avrdude

nano.upload.protocol=arduino

. . .

C’est le début du bloc qui nous intéresse.

-  faire un copier/coller de ce bloc à la suite.On dédouble ce bloc pour créer une copie modifiée.

-  la première ligne est à changer en :

nanowb.name=Arduino Nano without bootloader

-  ensuite toutes les lignes commençant par nano.xxx sont modifiées en nanowb.xxxx

-  pour la ligne se terminant par maximum_size= 30720 changer 30720 en 32768.C’est la mémoire gagnée par suppression du boot loader.

-  sauver l’ ensemble comme boards.txt à la place de l’original.

Exemple de bloc ajouté à la liste de tous les Arduino dans le fichier boards.txt.

##############################################################

nanowb.name=Arduino Nano without bootloader

nanowb.upload.tool=avrdude

nanowb.upload.protocol=arduino

nanowb.bootloader.tool=avrdude

nanowb.bootloader.unlock_bits=0x3F

nanowb.bootloader.lock_bits=0x0F

nanowb.build.f_cpu=16000000L

nanowb.build.board=AVR_NANO

nanowb.build.core=arduino

nanowb.build.variant=eightanaloginputs

## Arduino Nano w/ ATmega328

## -------------------------

nanowb.menu.cpu.atmega328=ATmega328

nanowb.menu.cpu.atmega328.upload.maximum_size=32768

nanowb.menu.cpu.atmega328.upload.maximum_data_size=2048

etc

##############################################################

-  Pour vérifier que tout s’est bien passé relancer l’IDE Arduino, Outils/Type de cartes

On doit trouver la nouvelle carte "Arduino Nano without bootloader " dans la liste.

Programmation sans boot loader

Cette programmation nécessite un autre Nano, classiquement équipé d’un boot loader.

On utilise le circuit ci dessus (voir : Reprogrammer le boot loader ) le Nano à programmer sans boot loader étant sur la gauche.

-  Aller dans Fichier/Exemples/Arduino as ISP.

-  Téléverser ce sketch

-  Outils/Type de carte/Arduino Nano without bootloader

-  Ouvrir le sketch à televerser sans bootloader

-  ATTENTION : ne PAS cliquer sur la flèche de televersement habituelle mais utiliser :

Croquis/Téléverser avec un programmateur

-  le Nano de droite écrit le sketch dans le Nano de gauche, en écrasant le boot loader s’il existait

On peut vérifier que le boot loader n’existe de plus de 2 façons :

-  l’execution du sketch démarre immédiatement, sans les 2 s de délai habituelles.

-  on ne peut plus programmer ce Nano.

Pour une reprogrammation ultérieure, on commencera par restituer le boot loader comme indiqué ci dessus.

Typon pour restituer un boot loader et/ou programmer un Arduino sans boot loader

Merci à l’auteur, LudoMini !

References

Il existe de nombreux ouvrages sur le "C" mais il me semble preferable de sélectionner des livres sur le langage "C Arduino" tels que :

-  "Arduino les bases de la programmation"par Simon Monk

-  "Sam teach Yourself Arduino Programming" par Richard Blum

-  "Arduino Cookbook" O’REILLY

Pourquoi ?

Pour éviter d’étudier des fonctions inutilisées à la syntaxe assez tordues comme printf () mais par contre découvrir les fonctions predefinies de haut niveau caractéristiques de l’Arduino telles que :

-  readAnalog(),writeAnalog()

-  constrain(x,Bas , Haut) qui contraint x entre les deux valeurs Bas et Haut, très utile pour les capteurs par exemple

Dans le domaine des applications concrètes je recommande :

-  "36 experiences de physique avec Arduino" par W. van Dreumel, Elektor. Pour découvrir les capteurs Hall, les ultrasons, les capteurs piezzo etc, mis en oeuvre dans des petits montages rapides à câbler, le sketch étant fourni bien sur.

Un peu hors sujet mais bien utile dès que l’on manipule des images

TOUS LES OUTILS POUR VOS IMAGES : https://convertir-une-image.com


 


Forum

2945 visites.