Go Down

Topic: Developed Pulsoximeter with 2 Arduinos. (Read 1 time) previous topic - next topic

die_Diode

Aug 15, 2014, 06:02 pm Last Edit: Aug 15, 2014, 06:19 pm by die_Diode Reason: 1
I have developed a pulsoximter with 2 Arduinos:

Pulse oximetry is a non-invasive method for monitoring of  a patient's oxygenation.
The Heartbeat BPM is detectable too.

Arduino Mega responsible  for the oximetry electronics and Arduino Uno for the PPG graph.
The electronics includes LED Driver, Photocurrent transformation, patient-dependent LED calibration , Active filters,  controlling the Nellcor SpO2 sensor.
Adafruit OLED displays Vitalparameter BPM und SPO2. Noritake VFD display GUU-100 shows the PPG(Photoplethysmograph). The boards are connected to the electronics with a Protoshield.

Compared to a clinical diagnostic device, the deviation in the average is 1 percent !!!
Both Arduino are in system updatable via USB.










my biggest Arduino -Project: http://blog.arduino.cc/2014/07/15/diy-pulsoximeter-developed-with-two-arduino/

raschemmel

Looks awesome ! Are you going to share the DIY documentation ? (schematics, code , etc ...)
Arduino UNOs, Pro-Minis, ATMega328, ATtiny85, LCDs, MCP4162, keypads,<br />DS18B20s,74c922,nRF24L01, RS232, SD card, RC fixed wing, quadcopter

die_Diode

#2
Aug 15, 2014, 07:50 pm Last Edit: Aug 15, 2014, 11:57 pm by die_Diode Reason: 1



//code for PPG

Code: [Select]
#include <Noritake_VFD_GUU100.h> // Bibliothek Noritake GU128X64E-U100GUU-100
#include "fonts/allFonts.h"      // Bibliothek Schriftarten

static Noritake_VFD_GUU100 vfd;
#define KEY_DDR         DDRD
#define KEY_PORT        PORTD
#define KEY_PIN         PIND
#define KEY0            PORTD0
#define KEY1            PORTD1
#define KEY2            PORTD2
#define ALL_KEYS        (1<<KEY0 | 1<<KEY1| )
#define REPEAT_MASK     (1<<KEY1 | 1<<KEY2)       // repeat: key1, key2
#define REPEAT_START    50                        // after 500ms
#define REPEAT_NEXT     20                        // every 200ms

volatile uint8_t key_state;                                // debounced and inverted key state:
volatile uint8_t key_press;                                // key press detect
volatile uint8_t key_rpt;                                  // key long press and repeat
ISR( TIMER2_OVF_vect )                            // every 10ms
{
 static uint8_t ct0, ct1, rpt;
 uint8_t i;
 TCNT2 = (uint8_t)(int16_t)-(16000000 / 1024 * 10e-3 + 0.5);  // preload for 10ms
 i = key_state ^ KEY_PIN;                        // Taster HIGH AKTIV!
 ct0 = ~( ct0 & i );                             // reset or count ct0
 ct1 = ct0 ^ (ct1 & i);                          // reset or count ct1
 i &= ct0 & ct1;                                 // count until roll over ?
 key_state ^= i;                                 // then toggle debounced state
 key_press |= key_state & i;                     // 0->1: key press detect

 if( (key_state & REPEAT_MASK) == 0 )            // check repeat function
   rpt = REPEAT_START;                          // start delay
 if( --rpt == 0 ){
   rpt = REPEAT_NEXT;                            // repeat delay
   key_rpt |= key_state & REPEAT_MASK;
 }
}
uint8_t get_key_press( uint8_t key_mask )
{
 cli();                                          // read and clear atomic !
 key_mask &= key_press;                          // read key(s)
 key_press ^= key_mask;                          // clear key(s)
 sei();
 return key_mask;
}
uint8_t get_key_rpt( uint8_t key_mask )
{
 cli();                                          // read and clear atomic !
 key_mask &= key_rpt;                            // read key(s)
 key_rpt ^= key_mask;                            // clear key(s)
 sei();
 return key_mask;
}
uint8_t get_key_state( uint8_t key_mask )
{
 key_mask &= key_state;
 return key_mask;
}
uint8_t get_key_short( uint8_t key_mask )
{
 cli();                                          // read key state and key press atomic !
 return get_key_press( ~key_state & key_mask );
}
uint8_t get_key_long( uint8_t key_mask )
{
 return get_key_press( get_key_rpt( key_mask ));
}
// Arduino Boot-Logo
static const uint8_t PROGMEM image_ArduinoLogo[] = {
 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0xc0,0xe0,0xe0,0xf0,0xf0,0xf8,0xf8,
 0xfc,0xfc,0xfc,0xfe,0xfe,0xfe,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
 0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfe,0xfe,0xfe,0xfc,0xfc,0xfc,0xf8,0xf8,
 0xf0,0xf0,0xf0,0xe0,0xc0,0xc0,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0xc0,0xe0,0xe0,0xf0,0xf0,0xf8,0xf8,
 0xf8,0xfc,0xfc,0xfc,0xfe,0xfe,0xfe,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfe,0xfe,0xfc,0xfc,0xfc,0xf8,0xf8,
 0xf8,0xf0,0xf0,0xe0,0xc0,0xc0,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 0x80,0xe0,0xf0,0xfc,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x1f,0x1f,0x0f,
 0x07,0x07,0x03,0x03,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x03,0x03,0x03,0x07,0x07,0x0f,0x1f,0x1f,
 0x3f,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfc,0xf8,0xf0,0xe0,0xc0,0xc0,0xe0,
 0xf0,0xf8,0xfc,0xfc,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x3f,0x1f,0x0f,0x0f,
 0x07,0x07,0x03,0x03,0x01,0x01,0x01,0x01,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,
 0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x03,0x03,0x03,0x07,0x07,0x0f,0x1f,0x3f,
 0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfc,0xf8,0xf0,0xc0,0x00,0x00,0xfe,0xff,
 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x01,0x00,0x00,0x00,0x00,0x00,0x00,
 0x00,0x00,0x00,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,
 0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 0x00,0x00,0x01,0x03,0x07,0x0f,0x9f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
 0xff,0xff,0xff,0xff,0x9f,0x0f,0x07,0x03,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 0x00,0x00,0x00,0x00,0xf8,0xf8,0xf8,0xf8,0xf8,0xff,0xff,0xff,0xff,0xff,0xff,0xf8,
 0xf8,0xf8,0xf8,0xf8,0xf8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 0x00,0x03,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf8,0x07,0x3f,0x7f,
 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf8,0xe0,0xc0,0x80,0x00,0x00,0x00,0x00,
 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xc0,0xe0,
 0xf0,0xf8,0xfc,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x3f,0x3f,0x7f,0xff,0xff,
 0xff,0xff,0xff,0xff,0xff,0xfe,0xfc,0xf0,0xe0,0xe0,0xc0,0x80,0x00,0x00,0x00,0x00,
 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x00,0x00,
 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0xc0,0xf0,
 0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x1f,0x03,0x00,0x00,0x00,0x01,
 0x03,0x07,0x0f,0x1f,0x3f,0x3f,0x7f,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfc,0xfc,
 0xf8,0xf8,0xf8,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xf0,
 0xf0,0xf0,0xf0,0xf0,0xf8,0xf8,0xf8,0xfc,0xfc,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,
 0x7f,0x3f,0x3f,0x1f,0x0f,0x07,0x03,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x03,
 0x07,0x0f,0x0f,0x1f,0x3f,0x7f,0x7f,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfc,0xfc,
 0xf8,0xf8,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xe0,0xe0,0xe0,0xe0,0xe0,0xe0,0xf0,0xf0,
 0xf0,0xf0,0xf0,0xf0,0xf8,0xf8,0xfc,0xfc,0xfc,0xfe,0xff,0xff,0xff,0xff,0xff,0x7f,
 0x7f,0x3f,0x1f,0x1f,0x0f,0x07,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x03,0x03,0x03,0x07,0x07,0x07,
 0x07,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,
 0x0f,0x0f,0x0f,0x0f,0x07,0x07,0x07,0x07,0x03,0x03,0x03,0x01,0x01,0x00,0x00,0x00,
 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x03,0x03,0x03,0x07,0x07,0x07,
 0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,
 0x0f,0x0f,0x0f,0x0f,0x07,0x07,0x07,0x07,0x03,0x03,0x01,0x01,0x00,0x00,0x00,0x00,
 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,
 0xf8,0xfe,0xff,0x3f,0x1f,0x7f,0xff,0xfe,0xf8,0xc0,0x00,0x00,0x00,0x00,0x00,0xfe,
 0xff,0xff,0xff,0xff,0x87,0x87,0x87,0x86,0xce,0xfe,0xfe,0xfc,0x7c,0x00,0x00,0x00,
 0x00,0xff,0xff,0xff,0xff,0x07,0x07,0x07,0x06,0x0e,0x0e,0x1e,0xfe,0xfc,0xfc,0xf8,
 0xc0,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,
 0xff,0xff,0x00,0x00,0x00,0x00,0x07,0x07,0x07,0x07,0xff,0xff,0xff,0xff,0xff,0x07,
 0x07,0x07,0x07,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0x7f,0xfe,0xf8,0xe0,0xc0,
 0x00,0x00,0xfe,0xff,0xff,0xff,0x00,0x00,0xe0,0xf8,0xfc,0xfe,0x7e,0x0e,0x07,0x07,
 0x07,0x07,0x07,0x0e,0xfe,0xfe,0xfc,0xf8,0xe0,0x00,0x80,0xf0,0xfc,0xff,0x7f,0x1f,
 0x1f,0x1c,0x1c,0x1c,0x1c,0x1f,0x1f,0x7f,0xff,0xff,0xf8,0xe0,0x00,0x00,0xff,0xff,
 0xff,0xff,0x7f,0x03,0x03,0x03,0x0f,0x3f,0x7f,0xfe,0xf8,0xf0,0xc0,0x00,0x00,0x00,
 0xff,0xff,0xff,0xff,0xe0,0xe0,0xe0,0xe0,0x60,0x70,0x78,0x7f,0x3f,0x1f,0x0f,0x03,
 0x00,0x00,0x3f,0x7f,0x7f,0xff,0xf0,0xe0,0xe0,0xe0,0xe0,0xe0,0xf0,0x7f,0x7f,0x3f,
 0x1f,0x00,0x00,0x00,0x00,0xe0,0xe0,0xe0,0xe0,0xff,0xff,0xff,0xff,0xff,0xe0,0xe0,
 0xe0,0xe0,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0x00,0x03,0x0f,0x1f,0x7f,
 0xfe,0xff,0xff,0xff,0xff,0x00,0x00,0x0f,0x1f,0x3f,0x7f,0x7e,0xf0,0xe0,0xe0,0xe0,
 0xe0,0xe0,0xf0,0x7f,0x7f,0x3f,0x1f,0x07
};

float U =0;
int i = 0;                                        // Wert X-Achse
int Pin = A0;                                     // ADC an PIN A0
int POTI10K = A1;                                 // POTI an ADC Pin A1
int PPG =0;                                       // einzulesene Spannung der PPG
int Poti=0;                                       // Potiwert um Framezeit zu variieren


my biggest Arduino -Project: http://blog.arduino.cc/2014/07/15/diy-pulsoximeter-developed-with-two-arduino/

die_Diode

#3
Aug 15, 2014, 07:51 pm Last Edit: Aug 15, 2014, 11:58 pm by die_Diode Reason: 1

// code PPG setup and loop
Code: [Select]

void setup(){
KEY_DDR &= ~ALL_KEYS;                // configure key port for input
 KEY_PORT |= ALL_KEYS;                // and turn on pull up resistors
 TCCR2B = (1<<CS22)|(1<<CS20);         // divide by 1024
 TCNT2 = (uint8_t)(int16_t)-(16000000 / 1024 * 10e-3 + 0.5);  // preload for 10ms
 TIMSK2 |= 1<<TOIE2;                   // enable timer interrupt
 sei();
 vfd.reset();
 vfd.init();
 vfd.clearScreen();
 delay(200);
 //Animation
 vfd.clearScreen();
 circleOut();
 vfd.clearScreen();
 circleOut();
 vfd.clearScreen();
 circleOut();
 vfd.reset();
 vfd.init();
 vfd.clearScreen();
 
// Startbalken
 for(int s = 0 ; s<= 127 ; s++)

 {

   vfd.setFont(thin_8x16);                         // Schriftgröße und Schriftart setzen
   vfd.setCursor(12,22);                           // Cursor setzen (Zeile 16, 21.Pixel)
   vfd.println("STARTING ...");                    // Schriebbefehl mit Inhalt
   vfd.drawLine(s,45,s,59,1);
   delay(25);
 }
 
 vfd.clearScreen();
 delay(200);
 vfd.init();
 vfd.drawImage(image_ArduinoLogo, 0,0, 127,63);   // Bitmapdatei Arduino-Logo schreiben
 delay(3000);                                     // Wartezeit von 5 sek.
 vfd.clearScreen();                               // Display löschen
 vfd.reset();
 vfd.init();
 vfd.clearScreen();
}
//Hauptprogramm
void loop(){
 vfd.clearScreen();                              // Display löschen
 vfd.drawRect(0,0,127,63,1);                     // Aussenrahmen zeichnen


 for (i = 0; i <= 127; i++)                     // Zähler bis 128 ( für Länge =128 Pixel= x-Achse)
 {  
   PPG = analogRead(Pin);                       // Spannungswert  PPG einlesen
   Poti = analogRead(POTI10K);                  // Spannungswert Poti einlesen

   U=PPG/4.6;                                   // U-Variable  Vorskalierung
   U=map(U,0,110,7,63);                         // Skalierung der Y-Achse ( 64 Pixel)
   int Z = Poti;                                // Z-Variable deklariert für variable Frames
   Z=map(Z,0,1023,1,35);                        // Wartezeit von Z in 1-35 Millisek skaliert
   delay(Z);                                    // Wartezeit von Z in 1-35 Millisek skaliert// Wartezeit aus Z entnehmen
   if( get_key_press( 1<<KEY0 ))                     // Wenn Digitaleingang 2 HIGH hat
   {
     vfd.drawLine(i,U,i,63,1);                  // PPG Graphen integriert schreiben
   }
   else if ( !get_key_press( 1<<KEY0 ))                // Wenn Digitaleingang 2 LOW hat
   {
     vfd.fillCircle(i,U-1,0.7,1);               // PPG Graphen als Linie schreiben
     vfd.fillCircle(i,U,0.7,1);
   }
 }                                    

}

void circleOut(void)                             // Animation beim Start
{
 uint8_t x, y;

 for(x=1; x<64; x++) {
   vfd.drawCircle(64, 32, x, 1);
   vfd.drawCircle(64, 32, x, 0);
 }
}




// code attiny85 for LED Multiplexing
Code: [Select]
#include <avr/io.h>                          // Bibliothek GPIOs
#include <avr/interrupt.h>                   // Bibliothek Interrupts

volatile byte counter = 0;                   // Counter für Case-Struktur
// Zuweisungen der anzusteuernden Pins
int main(void)
{
 DDRB = 0b00000011;                         // Port B0 & B1 aus Ausgang gesetzt
 PORTB &= ~(1<<PB0);                        // Port B0 mit LOW-Pegel
 PORTB &= ~(1<<PB1);                        // Port B1 mit LOW-Pegel
 

 TCCR1 = (1<<CS12)| (1<<CS11) | (1<<CS10);  
 OCR1A = 128;                               // Errechneter Zeitwert für 1000µs,124, Correktion without Ext. crystal=128
 TIMSK = (1<<OCIE1A);                      
 sei();                                     // Interrupt aktivieren
}

while(1)                                     //  Endlosschleife bleibt leer
 {}

ISR(TIMER1_COMPA_vect) {       // Aufruf  "Timer Interrupt" ISR CTC-Modus
 TCNT1 = 0;                   // Counterregister auf Null gesetzt
 counter = (counter + 1) % 6; // Counter von 0-3 für entsprechenden Schaltzustand zählen
 switch(counter) {
 case 0:
   PORTB |=  (1<<PB0);        // 1000µs LED rot an
   PORTB &= ~(1<<PB1);        // 1000µs LED infrarot aus
   break;
 case 1:
   PORTB |=  (1<<PB0);        // 1000µs  LED rot an
   PORTB &= ~(1<<PB1);        // 1000µs  LED infrarot aus
   break;
 case 2:
   PORTB &= ~(1<<PB0);        // 1000µs  LED rot aus
   PORTB &= ~(1<<PB1);        // 1000µs  LED infrarot aus
   break;
 case 3:
   PORTB &= ~(1<<PB0);        // 1000µs  LED rot aus
   PORTB |=  (1<<PB1);        // 1000µs  LED infrarot an
   break;
 case 4:
   PORTB &= ~(1<<PB0);        // 1000µs  LED rot aus
   PORTB |=  (1<<PB1);        // 1000µs  LED infrarot an
   break;
 case 5:
   PORTB &= ~(1<<PB0);        // 1000µs  LED rot aus
   PORTB &= ~(1<<PB1);        // 1000µs  LED infrarot aus
   break;
 }
}


code for SPO2 still follows
my biggest Arduino -Project: http://blog.arduino.cc/2014/07/15/diy-pulsoximeter-developed-with-two-arduino/

raschemmel

#4
Aug 15, 2014, 09:06 pm Last Edit: Aug 15, 2014, 09:09 pm by raschemmel Reason: 1
THANKS !

Do you have a PDF for the schematic (just curious. Not absolutely necessary . Just makes it easier to view online.)

Is your Avatar some kind of Germanium diode ? (Is there some significance to your handle "die_diode"  ?)


PS- The only part number I can't quite make out is the op amps. Are they OPA347s ?
Arduino UNOs, Pro-Minis, ATMega328, ATtiny85, LCDs, MCP4162, keypads,<br />DS18B20s,74c922,nRF24L01, RS232, SD card, RC fixed wing, quadcopter

raschemmel

#5
Aug 15, 2014, 09:47 pm Last Edit: Aug 15, 2014, 09:58 pm by raschemmel Reason: 1
The schematic is not printing correctly .
Arduino UNOs, Pro-Minis, ATMega328, ATtiny85, LCDs, MCP4162, keypads,<br />DS18B20s,74c922,nRF24L01, RS232, SD card, RC fixed wing, quadcopter

raschemmel

#6
Aug 15, 2014, 10:20 pm Last Edit: Aug 15, 2014, 11:34 pm by raschemmel Reason: 1
Overall , I would say that it looks professional enough that you should consider making it available in kit form (ala Heathkit
 http://en.wikipedia.org/wiki/Heathkit  
 http://www.heathkit-museum.com/  
 http://www.vintage-radio.info/heathkit/  

Obviously this would require making pcbs to replace the hand wired boards you have. You might want to consider a single board with everything. (using the ATmega328 chips to replace the Mega. You could take preliminary orders to see how much interest there is and if there is enough you can get quotes on the pcb in small qty. (less than 100) unless you have enough interest to warrant a larger run.
You would need an assembly drawing and instruction manual and possibly a video but from what I can see, the build should be pretty straight forward. I've built a lot of equipment and your box looks laid out well and easy to work with. What are the heatsinked devices ?
(regulators for the +9V and +5V supplies.  (I didn't see any other voltages)

Also,
Attached are datasheets for an analog switch and an op amp. Both are ideal for operation on  5V.
I'm not suggesting they are any better than what you used but you might take a look at their specs to see if they could be of use to you for this project.
Arduino UNOs, Pro-Minis, ATMega328, ATtiny85, LCDs, MCP4162, keypads,<br />DS18B20s,74c922,nRF24L01, RS232, SD card, RC fixed wing, quadcopter

die_Diode

great idea

Yes there are OPA 347, they are cheap, easy to wire, and suitable for single supply operation.
The MAX313 analog switches are great, have a very low resistance and can switch to several MHz.

The heat sinks are generously dimensioned. (For 9V and 5V), because the Noritake draws a lot of power:(

my biggest Arduino -Project: http://blog.arduino.cc/2014/07/15/diy-pulsoximeter-developed-with-two-arduino/

janost


Overall , I would say that it looks professional enough that you should consider making it available in kit form (ala Heathkit
 http://en.wikipedia.org/wiki/Heathkit  
 http://www.heathkit-museum.com/  
 http://www.vintage-radio.info/heathkit/  

Obviously this would require making pcbs to replace the hand wired boards you have. You might want to consider a single board with everything. (using the ATmega328 chips to replace the Mega. You could take preliminary orders to see how much interest there is and if there is enough you can get quotes on the pcb in small qty. (less than 100) unless you have enough interest to warrant a larger run.
You would need an assembly drawing and instruction manual and possibly a video but from what I can see, the build should be pretty straight forward. I've built a lot of equipment and your box looks laid out well and easy to work with. What are the heatsinked devices ?
(regulators for the +9V and +5V supplies.  (I didn't see any other voltages)

Also,
Attached are datasheets for an analog switch and an op amp. Both are ideal for operation on  5V.
I'm not suggesting they are any better than what you used but you might take a look at their specs to see if they could be of use to you for this project.


Who are you kidding?

In kit form?

You ask about regulators looking at the schematics?

I'd say, don't build it.
It could be a matter of life and death.

raschemmel

#9
Aug 16, 2014, 12:04 am Last Edit: Aug 19, 2014, 05:34 pm by raschemmel Reason: 1
@Janost,

What is that comment supposed to mean ? I asked if the heatsinked devices in the photo were the regulators? What does that have to do with the schematic ?  The regulator ic part numbers aren't even on the schematic.
Are you implying something about my knowledge of electronics or what ?  How much electronics experience do you have ? You comment indicates either you are not paying attention or don't know much about electronics. There was nothing unusual about my question about the heatsinks.  

Quote
It could be a matter of life and death  

That's nonsense.
It is certainly not a matter of life and death. If you had any hospital experience you would know that patients suffering from rapid heartbeat or low oxygenation cannot be fooled by a machine.
Also, this instrument is not critical care equipment. It is used by people who want to monitor their respiratory or circulatory condition.
They do not require this to know when they are in distress. They know that without any equipment. Have you worked in an ICU or a hospital ? Are you medically trained ? . That comment shows you know nothing about medical care and have no hospital experience. Patients  know when their pulse is too fast and when their oxygenation is too low. It presents itself as distress,the kind that cannot be ignored. (equivilent to alarm bells ringing in their head)  and it doesn't require any equipment to be aware of that. A patient  in distress due to low oxygenation or rapid heartbeat cannot be fooled by a machine. They will tell you without hesitation that there is a problem and they don't give a damn what the machine says.
Arduino UNOs, Pro-Minis, ATMega328, ATtiny85, LCDs, MCP4162, keypads,<br />DS18B20s,74c922,nRF24L01, RS232, SD card, RC fixed wing, quadcopter

mrburnette

@
die_Diode:

Nice project.  My wife is a nurse and I bought her one just to play with for about $20 off the eBay site.  It is Chinese but has an OLED screen and a graph function.  She has compared the results with the (seriously more expensive) office device and the two correlate.

Which brings me to the question, "Why?"  I know that in my playing around that I build lots of items that are primarily just for fun.  I usually take pictures, post the project, pixs, and code and then disassemble the unit.  From the looks of it, your unit is here to stay and the fact that you have access to a clinical unit for comparison seems to indicate that you have a use for the device.  So, is the attraction that you can interface your unit, save results, compare data on a PC, or perhaps further enhance to become an Internet thing?  Your BOM is greater than $20, so no criticism, just trying to understand.

Ray

Go Up