Pequeño problema para entender el ARDUINO

Buenas Foreros, soy nuevo aquí y espero un amable apoyo con un pequeño problema, intento aprender como hacer este tipo de proyecto, si pudieran ayudarme con el código seria de bastante ayuda. Gracias

CASO: PROYECTO 1

Se tiene un sistema electrónico compuesto por los siguientes elementos:

• Un interruptor sw1 conectado al pin A0 de la tarjeta Arduino.
• Un interruptor sw2 conectado al pin A1 de la tarjeta Arduino.
• Un led llamado led 1 conectado al pin 13 de la tarjeta Arduino.
• Un led llamado led 2 conectado al pin 12 de la tarjeta Arduino.
• Un led llamado led 3 conectado al pin 11 de la tarjeta Arduino.

El sistema hace lo siguiente:

• Cuando sw1 está cerrado, el led1 debe estar encendido. En caso contrario el led1 estará apagado.
• Cuando sw2 está abierto, el led2 debe estar encendido. En caso contrario el led2 estará apagado.
• Cuando sw1 y sw2 están cerrados, el led 3 debe estar encendido. En caso contrario el led3 estará apagado.

int L1 = 13;
int L2 = 12;
int L3 = 11;
  
  
int P1 = A0;
int P2 = A1;

int val = 0;
int state = 0;
int old_val = 0;

void setup()
{
  Serial.begin (9600);
  pinMode(P1, INPUT_PULLUP);
  pinMode(P2, INPUT_PULLUP);
  
  pinMode(L1,OUTPUT);
  pinMode(L2,OUTPUT);
  pinMode(L3,OUTPUT);
}

void loop()
{
  val = digitalRead(P1);
  if ((val == LOW) && (old_val == HIGH)){
    state = 1-state;
    delay (10);
  }
  old_val = val;
  if (state == 1){
    digitalWrite (L1,HIGH);
  }
  else {
    digitalWrite (L1,LOW);
    
  }
  
   

}

Es un buen comienzo, pero parece un poco confuso y faltan algunas cosas.

Escriba pseudocódigo tal como escribió sus declaraciones:

  1. Si solo el interruptor uno está cerrado, encienda el LED1.
  2. Si solo el interruptor dos está cerrado, encienda el LED2.
  3. Si el interruptor uno y el interruptor dos están cerrados, encienda el LED3.

Luego configure las declaraciones en orden para que el LED1 y el LED2 no estén encendidos cuando el LED3 debería estar encendido, y así sucesivamente.

  1. Si el interruptor uno está cerrado... (TRUE continúa en la siguiente línea, FALSE falla)
    Y si el interruptor dos está cerrado (TRUE continúa en la línea siguiente, FALSE falla)
    luego encienda el LED3 (porque el interruptor uno Y el interruptor dos están cerrados - la línea uno y la línea dos son TRUE)
    ELSE (la línea dos falla aquí)
    luz LED1 (porque el interruptor uno está cerrado)
  2. si el interruptor dos está cerrado (la línea uno falla aquí)
    AND si el interruptor uno está cerrado
    THEN luz LED3
    ELSE
    luz LED2

Luego traduce tu pseudocódigo a código Arduino...
(Inserte retrasos y asignaciones de pines como lo hizo antes)

void loop()
{
  if (digitalRead(P1))
  {
    if (digitalRead(P2))
      digitalWrite(L3, HIGH);
  }
  else
  {
    digitalWrite(L1, HIGH);
  }

  if (digitalRead(P2))
  {
    if (digitalRead(P1))
      digitalWrite(L3, HIGH);
  }
  else
  {
    digitalWrite (L2, HIGH);
  }
}

¿Donde el PO: dice Si Solo?.

Bien en crear un pseudocódigo primero , veamos:

Cuando sw1 está cerrado = " if (sw1 == LOW) "
el led1 debe estar encendido. = escribimos en el pin correspondiente un HIGH.
En caso contrario = else.
el led1 estará apagado. = escribimos en el pin correspondiente un LOW.
con lo cual nos deja un codigo para el primer punto:

if (sw1 == LOW) {digitalWrite (L1, HIGH);}
  else {digitalWrite (L1, LOW);}

Lo mismo para los siguientes , Obiamente haciendo una lectura analogica a los puertos correspondientes y asignando su valor a unas variables sw1 y sw2 definidas anteriormente.

Moderador:
Por favor, lee las Normas del foro y no pongas la palabra Ayuda en el título.
Lee el punto 5. Piensa un título y descriptivo

void loop()
{
  digitalWrite (L1, digitalRead (P1) == LOW);
  digitalWrite (L2, digitalRead (P2) == HIGH);
  digitalWrite (L3, (digitalRead (P1) || digitalRead(P2)) == LOW);
}

Estúdialo detalladamente, trata de entenderlo y pregunta si hace falta aclarar algo

Saludos

Si, todo, pero en primer lugar " || " ¿No tendria que ser " && "?
Saludos.

¡No!

¿Cuál es la tabla de verdad de AND?
Si hubiese puesto AND (&&) cualquiera de los 2 interruptores que estuviese cerrado daría false y al negarlo encendería el LED, y eso no es lo que pide el punto 3.

Si el interruptor uno y el interruptor dos están cerrados, encienda el LED3

Si P1 OR P2 están cerrados da false solo si ambos están en LOW, al hacer la igualdad obtengo true (o sea que hago la negación) encendiendo L3.
Podría haber puesto "!" pero creo que con la igualdad se entiende más facilmente.

Saludos

Deja de hacer ediciones porque asi no hay quien te siga....
Espero un rato...

Ok, no imaginé que alguien estaba tan pendiente.
Listo, no escribo más.

Sera mas que un rato, se ha hecho tarde y aún no pillo lo del "==" . Buenas noches , mañana sera un nuevo dia.

En ambas entradas se está usando la resistencia interna PULL-UP, por lo tanto cuando el interruptor está "abierto" el valor en la entrada será HIGH. Cuando el interruptor está "cerrado" el valor será LOW.

Cuando sw1 está cerrado, el led1 debe estar encendido. En caso contrario el led1 estará apagado.

Cuando sw1 se cierra, la entrada vale LOW y el led1 debe encendese. Si sw1 está abierto la entrada vale HIGH y el led1 deba apagarse. Basta con darse cuenta de que el led1 se enciende y apaga al valor contrario de la entrada sw1. Basta con hacer:

digitalWrite(led1, !digitalRead(sw1));
Cuando sw2 está abierto, el led2 debe estar encendido. En caso contrario el led2 estará apagado.

Si sw2 está abierto, en la entrada habrá un valor HIGH, y el led2 debe encenderse. Si sw2 está cerrado, la entrada valdrá LOW y el led2 debe estar apagado. En ese caso el led2 se enciende según el valor de la entrada:

digitalWrite(led2, digitalRead(sw2));
Cuando sw1 y sw2 están cerrados, el led 3 debe estar encendido. En caso contrario el led3 estará apagado.

Para que el led3 se encienda deben estar ambos interruptores cerrados, es decir, ambos deben valer LOW. Así que la condición debe ser:

digitalWrite(led3, digitalRead(sw1)==LOW && digitalRead(sw2)==LOW);

Este código se supone que es más "entendible". La propuesta de @Gatul es correcta, pero cuesta entenderla un poco.

Si observamos la tabla de verdad de una puerta OR tenemos:

A B  x  
0 0  0
0 1  1
1 0  1
1 1  1

Nos daremos cuenta de que cuando "A" y "B" son 0 (ambos interruptores cerrados) el resultado es 0. Por lo tanto si A||B es igual a 0 se cumple la condición y el led3 debe encenderse. La condición quedaría asi:

(A||B)==0

A ver si así @gonpezzi lo entiende mejor.

Para @razezardunew un consejo. Cuando te den un ejercicio y le den un nombre a cada cosa: led1, led2, sw1, sw2... es bastante recomendable respetar ese nombre en el código. Sobre todo para que el profesor al corregir no se lie y te de el ejercicio como malo.

Gracias, luego me di cuenta de eso.

Vale, ya lo he pilado. ! valla jeroglífico ¡ . Yo continuare con mis basicos:

if (sw1 == LOW && sw2 == LOW){digitalWrite (L3, HIGH);}
  else {digitalWrite (L3, LOW);}

Saludos.

Aun no logro entender cuando dice:
Cuando sw1 y sw2 están cerrados, el led 3 debe estar encendido. En caso contrario el led3 estará apagado.
Asumo que sw1 y sw2 deben de estar presionados para que el led3 recién encienda.
De estar equivocado podrían corregirme y si no, como mantengo los pulsadores (sw1 ysw2) cerrado.
Este es mi avance:

void loop()
{
 if (analogRead(sw1) == 0) 
 {digitalWrite (LED1, HIGH);
 }
  else 
  {digitalWrite (LED1, LOW);
  }
  
  if (analogRead(sw2) == 0) 
 {digitalWrite (LED2, LOW);
 }
  else 
  {digitalWrite (LED2, HIGH);
  }
  
  if(digitalRead(LED1)==HIGH || digitalRead(LED2)==HIGH)
  {digitalWrite(LED3, LOW);
  }
  
  else
  {
    digitalWrite(LED3,HIGH);
  }
 
}

Ibas estupendamente en los dos primeros If-else ,salvo que aunque sean pines analogicos ,estas usando una señal digital es mas conveniente que uses digitalRead como haces en el tercero.
Y para el tercero, dejate de filigranas informaticas y has lo que hacemos el resto de los mortales:

if(digitalRead(sw1)==LOW && digitalRead(sw2)==LOW)
  {digitalWrite(LED3, HIGH);
  }
  
  else
  {
    digitalWrite(LED3,LOW);
  }

Al menos de momento...

La consigna dice

Interruptor no pulsador, ahí está tu respuesta.

Respecto a lo que muy acertadamente te corrigió @gonpezzi , los pines A0 a A5 tienen doble funcionalidad, se comportan como entradas analógicas o como pines de entrada/salida digitales, por eso cuando conectas un interruptor, pulsador u otro periférico que solo devuelva 2 estados (HIGH/LOW, 0V/5V) es lógico utilizarlos en forma digital.
Usalos como analógicos (con analogRead()) sólo cuando las señales tengan niveles variables.

Tu código quedaría entonces

void loop()
{
 if (digitalRead(sw1) == 0) 
 {
   digitalWrite (LED1, HIGH);
 }
 else 
 {
   digitalWrite (LED1, LOW);
 }
  
 if (digiralRead(sw2) == 0) 
 {
   digitalWrite (LED2, LOW);
 }
 else 
 {
   digitalWrite (LED2, HIGH);
  }
  
  if(digitalRead(sw1)==HIGH || digitalRead(sw2)==HIGH)
  {
   digitalWrite(LED3, LOW);
  }
  
  else
  {
    digitalWrite(LED3,HIGH);
  }
 
}

Saludos

Valla dia llevamos @anon90500195 Tanto tu como yo andamos por las nubes . En el tercer if-else ¿leer el pin LED1 y LED2 ? mas bien sera leer sw1 y sw2.
Saludos.

Muy cierto, se me escapó la tortuga, ahí lo corregí. Gracias

Haciendo mía la teoría de victorjam de que los interruptores están cerrados cuando la entrada está LOW y nombrando los pines tal como él propone. Tenemos la «opción natural»:

if (digitalRead(sw1) == LOW) {
  digitalWrite(led1, HIGH);
}
else {
  digitalWrite(led1, LOW);
}

if (digitalRead(sw2) != LOW) {
  digitalWrite(led2, HIGH);
}
else {
  digitalWrite(led2, LOW);
}

if ((digitalRead(sw1) == LOW) && (digitalRead(sw2) == LOW)) {
  digitalWrite(led3, HIGH);
}
else {
  digitalWrite(led3, LOW);
}

Hay quien prefiere ahorrarse las llaves cuando sólo hay una sentencia en cada bloque. Yo personalmente prefiero poner las llaves por si añado posteriormente alguna línea. No sería la primera ni la última vez que añado una línea pensando que está dentro del if o del else y quedar fuera la añadida o la que estaba; por no estar dentro de un bloque delimitado por las llaves. Así que para quien le guste, esto es lo mismo que lo anterior, pero sin tanta llave:

if (digitalRead(sw1) == LOW)
  digitalWrite(led1, HIGH);
else
  digitalWrite(led1, LOW);

if (digitalRead(sw2) != LOW)
  digitalWrite(led2, HIGH);
else
  digitalWrite(led2, LOW);

if ((digitalRead(sw1) == LOW) && (digitalRead(sw2) == LOW))
  digitalWrite(led3, HIGH);
else
  digitalWrite(led3, LOW);

En este caso, como lo único que va a decidir cada una de las condiciones es el valor que queremos para el LED, podemos usar el operador ternario. Si no se sabe cómo funciona el operador ternario, no hay más que buscar en Google “operador ternario c”.

digitalWrite(led1, (digitalRead(sw1) == LOW) ? HIGH : LOW);
digitalWrite(led2, (digitalRead(sw2) != LOW) ? HIGH : LOW);
digitalWrite(led3, ((digitalRead(sw1) == LOW) && (digitalRead(sw2) == LOW)) ? HIGH : LOW);

Pero curiosamente, con el operador ternario lo único que se hace es pasar a digitalWrite() como segundo parámetro HIGH o LOW; dependiendo de si la evaluación de las comparaciones dan como resultado un «verdadero» o «falso». HIGH en el caso de ser «verdadero» y LOW en caso de ser «falso». Tengamos en cuenta que en C/C++ un valor «distinto a cero» se considera «verdadero», mientras que el valor «cero» es considerado «falso». Además, la función digitalWrite() usa el segundo parámetro para poner la salida a «nivel bajo» cuando se le pasa un valor igual a «cero» (LOW está definido con el valor 0). Si este parámetro tiene un valor distinto de «cero», digitalWrite() pone la salida a «nivel alto» (HIGH está definido con el valor 1), no importa si el valor es 1 o 69, sólo importa que sea «distinto de cero». Pues aprovechando eso, se puede utilizar directamente el valor de la comparación, sin necesidad del operador ternario. Les recuerdo que es «cero» si la condición es «falsa» y «distinto de cero» si la condición es «verdadera». Con lo que podemos poner así:

digitalWrite(led1, digitalRead(sw1) == LOW);
digitalWrite(led2, digitalRead(sw2) != LOW);
digitalWrite(led3, (digitalRead(sw1) == LOW) && (digitalRead(sw2) == LOW));

Ya llegados hasta aquí, podemos aprovechar que la función digitalRead() devuelve «cero» cuando la entrada está a «nivel bajo» (recordemos que LOW está definido con el valor 0) y que devuelve un valor «distinto de cero» si la entrada está a «nivel alto» (HIGH está definido con el valor 1 y obviamente es un valor «distinto de cero»). Así que es por eso que podemos hacerlo así:

digitalWrite(led1, !digitalRead(sw1));
digitalWrite(led2, digitalRead(sw2));
digitalWrite(led3, !digitalRead(sw1) && !digitalRead(sw2));

La exclamación ! invierte el valor «verdadero» o «falso». De tal forma que si lo que queremos es convertir el valor LOW en un «verdadero» y el HIGH en un «falso», nos basta con «negar el valor» de lo que tengamos anteponiendo el operador exclamación ! y listo.

Bueno, después de presentar unas cuantas formas aparentemente diferentes de hacer lo mismo, viene el momento de decir que si bien todas son válidas y que todas estas formas de implementarlo nos las podemos encontrar en cualquier momento en cualquier programa hecho por otro, yo recomiendo hacerlo de la siguiente manera (pongo todo el código):

// Definición de las constantes de los pines. Modificar según necesidad
#define PIN_LED_1               13
#define PIN_LED_2               12
#define PIN_LED_3               11

#define PIN_INTERRUPTOR_1       A0
#define PIN_INTERRUPTOR_2       A1

// Definición de las constantes de los valores. Modificar según necesidad
#define INTERRUPTOR_CERRADO     LOW
#define ENCENDER_LED            HIGH

// Definición de constantes que se autodefinen en función de lo definido anteriormente. No hay que modificarlas nunca
#define INTERRUPTOR_ABIERTO     (!INTERRUPTOR_CERRADO)
#define APAGAR_LED              (!ENCENDER_LED)

void setup () {
  pinMode(PIN_INTERRUPTOR_1, INPUT_PULLUP);
  pinMode(PIN_INTERRUPTOR_2, INPUT_PULLUP);

  pinMode(PIN_LED_1,OUTPUT);
  pinMode(PIN_LED_2,OUTPUT);
  pinMode(PIN_LED_3,OUTPUT);
}

void loop () {
  // Guardamos la lectura de los pines en sus correspondientes variables ya que el valor lo vamos a usar más de una vez y además hace más legible el código
  bool interuptor1 = digitalRead(PIN_INTERRUPTOR_1);
  bool interuptor2 = digitalRead(PIN_INTERRUPTOR_2);

  // Las tres líneas que contien la lógica del programa no necesitan comentario alguno, se explican ellas solas gracias a los nombres de las variables y constantes. Así como el uso del operador ternario
  digitalWrite(PIN_LED_1, (interuptor1 == INTERRUPTOR_CERRADO) ? ENCENDER_LED : APAGAR_LED);
  digitalWrite(PIN_LED_2, (interuptor2 == INTERRUPTOR_ABIERTO) ? ENCENDER_LED : APAGAR_LED);
  digitalWrite(PIN_LED_3, ((interuptor1 == INTERRUPTOR_CERRADO) && (interuptor2 == INTERRUPTOR_CERRADO)) ? ENCENDER_LED : APAGAR_LED);
}

No es el más compacto ni el más extenso, pero sí que creo que es el más fácil de leer y entender, eso sí, estando habituado al operador ternario. Pero el operador ternario, si no se abusa de él, una vez que se le pilla el truco, hace que el código sea más legible y cómodo de seguir en muchas ocasiones. Si el operador ternario lo usamos para decidir entre un simple valor u otro según una condición sencilla, sin buscar ofuscar el código, nos puede hacer mucho más fácil seguir el código y entenderlo. También es importante el uso de variables y constantes con nombres significativos y nada exotéricos. Observen cada uno de los ejemplos y miren a ver si en alguno de ellos se puede saber o intuir qué es lo que hace sin necesidad de comentarios o explicaciones adicionales. Tan sólo con el código que se va a compilar.

Si nos fijamos en las tres líneas de la discordia, no sólo se ve a simple vista qué es lo que hacen y el criterio que sigue (si se sabe «leer» las condiciones y el operador ternario) sino que la definición y uso de las constantes nos podría alterar el comportamiento del programa apenas tocando unas pocas líneas y ninguna de ellas tiene por qué ser una de esas tres líneas. Sin necesidad de estar buscando en todo el código para modificar la lógica del programa.

Por ejemplo, si nos dicen que el circuito se ha cambiado de tal manera que ahora se lee un HIGH cuando los interruptores están cerrados. En mi propuesta sólo hay que cambiar la línea:

#define INTERRUPTOR_CERRADO     HIGH

Sin necesidad de cambiar las líneas que controlan la lógica del programa. Mientras que si lo hubiésemos hecho con otra de las soluciones, tendríamos que cambiar en este caso tres zonas del código. Pero porque sólo son tres y no trescientas. A continuación pongo las tres líneas de uno de los ejemplos anteriores con el cambio propuesto. ¿Se tiene claro lo que hace ahora?

digitalWrite(led1, digitalRead(sw1));
digitalWrite(led2, !digitalRead(sw2));
digitalWrite(led3, digitalRead(sw1) && digitalRead(sw2));

Pues se supone que lo mismo que antes pero con la lógica de los interruptores cambiada.

Deberes para casa: ¿qué habría que cambiar en cada una de las formas de resolver el problema, si además del cambio de la lógica de los interruptores también cambia la lógica de los LED y ahora hay que poner la salida a «nivel bajo» para encender los LED?

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.