Modéliser un stimulateur cardiaque

Bonjour à la communauté.
Je suis débutant sur arduino mais j'ai déjà réalisé quelques montages.
Je suis aussi enseignant en lycée et dans les nouveaux programmes les microcontrôleurs sont introduits. J'aimerai proposer une activité en fin de lycée et j'ai pour projet de modéliser un stimulateur cardiaque en fabriquant un générateur d'impulsions.
Pour ce faire, je veux charger un condensateur de 470 ou 220 nF alimenter en 5V par l'entrée analogique d'arduino puis lorsque la charge est complète un commutateur bascule provoquant alors la décharge du condensateur à travers une résistance de 1 à 2 Mohms.

En pièce jointe je vous mets le schéma de principe du montage.

Mes questions sont :
Quel type de commutateur serait utile au montage ? ou bien faut-il ajouter d'autres composants...
Où est-ce que je pourrais trouver des lignes de programmes sur lesquelles m'appuyer pour piloter le commutateur ?
En effet, lorsque le condensateur a une tension disons de 4,9 V j'aimerais provoquer la bascule du commutateur de la position (1) à la position (2) pour faire se décharger le condensateur. Puisque lorsqu'il s'est décharger de 63% il faudrait que le commutateur repasse en position (1) pour recharger le condensateur.

Merci d'avance pour votre aide et vos contributions.

PJ.pdf (120 KB)

PJ.pdf (120 KB)

Bonsoir,
Pour moi le truc le plus simple un relais 1 repos travail, commandé par un sortie d2 ou autre
Et une lecture de tension sur le commun. Sur A0 par exemple.

Quelques lignes de code que tu trouvera partout Pour lire la tension aux bornes du condensateur, et qui commandera le relais.

Merci pour les infos. Je vais essayer.

Bonjour,

Avec un relais tu vas avoir des rebonds qui vont perturber ton signal.

A mon avis tu n'as pas besoin d'interface supplémentaire. Le schéma suivant devrait faire l'affaire.
Quand D3 est en OUTPUT HIGH tu charges le condensateur à travers la résistance de 120Ω, quand D3 est en INPUT tu décharges à travers la résistance de 1MΩ. Tu contrôles en fonction de la mesure de tension sur A0.
Simulateur-Cardiaque.png

Simulateur-Cardiaque.png

Merci, j'ai effectivement trouvé une proposition qui se rapproche de la tienne et ça marche plutôt bien (voir documents ci-joints).
Maintenant ce que je cherche à faire c'est copier les valeurs des mesures affichées dans le moniteur série vers un tableur qui me permettra de modéliser les mesures expérimentales.

Pour cela, je suis en train de m'inspirer de ce qui est proposé sur ce site :
Comment optimiser les mesures faites par le micro-contrôleur (...) - Sciences physiques et chimiques - ENCPB - Lycée Pierre Gilles de Gennes - M. Chamelot.
J'essaye de comprendre les lignes de code mais ce qui me surprend est qu'il n'y a aucun pinmode de déclaré. Est-ce normal ?
On ne voit pas bien le montage sur la vidéo mais on constate qu'il utilise un interrupteur pour la charge et la décharge, chose qu'il faudra que j'adapte dans le programme qui est proposé.

Si j'ai le temps je le teste demain et je vous tiens au courant.

Encore merci à vous tous.

Avec la PJ c'est mieux.

Tests.pdf (229 KB)

Tests.pdf (229 KB)

frederic_1975:
J'essaye de comprendre les lignes de code mais ce qui me surprend est qu'il n'y a aucun pinmode de déclaré. Est-ce normal ?

Oui, c'est normal. Au reset toutes les pins sont en entrée, de plus analogRead() configure proprement la pin pour une acquisition analogique.

Bonjour Frederic_1975,

Vous ne précisez pas à travers quelle résistance vous voulez charger le condensateur.

Cordialement,
bidouillelec

Bonjour bidouilleelec,

j'ai utilisé R1 = 220 ohms et R2 = 100 kohms avec C = 100 µF.

J'ai adapté le programme trouvé sur différents forums en éliminant la del qui ne m'était pas utile (voir programme en PJ et schéma du montage).

J'ai récupéré les données grâce à une console d'acquisition que j'ai reliée au montage : le traitement des mesures est en accord avec les valeurs attendues (temps de charge et de décharge OK entre autres).

Mais maintenant, mon problème est d'adapter le programme ci-dessus à celui proposé à l'adresse suivante : Comment optimiser les mesures faites par le micro-contrôleur (...) - Sciences physiques et chimiques - ENCPB - Lycée Pierre Gilles de Gennes - M. Chamelot afin de pouvoir récupérer les mesures et les injecter dans un tableur type excel et les traiter par la suite. Et en ce moment je galère. Donc votre aide me sera sans doute encore profitable pour avancer.

sketch_jun25_sans_diode.ino (1.75 KB)

les pj.

cordialement,

sketch_jun25_sans_diode.ino (1.75 KB)

A part des maladresses de presentation (indentation), votre code n'a rien de choquant

/* Test de charge décharge d'un condensateur */
const byte Entree_mesuree = 0; // Entrée analogique 0 utilisée.
const byte Sortie_CHARGE = 3;  // Broche 3 utilisée.
const byte Pilotage_decharge = 4;  // Broche 4 utilisée.
const byte LED_Arduino = 13;  // Broche 13 utilisée.
int CNA; // Mesure analogique retournée par le CNA.

float Tension_mesuree;    // Variable pour calculer U.
// float pour avoir U avec deux chiffres décimaux.

void setup() {
  Serial.begin(19200);
  pinMode(Sortie_CHARGE, INPUT);
  pinMode(Pilotage_decharge, OUTPUT);
  pinMode(LED_Arduino, OUTPUT);
}
const int TEMPO =200; // ajout par mes soins, pour parametrer cadence echantillonnage
   
void loop() {
  //============== CHARGE DU CONDENSATEUR ==============
    digitalWrite(Pilotage_decharge, HIGH); // Isoler R2 de l'U.C.
    pinMode(Sortie_CHARGE, OUTPUT);
    digitalWrite(Sortie_CHARGE, HIGH); // Début de la charge.
    digitalWrite(LED_Arduino, HIGH); // Indiquer la charge.
     do {CNA = analogRead(Entree_mesuree);
        Tension_mesuree = (float)CNA * 5.0 / 1023.0;  // Les 2 constantes avec un point décimal pour indiquer que ce sont des flottants
        // Pour 5 Vcc sur l'entree le CNA retourne 1023.
        Serial.print("Tension de charge : ");
        Serial.print(Tension_mesuree); Serial.println("Vcc.");
        delay(TEMPO); 
}        while (Tension_mesuree < 4.9);
    //============== DECHARGE DU CONDENSATEUR ==============
    pinMode(Sortie_CHARGE, INPUT);
    digitalWrite(Pilotage_decharge, LOW);   // Decharger C dans R2.
    digitalWrite(LED_Arduino, LOW); // Indiquer la decharge.
    do {CNA = analogRead(Entree_mesuree);
        Tension_mesuree = (float)CNA * 5 / 1023;
        Serial.print("   Tension de decharge : ");
        Serial.print(Tension_mesuree); Serial.println("Vcc.");
        delay(TEMPO); 
}   while (Tension_mesuree > 1.74);
}

IL y a des choses qui peuvent géner si vous voulez tracer sur le port serie;
côté arduino,
a) vous n'avez pas interet à transmettre trop : une séquence Tension de decharge ...Vcc mange 21 caractères; à 100 kbs, ça fait 2 millisecondes; vous pouvez être plus concis, en restant lisible
b) transmettre directement les données du CAN fait gagner quels cycles (convertir des float en ASCII n'est pas neutre), exploite les incomparables talents d'un PC pour gérer des floats -il sait faire, vite et bien- et est une bonne habitude à prendre -on envoye les données brutes au PC, sans se soucier des conversions : s'il y a une erreur, c'est plus facile à corriger côté PC-

côté PC.... voir suite

frederic_1975:
j'ai utilisé R1 = 220 ohms et R2 = 100 kohms avec C = 100 µF.

Ca fait une constante de temps de 10s. C'est un peu lent pour un simulateur cardiaque, ou alors le patient est dans un sale état :slight_smile:

JE comprends qu'in puisse galerer avec le terminal série de l'arduino, qui ne sait pas écrire dans un fichier (etape fort utile si on veut nourrire Excel en temps différé)

Je connais 3 solutions pour stocker dans un fichier (il y en a des dizaines d'autres):
a) celle que j'utilise avec satisfaction est python+pyserial + matplotlib (fait des beaux dessins, les convertit dans pas mal de formats graphique à la demande), sous GNUlinux -je crois que python fonctionne aussi sous windows- .
b) sous Windows, des logiciels de terminal serie (pas hyperterminal, qui est le pire des très affreux) permettent des captures de fichier: j'ai été satisfait de teraterm, mais les cpatures de fichier sont compliquée, bray terminal Terminal est plus recommandé -considéré comme le meilleur émulateur de terminal- et peur enrgistrer simplement.
c) Hackable Magazine utilisait processing pour dessiner -fonction qui a été rajoutée dans le terminal arduino- et enrigistrer des sorties d'arduino...

Merci à tous pour vos retour,
pour répondre à Kamil, le temps caractéristique de décharge a été choisi pour les tests, j'irais ensuite vers un tau autour de 1,2 s.

Merci à dbrion06 pour ses précieux conseils qui sont encore trop techniques pour moi qui débute en programmation.
j'aurai voulu adapter le fichier ci-dessous à celui de base qui convient à mon montage.

/* ----------------------------------------------------------------------
Suivi conductimétrique suivie avec Regressi
adapté par Serge Chamelot d'après module pour Regressi
Index of /WordPress/wp-arduino

Ce programme peut être adapté à n'importe quel appareil de mesure
qui dispose d'une sortie en tension 0-5V */

// QUELQUES CONSTANTES A MODIFIER EN CONNAISSANCE DE CAUSE
const float Npalliers = 1024.0; // en 10 bits, 1024 palliers - Ne pas modifier
const int plageTension = 5.0; // plage de numérisation 5V - Ne pas modifier
const int decoupage = 10; // en régime stable, 1 mesure est réalisée tous les 10ièmes de la duréée d'acquisition
const float EcartTension = 0.2; // écart à dépasser pour déclencher une mesure

// ------------------------------------------------------------------------//
int timeRes; // période d'échantillonnage en ms
unsigned long dureeAcquisition; // durée totale de l'acquisition en s
unsigned long tempsZero;
unsigned long tempsCourant;
int topDepart = 0;
String envoi;
float oldtension ;
float tension ;
unsigned long tempsPrec;

void setup() {
Serial.begin(9600);
tempsPrec = millis();
tempsZero = millis();
envoi = "0";
}

void lecture()
{
float tensionInt;
float ecartAbsolu ;

// Lecture et conversion des données
tensionInt = analogRead(A0); // entrée analogique A0 pour mesurer une valeur entre 0 et 1023
tension = (tensionInt)*plageTension/Npalliers; //
ecartAbsolu = abs(tension-oldtension);
// Envoie les données seulement si écart suffisant or attente suffisante
if ((ecartAbsolu >=EcartTension) or ((tempsCourant-tempsPrec)>(dureeAcquisition/decoupage))) {
Serial.print(tempsCourant/1000.0); // donne la date en secondes
Serial.print('\t'); // insère une tabulation
Serial.println(tension); // donne la valeur de tension
oldtension = tension;
tempsPrec = millis()-tempsZero;
}
}

// Pour la fonction suivante
// 3 commandes possibles à saisir dans le moniteur série d'Arduino
// échantillonnage : e100 où 100 est un exemple de période d'échantillonnage en ms
// durée acquisition : d20 où 20 est un exemple de durée en seconde
// déclancher manuellement une mesure m ou M
// s ou S : pour lancer l'acquisition

void reglages()
{
String calibre;
String prm;
String unite;
String rec;
int posCmaj;

while (topDepart==0) {
envoi = Serial.readString();
envoi.toLowerCase();

// Cherche la position du caractère D ou d pour fixer la durée
if (envoi.startsWith("d")) {
prm = envoi.substring(posCmaj + 1); // Prend la valeur située après le d
dureeAcquisition=prm.toInt()*1000; // Conversion en milliseconde
}

// Cherche la position du caractère E ou e pour fixer la période d'échantillonage
if (envoi.startsWith("e")) {
prm = envoi.substring(posCmaj + 1); // Prend la valeur située après le e
timeRes = prm.toInt();
}

// Cherche la position du caractère S ou s
if (envoi.startsWith("s")) {
topDepart = 1; // déclenche l'acquisition
tempsZero = millis();
Serial.print("t"); // et inscrit dans le moniteur les têtes de colonnes
Serial.print('\t');
Serial.println("Uc");
Serial.print("s");
Serial.print('\t');
Serial.println("V");
}
}
}

// Boucle principale

void loop() {
tempsCourant = millis()-tempsZero;
if ( topDepart == 0) {
reglages();
} else {
if (tempsCourant<=dureeAcquisition) {
lecture(); // lance la lecture d'une donnée avec un delay de timeRes
delay(timeRes);
} else {
topDepart=0;
}
}
}

Tout d'abord, je vous remercie pour le lien vers regressi. Le seul "piège" à éviter dans le code que vous liez consiste dans le fait qu'il est adapté à la lecture par un être humain: on n'affiche une nouvelle donnée que si elle diffère significativement de l'ancienne, pour éviter aux gens de mourir d'ennui devant un écran qui défile avec toujours la même valeur :

// Envoie les données seulement si écart suffisant or attente suffisante
  if ((ecartAbsolu >=EcartTension) or ((tempsCourant-tempsPrec)>(dureeAcquisition/decoupage)))

En fait, votre problème est un peu différent (excel, python, processing savent resister à l'ennui) et vous pouvez vous contenter d'un test du genre :

// Envoie les données seulement si attente suffisante, à cadence presque régulière

  if ((tempsCourant-tempsPrec)>(dureeAcquisition/decoupage))

qui garantit une acquisition à peu près régulière (même le traceur graphique du moniteur série de l'arduino peut s'en accommoder et sortir des jolies courbes ... pour vos yeux).
Le "à peu près" qui précède régulière est lié à la malchance, à certains temps de calcul... et est compensé par le fait que le monoteur série donne le temps exact -à la milliseconde près- dans ce logiciel.
J'ai remarqué que les données sont tabulées, assez concises (ce que je vous avais recommandé; les temps de transmission ne sont pas tout à fait négligeables...)
J'ai aussi remarqué que regressi utilise python sous Windows (je n'osais pas imaginer l'existence de python dans cet environnement... j'ai passé pas mal de temps à chercher des substituts à python).
Autre remarque : la configuration -dans reglage() est compliquée, et demande à l'arduino un travail de décodage de la config, puis de conversion: à mon avis, le PC sait mieux le faire... et le dialogue avec le PC pourrait se limiter à :
le PC demande des mesures (il envoie "s" ou "S")
l'arduino démarre ses mesures, et les transmet...

Bonjour,
je suis en passe d'atteindre mon objectif : j'arrive à enregistrer dans le moniteur série les valeurs du temps et de la tension sous forme de deux colonnes distinctes.
Mais je bloque encore sur deux points et j'ai besoin de vos réponses.

En PJ j'ai inséré une copie d'écran du moniteur série : avant les intitulés des colonnes (respectivement t et Uc) il y a des points d'interrogation. Pourquoi ? Et comment les retirer ?
Et enfin, j'ai systématiquement la première valeur de la date qui n'est pas nulle et supérieure à la date suivante, et de plus je n'ai pas de valeur pour Uc. S'agit-il d'un mauvais "calage" au niveau du temps et comme y remédier.

Document1.pdf (36.8 KB)

sketch_jun26b.ino (2.13 KB)

Tu utilises qu'elle carte?

Bon, vos sorties ne sont pas mal (peut être que la première ligne est choquante, mais on peut l'imputer au type de carte ou à un mauvais réglage du moniteur série; je n'ai rien vu d'affreux dans votre code)

Voisi votre code

/* Test de charge décharge d'un condensateur */
const byte Entree_mesuree = 0; // Entrée analogique 0 utilisée.
const byte Sortie_CHARGE = 3;  // Broche 3 utilisée.
const byte Pilotage_decharge = 4;  // Broche 4 utilisée.
const byte LED_Arduino = 13;  // Broche 13 utilisée.
const int TEMPO = 200; // pour parametrer cadence echantillonnage
int CNA; // Mesure analogique retournée par le CNA.

float Tension;    // Variable pour calculer U.
// float pour avoir U avec deux chiffres décimaux.

unsigned long temps;


void setup() {Serial.begin(19200);
  pinMode(Sortie_CHARGE, INPUT);
  pinMode(Pilotage_decharge, OUTPUT);
  pinMode(LED_Arduino, OUTPUT);

  Serial.print("t"); // inscrit dans le moniteur les entêtes de colonnes
  Serial.print('\t');
  Serial.println("Uc");
  Serial.print("s");
  Serial.print('\t');
  Serial.println("V");
}
   
void loop() {
   //============== CHARGE DU CONDENSATEUR ==============
    digitalWrite(Pilotage_decharge, HIGH);   // Isoler R2 de l'U.C.
    pinMode(Sortie_CHARGE, OUTPUT);
    digitalWrite(Sortie_CHARGE, HIGH); // Début de la charge.
    digitalWrite(LED_Arduino, HIGH); // Indiquer la charge.
     do {
        CNA = analogRead(Entree_mesuree);
        Tension = (float)CNA * 5.0 / 1023.0;  // Les 2 constantes avec un point décimal pour indiquer que ce sont des flottants
        // Pour 5 Vcc sur l'entrée le CNA retourne 1023.
        Serial.println(Tension);
        delay(200);
        temps = millis();
        Serial.print(temps/1000.0); // donne la date en secondes;
        Serial.print('\t');  // insère une tabulation
     }        while (Tension < 4.9);
          
    //============== DECHARGE DU CONDENSATEUR ==============
    pinMode(Sortie_CHARGE, INPUT);
    digitalWrite(Pilotage_decharge, LOW);   // Décharger C dans R2.
    digitalWrite(LED_Arduino, LOW); // Indiquer la décharge.
    do {
        CNA = analogRead(Entree_mesuree);
        Tension = (float)CNA * 5 / 1023; // pourquoi ne faites vous pas comme avant, avec toutes les conversions (ou pas de conversion du tout, ce qui est plus rapide)
        Serial.println(Tension);
        delay(200);
        temps = millis();
        Serial.print(temps/1000.0); // donne la date en secondes;
        Serial.print('\t');  // insère une tabulation
     }
        while (Tension > 2.00);
}

Si vous voulez que les données soient bien datées, essayez donc (pour la charge)

CNA = analogRead(Entree_mesuree);
        Tension = (float)CNA * 5.0 / 1023.0;  // Les 2 constantes avec un point décimal pour indiquer que ce sont des flottants
        // Pour 5 Vcc sur l'entrée le CNA retourne 1023.
        Serial.println(Tension);
        temps = millis();
        Serial.print(temps/1000.0); // donne la date en secondes;
        
        delay(TEMPO); // je fixerais TEMPO à 200 ms pour cet essai, mais paramètrer par une constante rendra  votre code plus facile à faire evoluer

(sur la même ligne, vous aurez la mesure, et, au temps de la conversion en float près et de la transmission série, le temps (ces delais parasites, squi me choquent, restent petits devant 200 ms... mais avec un C plus faible?

Bonjour frederic_1975,

frederic_1975:
Et enfin, j'ai systématiquement la première valeur de la date qui n'est pas nulle et supérieure à la date suivante, et de plus je n'ai pas de valeur pour Uc. S'agit-il d'un mauvais "calage" au niveau du temps et comme y remédier.

Dans :

     do {CNA = analogRead(Entree_mesuree);
        Tension = (float)CNA * 5.0 / 1023.0;  // Les 2 constantes avec un point décimal pour indiquer que ce sont des flottants
        // Pour 5 Vcc sur l'entrée le CNA retourne 1023.
        Serial.println(Tension);
        delay(200);
        temps = millis();
        Serial.print(temps/1000.0); // donne la date en secondes;
        Serial.print('\t');  // insère une tabulation
     }

""""

  • temps = millis();*
  • Serial.print(temps/1000.0); // donne la date en secondes;*
  • Serial.print('\t'); // insère une tabulation*
    """"
    est mal placé.

Cordialement,
bidouilleelec

Je vous remercie tous.
En déplaçant les trois lignes de codes indiquer par bidouilleelec je n'ai plus de décalage au niveau du temps.
Par contre, il reste les points d'interrogation. Une dernière idée.
Pour info j'ai une carte uno.

Cdt,