Tabla de la verdad con Arduino

Buenas:

Se hacer tabla de la verdad con ensamblador de los microcontroladores PIC, pero no de Arduino. Los códigos en asm de los PIC pongo algunos ejemplos.

index.php

Ver zoom.

Ejemplo 1:
Código:
; Controla el nivel de un depósito de líquido. Utiliza (entre paréntesis las líneas del
; microcontrolador a la que se han conectado):
; -    Tres sondas detectoras: SV, Sonda de Vacío (RA0); SLL, Sonda de LLenado (RA1);
;    SR, Sonda de Rebose (RA2).
; -    Dos bombas de agua: B1 (RB5), B2 (RB6).
; - Cinco indicadores: Vacio (RB0), Llenandose (RB1), Lleno (RB2), Rebose (RB3),
;    Alarma (RB4).
;
; Su funcionamiento: 
; -    Cuando ninguna de las sondas está mojada se entiende que el depósito está vacío y
;    se accionarán las dos bombas. El indicador "Vacio" se iluminará .
; -    Cuando el nivel del líquido toque la sonda de vacío "SV" seguirá llenándose el
;     depósito con las dos bombas. El indicador "Llenandose" se ilumina.
; -    Cuando el nivel del líquido toca la sonda de llenado "SLL", para la bomba B2, quedando
;    B1 activada en modo mantenimiento. El indicador "Lleno" se ilumina.
; -    Si el nivel del líquido moja la sonda de rebose "SR" se apaga también la bomba B1,
;    quedando las dos bombas fuera de servicio. El indicador "Rebose" se enciende.
; -    Cuando se produce un fallo o mal funcionamiento en las sondas de entrada (por
;    ejemplo que se active la sonda de rebose y no active la de vacío) se paran
;    las dos bombas. El indicador "Alarma" se ilumina.
;
; Según el enunciado del problema, teniendo en cuenta las conexiones citadas y poniendo la
; salida no utilizada (RB7) siempre a cero, la tabla de verdad resultante es:
;
; RA2.. RA0 | RB7 ...          ... RB0
; ------------|--------------------------------
;  0   0   0  |  0   1   1   0   0   0   0   1    (Configuración 0. Estado "Vacio").
;  0   0   1  |  0   1   1   0   0   0   1   0    (Configuración 1. Estado "Llenandose").
;  0   1   0  |  0   0   0   1   0   0   0   0    (Configuración 2. Estado "Alarma").
;  0   1   1  |  0   0   1   0   0   1   0   0    (Configuración 3. Estado "Lleno").
;  1   0   0  |  0   0   0   1   0   0   0   0    (Configuración 4. Estado "Alarma").
;  1   0   1  |  0   0   0   1   0   0   0   0    (Configuración 5. Estado "Alarma").
;  1   1   0  |  0   0   0   1   0   0   0   0    (Configuración 6. Estado "Alarma").
;  1   1   1  |  0   0   0   0   1   0   0   0    (Configuración 7. Estado "Rebose").
;
; ZONA DE DATOS **********************************************************************

    LIST        P=16F84A
    INCLUDE        <P16F84A.INC>
    __CONFIG    _CP_OFF &  _WDT_OFF & _PWRTE_ON & _XT_OSC

; ZONA DE CÓDIGOS ********************************************************************

    ORG     0                    ; El programa comienza en la dirección 0.
Inicio
    clrf    PORTB                ; Debe estar a cero cuando el puerto se configure como salida.
    bsf        STATUS,RP0            ; Acceso al Banco 1.
    clrf    TRISB                ; Las líneas del Puerto B se configuran como salida.
    movlw    b'00011111'            ; Las 5 líneas del Puerto A se configuran como entrada.
    movwf    TRISA
    bcf        STATUS,RP0            ; Acceso al Banco 0.
Principal
    movf    PORTA,W                ; Lee los sensores.
    andlw    b'00000111'            ; Máscara para quedarse con el valor de los sensores.
    addwf    PCL,F                ; Salta a la configuración adecuada.
    goto    Configuracion0
    goto    Configuracion1
    goto    Configuracion2
    goto    Configuracion3
    goto    Configuracion4
    goto    Configuracion5
    goto    Configuracion6
    goto    Configuracion7
Configuracion0
    movlw     b'01100001'            ; Estado "Vacio" (configuración 0).
    goto    ActivaSalida
Configuracion1
    movlw     b'01100010'            ; Estado "Llenándose" (configuración 1).
    goto    ActivaSalida
Configuracion2
    movlw     b'00010000'            ; Estado "Alarma" (configuración 2).
    goto    ActivaSalida
Configuracion3
    movlw     b'00100100'            ; Estado "Lleno" (configuración 3).
    goto    ActivaSalida
Configuracion4
    movlw     b'00010000'            ; Estado "Alarma" (configuración 4).
    goto    ActivaSalida
Configuracion5
    movlw     b'00010000'            ; Estado "Alarma" (configuración 5).
    goto    ActivaSalida
Configuracion6
    movlw     b'00010000'            ; Estado "Alarma" (configuración 6).
    goto    ActivaSalida
Configuracion7
    movlw     b'00001000'            ; Estado "Rebose" (configuración 7).
ActivaSalida
    movwf    PORTB                ; Visualiza por el puerto de salida.
    goto     Principal

    END
Ejemplo 2:
Código:
; ZONA DE DATOS **********************************************************************

    LIST        P=16F84A
    INCLUDE        <P16F84A.INC>
    __CONFIG    _CP_OFF &  _WDT_OFF & _PWRTE_ON & _XT_OSC

; ZONA DE CÓDIGOS ********************************************************************

    ORG     0                    ; El programa comienza en la dirección 0.
Inicio
    bsf        STATUS,RP0            ; Acceso al Banco 1.
    clrf    TRISB                ; Las líneas del Puerto B se configuran como salida.
    movlw    b'00011111'            ; Las 5 líneas del Puerto A se configuran como entrada.
    movwf    TRISA
    bcf        STATUS,RP0            ; Acceso al Banco 0.
Principal
    movf    PORTA,W                ; Lee los sensores.
    andlw    b'00000111'            ; Máscara para quedarse con valor de sensores.
    call    Estado
    movwf    PORTB                ; Resultado se visualiza por el puerto de salida.
    goto     Principal

; Subrutina "Estado" --------------------------------------------------------------------
;
Estado
    addwf    PCL,F
    retlw    b'01100001'            ; Entrada "Vacio".
    retlw    b'01100010'            ; Estado "Llenándose".
    retlw    b'00010000'            ; Estado "Alarma".
    retlw    b'00100100'            ; Estado "Lleno".
    retlw    b'00010000'            ; Estado "Alarma".
    retlw    b'00010000'            ; Estado "Alarma".
    retlw    b'00010000'            ; Estado "Alarma".
    retlw    b'00001000'            ; Estado "Rebose".

    END
En resumen, lo que tengo en asm, quiero saber como se hace en C de Arduino de la forma más elegante como este indicado arriba.

Un cordial saludo.
 
Lo normal en esos casos, de querer obtener un valor a partir de otro, es usando un arreglo.
 
En arduino también se puede leer un puerto de golpe y hacer lo mismo que en asm.
Otra posibilidad es hacer el maxterms o minterms de la ecuación y pasarlo a código tal cual solo cambiando la sintaxis and es &, or es | etc

Edito y aclaro:
Los operadores son and &&, or || y not !

Ejemplo de tabla cualquiera:
CBA S
000 1
001 0
010 0
011 0
100 0
101 1
110 1
111 0
La función lógica sale: S=(/c·/b·/a)+(c·/b·a)+(c·b·/a)

Eso pasado a arduino sería
(pseudocódigo, hay que arregla mayúsculas etc etc para que funcione)
Hay que definir las variables como boolean
loop{
C=digitalread(x);
B=digitalread(xx);
A=digitalread(xxx);
digitalwrite(S,(C!||B!||A!)&&(C||B!||A)&&(C||B||A!))
}

Nota: Esto no lo he probado, pero debería de funcionar
 
Última edición:
Usando arreglos (arrays) sería algo así (no probado):

PHP:
/* Entradas */
#define S_REBOSE  B00000001
#define S_LLENO   B00000010
#define S_VACIO   B00000100

/* Salidas */
#define VACIO     B00000001
#define LLENANDO  B00000010
#define LLENO     B00000100
#define REBOSE    B00001000
#define ALARMA    B00010000
#define BOMBA1    B00100000
#define BOMBA2    B01000000

char tabla[] = {
  /* B000 : vacío    */  BOMBA2|BOMBA1|VACIO,	
  /* B001 : llenando */  BOMBA2|BOMBA1|LLENANDO,
  /* B010 : alarma   */  ALARMA,
  /* B011 : lleno    */  BOMBA1|LLENO,	
  /* B100 : alarma   */  ALARMA,
  /* B101 : alarma   */  ALARMA,
  /* B110 : alarma   */  ALARMA,
  /* B111 : rebose   */  REBOSE
};

void setup() {
  /* entradas */
  DDRB &= ~(S_REBOSE | S_LLENO | S_VACIO);

  /* salidas */
  DDRD  = VACIO
        | LLENANDO
        | LLENO
        | REBOSE
        | ALARMA
        | BOMBA1
        | BOMBA2
        ;
}

void loop() {
  PORTD = tabla[ PORTB ];  /* el valor del puerto B */
                           /* apunta al valor del puerto D */
                           /* que deseamos */
  delay(1000);
}
Como ves, el programa está escrito para que sea muy fácil su mantenimiento y actualización. No hay que aprenderse los bits, ya que solo usamos nombres.

(Tengo una duda con respecto a la línea que inicializa el puerto B, que no sé si hace bien la operación matemática. Lo miro más tarde y reedito el mensaje.)
 
Última edición por un moderador:
Buenas:

Graicas por la aportaciones.

Este parece muy cómodo.

Código:
byte entrada=PORTB & B111;
      switch (entrada){
            case B000:
                  Serial.println("Vacio");
                  // resto de comandos, incluyendo llamadas a funciones
                  break;
            case B001:
                  Serial.println("Llenando");
                  break;
            case B011:
                  Serial.println("Lleno");
                  break;
            case B111:
                  Serial.println("Rebose");
                  break;
            default:     // esto se ejecutaría en el resto de casos. 
                  Serial.println("Alarma");
                  break;
      }

Cómo de actualizar y si quieres tambiñen puede incluir otras funciones por medio.

Saludo.
 
Depende de lo que necesites: si solo necesitas saber el valor de respuesta a una determinada entrada, te vale con usar un arreglo o una fórmula matemática como te comentaba Scooter. Pero si necesitas realizar más operaciones, entonces sí que debes usar el switch().
 
El problema es que hay que poner 256 "cases". Habría que ver el caso concreto para ver cual es el método mas eficiente.
 
Afortunadamente, contamos con los ordenadores, para simplificar el trabajo de generar los 256 casos:

Código:
perl -e 'printf("\t\tcase B%08b:\n", $_) for 0 .. 255'
Esta línea genera 256 líneas así:
Código:
                case B00000000:
                case B00000001:
                case B00000010:
                case B00000011:
                case B00000100:
Para el caso que nos ocupa, son solo 8 casos:
Código:
perl -e 'printf("\t\tcase B%03b:\n", $_) for 0 .. 7'
También hay que recordar que se pueden agrupar los casos, si tienen un comportamiento similar:
Código:
                case B0100:
                case B0101:
                case B0110:
            /* casos de la alarma */
            ...
Finalmente, existe la opción 'default', que se encargará de todos los casos no contemplados.
Código:
		default:
 
Tomes el camino que tomes en vez de poner la tabla sin mas primero se puede simplificar, para ello hay programas, y poner la función simplificada.
 
Atrás
Arriba