***Pour revenir à la page d’accueil** ICI
17/12/2024
Logiciel pour charger le bon driver, de 2022
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.
Un article sur la CONVERSION de TYPES
//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 générale Arduino*************
Pour se remémorer la syntaxe et aussi :
dialogue
en Bluetooth avec smartphone
Les deux timers 1 et 2
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.
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 ;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 :
#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;}
void loop()
{}
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 BGrace 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.
*******************Autre article sur Arduino et BlueTooth*****************
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.
Ce logiciel contient les principales fonctions pour les cartes SD.
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.
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).
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.
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...
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.
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 :
Dans: Outils / Programmateur Arduino as ISP / Selectionner Arduino as ISP
Puis aller dans Fichier / Exemples / Arduino as ISP.
Téléverser ce sketch
La restitution du boot loader est effectuée en
quelques secondes. Les deux Nano doivent clignoter
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.
Merci à l’auteur, LudoMini !
"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
Bonjour Christophe
sympa d’ouvrir les commentaires sur ce sujet !!
Les avis sont bons sur l’ouvrage que tu cites mais il me semble preferable de sélectionner un livre sur le langage "C Arduino" tel que "Sam teach Yourself Arduino Programming" par Richard Blum.
Pourquoi ?
Pour t’é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()
map(x,Bas , Haut) qui contraint x entre les deux valeurs Bas et Haut, très utile pour les capteurs par exemple