[SOLUCIONADO] ¿Existe en Arduino el concepto de "invertir salida"?

Hola foreros!! Dándole vueltas a un proyecto me ha hecho pensar en este concepto. Cuando estudié la FP hace ya años, recuerdo en las prácticas que los automátas programables para domótica se utilizaba mucho el concepto de "invertir salida". No hablo de mandar 0v y que eso sea valor alto, o viceversa, como por ejemplo, escribir !HIGH para invertirlo, sino de invertir el ESTADO de la salida. Es más, recuerdo que era un jaleo programarlo como activado o desactivado (cosa que aquí es sencillísimo), y era todo por comando. Una simple función de "invertir salida" ahorraba mucho trabajo, y lo bueno, es que mantenía la posibilidad de saber si esa salida está actualmente en alto o en bajo. Ahora me pregunto si este concepto existe aquí.

Por "invertir salida" me refiero a algún comando similar a digitalWrite (20, INVERTIR);. Sé que se puede hacer algo similar pero por cada entrada a leer, son necesarias, si no recuerdo mal, al menos dos variables de valor bajo y una programación un tanto dificultosa, ya que hay que seguir muy bien su lógica y es fácil equivocarse.

Me preguntaba si esto existe o es posible, y en caso de no ser posible, si en futuras versiones pudiera implementarse o si depende directamente del microcontrolador que posea o no esta función. :wink:

Saludos!!

invertir se hace con !

digitalWrite(pin, salida);

es lo que tienes ahora

digitalWrite(pin, !salida);

y ahora invertida.

Y si tienes que invertirla en función de lo que tenga entonces

digitalWrite(pin, !digitalRead(pin));

Hola Esfinterman, efectivamente existen dos métodos de hacerlo:

  1. El método que ya te menciono Surbyte. Mira este ejemplo.
void setup(){
   pinMode(13, OUTPUT);
}
void loop(){
   digitalWrite(13, !digitalRead(13));
   delay(500);  
}
  1. La manipulación directa de puertos usando los registros que requiere mucho mas conocimientos de programación avanzada.
void setup(){
   pinMode(13, OUTPUT);
}
void loop(){
   PINB = bit(5);
   delay(500);  
}

La ventaja de esta técnica es que podrías manipular varios pines del mismo banco (PB para D8~D13, PC para A0~A5 y PD para D0~D7) a la vez usando en una sola instruccion, con AND y OR bit a bit.

La gran desventaja es que depende del uC que estés usando. Mis ejemplos funciona en Arduino UNO (ATmega328P).

Hola!! Gracias por contestar, pero creo que no me estáis entendiendo. :smiley: No busco invertir un valor ni busco la lógica invertida, busco invertir el estado de una salida, sea cual sea su estado anterior, nada más. En los ejemplos que proponéis lo que hacéis es invertir el valor, de modo que siempre se mandará la misma orden, ya dé como resultado un 1 o un 0, pero siempre será ese uno o ese cero, de modo que quedaría algo así:

digitalWrite (20, !1);

Esto SIEMPRE enviará un 0 a la salida 20, SIEMPRE, y siempre que se ejecute esta orden, la salida 20 será 0.

ArduMyth:
Si el segundo parámetro de la función indica el estado del mismo no hay que invertir nada.

Sí, sí hay que invertir, porque es lo que busco, que con esa ejecución la salida se invierta sea cual sea su estado anterior:

//El pin 20 está en 0

digitalWrite (20, INVERTIR);  //Pues ahora me enciendo!!
digitalWrite (20, INVERTIR);  //Pues ahora me apago!!
digitalWrite (20, INVERTIR);  //Pues ahora me enciendo!!
digitalWrite (20, INVERTIR);  //Pues ahora me apago!!

Lo de digitalWrite(pin, !digitalRead(pin)); no es más que una inversión del resultado de la lectura de la entrada. "Si ahora es 1, te lo interpreto como 0 y si es 0 te lo interpreto como 1" pero no es una inversión del estado de la salida. "Con una pulsación, invierto la salida y con otra la vuelvo a invertir", de modo que mi planteamiento quedaría razonablemente cerca de esto:

if (digitalRead(10) == 1){
digitalWrite (20, INVERTIR)
}

De esta manera, y salvando las distancias del problema de mantener el botón pulsado, cada vez que se pulsa el botón la salida se invierte. "¿Cómo estaba antes, en 1? Pues pulso y es un 0. ¿Cómo estaba antes? Me da igual, pues lo invierto, y si estaba en 1 te lo paso a 0". Es eso lo que busco, invertir el estado de la salida, no el valor para actuar sobre la salida. :wink:

Si este concepto no existe y solo se puede hacer con uno o varios IF con varias variables, no pasa nada, simplemente pregunto si esto es posible. Mejor que lo fuese, claro que sí, pero si no, no pasa nada, una cosa más aprendida. :smiley:

Kike_GL:

void setup(){

pinMode(13, OUTPUT);
}
void loop(){
  PINB = bit(5);
  delay(500); 
}




La ventaja de esta técnica es que podrías manipular varios pines del mismo banco (PB para D8~D13, PC para A0~A5 y PD para D0~D7) a la vez usando en una sola instruccion, con AND y OR bit a bit.

Gracias!! ¿Hay algún enlace en español donde se explique bien la programación base de Atmel con todas sus posibilidades? Indagaré por ahí para ver si con esta programación es viable o si directamente no es posible. :smiley:

Gracias por contestar!! :wink:

Hola de nuevo!! Perdón por escribir tan rápido, pero creo que tengo la solución, y parece tan tonta como sencilla y efectiva. Tras vuestros comentarios me he puesto a trabajar con la placa y con el concepto de leer un pin ya tengo la solución. Como digo, es tan tonta como efectiva, y lo he probado y funciona. :smiley:

digitalWrite (13, !digitalRead(13));

Ahora sí se invierte SIEMPRE el resultado, porque toma como lectura el propio pin de la salida, y con la admiración, niegas el resultado. Cada vez que se ejecute esta línea, SIEMPRE, SIEMPRE y SIEMPRE invertirá su estado, que es prácticamente lo que buscaba. :smiley: Adjunto código completo. No me matéis por usar delay() para la demostración. :wink:

void setup() {

  pinMode (13, 1); //1 es salida, lo mismo que OUTPUT
  pinMode (12, 0); //0 es entrada, lo mismo que INPUT
}

void loop() {

  if (digitalRead (12) == 1) { //Lectura del estado de la entrada 12
    digitalWrite (13, !digitalRead(13)); //Pin 13 en 0, lectura del pin 13 como 0, negación (!0=1), escritura con 1
    delay(250); //Para la prueba
  }
}

Esto funciona, y es prácticamente lo que buscaba. Podría añadirse a una sección de "trucos" para programar aquí en el foro como problema solventado o simplificación de un programa. :wink:

Gracias!!

surbyte:
Y si tienes que invertirla en función de lo que tenga entonces

digitalWrite(pin, !digitalRead(pin));

Efectivamente, es esto. Al no poner el número de pines interpreté que hablabas del estado de la entrada para modificar la salida. :wink:

ArduMyth:
No sé si te has percatado que lo que has hecho es lo que te he indicado así cómo lo que dijo @surbyte como la solución de @Kike_GL es lo mismo que has hecho.

Al principio al ver el ejemplo sin número de pin, aunque sea de ejemplo, interpreté que el pin de salida era diferente al de entrada, como por ejemplo, salida 13, lectura del 12. En este caso no sirve de nada la negación y por eso deseché esta alternativa. Leyendo la de Kike me pareció ver, como pin de lectura, el número 12 en vez del 13. ¿Por qué? Seguramente por tener en mente desde antes un pin de lectura y otro de salida y, básicamente, porque soy humano y perfectamente me puedo equivocar. Releyendo a Kike después de un rato, sí, esa solución funciona. :wink:

ArduMyth:
Curiosamente en tu primer post dice que no quieres hacer algo cómo !HIGH y en lo último afirmas que hacer !digitalRead(pin) es la solución. Si nos damos cuenta es exactamente lo mismo porque lo importante es el operador, el boolean que niegue ya es cosa del usuario.

En lo único que se parece !HIGH y !digitalread es que tienen una negación. El resto es diferente. "!HIGH" SIEMPRE, SIEMPRE, SIEMPRE por siempre jamás y por los infinitos más absolutos, SIEMPRE te devolverá un 0. Da igual que le pilles recién levantado o después de comer. "!HIGH" SIEMPRE te devolverá un cero. De esta forma, ejecutar continuamente la línea digitalWrite (20, !HIGH); SIEMPRE apagará la salida 20, SIEMPRE. En el caso de digitalRead te devolverá... Pues depende del estado del pin. :smiley: Si está activado, te devolverá un 1, y si está desactivado, pues un 0. ¿Qué pasará si escribo múltiples veces digitalWrite (20, !digitalRead(20);? Pues que el resultado variará, es decir, no es fijo. Por lo tanto, en lo único que se parecen "!HIGH" y "!digitalRead" es que tienen una negación. :wink:

En cuanto a lo de FP significa Formación Profesional, los estudios optativos después de la Enseñanza Secundaria Obligatoria que se hacen en España y hay multitud de ramas, como administrativo, cocinero, informática, electricidad (lo que yo hice), electrónica, alta tensión y un largo etcétera. :wink:

buen ejemplo Ardumyth. Por añadir algo tambien puede usarse XOR

en el setup()
DDRD = DDRD | B00010000;

en el loop()
PORTD = PORTD ^ B00010000;

Así se invierte el pin 4.

ArduMyth:
¿Y usted de donde cree que soy? Aquí la cuestión es que usted estudió FP lo cual ya no existe y yo estudié lo que está vigente a día de hoy.

De acuerdo. Es usted poseedor de la verdad absoluta y no se puede dialogar con usted. No volveré a tropezarme con usted, se lo garantizo. :wink:

Esfinterman, yo no voy a entrar en polémicas, yo puse un ejemplo con xor usanso Port y espero te sirva o sirva a alguien...pero creo que te dijeron como era...y entiendo lo que te dicen. Les dices que no era así y tu solición era la misma cambiando la variable del segundo parametro.

Ardumyth creo que es un usuario que no se muerde la lengua(y no lo digo buscando jaleo) pero no le puedes decir que lo que dice sea mentira. No sólo era lo que te dijeron sino que yo tb soy español y FP dejó de existir cuando estaba Secundaria que fue después del cambio de 7° y 8° a 1 y 2 ESO que luego se amplió a 3° y 4°. Es imposible que con la ESO tengas FP o con FP tengas la ESO. Son épocas muy diferentes en años.

Y que ninguno de ustedes se enfade conmigo :slight_smile: