Bonjour
J'ai "récupéré" sur internet un programme pour la numerisation de valeur issue d'un capteur ECG que j'ai réalisé. Novice en Arduino, je ne comprends pas grand chose, pourriez m'expliquer en gros et surtout en details, ligne par ligne ce que fait ce mini programme, ça serait génial !
Merci de votre aide...
#include <Arduino.h>
#include <math.h>
int ecgPin = A0;
int ledPin = 13;
volatile int ecgValue = 0;
volatile float ecgValueFloat;
volatile bool flag;
volatile int data=0;
// put function declarations here:
void timerSetup(void);
void setup() {
// put your setup code here, to run once:
timerSetup();
// declare the ledPin as an OUTPUT
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, LOW);
flag = false;
Serial.begin(115200); // initialize UART with baud rate of 9600 bps
}
void loop() {
// put your main code here, to run repeatedly:
}
void timerSetup(void){
noInterrupts();
TCCR1A = 0;
TCCR1B = 0;
// 15625 = 16Mhz/1024 (prescalar)
// echantillonage toute le 100 ms
TCNT1 = 65536 - 1562;
//TCNT1 = 55536; // preload timer 65536-16MHz/8/200Hz
TCCR1B |= (1 << CS00); // prescaler : 1024
TCCR1B |= (1 << CS02);
TIMSK1 |= (1 << TOIE1); // enable timer overflow interrupt JMJ
// JMJ added
TIFR1 |= 1;
interrupts(); // enable all interrupts
}
ISR(TIMER1_OVF_vect){
char buff[10];
ecgValue = analogRead(ecgPin); // int : two bytes
Serial.print("ecgValue: ");
Serial.println(ecgValue);
ecgValueFloat = (ecgValue * 5) / 1024.0;
dtostrf(ecgValueFloat, 4, 6, buff);
//snprintf (buff, sizeof(buff), "%f", ecgValueFloat);
Serial.print("ecgValueFloat: ");
Serial.println(ecgValueFloat,2);
//Serial.write(ecgValue >> 8); // send first byte
//Serial.write(ecgValue); // send second byte
//TCNT1 = 55536; // reset intterupt
TCNT1 = 65536 - 1562;
flag = ! flag;
if (flag == true) digitalWrite(ledPin, LOW);
else digitalWrite(ledPin, HIGH);
}
Bonjour @chris3874, je pense qu'il faudrait que tu te documentes un peu sur l'Arduino avant de te lancer dans la compréhension du programme, d'autant plus que ce n'est pas un code basique car il y a des variables "volatile" et des "interruptions".
Il y a de très bons livres.
Essaye de comprendre par toi même et n'hésite pas à revenir vers nous avec des questions.
J'ai traduis à chaque ligne par un commentaire ce que j'avais compris du programme avec les liens fournis et les infos mais je bloque encore pas mal et surtout sur la derniere partie du programme ou en plus des timers il y a une fonction interruption..
Si qq peut m'aider à traduire ces lignes pour y voir un peu plus clair...
#include <Arduino.h>
#include <math.h>
int ecgPin = A0; Le signal ecgPin est visualisé au pin A0
int ledPin = 13;
volatile int ecgValue = 0; Mise à 0 ecgValue au début
volatile float ecgValueFloat; ecgValueFloat variable decimale mais pourquoi volatile ?
volatile bool flag; drapeau boolean (false or true) ?
volatile int data= 0; initialization data à 0.
// put function declarations here:
void timerSetup( void); Déclaration d’une fonction implémentée par la suite
void setup(){
// put your setup code here, to run once:
timerSetup();
// declare the ledPin as an OUTPUT
pinMode( ledPin, OUTPUT); ledPIN = sortie
digitalWrite( ledPin, LOW); LedPin éteinte
flag =false; initialization du drapeau
Serial. begin( 115200);// initialize UART with baud rate of 9600 bps
pourquoi 115200 alors qu’on est à 9600bit/s ?
}
void loop()
{
// put your main code here, to run repeatedly:
}
void timerSetup( void)
{
noInterrupts(); ???
TCCR1A = 0; Remise à 0 , registre timer 1 sur les 8 premiers bits
TCCR1B = 0; Remise à 0 , registre timer 1 sur les 8 bits suivants
// 15625 = 16Mhz/1024 (prescalar) diviseur de frequence generale par 1024
// echantillonage toute le 100 ms ? ??? comment obtenir ce chiffre ?
TCNT1 = 65536 - 1562; ???
//TCNT1 = 55536; // preload timer 65536-16MHz/8/200Hz
TCCR1B |= ( 1 << CS00); // prescaler : 1024
TCCR1B |= ( 1 << CS02);CS00 et CS02 correspondent au cght de frequence du timer 0 , on avait déclaré le timer 1 jusque la ??
TIMSK1 |= ( 1 << TOIE1);// enable timer overflow interrupt JMJ
// JMJ added Registre d’interuption mais pourquoi ici ?
TIFR1 |= 1;
interrupts();// enable all interrupts
}
ISR( TIMER1_OVF_vect){
char buff[ 10];
ecgValue = analogRead( ecgPin); // int : two bytes
Serial. print( "ecgValue: ");
Serial. println( ecgValue);
ecgValueFloat = ( ecgValue 5)/ 1024.0;
dtostrf( ecgValueFloat, 4, 6, buff);
//snprintf (buff, sizeof(buff), "%f", ecgValueFloat);
Serial. print( "ecgValueFloat: ");
Serial. println( ecgValueFloat, 2);
//Serial.write(ecgValue >> 8); // send first byte
//Serial.write(ecgValue); // send second byte
//TCNT1 = 55536; // reset intterupt
TCNT1 = 65536 - 1562;
flag =! flag;
if ( flag == true ) digitalWrite( ledPin, LOW);
else digitalWrite(ledPin, HIGH);
}
Si tu ne fait pas d'effort pour rendre lisible ton code grâce au balise < code>.
J'ai peur que tu ne trouves pas beaucoup de gens pour faire l'effort de déchiffrer ton code
Tu es peut-être novice en Arduino mais tu ne l'es pas en français donc tu devrais comprendre ce que l'on te demande.
Dans mon premier message, je t'ai demandé d'appliquer les règles du forum pour présenter ton code. On aimerait bien que ce soit appliqué!
Code entre balise
Code indenté correctement
Tu peut rééditer tes messages précédents en cliquant sur l'icône crayon qui se trouve sous chacun de tes messages.
@chris3874 une variable volatile c'est une variable qui n'est pas optimisé à la compilation et qui sera toujours mise à jour.
Ce type de variable est utile pour la programmation multi-thread (variable utilisée par plusieurs tâches) ou encore dans le cadre d'Arduino lors de l'utilisation de méthodes liées à des interruptions.
// echantillonage toute le 100 ms ? ??? comment obtenir ce chiffre ?
//16000000/1024= 15624 tics par seconde
//durée d'un tic horloge en sortie du préscaler de 1024 :
//1S ==> 1000ms/15624=0.064mS soit 64µS
//nb de tics pour 100mS==>100000µ/64µ=1562
//le timer 1 est composé de plusieurs registres dont
//TCNT1 qui est le compteur
//le timer compte de 0 à 65536 puis repasse à 0 et recompte jusqu'à 65536 etc..
//lorsque le timer 1 arrive à 65536, on dit qu'il "déborde". à ce moment est déclenchée une interruption
//dite de débordement " overflow" d'ou le nom de la fonction "ISR( TIMER1_OVF_vect)"
//nous savons que pour une durée de 100mS le timer doit compter de 0 à 1562
//il suffit de faire partir le compteur de 65536-1562=63974 en mettant cette valeur dans TCNT1
//en résumé, le timer 1 compte 1562 tics (100ms) et son interruption d'overflow est exécutée.
//dans cette fonction, est lue "l'entrée ecg". donc, toutes les 100ms, l'entrée ecg est lue.
Ton programme complet est dans le premier message : édites le aussi.
Débuter sur la programmation simultanément avec les interruptions et les registres du micro, c'est casse-gueule.
Ce n'est pas un hasard si les bibliothèques Wiring/Arduino ont été écrites pour masquer les appels aux registres du microcontrôleur.
Comprendre et utiliser les registres, c'est lire une datasheet de 400 pages. Es-tu prêt à le faire ?
Si l'auteur du programme que tu cherches à comprendre fait appel aux registres, c'est que son projet est pointu, c'est-à-dire pas vraiment pour un débutant.
Tu fais comme tu veux, mais une approche, certes plus lente, avec les tutos d'Eskimon et quelques tutos d'initiation au C/C** serait bien plus efficace.
→ il n'y a pas de langage Arduino.
Wiring/Arduino, c'est des bibliothèques de fonctions ou des classes écrites en C (fonctions) ou en C++ (classes).
Quand on découvre le sujet, c'est le premier message que l'on voit en premier, c'est une La Palissade, mais c'est la réalité.
Selon l'humeur, on parcourt ou on ferme immédiatement.
Super merci infiniment , je comprends mieux les parties jusqu'à ISR.
En revanche , pourrais tu me detailller toutes les lignes de cette fonction car je bloque meme si je comprends sa globalité.
Encore merci à tous pour votre aide !!
pour finir voici ton programme épuré et commenté
(épuré car c'est un vieux prog comprenant d'anciens "include" et façon d'écrire)
int ecgPin = A0; //Le signal ecgPin est visualisé au pin A0
int ledPin = 13;
volatile int ecgValue = 0; //Mise à 0 ecgValue au début
volatile float ecgValueFloat = 0.00; //ecgValueFloat variable decimale mais pourquoi volatile ?
void timerSetup( void); //Déclaration d’une fonction implémentée par la suite
void setup() {
timerSetup(); //on va initialiser les registres du timer 1
digitalWrite( ledPin, LOW); //sortie positionnée avant d'etre initialisée en tant que sortie
pinMode( ledPin, OUTPUT); // ledPIN = sortie
Serial. begin( 115200); //
//pourquoi 115200 alors qu’on est à 9600bit / s ?
//9600, c'est lent et 115200 est très fiable, alors gagnons du temps pour
//l'exécution du programme
}
void loop()
{
}
void timerSetup( void)
{
cli();//noInterrupts();// interdit les interruption pendant les manip sur les registres
TCCR1A = 0; //Remise à 0 , registre de configuration du timer 1
TCCR1B = 0; //Remise à 0 , registre de configuration du timer 1
// 15625 = 16Mhz/1024 (prescalar) diviseur de frequence generale par 1024
// echantillonage toute le 100 ms ? ??? comment obtenir ce chiffre ?
//16000000/1024= 15624 tics par seconde
//durée d'un tic horloge en sortie du préscaler de 1024 :
//1S ==> 1000ms/15624=0.064mS soit 64µS
//nb de tics pour 100mS==>100000µ/64µ=1562
//le timer 1 est composé de plusieurs registres dont
//TCNT1 qui est le compteur
//le timer compte de 0 à 65536 puis repasse à 0 et recompte jusqu'à 65536 etc..
//lorsque le timer 1 arrive à 65536, on dit qu'il "déborde". à ce moment est déclenchée une interruption
//dite de débordement " overflow" d'ou le nom de la fonction "ISR( TIMER1_OVF_vect)"
//nous savons que pour une durée de 100mS le timer doit compter de 0 à 1562
//il suffit de faire partir le compteur de 65536-1562=63974 en mettant cette valeur dans TCNT1
//en résumé, le timer 1 compte 1562 tics (100ms) et son interruption d'overflow est exécutée.
//dans cette fonction, est lue "l'entrée ecg". donc, totes les 100ms, l'entrée ecg est lue.
TCNT1 = 65536 - 1562;// registre de comptage du timer1 prépositionné à 63974
//TCNT1 = 55536; // preload timer 65536-16MHz/8/200Hz
//TCCR1B |= ( 1 << CS00); // prescaler : 1024
//TCCR1B |= ( 1 << CS02);//CS00 et CS02 correspondent au cght de frequence du timer 1 , on avait déclaré le timer 1 jusque la ??
TCCR1B |= (1 << CS02) | (1 << CS00);
TIMSK1 |= ( 1 << TOIE1);// autorise la prise en compte de l'interruption "overflow" du timer1
TIFR1 |= 1;
sei();//interrupts();// enable all interrupts
}
//c'est un vieux prog, l'affichage ne se fait plus
//maintenant,c'est Serial.print. j'ai viré et remplacé
//sur une enrée analogique, le signal analogique peut etre de 0 à 5V.
//derriere l'entrée analogique, il y a un convertisseur analogique vers digital qui
//donne 0 pour 0V et 1023 pour 5V
//supposons que le signal soit de 2.5V, le convertisseur donnera 512
//dans la fonction, le résultat de la lecture est remis à l'échelle
//pour retrouver la valeur qui à été présentée en entrée analogique
//dans notre exemple:
//2.5V =>512
//(512*5)/1024=2.5
//cette opération est facultative, on peut utilser la valeur brute ou une autre formule
//Serial.print affiche la valeur lue avec une précision de 2 chiffres après la virgule
//TCNT1=63974 initialise le registre de comptage pour les 100ms secondes suivantes
//puis on inverse la led
ISR( TIMER1_OVF_vect) { //fonction exécutée toutes les 100ms
ecgValue = analogRead( ecgPin); // lecture du signal ECG
ecgValueFloat = (( ecgValue * 5) / 1024.0);
Serial. print( "ecgValueFloat: "); Serial. println( ecgValueFloat, 2);
TCNT1 = 65536 - 1562;//63974
digitalWrite(ledPin, (!digitalRead(ledPin)));
}
Merci dfgh, et en plus tu as remis ce programme au gout du jour...
En revanche, par curiosité, j'aurais bien aimé comprendre ce que signifie :
Char Buff(10)
dtostrf(ecgvaluefloat,4,6,buff)
De plus un peu plus haut lors du reglage du prescaler , pourquoi ne mettent ils pas
TCCR1B |= (0<<CSO1), ce bit du registre n'est pas renseigné , pourquoi ?
Idem pour Interrupt JMJ
TIFR1|=1; A quoi cela sert il ?
Encore merci pour ces reponses qui me permettent de progresser rapidement...
NB : Si tu as des tutos sympas sur les timers et surtout interruption je suis preneur..
TIFR1
Bit 0 = TOV1 passe à 1 lorsque timer1 arrive en overflow. Et passe à zéro lorsque la routine d'overflow est exécutée.
Bit 1 = OCF1A même fonctionnement que TOV1,mais pour la comparaison partie A.
Bit 2 = OCF1B idem
Le micro gère ces bits et je ne vois pas leur utilité
Voir page 137 et 138 de la datasheet du 328
TCCR1B : oui le Bit CS0 peut être mis à 0 . C'est effectivement plus sécurisant.
Rappel: tu ne trouveras ce qui suit que dans les vieux programmes. C'est beaucoup plus simple de nos jours.
Char buff(10)
Crée un tampon de 10 octets
dtostrf(valeurecg, 4,6,buffer)
Dans le but d'afficher la valeur flottante ecg, cette
Fonction transforme valeur ecg en une chaîne de 4 chiffres avant la virgule et de 6 chiffres pour la partie décimale. Cette chaîne est rangée dans le buffer prévu à cet effet. Et c'est ce buffer qui est affiché ensuite.
En résumé, on fait une mise en forme de la valeur ecg aux fins d'affichage.
Je te conseille de te référer à la datasheet atmel du 328
Je te conseille également le site de locoduino qui explique notamment les timers.