I don't know much on how to combine these codes and we really need these to work for our project. Hoping someone can help me
Code for Oximeter, Respiratory Rate and Temperature Scanner
#include <Wire.h>
#include "MAX30105.h"
#include <Adafruit_MLX90614.h>
// MAX30105 Oximeter setup
MAX30105 particleSensor;
long redValue = 0;
long irValue = 0;
float SpO2 = 0.0;
int SpO2Index = 0;
float SpO2MovingAvg[10] = {0};
unsigned long lastBeat = 0;
unsigned long lastPrintTime = 0;
const unsigned long printInterval = 3000;
unsigned long warmUpStartTime = 0;
unsigned long fingerDetectedTime = 0;
const unsigned long fingerDetectionDelay = 5000;
const unsigned long minBeatInterval = 200;
float beatsPerMinute = 0;
const int movingAverageSize = 15;
float beatIntervals[movingAverageSize] = {0};
int beatIndex = 0;
bool fingerDetected = false;
bool isInitialized = false;
float smoothedBPM = 0;
const float minBPM = 60.0;
const float bpmAlpha = 0.3;
bool peakDetected = false;
bool isReadingComplete = false;
bool messagePrinted = false;
const byte RATE_SIZE = 4;
byte rates[RATE_SIZE];
byte rateSpot = 0;
int beatAvg = 0;
// MLX90614 Temperature Scanner setup
Adafruit_MLX90614 mlx = Adafruit_MLX90614();
const int mlxButtonPin = 19; // Button for triggering MLX90614 temperature reading
const int maxButtonPin = 18; // Button for controlling MAX30105 readings
const int numSamples = 10; // Temperature samples for averaging
float calibrationOffset = 1.8; // Calibration offset for temperature
int mlxButtonState = 0; // State of the MLX button
int maxButtonState = 0; // State of the MAX button
bool maxButtonPressed = false; // Flag for MAX button press
bool mlxButtonPressed = false; // Flag for MLX button press
bool mlxReadingStarted = false; // Flag to check if MLX reading has started
bool maxReadingStarted = false; // Flag to check if MAX reading has started
bool isMaxReadingComplete = false; // Flag to check if MAX reading is complete
bool isMLXReadingComplete = false; // Flag for MLX reading complete
// Respiratory rate system buttons and variables
const int countButtonPin = 2; // Pin connected to the count button
const int powerButtonPin = 15; // Pin connected to the power button
int countButtonState = 0; // Variable to hold count button state
int lastCountButtonState = 0; // Last state of count button (for debouncing)
int powerButtonState = 0; // Variable to hold power button state
int lastPowerButtonState = 0; // Last state of power button (for debouncing)
unsigned long previousMillis = 0; // Last time timer was updated
const long interval = 60000; // 1 minute interval (60000 milliseconds)
int counter = 0; // Counter for respiratory rate
bool systemActive = false; // Flag to track whether the system is on or off
void setup() {
Serial.begin(115200); // Start serial communication
pinMode(countButtonPin, INPUT_PULLUP); // Set count button pin as input with internal pull-up
pinMode(powerButtonPin, INPUT_PULLUP); // Set power button pin as input with internal pull-up
pinMode(maxButtonPin, INPUT_PULLUP);
pinMode(mlxButtonPin, INPUT_PULLUP);
Serial.println("System Initialized!");
// Initialize MAX30105 Oximeter sensor
if (!particleSensor.begin(Wire, I2C_SPEED_STANDARD)) {
Serial.println("MAX30102 was not found. Please check wiring/power.");
while (1); // Halt if sensor isn't found
}
particleSensor.setup();
Serial.println("MAX30105 ready. Start reading...");
// Initialize MLX90614 Temperature sensor
if (!mlx.begin()) {
Serial.println("Couldn't find the temperature sensor!");
while (1); // Halt if sensor isn't found
}
}
void loop() {
// Read the power button state
powerButtonState = digitalRead(powerButtonPin);
if (powerButtonState == LOW && lastPowerButtonState == HIGH) {
// Toggle system on/off
systemActive = !systemActive;
if (systemActive) {
Serial.println("Respiratory Rate Activated");
} else {
Serial.println("Respiratory Rate Deactivated");
counter = 0;
}
delay(500); // debounce delay for power button
}
lastPowerButtonState = powerButtonState;
// If the system is active, handle the counting and timer
if (systemActive) {
// Handle count button press
countButtonState = digitalRead(countButtonPin);
if (countButtonState == LOW && lastCountButtonState == HIGH) {
// Increment counter when button is pressed
counter++;
Serial.print("Count: ");
Serial.println(counter);
delay(200); // debounce delay for count button
}
lastCountButtonState = countButtonState;
// Check if one minute has passed
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
// Log the count per minute
Serial.print("Respiratory Rate per minute: ");
Serial.println(counter);
// Reset the counter for the next minute
counter = 0;
previousMillis = currentMillis; // Reset the timer
}
}
// Handle MAX30105 oximeter readings
maxButtonState = digitalRead(maxButtonPin); // Read the MAX button state
if (maxButtonState == LOW && !maxButtonPressed && !maxReadingStarted) {
maxButtonPressed = true;
maxReadingStarted = true; // Start reading when button is pressed
warmUpStartTime = millis(); // Start the warm-up time for MAX30105
Serial.println("Oximeter Calibrating");
} else if (maxButtonState == HIGH) {
maxButtonPressed = false; // Reset the flag when the button is released
}
// Wait for MAX sensor calibration period (warm-up time of 8 seconds)
if (maxReadingStarted && millis() - warmUpStartTime < 5000) {
delay(2000);
return; // Wait for 8 seconds of calibration before taking readings
}
// After calibration is done, ask the user to place the finger
if (maxReadingStarted && millis() - warmUpStartTime >= 5000 && !messagePrinted) {
messagePrinted = true;
Serial.println("Place your finger");
}
// Get raw sensor readings for SpO2 and BPM
redValue = particleSensor.getRed();
irValue = particleSensor.getIR();
// Check if we have valid sensor readings
if (redValue == 0 || irValue == 0) {
Serial.println("Error: No signal detected. Please check finger placement or sensor.");
return;
}
// Apply filtering and compensation
redValue = filterSignal(redValue);
irValue = filterSignal(irValue);
irValue = compensateAmbientLight(irValue);
redValue = compensateAmbientLight(redValue);
// Check for finger detection
if (irValue > 10000 && redValue > 5000) {
if (!fingerDetected) {
fingerDetected = true;
fingerDetectedTime = millis();
}
} else {
fingerDetected = false;
}
// Don't calculate SpO2/BPM until the finger is placed properly
if (fingerDetected && (millis() - fingerDetectedTime) < fingerDetectionDelay) {
return;
}
// If the sensor is stabilized and finger detected, calculate BPM and SpO2
if (!isSignalStable(irValue) || !isFingerStable()) {
return;
}
if (customCheckForBeat(irValue)) {
peakDetected = true;
}
// Calculate BPM
if (peakDetected) {
unsigned long currentTime = millis();
unsigned long delta = currentTime - lastBeat;
if (delta > minBeatInterval) {
float instantBPM = 60 / (delta / 1000.0);
instantBPM = constrain(instantBPM, minBPM, 180.0);
beatsPerMinute = (bpmAlpha * instantBPM) + ((1 - bpmAlpha) * beatsPerMinute);
rates[rateSpot++] = (byte)beatsPerMinute;
rateSpot %= RATE_SIZE;
beatAvg = 0;
for (byte x = 0; x < RATE_SIZE; x++) {
beatAvg += rates[x];
}
beatAvg /= RATE_SIZE;
lastBeat = currentTime;
peakDetected = false;
if (!isInitialized) {
isInitialized = true;
}
}
}
// Calculate SpO2
calculateSpO2(redValue, irValue);
// Print BPM and SpO2 readings to serial monitor
if (isInitialized && fingerDetected && millis() - lastPrintTime >= printInterval && !isReadingComplete) {
lastPrintTime = millis();
Serial.print("Heart Rate: ");
Serial.print(beatAvg);
Serial.println(" bpm");
Serial.print("SpO2: ");
Serial.print((int)round(SpO2));
Serial.println(" %");
// **After printing the values, stop reading until the button is pressed again**
isReadingComplete = true;
Serial.println("Remove your finger");
return;
}
// Reset for the next reading after the finger is removed
if (isReadingComplete && !fingerDetected) {
isReadingComplete = false;
messagePrinted = false;
maxReadingStarted = false; // Reset the flag to allow a new reading on next button press
return;
}
// MLX Button pressed (trigger temperature reading once)
mlxButtonState = digitalRead(mlxButtonPin); // Read the MLX button state
if (mlxButtonState == LOW && !mlxButtonPressed && !mlxReadingStarted) {
mlxButtonPressed = true;
mlxReadingStarted = true; // Start reading when button is pressed
float temperature = getAverageTemperature(); // Get temperature from MLX90614
Serial.print("Temperature: ");
Serial.print(temperature);
Serial.println(" °C");
} else if (mlxButtonState == HIGH) {
mlxButtonPressed = false; // Reset the flag when the button is released
}
// Allow another reading for the MLX sensor after button press
if (mlxReadingStarted && mlxButtonState == HIGH) {
mlxReadingStarted = false;
}
delay(100); // Short delay to reduce serial monitor updates
}
float getAverageTemperature() {
float sum = 0.0;
for (int i = 0; i < numSamples; i++) {
float objectTemperature = mlx.readObjectTempC();
objectTemperature += calibrationOffset; // Apply calibration offset
sum += objectTemperature;
delay(100); // Small delay between readings to stabilize sensor
}
return sum / numSamples;
}
// Function to calculate SpO2 based on red and IR values
void calculateSpO2(long red, long ir) {
static long redDC = 0;
static long irDC = 0;
const float alpha = 0.2; // Adjusted filter constant for quicker response
redDC = (alpha * red) + ((1 - alpha) * redDC);
irDC = (alpha * ir) + ((1 - alpha) * irDC);
long redAC = red - redDC;
long irAC = ir - irDC;
float ratio = (float)redAC / (float)irAC;
SpO2 = 100 - (5 * ratio); // Simple approximation for SpO2
SpO2 = constrain(SpO2, 90.0, 100.0);
// Adjust moving average window size
SpO2MovingAvg[SpO2Index] = SpO2;
SpO2Index = (SpO2Index + 1) % 9; // Reduced to 5 for faster update
float avgSpO2 = 0;
for (int i = 0; i < 5; i++) {
avgSpO2 += SpO2MovingAvg[i];
}
SpO2 = avgSpO2 / 5.0; // Calculate moving average over reduced window
}
bool customCheckForBeat(long irValue) {
static long lastIrValue = 0;
static bool isIncreasing = false;
static long lastPeakTime = 0;
long currentTime = millis();
if (irValue > lastIrValue && !isIncreasing) {
isIncreasing = true;
} else if (irValue < lastIrValue && isIncreasing) {
isIncreasing = false;
if ((currentTime - lastPeakTime) > minBeatInterval) {
lastPeakTime = currentTime;
return true;
}
}
lastIrValue = irValue;
return false;
}
bool isSignalStable(long irValue) {
static long previousIrValue = 0;
static int stableCount = 0;
const int stableThreshold = 6;
const long variationLimit = 600;
if (abs(irValue - previousIrValue) < variationLimit) {
stableCount++;
} else {
stableCount = 0;
}
previousIrValue = irValue;
return (stableCount >= stableThreshold);
}
bool isFingerStable() {
return true;
}
long filterSignal(long irValue) {
static float filteredValue = 0;
const float smoothingFactor = 0.3;
filteredValue = (smoothingFactor * irValue) + ((1 - smoothingFactor) * filteredValue);
return (long)filteredValue;
}
long compensateAmbientLight(long irValue) {
static long ambientLightLevel = 0;
irValue -= ambientLightLevel;
return (irValue > 0) ? irValue : 0;
}
Welcome to the forum
What do the individual sketches do ?
What should the combined sketch do ?
Do the 3 sketches share any resources such as pins ?
Do you use delay() in any of the sketches ?
Please post the 3 sketches, using code tags when you do
The code for Oximeter, Respiratory Rate and Temperature scanner:
Oximeter have a power button so when pressed it will measure the Oxygen Saturation and the Beat per min
Respiratory rate have 2 buttons: The powerbutton to turn on and off then the other button is the counter then after a minute mark i will get the Counter per min.
Temperature is basically just a button and the sensor once pressed the readings will show us
Next is the Blood Pressure code it is working now but we dont know if its accurate but it is working it also has a power button to activate the readings
Last is the ESP32 NodeMCU sender code to our CYD(Cheap Yellow Display)
We want that all final readings from the Oximeter, Respiratory Rate, Temp Scanner and BP in ESP32 will send to the CYD
have you tested each device in a separate program?
upload a schematic showing wiring and power supplies?
upload your code using code tags </>, e.g. elect “Edit>Copy for forum” then select < CODE/ > and paste the code or text where it says “type or paste code here”
Please, always include the code inside <CODE/>
tags! The way you posted the sources here makes everything not only unreadable, but prevents anyone from trying to examine and test your code because the forum "interprets" characters and damages the listings.
If you won't do it, you won't get any useful answer, so edit each one of your posts, then remove the sources, select the <CODE/>
button and paste a "fresh new" well-formatted code inside the tags.
Please, do it now!
#include <Wire.h>
#include "MAX30105.h"
#include <Adafruit_MLX90614.h>
// MAX30105 Oximeter setup
MAX30105 particleSensor;
long redValue = 0;
long irValue = 0;
float SpO2 = 0.0;
int SpO2Index = 0;
float SpO2MovingAvg[10] = {0};
unsigned long lastBeat = 0;
unsigned long lastPrintTime = 0;
const unsigned long printInterval = 3000;
unsigned long warmUpStartTime = 0;
unsigned long fingerDetectedTime = 0;
const unsigned long fingerDetectionDelay = 5000;
const unsigned long minBeatInterval = 200;
float beatsPerMinute = 0;
const int movingAverageSize = 15;
float beatIntervals[movingAverageSize] = {0};
int beatIndex = 0;
bool fingerDetected = false;
bool isInitialized = false;
float smoothedBPM = 0;
const float minBPM = 60.0;
const float bpmAlpha = 0.3;
bool peakDetected = false;
bool isReadingComplete = false;
bool messagePrinted = false;
const byte RATE_SIZE = 4;
byte rates[RATE_SIZE];
byte rateSpot = 0;
int beatAvg = 0;
// MLX90614 Temperature Scanner setup
Adafruit_MLX90614 mlx = Adafruit_MLX90614();
const int mlxButtonPin = 19; // Button for triggering MLX90614 temperature reading
const int maxButtonPin = 18; // Button for controlling MAX30105 readings
const int numSamples = 10; // Temperature samples for averaging
float calibrationOffset = 1.8; // Calibration offset for temperature
int mlxButtonState = 0; // State of the MLX button
int maxButtonState = 0; // State of the MAX button
bool maxButtonPressed = false; // Flag for MAX button press
bool mlxButtonPressed = false; // Flag for MLX button press
bool mlxReadingStarted = false; // Flag to check if MLX reading has started
bool maxReadingStarted = false; // Flag to check if MAX reading has started
bool isMaxReadingComplete = false; // Flag to check if MAX reading is complete
bool isMLXReadingComplete = false; // Flag for MLX reading complete
// Respiratory rate system buttons and variables
const int countButtonPin = 2; // Pin connected to the count button
const int powerButtonPin = 15; // Pin connected to the power button
int countButtonState = 0; // Variable to hold count button state
int lastCountButtonState = 0; // Last state of count button (for debouncing)
int powerButtonState = 0; // Variable to hold power button state
int lastPowerButtonState = 0; // Last state of power button (for debouncing)
unsigned long previousMillis = 0; // Last time timer was updated
const long interval = 60000; // 1 minute interval (60000 milliseconds)
int counter = 0; // Counter for respiratory rate
bool systemActive = false; // Flag to track whether the system is on or off
void setup() {
Serial.begin(115200); // Start serial communication
pinMode(countButtonPin, INPUT_PULLUP); // Set count button pin as input with internal pull-up
pinMode(powerButtonPin, INPUT_PULLUP); // Set power button pin as input with internal pull-up
pinMode(maxButtonPin, INPUT_PULLUP);
pinMode(mlxButtonPin, INPUT_PULLUP);
Serial.println("System Initialized!");
// Initialize MAX30105 Oximeter sensor
if (!particleSensor.begin(Wire, I2C_SPEED_STANDARD)) {
Serial.println("MAX30102 was not found. Please check wiring/power.");
while (1); // Halt if sensor isn't found
}
particleSensor.setup();
Serial.println("MAX30105 ready. Start reading...");
// Initialize MLX90614 Temperature sensor
if (!mlx.begin()) {
Serial.println("Couldn't find the temperature sensor!");
while (1); // Halt if sensor isn't found
}
}
void loop() {
// Read the power button state
powerButtonState = digitalRead(powerButtonPin);
if (powerButtonState == LOW && lastPowerButtonState == HIGH) {
// Toggle system on/off
systemActive = !systemActive;
if (systemActive) {
Serial.println("Respiratory Rate Activated");
} else {
Serial.println("Respiratory Rate Deactivated");
counter = 0;
}
delay(500); // debounce delay for power button
}
lastPowerButtonState = powerButtonState;
// If the system is active, handle the counting and timer
if (systemActive) {
// Handle count button press
countButtonState = digitalRead(countButtonPin);
if (countButtonState == LOW && lastCountButtonState == HIGH) {
// Increment counter when button is pressed
counter++;
Serial.print("Count: ");
Serial.println(counter);
delay(200); // debounce delay for count button
}
lastCountButtonState = countButtonState;
// Check if one minute has passed
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
// Log the count per minute
Serial.print("Respiratory Rate per minute: ");
Serial.println(counter);
// Reset the counter for the next minute
counter = 0;
previousMillis = currentMillis; // Reset the timer
}
}
// Handle MAX30105 oximeter readings
maxButtonState = digitalRead(maxButtonPin); // Read the MAX button state
if (maxButtonState == LOW && !maxButtonPressed && !maxReadingStarted) {
maxButtonPressed = true;
maxReadingStarted = true; // Start reading when button is pressed
warmUpStartTime = millis(); // Start the warm-up time for MAX30105
Serial.println("Oximeter Calibrating");
} else if (maxButtonState == HIGH) {
maxButtonPressed = false; // Reset the flag when the button is released
}
// **Wait for MAX sensor calibration period (warm-up time of 8 seconds)**
if (maxReadingStarted && millis() - warmUpStartTime < 5000) {
delay(2000);
return; // Wait for 8 seconds of calibration before taking readings
}
// **After calibration is done, ask the user to place the finger**
if (maxReadingStarted && millis() - warmUpStartTime >= 5000 && !messagePrinted) {
messagePrinted = true;
Serial.println("Place your finger");
}
// Get raw sensor readings for SpO2 and BPM
redValue = particleSensor.getRed();
irValue = particleSensor.getIR();
// **Check if we have valid sensor readings**
if (redValue == 0 || irValue == 0) {
Serial.println("Error: No signal detected. Please check finger placement or sensor.");
return;
}
// **Apply filtering and compensation**
redValue = filterSignal(redValue);
irValue = filterSignal(irValue);
irValue = compensateAmbientLight(irValue);
redValue = compensateAmbientLight(redValue);
// **Check for finger detection**
if (irValue > 10000 && redValue > 5000) {
if (!fingerDetected) {
fingerDetected = true;
fingerDetectedTime = millis();
}
} else {
fingerDetected = false;
}
// **Don't calculate SpO2/BPM until the finger is placed properly**
if (fingerDetected && (millis() - fingerDetectedTime) < fingerDetectionDelay) {
return;
}
// **If the sensor is stabilized and finger detected, calculate BPM and SpO2**
if (!isSignalStable(irValue) || !isFingerStable()) {
return;
}
if (customCheckForBeat(irValue)) {
peakDetected = true;
}
// **Calculate BPM**
if (peakDetected) {
unsigned long currentTime = millis();
unsigned long delta = currentTime - lastBeat;
if (delta > minBeatInterval) {
float instantBPM = 60 / (delta / 1000.0);
instantBPM = constrain(instantBPM, minBPM, 180.0);
beatsPerMinute = (bpmAlpha * instantBPM) + ((1 - bpmAlpha) * beatsPerMinute);
rates[rateSpot++] = (byte)beatsPerMinute;
rateSpot %= RATE_SIZE;
beatAvg = 0;
for (byte x = 0; x < RATE_SIZE; x++) {
beatAvg += rates[x];
}
beatAvg /= RATE_SIZE;
lastBeat = currentTime;
peakDetected = false;
if (!isInitialized) {
isInitialized = true;
}
}
}
// **Calculate SpO2**
calculateSpO2(redValue, irValue);
// **Print BPM and SpO2 readings to serial monitor**
if (isInitialized && fingerDetected && millis() - lastPrintTime >= printInterval && !isReadingComplete) {
lastPrintTime = millis();
Serial.print("Heart Rate: ");
Serial.print(beatAvg);
Serial.println(" bpm");
Serial.print("SpO2: ");
Serial.print((int)round(SpO2));
Serial.println(" %");
// **After printing the values, stop reading until the button is pressed again**
isReadingComplete = true;
Serial.println("Remove your finger");
return;
}
// **Reset for the next reading after the finger is removed**
if (isReadingComplete && !fingerDetected) {
isReadingComplete = false;
messagePrinted = false;
maxReadingStarted = false; // Reset the flag to allow a new reading on next button press
return;
}
// MLX Button pressed (trigger temperature reading once)
mlxButtonState = digitalRead(mlxButtonPin); // Read the MLX button state
if (mlxButtonState == LOW && !mlxButtonPressed && !mlxReadingStarted) {
mlxButtonPressed = true;
mlxReadingStarted = true; // Start reading when button is pressed
float temperature = getAverageTemperature(); // Get temperature from MLX90614
Serial.print("Temperature: ");
Serial.print(temperature);
Serial.println(" °C");
} else if (mlxButtonState == HIGH) {
mlxButtonPressed = false; // Reset the flag when the button is released
}
// Allow another reading for the MLX sensor after button press
if (mlxReadingStarted && mlxButtonState == HIGH) {
mlxReadingStarted = false;
}
delay(100); // Short delay to reduce serial monitor updates
}
float getAverageTemperature() {
float sum = 0.0;
for (int i = 0; i < numSamples; i++) {
float objectTemperature = mlx.readObjectTempC();
objectTemperature += calibrationOffset; // Apply calibration offset
sum += objectTemperature;
delay(100); // Small delay between readings to stabilize sensor
}
return sum / numSamples;
}
// Function to calculate SpO2 based on red and IR values
void calculateSpO2(long red, long ir) {
static long redDC = 0;
static long irDC = 0;
const float alpha = 0.2; // Adjusted filter constant for quicker response
redDC = (alpha * red) + ((1 - alpha) * redDC);
irDC = (alpha * ir) + ((1 - alpha) * irDC);
long redAC = red - redDC;
long irAC = ir - irDC;
float ratio = (float)redAC / (float)irAC;
SpO2 = 100 - (5 * ratio); // Simple approximation for SpO2
SpO2 = constrain(SpO2, 90.0, 100.0);
// Adjust moving average window size
SpO2MovingAvg[SpO2Index] = SpO2;
SpO2Index = (SpO2Index + 1) % 9; // Reduced to 5 for faster update
float avgSpO2 = 0;
for (int i = 0; i < 5; i++) {
avgSpO2 += SpO2MovingAvg[i];
}
SpO2 = avgSpO2 / 5.0; // Calculate moving average over reduced window
}
bool customCheckForBeat(long irValue) {
static long lastIrValue = 0;
static bool isIncreasing = false;
static long lastPeakTime = 0;
long currentTime = millis();
if (irValue > lastIrValue && !isIncreasing) {
isIncreasing = true;
} else if (irValue < lastIrValue && isIncreasing) {
isIncreasing = false;
if ((currentTime - lastPeakTime) > minBeatInterval) {
lastPeakTime = currentTime;
return true;
}
}
lastIrValue = irValue;
return false;
}
bool isSignalStable(long irValue) {
static long previousIrValue = 0;
static int stableCount = 0;
const int stableThreshold = 6;
const long variationLimit = 600;
if (abs(irValue - previousIrValue) < variationLimit) {
stableCount++;
} else {
stableCount = 0;
}
previousIrValue = irValue;
return (stableCount >= stableThreshold);
}
bool isFingerStable() {
return true;
}
long filterSignal(long irValue) {
static float filteredValue = 0;
const float smoothingFactor = 0.3;
filteredValue = (smoothingFactor * irValue) + ((1 - smoothingFactor) * filteredValue);
return (long)filteredValue;
}
long compensateAmbientLight(long irValue) {
static long ambientLightLevel = 0;
irValue -= ambientLightLevel;
return (irValue > 0) ? irValue : 0;
}
#include "HX711.h"
#define BUTTON_PIN 5 // GPIO5
#define PUMP_RELAY_PIN 4 // GPIO4
#define VALVE_RELAY_PIN 0 // GPIO0
#define DT_PIN 17 // GPIO17
#define SCK_PIN 16 // GPIO16
HX711 hx710b;
float calibrationFactor = 2000.0;
float systolic = 0;
float diastolic = 200;
bool systolicDetected = false;
bool diastolicDetected = false;
bool cuffError = false; // New flag to indicate cuff placement issues
void setup() {
Serial.begin(115200);
pinMode(BUTTON_PIN, INPUT_PULLUP);
pinMode(PUMP_RELAY_PIN, OUTPUT);
pinMode(VALVE_RELAY_PIN, OUTPUT);
digitalWrite(PUMP_RELAY_PIN, LOW);
digitalWrite(VALVE_RELAY_PIN, LOW);
hx710b.begin(DT_PIN, SCK_PIN);
Serial.println("Setup complete. Ready to start.");
}
void loop() {
if (digitalRead(BUTTON_PIN) == LOW) {
delay(50);
while (digitalRead(BUTTON_PIN) == LOW);
Serial.println("Starting Measurement...");
inflateCuff();
Serial.println("Stopping Pump...");
// Check cuff condition before proceeding
if (checkCuffPlacement()) {
Serial.println("Error: Check Cuff Placement!");
return;
}
Serial.println("Deflating Cuff...");
deflateCuff();
measurePressure();
Serial.println("Measurement Complete");
printResults();
}
}
void inflateCuff() {
Serial.println("Inflating Cuff...");
digitalWrite(PUMP_RELAY_PIN, HIGH);
delay(12000);
digitalWrite(PUMP_RELAY_PIN, LOW);
}
bool checkCuffPlacement() {
Serial.println("Checking Cuff Placement...");
float pressureSum = 0;
int validReadings = 0;
int erraticReadings = 0;
int highPressureCount = 0;
int lowPressureCount = 0;
float lastPressure = 0;
float totalOscillation = 0; // Track total oscillations
for (int i = 0; i < 20; i++) {
if (hx710b.is_ready()) {
long rawValue = hx710b.read();
if (rawValue == -2147483648) continue; // Ignore invalid readings
float pressure = (rawValue / calibrationFactor);
// Ignore extreme out-of-range values
if (pressure < -50 || pressure > 300) {
erraticReadings++;
continue;
}
pressureSum += pressure;
validReadings++;
float oscillation = abs(pressure - lastPressure);
totalOscillation += oscillation; // Add to oscillation sum
lastPressure = pressure;
// "Too Tight" Check: Only fail if 270+ mmHg in 12 readings
if (pressure > 220) highPressureCount++;
// "Too Loose" Check: Only fail if 5 mmHg in 15 readings
if (pressure < 5) lowPressureCount++;
}
delay(100);
}
float avgPressure = pressureSum / validReadings;
float avgOscillation = totalOscillation / validReadings;
// **New Loose Cuff Detection**
if (avgPressure > 170 && avgOscillation < 15) {
Serial.println("⚠️ ERROR! Cuff Too Loose!");
return true;
}
// More forgiving "Too Tight" detection
if (highPressureCount >= 12) {
Serial.println("⚠️ ERROR! Cuff Too Tight!");
return true;
}
// More forgiving "Too Loose" detection
if (lowPressureCount >= 15 || avgPressure < 5) {
Serial.println("⚠️ Cuff Too Loose! Try tightening it.");
return true;
}
return false; // ✅ Cuff is placed correctly
}
void measurePressure() {
if (cuffError) return; // Stop measurement if there was a cuff placement issue
Serial.println("Measuring Pressure...");
systolicDetected = false;
diastolicDetected = false;
float lastPressure = 0;
float lastOscillation = 0;
float oscillationThreshold = 2.5;
float minOscillationThreshold = 0.5;
int stableReadings = 0;
bool validOscillations = false;
int oscillationStreak = 0;
for (int i = 0; i < 100; i++) {
if (hx710b.is_ready()) {
long rawValue = hx710b.read();
if (rawValue == -2147483648) continue;
float pressure = (rawValue / calibrationFactor);
if (pressure < -50 || pressure > 300) continue;
Serial.print("Deflating Pressure: "); Serial.println(pressure);
float oscillation = abs(pressure - lastPressure);
if (oscillation > minOscillationThreshold) {
oscillationStreak++;
} else {
oscillationStreak = 0;
}
if (oscillationStreak >= 0) {
validOscillations = true;
}
if (!systolicDetected && validOscillations && pressure > 85 && oscillation > oscillationThreshold) {
systolic = pressure * 0.95;
systolicDetected = true;
Serial.println("Systolic Detected!");
}
if (systolicDetected && !diastolicDetected) {
if (oscillation < lastOscillation * 0.12) {
diastolic = pressure;
diastolicDetected = true;
Serial.println("Diastolic Detected!");
break;
}
}
lastOscillation = oscillation;
lastPressure = pressure;
}
delay(100);
}
if (diastolicDetected) {
if (diastolic > systolic * 0.65) {
diastolic = systolic * 0.65;
}
}
if (!diastolicDetected) {
diastolic = systolic * 0.65;
diastolicDetected = true;
}
}
void deflateCuff() {
digitalWrite(VALVE_RELAY_PIN, HIGH);
delay(5000);
digitalWrite(VALVE_RELAY_PIN, LOW);
}
void printResults() {
if (cuffError) {
Serial.println("Measurement Error: Cuff Not Properly Placed!");
return;
}
Serial.print("Blood Pressure: ");
Serial.print(systolicDetected ? systolic : 0);
Serial.print("/ ");
Serial.println(diastolicDetected ? diastolic : 0);
}
#include <esp_now.h>
#include <WiFi.h>
// Define struct to hold data
typedef struct struct_message {
char temp[8];
char rr[8];
char spo2[8];
char bpm[8];
char bp[16];
} struct_message;
struct_message message;
// Define CYD MAC address
uint8_t cydMAC[] = {0x5C, 0x01, 0x3B, 0x86, 0xBE, 0xEC};
// Define sensor data values (to simulate or integrate with actual sensors)
const char temp[] = "36.5C";
const char rr[] = "16";
const char spo2[] = "99%";
const char bpm[] = "80";
const char bp[] = "120/80";
// ESP-NOW send callback function
void sentCallback(const uint8_t *macAddr, esp_now_send_status_t status) {
Serial.print("Send Status: ");
Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Success" : "Fail");
}
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_STA);
if (esp_now_init() != ESP_OK) {
Serial.println("ESP-NOW Init Failed");
return;
}
esp_now_register_send_cb(sentCallback);
// Add receiver as a peer
esp_now_peer_info_t peerInfo = {};
memcpy(peerInfo.peer_addr, cydMAC, 6);
peerInfo.channel = 0;
peerInfo.encrypt = false;
if (esp_now_add_peer(&peerInfo) != ESP_OK) {
Serial.println("Failed to add peer");
return;
}
}
void loop() {
// Simulate data to be sent (replace with actual sensor data)
strcpy(message.temp, temp);
strcpy(message.rr, rr);
strcpy(message.spo2, spo2);
strcpy(message.bpm, bpm);
strcpy(message.bp, bp);
// Send the data over ESP-NOW
esp_now_send(cydMAC, (uint8_t *)&message, sizeof(message));
Serial.println("Data Sent!");
delay(10000); // Wait for 10 seconds before sending again
}
cant send files since I am new here it refrains me sending files
To post images etc. you need trust level 1, you can get there by:
- Entering at least 5 topics
- Reading at least 30 posts
- Spend a total of 10 minutes reading posts
Users at trust level 1 can...
- Use all core Discourse functions; all new user restrictions are removed
- Send PMs
- Upload images and attachments
Testing it like individual code it works but I need to show it to my CYD
At the very least all of the calls to delay() that occur in loop() will need to be replaced by non blocking code unless you want the combined sketch to stutter and run unevenly. During the delay() period nothing else happens. This may be acceptable if the sketch is only doing one thing but not if you want it to appear to be doing more than one thing at the same time
See Using millis() for timing. A beginners guide, Several things at the same time and the BlinkWithoutDelay example in the IDE
Which files?
It's far preferred to place code in the posts (as you did).
You can drag images into the reply window.
Good, thanks, now as you can see the sketches are "readable", anyway I asked you to edit your first posts, and not adding new ones with the same code...
implement a single program with all the sensors displaying information of the serial monitor
when it is working OK implement communication with the CYD
have you tested the CYD with simple test programs?
thank you, sorry also I am just new here
yes CYD works fine, in the code for our esp32 sender is just sample and I just want to implement the Oxi,RR, temp and bp there
I can understand that, btw, please clean the first posts up by removing all unnecessary and badly formatted code, keeping just the problem description. This could help you to avoid having a very long post, discouraging other people from going after the first 2 or 3 posts...