Llamado de Enfermeria

Buenas tardes;

Soy nuevo en el foro y necesito la colaboración de esta comunidad en un proyecto que estoy emprendiendo, tengo 2 pulsadores y un swicth para cada cama de los pacientes de un hospital, necesito enviar un mensaje por cada botón al puerto serial cuando se oprima alguno de ellos, el primer botón sera el de llamado del paciente el cual generara una alerta sonora hasta cuando se oprima el segundo botón (el que se oprime cuando es atendido); estos botones anteriores son tipo pulsador; el tercer botón es un interruptor y es para el código azul; este debe funcionar de manera independiente a los otros 2; y también debe enviar un solo mensaje al monitor serial… Adicional a este tener en cuenta que los pines donde están los switch’s van estar leyéndose constantemente;

Agradezco su colaboracion…!!!
Anexo el codigo que he elaborado hasta ahora.

Llamado_de_Enfermeria_Definitivo_1.ino (21.2 KB)

Creo que no tienes claro el uso del continue en los bucles. Cuando se ejecuta el continue el programa pasa inmediatamente una nueva iteración del bucle. En tu caso vuelve al principio del while(1), sin ejecutar nada más de lo que hay después del continue. Con lo que si los condiinales de una de las "habitaciones" hace que se ejecute un continue vuelve a empezar el while y el programa no atiende el resto de "habitaciones". El continue es una forma "cómoda" de "terminar" con el "paso actual" del bucle y pasar al "siguente paso" del bucle.

Te recomiendo que leas de arriba abajo el hilo Detener alarma con pulsador en donde se plantea un problema similar al tuyo. Creo que de ahí podrías sacar alguna idea de cómo hacerlo.

Ayuda mucho que detallas el hardware. Qué Arduino es. Cómo tienes conectados los pulsadores y switcth (si con resistencias pull-down o pull-up internas o externas). Cómo los vas a conectar los LED. Qué tipo de alerta sonora es y cómo la conectas.

También ayuda que expliques lo más detalladamente el funcionameinto que quieres. Una cosa que me intriga es para qué quieres enviar "mensajes" al monitor serie. ¿Es sólo para depurar el programa durante el dasarrollo?

¿El proyecto es un hobby, son deberes para clase o es para "montarlo de verdad"?

@IgnoranteAbsoluto, Yo estaba armando dos estructuras para facilitar todo.

#define NRO_HAB  6

struct Cama {
        int cont;
        byte pin_star;
        bool status_star;
        byte pin_stop;
        bool status_stop;
        byte pin_cod_azul;
        bool status_cod_azul;
        bool inicio;
        bool inico_cod;
        char *nombre;
}

struct Habitacion {
  byte cant_camas;
  struct Cama *cama;
  byte Led_Llamado;
  byte Led_Cod_Azul;
}

Habitacion habitacion[6] = {{3, {0, 13, false, 12, false, 11, false, false, false, "402A"},{0, 10, false,  9, false,  8, false, false, false, "402B"}, {0,  7, false,  6, false,  5,  false, false, false, "402C"},  4,  3},
                            {4, {0,  2, false, 13, false, 15, false, false, false, "403A"},{0, 16, false, 17, false, 18, false, false, false, "403B"}, {0, 19, false, 20, false,  21, false, false, false, "403C"}, {0, 22, false, 23, false, 24, false, false, false, "403D"}, 25, 26},
                            {1,{0, 27, false, 28, false, 29, false, false, false, "404"}, 30, 31},
                            {1,{0, 32, false, 33, false, 34, false, false, false, "405"}, 35, 36},
                            {1,{0, 37, false, 38, false, 39, false, false, false, "406"}, 40, 41},
                            {1,{0, 42, false, 43, false, 44, false, false, false, "407"}, 45, 46},
                            {1,{0, 47, false, 48, false, 49, false, false, false, "407"}, 50, 51}
                           };

El setup

void setup() {
  Serial.begin(9600);
  for (byte i=0; i<NRO_HAB; i++){
      for (byte j=0; j<habitacion[i].cant_camas; j++) 
          pinMode(habitacion[i].cama[j].pin_star, INPUT);
          pinMode(habitacion[i].cama[j].pin_stop, INPUT);
          pinMode(habitacion[i].cama[j].pin_cod_azul, INPUT);
      }
      pinMode(habitacion[i].Led_Llamado, OUTPUT);
      pinMode(habitacion[i].Led_Cod_Azul, OUTPUT);
  }
  
  //---------- Alarma Sonora ----------
  pinMode(52, OUTPUT); // 
  digitalWrite(52, HIGH);
  pinMode(53, OUTPUT); // Rele_Zumbador_Cod_Azul
  digitalWrite(53, HIGH);

}

Y comencé a definir cosas pero me venció el sueÑo.

void prueba_logica(){
    bool maluso = true;
    
    //----- Habitacion 402 -----  
    for (byte i=0; i<NRO_HAB; i++){
        for (byte j=0; j<habitacion[i].cant_camas; j++) 
             habitacion[i].cama[j].status_star = digitalRead(habitacion[i].cama[j].pin_star);
             maluso = maluso && habitacion[i].cama[j].status_star;
    }
    if (maluso)
        Serial.println("Mal uso de los controles");
    else {

@surbyte, en C++ las estructuras admiten funciones. Digamos que en C++ las estructuras son clases cuyas funciones y variables son por defecto públicas. Mientras que las clases son estructuras cuyas funciones y variables son por defecto privadas. Personalmente lo defino como estructura cuando la quiero como un simple contenedor de datos, entre otras cosas porque precisamente porque todos sus campos son públicos. Mientras que si tengo previsto darle algo más de “inteligencia” la defino como clase. Para mí, más que una estructura, sería una clase. No obstante, en este caso, aún dejándolas como estructuras, no estaría de más definir un constructor a las estructuras. De esta manera nos ahorramos tener que especificar los campos que queremos inicializar siempre con un mismo valor. A la vez que si durante el desarrollo nos vemos en la necesidad de añadir un campo “auxiliar” a la estructura, de los que se inicializan siempre con un valor conocido, nos ahorramos tener que añadirlo como parámetro en cada sitio donde instanciamos la estructura.

Si a la estructura Cama le añadimos un constructor al que sólo le pasams los pines y el nombre, nos quedaría así:

struct Cama {
        Cama(byte pin_star, byte pin_stop, byte pin_cod_azul, char *nombre) // Constructor de la estructura
            : cont(0)
            , pin_star(pin_star)
            , status_star(false)
            , pin_stop(pin_stop)
            , status_stop(false)
            , pin_cod_azul(pin_cod_azul)
            , status_cod_azul(false)
            , inicio(false)
            , inico_cod(false)
            , nombre(nombre)
            {}
        // Variables de la estructura
        int cont;
        byte pin_star;
        bool status_star;
        byte pin_stop;
        bool status_stop;
        byte pin_cod_azul;
        bool status_cod_azul;
        bool inicio;
        bool inico_cod;
        char *nombre;
}

Ahora la definición del array habitación sería un poco más simple (cierto que no mucho más):

Habitacion habitacion[6] = {{3, {13, 12, 11, "402A"}, {10,  9,  8, "402B"}, { 7,  6,  5,  "402C"},  4,  3},
                            {4, { 2, 13, 15, "403A"}, {16, 17, 18, "403B"}, {19, 20,  21, "403C"}, {22, 23, 24, "403D"}, 25, 26},
                            {1, {27, 28, 29, "404"}, 30, 31},
                            {1, {32, 33, 34, "405"}, 35, 36},
                            {1, {37, 38, 39, "406"}, 40, 41},
                            {1, {42, 43, 44, "407"}, 45, 46},
                            {1, {47, 48, 49, "407"}, 50, 51}
                           };

Yo, sin tener una información más detallada de qué es lo que quiere hacer, no me aventuro a indicar qué código hacer. Porque antes de teclear la solución, hay que hacer un análisis del problema. Y para hacer un análisis del problema hay que saber cuál es el problema (qué es lo que se quiere hacer). Otra cosa es que una vez hecho el análisis, mientras se está implementando, se descubra algo en lo que no se había caído. Eso suele pasar y hacerte reestructurar alguna que otra cosa. Pero decir cómo se hace lo que no se sabe qué ha de hacer, muchas veces es una pérdida de tiempo. Puede que se intuya lo que quiere hacer, pero, ¿para qué tratar de adivinar lo que nos pueden decir sin más?

Porque si bien muchos tenemos claro que la solución más fácil es usar arrays de estructuras u objetos, máquinas de estados y habitación. Hay cosas que me desconciertan como el uso de “los contadores” como cont_402. ¿Qué es lo que se quiere contar?

¿Qué es eso de «Mal uso de los controles»? ¿Que si se pulsa el botón de “llamada” a la vez que se pulsa el de “respuesta” hay que castigar a alguien? Yo entiendo que si se pulsan ambos a la vez es porque el que “llama” no sabe que el que ya le están “respondiendo” y el que “responde” no sabe que le están “llamando”. Yo más bien, lo que haría, es que si se pulsa el botón de “respuesta”, lo “apagaría” y hasta pasado unos segundos no haría caso a una nueva llamada. Pero esto son elucubraciones mías, porque no han explicado qué es lo que se quiere hacer y cómo se quiere que se comporte.

En resumen: me faltan datos. Yo esperaré a ver si dan más pistas. Y cuanto más detallado mejor. Porque no lo veo como una simple ayuda puntual, sino como un rehacer por completo el código.

Este enfoque lo desconocía y me parece mas simple.

O sea que Cama es ahora una Clase y Habitacion una estructura que contiene esta Clase?

No @surbyte, Cama sigue siendo una estructura. Pero una estructura con un constructor que hemos definido nosotros, en sustitución del constructor por defecto de la estructura. El "secreto" radica en que en C++ las structuras (struct) y las clases (class) son prácticamente la misma cosa salvo dos diferencias. En las clase (class) por defecto la visibilidad los miembros son privados (private), mientras que en la estructura (struct) por defecto son públicos (public). La otra diferencia es que las clases (class) se pueden utilizar para declarar tipos en una plantilla (template), mientras que las estructuras (struct) no.

Para que se vea cuan igual son las estructuras y las clase en C++, aquí tienen un código que define una estructura y una clase "idénticas". Ambas hacen lo mismo. Ambas con una función miembro y sin constructor declarado. Por lo que usan el constructor por defecto.

struct Estructura {
    int entero;
    char caracter;
    int tripleEntero;
    void mostrar() {    // Función miembro de la estructura
        Serial.print(this->entero);
        Serial.print(F(", "));
        Serial.print(this->caracter);
        Serial.print(F(", "));
        Serial.println(this->tripleEntero);
    }
};

class Clase {
    public: // Para que sea como una struct declaramos que todo sea público porque por defecto todos los miembros de la clase son privados
        int entero;
        char caracter;
        int tripleEntero;
        void mostrar() {    // Función miembro de la clase
            Serial.print(this->entero);
            Serial.print(F(", "));
            Serial.print(this->caracter);
            Serial.print(F(", "));
            Serial.println(this->tripleEntero);
        }
};

Estructura estructura = {1, 'a'};
Clase clase = {2, 'b'};

void setup() {
    Serial.begin(9600);

    // Asignamos el valor a tripleEntero (queremos que valga el triple que "entero")
    estructura.tripleEntero = estructura.entero * 3;
    clase.tripleEntero = clase.entero * 3;

    Serial.print(F("estructura: "));
    estructura.mostrar();
    Serial.print(F("     clase: "));
    clase.mostrar();
}

Se puede observar que hacen lo mismo y se comportan igual si cambiamos los valores con se que inicializan y ponemos los mismos parámetro para ver que muestran los mismos valores.

Ahora vamos a declara un constructor a ambos. Este constructor recibe sólo dos parámetros y le asigna a tripleEntero el triple del valor de entero sin necesidad de "hacerlo a mano".

struct Estructura {
    int entero;
    char caracter;
    int tripleEntero;
    Estructura(int entero, char caracter)   // Constructor de la estructura
        : entero(entero)             // Lista de inicialización de variables miembro de la estructura
          , caracter(caracter)
          , tripleEntero(entero * 3) // Inicializamos tripleEntero con el triple del valor de "entero"
        {
            // El constructor no necesita hacer nada en su "cuerpo"
        }
    void mostrar() {    // Función miembro de la estructura
        Serial.print(this->entero);
        Serial.print(F(", "));
        Serial.print(this->caracter);
        Serial.print(F(", "));
        Serial.println(this->tripleEntero);
    }
};

class Clase {
    public: // Para que sea como una struct declaramos que todo sea público porque por defecto todos los miembros de la clase son privados
        int entero;
        char caracter;
        int tripleEntero;
        Clase (int entero, char caracter)   // Constructor de la clase
            : entero(entero)             // Lista de inicialización de variables miembro de la clase
              , caracter(caracter)
              , tripleEntero(entero * 3) // Inicializamos tripleEntero con el triple del valor pasado
            {
                // El constructor no necesita hacer nada en su "cuerpo"
            }
        void mostrar() {    // Función miembro de la clase
            Serial.print(this->entero);
            Serial.print(F(", "));
            Serial.print(this->caracter);
            Serial.print(F(", "));
            Serial.println(this->tripleEntero);
        }
};

Estructura estructura = {1, 'a'};
Clase clase = {2, 'b'};

void setup() {
    Serial.begin(9600);

    // No hace falta inicializar "tripleEntero" porque ya lo hacen los constructores
    Serial.print(F("estructura: "));
    estructura.mostrar();
    Serial.print(F("     clase: "));
    clase.mostrar();
}

void loop() {
}

Como se podrá observan, ya no hacen falta las líneas:

   estructura.tripleEntero = estructura.entero * 3;
    clase.tripleEntero = clase.entero * 3;

Así que no nos tenemos que preocupar ya de no olvidarnos de asignar el triple de entero a tripleEntero.

Para ver otra semejanza más entre las clases y las estructuras, también se pueden declarar igual. Ahora en vez de poner:

Estructura estructura = {1, 'a'};
Clase clase = {2, 'b'};

Podemos poner:

Estructura estructura(1, 'a');
Clase clase(2, 'b');

Como se puede observar, a no ser que queramos utilizarlo como un tipo para una plantilla, podemos usar indistintamente una estructura o una clase. Aún así, yo prefiero usar una estructura si lo que quiero es un "simple contenedor de datos", mientras que lo declaro como clase si quiero "dotar de inteligencia" al conjunto de datos.

Un lujo lo suyo @IgnoranteAbsoluto!!!

Y el interesado para cuando responde?