Mostrar varias tareas en el LCD

Hola a todos.

Estoy escribiendo un programa para el LCD. Lo estoy haciendo con subrutinas para no llenar de texto el loop pero tengo el problema de que no soy capaz de mostrar una rutina el la linea de arriba del LCD y otra distinta en la de abajo.

En la linea de arriba quiero mostrar constantemente un reloj y en la de abajo una rutina de servos. Sin embargo cuando ejecuto el programa no funciona. Sale el reloj un segundo, luego se borra, se ejecuta la rutina de los servos con sus textos y luego vuelve a mostrarse el reloj donde se había quedado.

Adjunto texto

#include <LiquidCrystal_I2C.h>
#include <Wire.h>

#include <Servo.h>


LiquidCrystal_I2C lcd(0x27, 16, 2); 
Servo servo1;  
Servo servo2;
Servo servo3;
Servo servo4;
Servo servo5;
bool mediaVuelta1 = false;
bool mediaVuelta2 = false;
bool mediaVuelta3 = false;
bool mediaVuelta4 = false;
bool mediaVuelta5 = false;

int h = 12;
int m;
int s;
int flag;
int TIME;

const int hs = 8;
const int ms = 9;

int state1;
int state2;

void setup() {

  lcd.init();                     
  lcd.init(); 
  lcd.backlight();
  pinMode(hs, INPUT_PULLUP);
  pinMode(ms, INPUT_PULLUP);


  servo1.attach(5); 
  servo2.attach(6);
  servo3.attach(7);
  servo4.attach(8);
  servo5.attach(9);

  servo1.write(0);
  servo2.write(0);
  servo3.write(0);
  servo4.write(0);
  servo5.write(0);

}

void loop() {

  reloj();
  servos();
}

void servos()
{
  acc_servo1();
  acc_servo2();
  acc_servo3();
  acc_servo4();
  acc_servo5();

}

void acc_servo1() {

  if (mediaVuelta1 == false) {

    lcd.setCursor(0, 1);
    lcd.print("Servo 1 saliendo");

    servo1.write(180);
    delay(1000);
    servo1.write(0);
    delay(1000);
    mediaVuelta1 = true;
  }

}



void acc_servo2() {

  if (mediaVuelta2 == false) {

    lcd.setCursor(0, 1);
    lcd.print("Servo 2 saliendo");

    servo2.write(180);
    delay(1000);
    servo2.write(0);
    delay(1000);
    mediaVuelta2 = true;
  }

}

void acc_servo3() {

  if (mediaVuelta3 == false) {

    lcd.setCursor(0, 1);
    lcd.print("Servo 3 saliendo");

    servo3.write(180);
    delay(1000);
    servo3.write(0);
    delay(1000);
    mediaVuelta3 = true;
  }

}

void acc_servo4() {

  if (mediaVuelta4 == false) {

    lcd.setCursor(0, 1);
    lcd.print("Servo 4 saliendo");

    servo4.write(180);
    delay(1000);
    servo4.write(0);
    delay(1000);
    mediaVuelta4 = true;
  }

}

void acc_servo5() {

  if (mediaVuelta5 == false) {

    lcd.setCursor(0, 1);
    lcd.print("Servo 5 saliendo");

    servo5.write(180);
    delay(1000);
    servo5.write(0);
    delay(1000);
    mediaVuelta5 = true;
  }
}

void reloj() {
  lcd.setCursor(0, 0);
  s = s + 1;
  lcd.print(h);
  lcd.print(":");
  lcd.print(m);
  lcd.print(":");
  lcd.print(s);

  if (flag < 12)lcd.print("AM");
  if (flag == 12)lcd.print("PM");
  if (flag > 12)lcd.print("PM");
  if (flag == 24)flag = 0;

  delay(1000);
  lcd.clear();
  if (s == 60) {
    s = 0;
    m = m + 1;
  }
  if (m == 60)
  {
    m = 0;
    h = h + 1;
    flag = flag + 1;
  }
  if (h == 13)
  {
    h = 1;
  }



}

Que te parece algo asi, donde se simplifican las cosas.

#include <LiquidCrystal_I2C.h>
#include <Wire.h>

#include <Servo.h>


LiquidCrystal_I2C lcd(0x27, 16, 2);

#define CANT_SERVOS 5

Servo servo[CANT_SERVOS];
bool mediaVuelta[CANT_SERVOS] = false;

int h = 12;
int m;
int s;
int flag;
int TIME;

const int hs = 8;
const int ms = 9;

int state1;
int state2;

void setup() {

  lcd.init();                     
  lcd.init();
  lcd.backlight();
  pinMode(hs, INPUT_PULLUP);
  pinMode(ms, INPUT_PULLUP);

  for (int i=0; i<5; i++) {
	servo[i].attach(5);  
	servo[i].write(0);
  }
}

void loop() {
  reloj();
  for (int i=0; i<CANT_SERVOS; i++) {
	acc_servo(i);  
  }
}

void acc_servo1(int iServo) {
  if (mediaVuelta[iServo] == false) {
    lcd.setCursor(0, 1);
    lcd.print("Servo "+ String(iServo) +" saliendo");

    servo1.write(180);
    delay(1000);
    servo[iServo].write(0);
    delay(1000);
    mediaVuelta[iServo] = true;
  }
}

void reloj() {
	lcd.setCursor(0, 0);
	s = s + 1;
	lcd.print(h);
	lcd.print(":");
	lcd.print(m);
	lcd.print(":");
	lcd.print(s);

	if (flag < 12)
		lcd.print("AM");
	if (flag == 12)
		lcd.print("PM");
	if (flag > 12)
		lcd.print("PM");
	if (flag == 24)
		flag = 0;

	delay(1000);
	lcd.clear();
	if (s == 60) {
		s = 0;
		m = m + 1;
	}
	if (m == 60)	{
		m = 0;
		h = h + 1;
		flag = flag + 1;
	}
	if (h == 13){
		h = 1;
	}
}

Restaría eliminar los delay() y mejorar el tema del reloj, justamente sin usar delay(), reemplazándolo por millis() con lo que te quedaría un código muy fluído.

Lee en documentación alguno de los tutoriales referidos a millis().

Hola surbyte

Muchas gracias por simplificar el código, estoy empezando con esto y tengo la programación algo oxidada. Entiendo lo que has hecho pero al compilar me ha dado varios errores. Eran de sintaxis, sin embargo, después de depurar esos errores, y cargar el programa en el Arduino, éste no funciona.

Lo que debería hacer el dispositivo es, por un lado, una secuencia de rotación de 180º de 5 servos que están conectados en los pines 5 a 9. Y en el LCD, mostrar siempre un reloj en la linea superior y en la inferior mostrar la secuencia de texto (Servo "X" saliendo) a la vez que se acciona cada servo.

El tema es que cuando pase a la segunda parte del programa, la secuencia de servos sería disitinta según la hora que tienen programados para activarse, vamos que no sería secuencial (creo entonces que los bucles ahí no me hacen falta)

Adjunto el código con todas las correcciones que he hecho. Ya no se que se me escapa...

#include <LiquidCrystal_I2C.h>
#include <Wire.h>

#include <Servo.h>


LiquidCrystal_I2C lcd(0x27, 16, 2);

#define CANT_SERVOS 5

Servo servo[CANT_SERVOS];
bool mediaVuelta[CANT_SERVOS] = {false};

int h = 12;
int m;
int s;
int flag;
int TIME;

const int hs = 8;
const int ms = 9;

int state1;
int state2;

void setup() {

  lcd.init();                     
  lcd.init();
  lcd.backlight();
  pinMode(hs, INPUT_PULLUP);
  pinMode(ms, INPUT_PULLUP);

  for (int i=0; i<5; i++) {
  servo[i].attach(0); 
  servo[i].write(0);
  }
}

void loop() {
  reloj();
  for (int i=0; i<CANT_SERVOS; i++) {
  acc_servo(i); 
  }
}

void acc_servo(int iServo) {
  if (mediaVuelta[iServo] == false) {
    lcd.setCursor(0, 1);
    lcd.print("Servo "+ String(iServo) +" saliendo");

    servo[iServo].write(180);
    delay(1000);
    servo[iServo].write(0);
    delay(1000);
    mediaVuelta[iServo] = true;
  }
}

void reloj() {
  lcd.setCursor(0, 0);
  s = s + 1;
  lcd.print(h);
  lcd.print(":");
  lcd.print(m);
  lcd.print(":");
  lcd.print(s);

  if (flag < 12)
    lcd.print("AM");
  if (flag == 12)
    lcd.print("PM");
  if (flag > 12)
    lcd.print("PM");
  if (flag == 24)
    flag = 0;

  delay(1000);
  lcd.clear();
  if (s == 60) {
    s = 0;
    m = m + 1;
  }
  if (m == 60)  {
    m = 0;
    h = h + 1;
    flag = flag + 1;
  }
  if (h == 13){
    h = 1;
  }
}

Lo que me comentas de los tutoriales de millis(), ¿hay alguno en concreto que me pueda ir bien?

Saludos!

Hola @Poleas. No he probado tu programa pero, aparte de lo indicado por @Surbyte con respecto a los delay(), yo eliminaría el lcd.clear() dentro del void reloj. Eso hace que la pantalla se esté borrando permanentemente en cada loop. Total vos sobreescribís los datos nuevos sobre los anteriores.

Gracias Pablo.

Tu consejo hace que ahora se muestre el reloj mientras sale el texto servo X saliendo. Sin embargo el reloj no pasa de 1 segundo hasta que no termina de ejecutar la rutina de los servos.

He estado mirando un poco más y entiendo más la respuesta de surbyte. Son los delays los que interrumpen el programa y no permiten ejecutar dos tareas a la vez. He estado investigando el tema de los millis() y me esta costando entender como integrarlo en el programa.

millis() es un contador interno del micro que arranca al alimentarlo o resetaearlo incrementándose cada 1 mSeg. Básicamente cuando querés contar un tiempo le asignás a una variable el valor de millis(), ( que va a ser el valor actual del contador al momento de asignarla ) y luego comparás el valor de esa variable con otra asignada más adelante. Por ejemplo:

diferencia=0;
tiempofinal=millis();// inicializo teimpofinal
tiempoinicial=millis(); // inicializo tiempoinicial
void loop()
{
  if(tiempofinal-tiempoinicial > 1000) // si la diferencia es mayor a un segundo
   {
     cambiarsegundos();// actualizo reloj en el display
     tiempoinicial=millis();// reseteo para volver a comparar
    }
   tiempofinal= millis();// acualizo variable
  // resto del codigo

De esta forma podrías verificar si pasó un segundo para actualizar el reloj en el display sin desatender el resto del código. El delay no está prohibido pero es algo a utilizar con mucho ciudado porque " congela" el programa.