Бибки для проекта скиньте, проверю.
Если поняли, что по приезду контроллеров, я планировал проверить MAX30102, то ввел Вас в заблуждение, у меня нет такой микрухи.
прицепил LCD1602 - ничего не показывает. Красный диод зажигает на MAX30102 - значит микросхема активирована.
Получил сегодня сенсор тоже. Попробовал пример с первого поста, показания очень нестабильные. Пример с первого поста с библиотекой для дисплея из описания не работает. Нашёл другую библиотеку для дисплея, по названию файла , текст на дисплее получился очень мелкий, но самое главное показания то есть то нет.
Код: Выделить всё
/*
Вывод значений уровня SpO2 в монитор порта
-------------------------------------------------------------
ESP32 компилируется 18.11.2020 (Ядро Release Version 1.0.4).
ESP32 подключение I2C
SDA: SDA (default is GPIO 21)
SCL: SCL (default is GPIO 22)
-------------------------------------------------------------
ESP8266 компилируется 18.11.2020 (Ядро Release Version 2.7.4).
STM32F103C8 компилируется 18.11.2020 (Ядро Release Version 1.9.0).
*/
#define MAX_BRIGHTNESS 255 // Задаём переменную максимальной яркости свечения светодиода
//--------------------------------------------------//
#include "Wire.h" // Подключаем библиотеку для работы с шиной I2C
#include "MAX30105.h" // Подключаем библиотеку для работы с модулем. Библиотека SparkFun_MAX3010x_Sensor_Library
#include "spo2_algorithm.h" // Подключаем блок работы с насыщением крови кислородом
MAX30105 PARTICLE_SENSOR; // Создаём объект для работы с библиотекой
//--------------------------------------------------//
// 32-битная переменная занимает в памяти 4 байта. Дальше используется 2 массива, каждый из которых содержит 100 значений.
// Если эти переменные будут 32-х битные, то они займут 100*4*2 = 800 байт. Arduino UNO имеет всего 2 Килобайт (2048 байт) памяти,
// поэтому при создании всех остальных переменных её объёма памяти не хватит. В связи с этим при запуске скетча выполняется проверка
// типа платы. Если это Arduino UNO (имеющая на борту микроконтроллер ATmega328), то будут созданы 16-битные массивы, чтобы занимать
// в 2 раза меньше места. Так как данные с сенсора считываются в 32-битном формате, то при записи в 16-битный массив эти значения
// будут автоматически обрезаны.
/* #if defined(__AVR_ATmega328P__) || defined(__AVR_ATmega168__)
uint16_t irBuffer[100]; // 16-битный массив данных от сенсора со значениями от ИК-светодиода
uint16_t redBuffer[100]; // 16-битный массив данных от сенсора со значениями от красного светодиода
#else
*/
uint32_t irBuffer[100]; // 32-битный массив данных от ИК-фотодиода (сенсора) со значениями от засветки на палец ИК-светодиодом
uint32_t redBuffer[100]; // 32-битный массив данных от фотодиода (сенсора) со значениями от красного светодиода
// #endif
//--------------------------------------------------//
int32_t bufferLength; // длина буфера данных
int32_t spo2; // значение SpO2 (насыщенности крови кислородом)
int8_t validSPO2; // флаг валидности значений сенсора по SpO2
int32_t heartRate; // значение ЧСС
int8_t validHeartRate; // флаг валидности значений сенсора по ЧСС
//--------------------------------------------------//
void setup() {
Serial.begin(115200); // инициируем работу с монитором последовательного порта на скорости 115200 бод
if (!PARTICLE_SENSOR.begin()) { // инициируем работу с сенсором. Если этого не произошло, то
Serial.println(F("MAX30105 was not found.")); // Выводим сообщением об этом и
while (1); // останавливаем дальнейшее выполнение скетча
}
Serial.println(F("Press any key!")); // Прежде, чем переходить к считыванию, выводим в монитор порта сообщение и
while (Serial.available() == 0); // ждём отправки любого символа в монитор порта (нажмите Enter, находясь в строке отправки)
Serial.read(); // Если символ получен, то скетч будет выполнен дальше
//------------------------------------------------//
// Блок настроек сенсора для работы в режиме определения насыщенности крови кислородом и определения ЧСС:
byte ledBrightness = 60; // 60 -Задаём яркость работы светодиода, при этом потребление тока будет следующим: 0 - 0мА, 255 - 50 мА
byte sampleAverage = 4; // Устанавливаем коэффициент усреднения. Возможные варианты значений: 1, 2, 4, 8, 16, 32
byte ledMode = 2; // Устанавливаем режим работы светодиодов на сенсоре: 1 - только красный (Red only), 2 - красный и ИК (Red + IR), 3 - красный, ИК и зелёный (Red + IR + Green)
byte sampleRate = 100; // Устанавливаем частоту дискретизации (сглаживания сигнала). Варианты: 50, 100, 200, 400, 800, 1000, 1600, 3200
int pulseWidth = 411; // Устанавливаем ширину импульса. Варианты: 69, 118, 215, 411
int adcRange = 4096; // Устанавливаем диапазон значений с АЦП. Варианты: 2048(11 бит), 4096(12 бит), 8192(13 бит), 16384(14 бит)
//------------------------------------------------//
// Настраиваем сенсор согласно вышеуказанным настройкам
PARTICLE_SENSOR.setup(ledBrightness, sampleAverage, ledMode, sampleRate, pulseWidth, adcRange);
}
//----------------------------------------------------//
void loop() {
bufferLength = 100; // Устанавливаем длину буфера равным 100 (куда будут записаны пакеты по 25 значений в течении 4 секунд)
// считываем первые 100 значений и определяем диапазон значений сигнала:
for (byte i = 0 ; i < bufferLength ; i++) { // проходим в цикле по буферу и
while (PARTICLE_SENSOR.available() == false) // отправляем сенсору запрос на получение новых данных
PARTICLE_SENSOR.check();
redBuffer[i] = PARTICLE_SENSOR.getRed(); // Записываем в массив значения сенсора, полученные при работе с КРАСНЫМ светодиодом
irBuffer[i] = PARTICLE_SENSOR.getIR(); // Записываем в массив значения сенсора, полученные при работе с ИК светодиодом
PARTICLE_SENSOR.nextSample(); // Как только в буфер было записано 100 значений - отправляем сенсору команду начать вычислять значения ЧСС и SpO2
Serial.print(F("red=")); // Выводим текст в монитор последовательного порта
Serial.print(redBuffer[i], DEC); // Выводим значение переменной redBuffer[i] в монитор последовательного порта
Serial.print(F(", ir=")); // Выводим текст в монитор последовательного порта
Serial.println(irBuffer[i], DEC); // Выводим значение переменной irBuffer[i] в монитор последовательного порта
}
// Вычисляем значения ЧСС и SpO2 по первым полученным 100 значениям:
maxim_heart_rate_and_oxygen_saturation(irBuffer, bufferLength, redBuffer, &spo2, &validSPO2, &heartRate, &validHeartRate);
// Непрерывно считываем значений с сенсора и вычисляем значения ЧСС и SpO2 каждую секунду
while (1) {
// Сбрасываем первые полученные 25 значений из буфера, а оставшиеся 75 сдвигаем влево в массиве
for (byte i = 25; i < 100; i++) {
redBuffer[i - 25] = redBuffer[i];
irBuffer[i - 25] = irBuffer[i];
}
// Получаем новые 25 значений прежде чем переходить к вычислению ЧСС
for (byte i = 75; i < 100; i++) {
while (PARTICLE_SENSOR.available() == false) { // Опрашиваем сенсор на предмет наличия новых значений
PARTICLE_SENSOR.check();
}
redBuffer[i] = PARTICLE_SENSOR.getRed(); // Записываем в массив значения сенсора, полученные при работе с КРАСНЫМ светодиодом
irBuffer[i] = PARTICLE_SENSOR.getIR(); // Записываем в массив значения сенсора, полученные при работе с ИК светодиодом
PARTICLE_SENSOR.nextSample(); // Как только в буфер было записано 100 значений - отправляем сенсору команду начать вычислять значения ЧСС и SpO2
Serial.print(F("red=")); // Выводим текст в монитор последовательного порта
Serial.print(redBuffer[i], DEC); // Выводим значение переменной redBuffer[i](красный-фотодиод)в монитор последовательного порта
Serial.print(F(", ir=")); // Выводим текст в монитор последовательного порта
Serial.print(irBuffer[i], DEC); // Выводим значение переменной irBuffer[i] (ИК-фотодиод)в монитор последовательного порта
Serial.print(F(", HR=")); // Выводим текст в монитор последовательного порта
Serial.print(heartRate, DEC); // Выводим значение переменной heartRate в монитор последовательного порта
Serial.print(F(", HRvalid=")); // Выводим текст в монитор последовательного порта
Serial.print(validHeartRate, DEC); // Выводим значение переменной validHeartRate в монитор последовательного порта
Serial.print(F(", SPO2=")); // Выводим текст в монитор последовательного порта
Serial.print(spo2, DEC); // Выводим значение переменной spo2 в монитор последовательного порта
Serial.print(F(", SPO2Valid=")); // Выводим текст в монитор последовательного порта
Serial.println(validSPO2, DEC); // Выводим значение переменной validSPO2 в монитор последовательного порта
}
// После получения очередного пакета из 25 значений повторно считаем значения ЧСС и SpO2
maxim_heart_rate_and_oxygen_saturation(irBuffer, bufferLength, redBuffer, &spo2, &validSPO2, &heartRate, &validHeartRate);
}
}
Подредактировал проект данные пошли на ардуино, но все так же нестабильно. Пример бы нормальный а то, тот что в библиотеке работает ужасно нестабильно.
Код: Выделить всё
/*
## Hardware Connections (Breakoutboard to ESP32 Arduino):
-VIN = 3.3V
-GND = GND
-SDA = 21 (or SDA)
-SCL = 22 (or SCL)
-INT = Not connected
*/
#include <Wire.h>
#include "MAX30105.h" //sparkfun MAX3010X library
MAX30105 particleSensor;
//#define MAX30105 //if you have Sparkfun's MAX30105 breakout board , try #define MAX30105
#define USEFIFO
void setup()
{
Serial.begin(115200);
Serial.println("Initializing...");
// Initialize sensor
if (!particleSensor.begin(Wire, I2C_SPEED_FAST)) //Use default I2C port, 400kHz speed
{
Serial.println("MAX30102 was not found. Please check wiring/power/solder jumper at MH-ET LIVE MAX30102 board. ");
while (1);
}
//Setup to sense a nice looking saw tooth on the plotter
byte ledBrightness = 0x7F; //Options: 0=Off to 255=50mA
byte sampleAverage = 4; //Options: 1, 2, 4, 8, 16, 32
byte ledMode = 2; //Options: 1 = Red only, 2 = Red + IR, 3 = Red + IR + Green
//Options: 1 = IR only, 2 = Red + IR on MH-ET LIVE MAX30102 board
int sampleRate = 200; //Options: 50, 100, 200, 400, 800, 1000, 1600, 3200
int pulseWidth = 411; //Options: 69, 118, 215, 411
int adcRange = 16384; //Options: 2048, 4096, 8192, 16384
// Set up the wanted parameters
particleSensor.setup(ledBrightness, sampleAverage, ledMode, sampleRate, pulseWidth, adcRange); //Configure sensor with these settings
}
double avered = 0; double aveir = 0;
double sumirrms = 0;
double sumredrms = 0;
int i = 0;
int Num = 100;//calculate SpO2 by this sampling interval
double ESpO2 = 95.0;//initial value of estimated SpO2
double FSpO2 = 0.7; //filter factor for estimated SpO2
double frate = 0.95; //low pass filter for IR/red LED value to eliminate AC component
#define TIMETOBOOT 3000 // wait for this time(msec) to output SpO2
#define SCALE 88.0 //adjust to display heart beat and SpO2 in the same scale
#define SAMPLING 5 //if you want to see heart beat more precisely , set SAMPLING to 1
#define FINGER_ON 30000 // if red signal is lower than this , it indicates your finger is not on the sensor
#define MINIMUM_SPO2 80.0
void loop()
{
uint32_t ir, red , green;
double fred, fir;
double SpO2 = 0; //raw SpO2 before low pass filtered
#ifdef USEFIFO
particleSensor.check(); //Check the sensor, read up to 3 samples
while (particleSensor.available()) {//do we have new data
#ifdef MAX30105
red = particleSensor.getFIFORed(); //Sparkfun's MAX30105
ir = particleSensor.getFIFOIR(); //Sparkfun's MAX30105
#else
red = particleSensor.getFIFOIR(); //why getFOFOIR output Red data by MAX30102 on MH-ET LIVE breakout board
ir = particleSensor.getFIFORed(); //why getFIFORed output IR data by MAX30102 on MH-ET LIVE breakout board
#endif
i++;
fred = (double)red;
fir = (double)ir;
avered = avered * frate + (double)red * (1.0 - frate);//average red level by low pass filter
aveir = aveir * frate + (double)ir * (1.0 - frate); //average IR level by low pass filter
sumredrms += (fred - avered) * (fred - avered); //square sum of alternate component of red level
sumirrms += (fir - aveir) * (fir - aveir);//square sum of alternate component of IR level
if ((i % SAMPLING) == 0) {//slow down graph plotting speed for arduino Serial plotter by thin out
if ( millis() > TIMETOBOOT) {
float ir_forGraph = (2.0 * fir - aveir) / aveir * SCALE;
float red_forGraph = (2.0 * fred - avered) / avered * SCALE;
//trancation for Serial plotter's autoscaling
if ( ir_forGraph > 100.0) ir_forGraph = 100.0;
if ( ir_forGraph < 80.0) ir_forGraph = 80.0;
if ( red_forGraph > 100.0 ) red_forGraph = 100.0;
if ( red_forGraph < 80.0 ) red_forGraph = 80.0;
// Serial.print(red); Serial.print(","); Serial.print(ir);Serial.print(".");
if (ir < FINGER_ON) ESpO2 = MINIMUM_SPO2; //indicator for finger detached
Serial.print(ir_forGraph); // to display pulse wave at the same time with SpO2 data
Serial.print(","); Serial.print(red_forGraph); // to display pulse wave at the same time with SpO2 data
Serial.print(",");
Serial.print(ESpO2); //low pass filtered SpO2
Serial.print(","); Serial.print(85.0); //reference SpO2 line
Serial.print(","); Serial.print(90.0); //warning SpO2 line
Serial.print(","); Serial.print(95.0); //safe SpO2 line
Serial.print(","); Serial.println(100.0); //max SpO2 line
}
}
if ((i % Num) == 0) {
double R = (sqrt(sumredrms) / avered) / (sqrt(sumirrms) / aveir);
// Serial.println(R);
SpO2 = -23.3 * (R - 0.4) + 100; //http://ww1.microchip.com/downloads/jp/AppNotes/00001525B_JP.pdf
ESpO2 = FSpO2 * ESpO2 + (1.0 - FSpO2) * SpO2;//low pass filter
// Serial.print(SpO2);Serial.print(",");Serial.println(ESpO2);
sumredrms = 0.0; sumirrms = 0.0; i = 0;
break;
}
particleSensor.nextSample(); //We're finished with this sample so move to next sample
//Serial.println(SpO2);
}
#else
while (1) {//do we have new data
#ifdef MAX30105
red = particleSensor.getRed(); //Sparkfun's MAX30105
ir = particleSensor.getIR(); //Sparkfun's MAX30105
#else
red = particleSensor.getIR(); //why getFOFOIR outputs Red data by MAX30102 on MH-ET LIVE breakout board
ir = particleSensor.getRed(); //why getFIFORed outputs IR data by MAX30102 on MH-ET LIVE breakout board
#endif
i++;
fred = (double)red;
fir = (double)ir;
avered = avered * frate + (double)red * (1.0 - frate);//average red level by low pass filter
aveir = aveir * frate + (double)ir * (1.0 - frate); //average IR level by low pass filter
sumredrms += (fred - avered) * (fred - avered); //square sum of alternate component of red level
sumirrms += (fir - aveir) * (fir - aveir);//square sum of alternate component of IR level
if ((i % SAMPLING) == 0) {//slow down graph plotting speed for arduino IDE toos menu by thin out
//#if 0
if ( millis() > TIMETOBOOT) {
float ir_forGraph = (2.0 * fir - aveir) / aveir * SCALE;
float red_forGraph = (2.0 * fred - avered) / avered * SCALE;
//trancation for Serial plotter's autoscaling
if ( ir_forGraph > 100.0) ir_forGraph = 100.0;
if ( ir_forGraph < 80.0) ir_forGraph = 80.0;
if ( red_forGraph > 100.0 ) red_forGraph = 100.0;
if ( red_forGraph < 80.0 ) red_forGraph = 80.0;
// Serial.print(red); Serial.print(","); Serial.print(ir);Serial.print(".");
if (ir < FINGER_ON) ESpO2 = MINIMUM_SPO2; //indicator for finger detached
Serial.print((2.0 * fir - aveir) / aveir * SCALE); // to display pulse wave at the same time with SpO2 data
Serial.print(","); Serial.print((2.0 * fred - avered) / avered * SCALE); // to display pulse wave at the same time with SpO2 data
Serial.print(","); Serial.print(ESpO2); //low pass filtered SpO2
Serial.print(","); Serial.print(85.0); //
Serial.print(","); Serial.print(90.0); //warning SpO2 line
Serial.print(","); Serial.print(95.0); //safe SpO2 line
Serial.print(","); Serial.println(100.0); //max SpO2 line
//#endif
}
}
if ((i % Num) == 0) {
double R = (sqrt(sumredrms) / avered) / (sqrt(sumirrms) / aveir);
// Serial.println(R);
SpO2 = -23.3 * (R - 0.4) + 100; //http://ww1.microchip.com/downloads/jp/AppNotes/00001525B_JP.pdf
ESpO2 = FSpO2 * ESpO2 + (1.0 - FSpO2) * SpO2;
// Serial.print(SpO2);Serial.print(",");Serial.println(ESpO2);
sumredrms = 0.0; sumirrms = 0.0; i = 0;
break;
}
particleSensor.nextSample(); //We're finished with this sample so move to next sample
//Serial.println(SpO2);
}
#endif
}
Попробуйте. Под ESP32 и arduino компилируется нормально и памяти жрет в 2 раза меньше.
Пока не вникал в тонкости его работы(на днях выписал такой датчик)
из-за отсутствия ATtiny85 , нашёлся у автора скетч для нано , собрал на нано этот проект https://github.com/jeffmer/tinyPulsePPG ... noPulsePPG , как то работает , но показания скачут на трех подопытныхDmabst писал(а): ↑14.12.2020{, 23:39}"Делаем пульсоксиметр и фотоплетизмограф на микроконтроллере ATtiny85"
https://www.rlocman.ru/shem/schematics.html?di=615757
Вернуться к началу