Générateur ECG/Signal Carré ou sinusoïdal

Bonjour,

Je n'ai pas de réponse claire à t'apporter malheureusement. Je suis novice dans l'arduinisme.
Ce que je constate c'est que le signal QRS est répété encore et encore et que sa fréquence varie grâce au potentiomètre.

Si cela t'intéresse tu devrait lire le tutoriel de l'auteur, Jim Lynch. Il explique bien sa méthode (ECG simulator).

J'ai essayé l'autre projet.

Le code est plus simple à comprendre. Le montage est plus facile même s'il y a plus d'éléments.
Et les boutons rajoutent un vrai plus.

Il ne me reste plus qu'à passer de la platine d'essai à une première mise en boîte.

Merci à tous pour votre aide. :slight_smile:

Bonne journée.

Je me permets de poster encore un autre message.

J'essaie d'améliorer le système en passant de 3 interrupteurs à 1 seul "interrupteur". Je pensais utiliser un encodeur rotatif. Mais peut être existe-t-il un autre système.

Avez-vous des idées ?

Merci.

Bonjour ez3khiel

Si c'est pour sélectionner 3 actions ou valeurs différentes, avec un seul bouton et une bobliothèque comme OneButton tu peux trigger sur 3 événements du bouton qui sont:
click = action 1
doubleClick = action 2
longPress = action 3

Si tu me dis quelles sont ces actions, je peut te faire un exemple.

A+
Cordialement
jpbbricole

Merci @jpbbricole.

En fait dans mon système, il y a 3 interrupteurs qui renvoie chacun une valeur (Ouvert/Fermé).
Ces valeurs forment un code binaire qui en fonction de sa valeur renvoie un type de simulation.

L'idée c'est de réduire le nombre d'élément à un seul si cela est possible en sachant qu'il y a 8 simulations différentes.

MODE BINAIRE BOUTON3 BOUTON2 BOUTON1
Normal (80 BPM) 0 000 0 0 0
Low (40 BPM) 1 001 0 0 1
High (120 BPM) 2 010 0 1 0
High (160 BPM) 3 011 0 1 1
Normal with apnea (80 BPM ) 4 100 1 0 0
Normal with hyperventilation (80 BPM) 5 101 1 0 1
Ventricular Fibrillation 6 110 1 1 0
Sinus rhythm with respiratory rate off 7 111 1 1 1

.

Bon après je peux réduire le nombre de simulation certaines ne sont pas très utiles.

Bonjour ez3khiel

Dans ce cas, je pense qu'un codeur de ce genre, serait plus pratique:
image
Avec une bibliothèque comme Encoder.

Si non, pour le fun, si tu as du Bluetooth, utiliser ton smartphone, il existe des applications pour faire ça, aisément.
Quel type de Nano vas tu utiliser?

A+
Cordialement
jpbbricole

Bonjour,

Pourquoi ne pas incrémenter le numéro de la simulation avec un seul bouton.

Merci @jpbbricole et @kamill.

Vos deux idées sont incroyables. Je ne comprend pas pourquoi je n'ai pas penser à l'idée d'incrémenter les modes avec un seul bouton...

Je comprend pourquoi l'intérêt d'avoir 3 interrupteurs : l'utilisateur peut "lire" le numéro de la simulation dans laquelle il se trouve. Il faudra que je rajoute un digit ou un écran avec l'une de vos deux solutions (Encodeur ou Bouton).

Mon âme de geek te dit "Oui" ! J'utilise une Nano basique. J'ai une Nano33 BLE et Nano33 iOT mais il me semble que le code actuel ne fonctionne pas avec.

Bonjour ez3khiel

Encore une autre proposition, un simple potentiomètre, divisé en 8 secteurs (fonction map()), ainsi tu peux "voir" la sélection.

A+
Cordialement
jpbbricole

J'y ai pensé également. Pour le coup c'est simple aussi.
Est ce que de potentiomètre "crantés" existent ? Histoire de bien s'arrêter sur chaque zone ?

Bonjour @ez3khiel

Mon moteur de recherche ( le tien aussi je suppose.....) apporte des réponses à la question de l'existence en 2023 de potentiomètres à crans,

l'une d'elles dans l'excellente boutique parisienne Saint Quentin radio
https://www.stquentin-radio.com/?page=categorie&cat=2&id=0&act=0&sous_cat1=32&sous_cat2=970&ar_cat=2&v=1

Donc oui, ça existe encore malgré leur disparition progressive , les encodeurs occupant largement le terrain

Autre solution , prendre un commutateur 1 circuit 12 positions et y souder les résistances de ton choix pour former un 'potentiomètre cranté' sur mesure
image

Une roue codeuse, un commutateur rotatif codé héxa, .....

Si tu veux parler de ceci, j'adore :

Bonjour,

Merci pour tout vos retours. L'option avec deux boutons poussoirs fonctionnent parfaitement.
Je vais donc rester sur cette méthode.

J'ai modifier le code afin de l'alléger et de le comprendre un peu plus. Comme dit plus haut, il fonctionne. Cela dit, je serais intéresser par toute remarque qui pourrait le rendre encore plus optimisé.

#define ENABLE_CUSTOM_WAVE
#define ENABLE_RESP_SIM    
#define ENABLE_RESP_LED
#define F_CPU 16000000UL

#define BOUTON_PLUS 2 
#define BOUTON_MOINS 3
#define PINOUT 9
#define RESP 10
#define RESP_LED 13
int MODE = 0;

#include "wave.h"
#include <string.h>

//Définition de la variable hr_rate et de ses valeurs.
enum hr_rate {
    BPM40  = 0x3C,  //60
    BPM80  = 0x1E,  //30
    BPM120 = 0x14,  //20
    TACH = 0xF,     //15
};

//Définition de la variable resp_rate et de ses valeurs.
enum resp_rate {
    RESP12 = 150,
    RESP38 = 50 
};

uint8_t nsr_fragment[] = {
    35, 38, 35, 20, 20, 20, 25, 5, 
    140, 255, 0, 20, 20, 20, 25, 
    35, 45, 55, 58, 56, 25
};

uint8_t pwm_vtach[0x10] {     //16
    0, 100, 150, 200, 220, 240, 250, 240, 
    255, 210, 180, 140, 100, 80, 40, 10,
};

uint8_t pwm_norm_sr[0x40];    //64
uint8_t pwm_vfib[0x40];     //64 
uint8_t custom_wave[0x40];  //64

void disable_resp(void) {     //Désactivation de la fréquence respiratoire
    DDRB = DDRB | 0x4;
    TCCR2B = 0;
}

void enable_resp(void) {      //Désactivation de la fréquence respiratoire
    TCCR2B = 0x7;
}

void (*resp_enable_fp)(void) = enable_resp;

void __attribute__((always_inline)) pwm_dc(const uint8_t duty_cycle) {
    OCR1A = duty_cycle;
}

void __attribute__((hot)) pwm_array_sequence(const uint8_t *const sequence_array, const uint8_t rate) {   //Création du signal Fréquance Cardiaque
    static uint8_t counter;
    uint8_t value = sequence_array[counter];
    counter = (counter + 1) % rate;
    pwm_dc(value);
    PORTD = PORTD & ~0x20;
    if(value == 255)
        PORTD = PORTD | (1 << PD5);
}
 
static long resp_rate = RESP12; //Création du siganl Fréquence Respiratoire
ISR(TIMER2_OVF_vect) {
    static uint8_t counter = 0;
    counter = (counter + 1) % resp_rate;
    if(counter == 0) {
        DDRB = DDRB ^ 0x4;
        PORTB = PORTB & ~0x4;
        PORTB = (PORTB ^ 0x20);
    }
}
void setup(void) {
pinMode(BOUTON_PLUS, INPUT_PULLUP);
pinMode(BOUTON_MOINS, INPUT_PULLUP);
pinMode(5, OUTPUT);
pinMode(RESP, OUTPUT);
pinMode(RESP_LED, OUTPUT);
pinMode(PINOUT, OUTPUT);
Serial.begin(9600);

cli();
TCCR1A |= _BV(COM1A1) | _BV(WGM10);
TCCR1B |= _BV(CS10) | _BV(WGM12);

TCCR2A = 0;
enable_resp(); 
TCNT2 = 0;
TIMSK2 = _BV(TOIE2);
sei();

for(uint8_t i = 0; i < sizeof(pwm_vfib); i++)
    pwm_vfib[i] = (50 * (sin(i / 3) * sin((i / 3) * 2))) + 50;

for(uint8_t i = 0; i < sizeof(pwm_norm_sr); i++)
    pwm_norm_sr[i] = 20;
for(uint8_t i = 0; i < sizeof(nsr_fragment); i++)
    pwm_norm_sr[i] = nsr_fragment[i];

for(uint8_t i = 0; i < sizeof(custom_wave); i++)
    custom_wave[i] = extern_baseline;
uint8_t bcount = sizeof(extern_wave_fragment);
if(bcount > sizeof(custom_wave))
    bcount = sizeof(custom_wave);
memcpy(custom_wave, extern_wave_fragment, bcount);
}

void __attribute__((hot)) loop(void) {
uint8_t *current_sequence = pwm_norm_sr;
uint8_t heart_rate = BPM80;
uint8_t master_delay = 25;

while(1) {
boolean ETAT_BOUTON_PLUS = digitalRead(BOUTON_PLUS);
boolean ETAT_BOUTON_MOINS = digitalRead(BOUTON_MOINS);

if (ETAT_BOUTON_PLUS == LOW) {
  MODE = (MODE + 1) % 8;
  Serial.println("Mode actuel : " + String(MODE));
  delay(200);} 
else if (ETAT_BOUTON_MOINS == LOW) {
  MODE = (MODE - 1 + 8) % 8;
  Serial.println("Mode actuel : " + String(MODE));
  delay(200);}

pwm_array_sequence(current_sequence, heart_rate);
current_sequence = pwm_norm_sr;
heart_rate = BPM80;
resp_rate = RESP12;
resp_enable_fp();
switch(MODE) {
  case 0:             // normal sinus rhythm, 80BPM 
      break;
  case 1:             // normal sinus rhythm, 40BPM
      heart_rate = BPM40;
      break;
  case 2:             // normal sinus rhythm, 120BPM
      heart_rate = BPM120;
      break;  
  case 3:             // normal sinus rhythm, tach
      heart_rate = TACH;
      break; 
  case 4:             // normal sinus rhythm, bpm80, apnea
      heart_rate = BPM80;
      disable_resp();
      break;   
  case 5:             // normal sinus rhythm, bpm80, hyperventilation
      resp_rate = RESP38;
      break;
  case 6:             // V-tach
      current_sequence = pwm_vtach;
      heart_rate = TACH;
      resp_rate = RESP38;
      break;
  case 7:             // V-fib
      disable_resp();
      current_sequence = custom_wave;
      break;                                                           
  }
delay(master_delay);
}
}

Plus tard, à la place du moniteur série, j'inclurai un écran LCD pour indiquer le nom et le numéro du programme.

Merci.

Désolé pour ce double-post.

J'ai modifié mon code en y ajoutant l'écran LCD et une fonction RESET en cas d'appui simultané sur les deux boutons poussoirs.

J'ai d'abord ajouté toutes les lignes relative à l'écran LCD dans la fonction switch() qui gère les différents modes. Mais j'obtenais des erreurs de valeurs au niveau de la fréquence cardiaque et respiratoire (Consigne de 80 BPM - Valeur mesuré 57 BPM). Ce problème était certainement lié au fait que la communication avec l'écran se faisait à chaque boucle.

J'ai donc inclus les lignes nécessaire à l'affichage directement lorsque le bouton moins ou le bouton plus est appuyé. Ca marche parfaitement. Le code pourrait peut être plus simple à ce niveau mais je suis content d'avoir trouver cette méthode de moi-même. :slight_smile:

void __attribute__((hot)) loop(void) {
uint8_t *current_sequence = pwm_norm_sr;
uint8_t heart_rate = BPM80;
uint8_t master_delay = 25;
String L1 = "FC = 80 BPM";
String L2 = "FR = Normal";

lcd.clear();
lcd.print(L1);
lcd.setCursor(0, 1);
lcd.print(L2);

while(1) {
boolean ETAT_BOUTON_PLUS = digitalRead(BOUTON_PLUS);
boolean ETAT_BOUTON_MOINS = digitalRead(BOUTON_MOINS);

if (ETAT_BOUTON_PLUS == LOW && ETAT_BOUTON_MOINS == LOW) {
  lcd.clear();
  lcd.print("RESET EN COURS.");
  delay(2000);
  asm volatile("jmp 0x00");}

if (ETAT_BOUTON_PLUS == LOW || ETAT_BOUTON_MOINS == LOW) {
  if (ETAT_BOUTON_PLUS == LOW){MODE = (MODE + 1) % 8;}
  else if (ETAT_BOUTON_MOINS == LOW) {MODE = (MODE - 1 + 8) % 8;}
  switch(MODE){
    case 0:             // normal sinus rhythm, 120BPM
      L1 = "FC = 80 BPM";
      L2 = "FR = Normal";
      break;
    case 1:             // normal sinus rhythm, 40BPM
      L1 = "FC = 40 BPM";
      L2 = "FR = Normal";
      break;
    case 2:             // normal sinus rhythm, 120BPM
      L1 = "FC = 120 BPM";
      L2 = "FR = Normal";
      break;  
    case 3:             // normal sinus rhythm, tach
      L1 = "FC = 160 BPM";
      L2 = "FR = Normal";
      break; 
    case 4:             // normal sinus rhythm, bpm80, apnea
      L1 = "FC = 80 BPM";
      L2 = "FR = Apnee";
      break;   
    case 5:             // normal sinus rhythm, bpm80, hyperventilation
      L1 = "FC = 80 BPM";
      L2 = "FR = Hyperventilation";
      break;
    case 6:             // V-tach
      L1 = "FC = Tachycardie";
      L2 = "FR = Hyperventilation";
      break;
    case 7:             // V-fib
      L1 = "FC = Fibrilation";
      L2 = "FR = Apnee";
      break;}
  lcd.clear();
  lcd.print(L1);
  lcd.setCursor(0, 1);
  lcd.print(L2);
  delay(200);} 

pwm_array_sequence(current_sequence, heart_rate);
current_sequence = pwm_norm_sr;
heart_rate = BPM80;
resp_rate = RESP12;
resp_enable_fp();
switch(MODE) {
  case 0:             // normal sinus rhythm, 80BPM 
      break;
  case 1:             // normal sinus rhythm, 40BPM
      heart_rate = BPM40;
      break;
  case 2:             // normal sinus rhythm, 120BPM
      heart_rate = BPM120;
      break;  
  case 3:             // normal sinus rhythm, tach
      heart_rate = TACH;
      break; 
  case 4:             // normal sinus rhythm, bpm80, apnea
      heart_rate = BPM80;
      disable_resp();
      break;   
  case 5:             // normal sinus rhythm, bpm80, hyperventilation
      resp_rate = RESP38;
      break;
  case 6:             // V-tach
      current_sequence = pwm_vtach;
      heart_rate = TACH;
      resp_rate = RESP38;
      break;
  case 7:             // V-fib
      disable_resp();
      current_sequence = custom_wave;
      break;                                                           
  }
delay(master_delay);
}
}

Dernier message pour clôturer le sujet.

Merci à tous pour votre aide. Mon projet est terminé grâce à vous.
Voici à quoi ressemble le boitier :

Merci encore et bonne journée.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.