LCD I2C with module error coding

Hi, so someone helped me figure the code of my BPM and now I'm getting it when I have the serial monitor and no code for the LCD display, however, with this following code:

#define PEAK_THRESHOLD 0.3
#define ROLLING_SIZE 3
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 16,2);
 
int value = 0;
float voltage;
bool peaked = false;
int bpm;
 
unsigned long beat_times[ROLLING_SIZE] = {0, 0, 0};
unsigned long current_time;
 
bool contains_zero() {
  for (int i = 0; i < ROLLING_SIZE; i++) {
    if (beat_times[i] == 0) {
      return true;
    }
  }
  return false;
}
 
void shift_times() {
  for (int i = 1; i < ROLLING_SIZE; i++) {
    beat_times[i - 1] = beat_times[i];
  }
}

void setup() {
    lcd.init();
  lcd.backlight();
  lcd.setCursor(0,0);
  lcd.print("MACHA TES");          
  Serial.begin(9600);
  delay(500);
}

void loop() {

   
  
  value = analogRead(A0);
  voltage = (value * 5.0/1023);
 
  current_time = millis();
 
  if (voltage > PEAK_THRESHOLD && !peaked) {
    peaked = true;
 
    shift_times();
    beat_times[ROLLING_SIZE - 1] = current_time;
  } else if (voltage <= PEAK_THRESHOLD && peaked) {
    peaked = false;
  }
  
  if (contains_zero()) {
    return;
  }
 
  bpm = (ROLLING_SIZE - 1) * 60000 / ( beat_times[ROLLING_SIZE - 1] - beat_times[0]);
  
    if (bpm >= 100){
      lcd.setCursor(0,1);
         lcd.print("Sinus Tachycardia");
         
    }
    else if (bpm <= 60){
      lcd.setCursor(0,1);
         lcd.print("Sinus Bradycardia");
          
    }
    else {
      lcd.setCursor(0,1);
         lcd.print("Normal Sinus");
          
    }
  lcd.setCursor(0,2);
    lcd.print(bpm);
     
}

That is contradictory. You say you don' get anything, but then say you get something. What does that mean? Are you talking about the LCD or serial? What are the things and characters? Post a photo or something so that we can see what you are talking about.

I get different types of characters. My bad

Assuming a fairly reasonable BPM rate, the code is spending a lot of time clearing the LCD display then re-displaying the same data, which can make the display hard to read or give a flickering appearance. Generally a good idea to only update the display when the data changes value, and then you don't need to clear the display, just overwrite the display.

How do I do that? I'm sorry I'm very new with the coding.

Does your LCD display work properly with the example code from the library? The subject of my previous post would not cause what is shown on your display.

LiquidCrystal_I2C lcd = LiquidCrystal_I2C(0x27, 16, 2);

This line is for a 16 x 2 (sixteen character per line, two lines) LCD display, you have a 20 x 4 display, that may be confusing the library.

I changed that as well and it didn't work. it kept showing the same thing.

First thing is to get the display working with the example code from the library. You might have a problem with the wiring between the arduino and the display.

You were right, my code is kinda working now. Thank you.

Hi, I'm trying to get the code to run every 15 seconds and then start again. I have no idea how to start and how to end, I saw something in here that we need to use milis () but I'm not sure on how to do it.

Well millis() is certainly recommended, but sometimes just a simple delay() makes life easier. It depends on the specifics of what you want to do, and how future-proof you want it.

The two approaches are used in the examples "blink" which uses delay() and "blinkwithoutdelay" which (no surprises here) does not.

It is probably worth it to invest the effort in using millis() so start with "blinkwithoutdelay" and see if that fits your needs.

Hello
Post your current sketch to see how we can help.

void loop()
{
RunCode();
delay(15*1000);
}

Warning: This expression only works for up to 32 seconds because 33000 won't fit in the 16-bit signed integers of the Arduino UNO/NANO/MEGA/Leonardo/Mini/Micro. You should get in the habit of using the expression:
delay(15*1000ul);
The 'ul' tells the compiler to treat the 1000 as an 'unsigned long' value. The '15' is then promoted to 'unsigned long' so the multiplication won't overflow.

I need to make the calculation of the BPM of my ECG signal. So I'm trying to detect the peaks of the heart for 15 seconds, and after that to start again the count. I'm not sure if it makes sense.

Makes sense. Do not use delay(n) for sensitive timing.

using millis()

More complex usage:
https://learn.adafruit.com/multi-tasking-the-arduino-part-1/using-millis-for-timing

Well there is a difference to run every 15 sec and to run for 15 seconds. I gave you wrong suggestion in this case.

Sure this makes sense. And it is the at least bare minimum of what you have to describe about your project to get an answer that fits to your project.

You want to "detect the peaks of an ECG-signal" this means your microcontroller is heavy busy all the time to detect and count the peaks.

delay() would send your microcontroller into unconsciousness. So using the function millis() is a must.

It is a very good idea to write much more details of your project to get suggestions for a good working solution. As long as you don't extent to a 3 screens long single-paragraph-text everybody here will feel entertained by the more exemplary project-description that avoids dozens of
asking-back-questions.

So please post

  • exact type of microxcontroller you are using
  • datasheets of the components that you use or at least links where you bought them from
  • a schematic how the ECG-signal is beeing feeded into your microcontroller
  • a rough description how much you know about electronics
  • what measurement equipment you have.

You are working on a very interesting project I would like to read more about it.
There will be some challenges to make it work and I guess the electronic specialists here are eager to post their ideas how it can be improved.

best regards Stefan

We have to agree to disagree on this. It is not nice and confusing in most cases. Just because you can doesnt mean you should

unsigned long tMeasurementTime   = 15000UL;
unsigned long tMeasurementPassed = millis();
unsigned long tReadingTime       = 1000UL;
unsigned long tReadingPassed     = millis();
////
void setup()
{

  tMeasurementPassed     = millis(); 
  tReadingPassed = millis();// last line in setup
} //void setup()
////
void loop()
{
  if ( (millis() - tMeasurementPassed)  >= tMeasurementTime )
  {
    //if 15 seconds has passed do things with the numbers collected
    //reset the 15 second measurement time
    tMeasurementPassed = millis();
    tReadingPassed = millis();
  } else {
    if ( (millis() - tReadingPassed) >= tReadingTime )
    {
      //take a reading and store the readings in some thingy, like an array
      tReadingPassed = millis(); //rest take a reading time
    }
  }
} // void loop()

An idea using millis()