Hi Paul,
here is my code. It is a bit too long but I think all of it matters for the case. Most of the Arduino code is copied from the MAXREFDES117# firmware given from MAXIM INTEGRATED. It can be found here:
Inside the while(1) loop I integrated the readings from the analog inputs and the printing of the data if 'S' is received.
Arduino Code:
#include <Arduino.h>
#include "algorithm.h"
#include "max30102.h"
//Bluetooth Transmission
#include <SoftwareSerial.h>
SoftwareSerial blueSerial(11, 12); //RX, TX
char doi;
#define MAX_BRIGHTNESS 255
uint16_t aun_ir_buffer[100]; //infrared LED sensor data
uint16_t aun_red_buffer[100]; //red LED sensor data
int32_t n_ir_buffer_length; //data length
int32_t n_spo2; //SPO2 value
int8_t ch_spo2_valid; //indicator to show if the SPO2 calculation is valid
int32_t n_heart_rate; //heart rate value
int8_t ch_hr_valid; //indicator to show if the heart rate calculation is valid
uint8_t uch_dummy;
// the setup routine runs once when you press reset:
void setup() {
pinMode(13, OUTPUT); //LED output pin 13 on Arduino
maxim_max30102_reset(); //resets the MAX30102
// initialize serial communication at 115200 bits per second:
Serial.begin(115200);
// initialize Bluetooth communication at baudrate 57600
blueSerial.begin(57600);
pinMode(10, INPUT); //pin D10 connects to the interrupt output pin of the MAX30102
delay(1000);
maxim_max30102_read_reg(REG_INTR_STATUS_1,&uch_dummy); //Reads/clears the interrupt status register
delay(10000); // Give enough time to open the serial monitor for debugging purposes
Serial.println(F("Waiting for connection..."));
delay(1000);
maxim_max30102_init(); //initialize the MAX30102
}
// the loop routine
void loop() {
uint32_t un_min, un_max, un_prev_data, un_brightness; //variables to calculate the on-board LED brightness that reflects the heartbeats
float f_temp;
un_brightness=0;
un_min=0x3FFFF;
un_max=0;
int isample=0; // Samples counter for debugging purposes
//char str_buff[50];
char doi; int val, xval, yval, zval;
n_ir_buffer_length=100; // buffer length of 100 stores 4 seconds of samples running at 25sps
//read the first 100 samples, and determine the signal range
for(i=0;i<n_ir_buffer_length;i++)
{
while(digitalRead(10)==1); //wait until the interrupt pin asserts
maxim_max30102_read_fifo((aun_red_buffer+i), (aun_ir_buffer+i)); //read from MAX30102 FIFO
if(un_min>aun_red_buffer[i])
un_min=aun_red_buffer[i]; //update signal min
if(un_max<aun_red_buffer[i])
un_max=aun_red_buffer[i]; //update signal max
}
un_prev_data=aun_red_buffer[i];
//calculate heart rate and SpO2 after first 100 samples (first 4 seconds of samples)
maxim_heart_rate_and_oxygen_saturation(aun_ir_buffer, n_ir_buffer_length, aun_red_buffer, &n_spo2, &ch_spo2_valid, &n_heart_rate, &ch_hr_valid);
//Continuously taking samples from MAX30102. Heart rate and SpO2 are calculated every 1 second
while(1)
{
i=0;
un_min=0x3FFFF;
un_max=0;
//dumping the first 25 sets of samples in the memory and shift the last 75 sets of samples to the top
for(i=25;i<100;i++)
{
aun_red_buffer[i-25]=aun_red_buffer[i];
aun_ir_buffer[i-25]=aun_ir_buffer[i];
//update the signal min and max
if(un_min>aun_red_buffer[i])
un_min=aun_red_buffer[i];
if(un_max<aun_red_buffer[i])
un_max=aun_red_buffer[i];
}
//take 25 sets of samples before calculating the heart rate.
for(i=75;i<100;i++)
{
un_prev_data=aun_red_buffer[i-1];
while(digitalRead(10)==1);
digitalWrite(9, !digitalRead(9));
maxim_max30102_read_fifo((aun_red_buffer+i), (aun_ir_buffer+i));
if(blueSerial.available()){
doi = (char)blueSerial.read();
if(doi == 'S'){ //if processing program requests a new measurement
val = analogRead(A2); // Read from ECG sensor
xval = analogRead(A3); // Read value for X axis of accelerometer
yval = analogRead(A4); // Read value for Y axis of accelerometer
zval = analogRead(A5); // Read value for Z axis of accelerometer
//send samples and calculation result to terminal program through UART
// PPG sensor
Serial.print(isample); // Print sample number and value
Serial.print(" ");
Serial.println(aun_ir_buffer[i], DEC); // Value of infrared LED of PPG sensor
blueSerial.print("R"); // Identifier for the value of red LED of PPG sensor
blueSerial.print(aun_red_buffer[i], DEC); // Value of red LED of PPG sensor
blueSerial.print("I"); // Identifier for the value of infrared LED of PPG sensor
blueSerial.print(aun_ir_buffer[i], DEC); // Value of infrared LED of PPG sensor
blueSerial.print("H"); // Identifier for the value of calculated heart rate from PPG sensor
blueSerial.print(n_heart_rate, DEC); // Value of calculated heart rate from PPG sensor
blueSerial.print("V"); // Identifier if calculated heart rate from PPG sensor is valid
blueSerial.print(ch_hr_valid, DEC); // 1 - value is valid; 0 - value is not valid
blueSerial.print("S"); // Identifier for the value of calculated SpO2
blueSerial.print(n_spo2, DEC); // Value of calculated Sp02
blueSerial.print("W"); // Identifier if calculated SpO2 value from PPG sensor is valid
blueSerial.print(ch_spo2_valid, DEC); // 1 - value is valid; 0 - value is not valid
//ECG sensor
blueSerial.print("E"); // Identifier for the value of ECG sensor
blueSerial.print(val); // Value of ECG sensor
//Accelerometer
blueSerial.print("X"); // Identifier for the value of X axis of the accelerometer
blueSerial.print(xval); // Value of X axis of the accelerometer
blueSerial.print("Y"); // Identifier for the value of Y axis of the accelerometer
blueSerial.print(yval); // Value of Y axis of the accelerometer
blueSerial.print("Z"); // Identifier for the value of Z axis of the accelerometer
blueSerial.println(zval); // Value of Z axis of the accelerometer
isample+=1;
}
}
}
maxim_heart_rate_and_oxygen_saturation(aun_ir_buffer, n_ir_buffer_length, aun_red_buffer, &n_spo2, &ch_spo2_valid, &n_heart_rate, &ch_hr_valid);
}
}
Matlab code:
%% Setup Bluetooth connection
instrhwinfo('Bluetooth','TexMatITA')
bt = Bluetooth('TexMatITA', 1)
fopen(bt)
set(bt, 'TimeOut', .5);
figure(1);
v=0;
xlabel('Time');
ylabel('PPG');
g = animatedline;
g.Color = 'red'; %EKG
ax = gca;
s=0;
x_axis_sec = datenum(seconds(8));
t_num = 0;
double ppg_red;
double ppg_ir;
double ppg_hr;
double ppg_hr_v;
double ppg_spo2;
double ppg_spo2_v;
double ecg_val;
double acc_x;
double acc_y;
double acc_z;
del = {'R', 'I', 'H', 'V', 'S', 'W','E','X','Y','Z'}; %delimiters to split the incoming string
char temp; %variable to store the incoming string
char split_temp[]; %variable to store split string
double num_temp[]; %variable to store split string converted to numbers
stop = false;
startTime = datetime('now');
t_start_num = datenum(startTime); % Convert to num for faster calculations
fprintf(bt,'S'); % Request first value
while ~stop;
try
temp = fgetl(bt); % Read value
fprintf(bt,'S'); % Request new value until processing the current one
split_temp = strsplit(temp, del); % Split incoming string
num_temp = str2double(convertCharsToStrings(split_temp)); % Convert to numbers
ppg_red = num_temp(2);
ppg_ir = num_temp(3);
ppg_hr = num_temp(4);
ppg_hr_v = num_temp(5);
ppg_spo2 = num_temp(6);
ppg_spo2_v = num_temp(7);
ecg_val = num_temp(8);
acc_x = num_temp(9);
acc_y = num_temp(10);
acc_z = num_temp(11);
% Get current times
t_num = datenum(datetime('now')) - t_start_num;
% Add points to animation – in this case only for PPG
addpoints(g, t_num, ppg_ir); % PPG infrared LED
% Update axes
ax.XLim = [t_num - x_axis_sec, t_num];
% datetick('x','keeplimits');
drawnow
catch
end
end
Plotting of only one of the sensor values (in this case the one of the infrared LED of the PPG sensor) is given in the code. I would like to implement more processing in the loop if possible.