Saltar al contenido principal

Funciones lógicas

Operaciones booleanas​

Las variables o señales booleanas solo pueden adoptar 2 estados, que según el contexto pueden describirse con distintos mnemónicos

01
falsetrue
noyes
offon
lowhigh

A continuación se supone además el símbolo X para "don't care", es decir, el valor no influye en el resultado. Los flancos se indican con la notación correspondiente 0->1 o 1->0.

A modo de comparación, en muchos puntos se muestra la relación con los circuitos integrados clásicos de puertas lógicas de la serie 74 (p. ej., 74HC147). La función implementada en el módulo Math tiene, en los componentes complejos, normalmente más opciones que el modelo citado.

La función lógica elemental más sencilla es el elemento inversor "NOT":

NOT A
A(74HC04)
01
10

Cuando se combinan entre sí dos variables o señales booleanas, se aplican 2 funciones lógicas AND y OR elementales:

A AND BA OR BA XOR B
AB(74HC21)(74HC32)(74HC86)
00000
01011
10011
11110

El elemento XOR (OR exclusivo) puede realizarse mediante una combinación compleja de AND, OR y NOT y se enumera aquí como elemento propio para ilustrar más fácilmente la función a continuación.

XOR(A,B)=AND(OR(A,B),NOT(AND(A,B))XOR(A, B) = AND(OR(A,B), NOT(AND(A,B))

Mediante la combinación con una etapa NOT se obtiene, respectivamente,

A NAND BA NOR BA NXOR B
AB(74HC00)(74HC02)(74HC266)
00111
01100
10100
11001

Según los tipos de datos, se aplican los siguientes operadores y funciones lógicos, de modo que los 64 bits del tipo numérico <uint> (unsigned integer) se aplican individualmente a las funciones lógicas:

<bool> A, B<uint> A, B
NOT!AbNot(A)
ANDA && BbAnd(A,B)
ORA || BbOr(A,B)
XORA ^^ BbXOr(A,B)
NAND!(A && B)bNAnd(A,B)
NOR!(A || B)bNOr(A,B)
NXOR!(A ^^ B)bNXOr(A,B)

Funciones orientadas a bits​

precaución

Estas funciones de bits no son operadores lógicos. Trabajan siempre sobre la representación interna como <uint> y, por ello, convierten primero todos los parámetros al tipo <uint>. Esto se aprecia, por ejemplo, en la función bNot(), que invierte todos los bits del valor de entrada.

  • bNot(false) => bNot(0x00) => 0xFFFFFFFFFFFFFFFF => logic: true
  • bNot(true) => bNot(0x01) => 0xFFFFFFFFFFFFFFFE => logic: true

Aunque el resultado del operador XOR ^^ se parece al de != (distinto), el primero fuerza el tipo de datos <bool> para sus operandos, mientras que != o == buscan la mejor representación posible para ambos tipos de datos y, por tanto, al mezclar tipos de datos diferentes, por lo general convierten el operando booleano en un valor numérico 0 o 1 (<uint>, <int>, <dbl>) para la comparación.

FunciónDescripción
bNot(x)inversión orientada a bits de x (véase también el operador ~)
Para un NOT lógico sobre un término <bool> debe utilizarse el operador !.
bAnd(x1, ..., xN)conjunción bit a bit (AND) de todas las expresiones x1, ..., xN
bNAnd(x1, ..., xN)conjunción bit a bit (AND) de todas las expresiones x1, ..., xN con inversión posterior
bOr(x1, ..., xN)disyunción bit a bit (OR) de todas las expresiones x1, ..., xN
bNOr(x1, ..., xN)disyunción bit a bit (OR) de todas las expresiones x1, ..., xN con inversión posterior
bXor(x1, ..., xN)disyunción exclusiva bit a bit (OR) de todas las expresiones x1, ..., xN
bNXor(x1, ..., xN)disyunción exclusiva bit a bit (OR) de todas las expresiones x1, ..., xN con inversión posterior
bShift(x,n)desplazamiento bit a bit (SHIFT) de x en n posiciones hacia la izquierda; con n negativo, hacia la derecha
bCount(x)número de bits activados en x
bTest(x,n)consulta si en x está activado el n-ésimo bit; n corresponde al peso del bit 2n,n∈[0..63]2^n, n \in [0 ..63]
bSet(x,n,v)activación (v=true) o borrado (v=false) del bit 2n,n∈[0..63]2^n, n \in [0 ..63] en x

Elementos lógicos​

Detección de flancos "posedge", "negedge", "onchange"​

Para los elementos de detección de flancos, la señal de entrada puede ser cualquier valor numérico escalar de tipo <bool>, <uint>, <int> o <dbl>.

FunciónDescripción
posedge(x)devuelve true durante un nanosegundo cuando el valor actual de la señal y es mayor que su valor anterior
negedge(x)devuelve true durante un nanosegundo cuando el valor actual de la señal y es menor que su valor anterior
onchange(x)devuelve true durante un nanosegundo cuando el valor actual de la señal y ha cambiado respecto al valor anterior

Detección de flancos

nota

Debido a la duración extremadamente corta de la señal, de solo 1 ns, una señal de este tipo suele pasar desapercibida en la transmisión MQTT. Por ello, para su comprobación o visualización solo resultan adecuados los registros en archivos OSF.

Flip-flop RS "rsFF"​

Con true en la entrada reset, la salida pasa a false, y con true en la entrada set, la salida se pone a true. reset tiene prioridad.

Las entradas reset y set se interpretan como <bool>.

Q = rsFF(reset, set);
// Optionale Konfiguration
Qx = rsFF(..., { storage: <str>
});
PropiedadValorDescripción
storage<str>Nombre de una memoria persistente para el estado interno. Con ello, tras un reinicio del sistema, la salida recibe el último valor guardado. El contenido de esta memoria no se puede utilizar en ningún otro lugar del smartCORE.
resetsetSalida
00Se mantiene el último estado
011
1X0

Flip-flop JK "jkFF"​

Con un flanco de subida en la entrada clock, las entradas de preparación j y k deciden cómo se modifica la salida (74HC73).

Con true en la entrada reset, la salida pasa a false, y con true en la entrada set, la salida se pone a true. reset tiene prioridad.

Todas las entradas se interpretan como <bool>.

Q1 = jkFF(clock, j, k);
Q2 = jkFF(clock, j, k, reset);
Q3 = jkFF(clock, j, k, reset, set);
// Optionale Konfiguration für alle Varianten
Qx = jkFF(..., { storage: <str>
});
PropiedadValorDescripción
storage<str>Nombre de una memoria persistente para el estado interno. Con ello, tras un reinicio del sistema, la salida recibe el último valor guardado. El contenido de esta memoria no se puede utilizar en ningún otro lugar del smartCORE.
clockjkresetsetSalida
0XX00Se mantiene el último estado
1XX00Se mantiene el último estado
0->10000Se mantiene el último estado
0->101000
0->110001
0->11100La salida cambia de estado
XXX1X0
XXX011

Flip-flop D "dFF"​

Con un flanco de subida en la entrada clock, se guarda el valor de la entrada data (74HC74).

Con true en la entrada reset, la salida pasa a false, y con true en la entrada set, la salida se pone a true. reset tiene prioridad.

Este flip-flop puede almacenar todos los tipos de datos. Salvo data, todas las entradas se interpretan como <bool>.

Q1 = dFF(clock, data);
Q2 = dFF(clock, data, reset);
Q3 = dFF(clock, data, reset, set);
// Optionale Konfiguration für alle Varianten
Qx = dFF(..., { storage: <str>
});
PropiedadValorDescripción
storage<str>Nombre de una memoria persistente para el estado interno. Con ello, tras un reinicio del sistema, la salida recibe el último valor guardado. El contenido de esta memoria no se puede utilizar en ningún otro lugar del smartCORE.
clockdataresetsetSalida
0X00Se mantiene el último valor de salida
1X00Se mantiene el último valor de salida
0->1<var>00Salida y almacenamiento del valor en data
XX1XLa salida se pone a <false>
XX01La salida se pone a <true>

Latch D "dLatch"​

Con true en la entrada hold se guarda el último valor de la entrada data; en caso contrario, la salida sigue directamente a la entrada data (74HC75). Este flip-flop puede almacenar todos los tipos de datos. La entrada hold se interpreta como <bool>.

Q = dLatch(hold, data);
// Optionale Konfiguration
Qx = dLatch(..., { storage: <str>
});
PropiedadValorDescripción
storage<str>Nombre de una memoria persistente para el estado interno. Con ello, tras un reinicio del sistema, la salida recibe el último valor guardado. El contenido de esta memoria no se puede utilizar en ningún otro lugar del smartCORE.
holddataSalida
0<var>Sigue al valor en data
1XSe mantiene el último valor de salida
información

Si hold y data cambian simultáneamente, el nuevo valor de data ya no se utiliza.

Memoria indexada "memory" 1​

La función memory representa un dLatch() o un dFF() direccionable con funcionalidad ampliada. El valor devuelto es el vector de datos almacenado. El tipo de datos se determina mediante el parámetro preset.

MEM1 = memory(control, index, data, {...});
MEM2 = memory(control, index, data, reset, {...});
// mandatory configuration
MEMx = memory(..., { mode: <enum> // mandatory
, size: <uint> // mandatory
                   , preset: <var> // recommended
, weight: <dbl>
, storage: <str>
});
PropiedadValorDescripción
mode<enum>latch: con true en la entrada control se guarda el último valor de la entrada data en el elemento index; en caso contrario, el elemento sigue directamente a la entrada data (como dLatch())
set: mem[index] = data, con un flanco de subida en la entrada control se guarda el valor de la entrada data en el elemento index (como dFF())
add: mem[index] += data, con un flanco de subida en la entrada control el valor de la entrada data se suma al elemento index:
mult: mem[index] *= data, con un flanco de subida en la entrada control el valor de la entrada data se multiplica por el elemento index
weight: mem[index] = (1-weight)*mem[index] + weight*data, con un flanco de subida en la entrada control el valor de la entrada data se multiplica por este factor de ponderación y se suma al elemento index ponderado de forma complementaria.
sizeNúmero de posiciones de memoria reservadas (indexadas desde 0 hasta size-1) y tamaño del vector de salida.
presetInicialización de la memoria (con reset = true) y determinación del tipo de datos, p. ej., 0.0 para <dbl> o 0 para <int>.
weightFactor de ponderación para el modo weight, rango de valores válido [0..1.0][0 .. 1.0]
storage<str>Nombre de una memoria persistente para el vector de datos. Con ello, tras un reinicio del sistema, la salida recibe el último valor guardado. El contenido de esta memoria no se puede utilizar en ningún otro lugar del smartCORE.

En una memoria numérica (preset numérico), los valores NaN e INF en la entrada data se sustituyen por el último valor finito recibido; antes del primer valor finito no se guarda nada. Los elementos no finitos de la memoria persistente se sustituyen por preset al arrancar. Una cadena de texto o un valor complejo en data devuelve entonces el mensaje de error Input Value is not a numerical scalar.

consejo

Un elemento del vector "memoria" puede leerse mediante la sintaxis de indexación [...] o la función GetCol(), también en distintos puntos del texto de la fórmula:

e1 = MEMx[rdIndex];
e2 = GetCol(MEMx, rdIndex);
consejo

Un caso de uso frecuente de la función memory() es, por ejemplo, el almacenamiento de lecturas de contadores de energía. En este caso, en el modo latch se obtendría el índice de la función decodeTime(), p. ej., como día de la semana, y se suministraría como data la lectura acumulada del contador de energía. La entrada control está constantemente en false para seguir los valores del contador de energía.

Una segunda memoria conserva de forma similar los valores del día anterior, de modo que el consumo diario resulta de la diferencia de los vectores.

Puede encontrarse una implementación en el Ejemplo 1c).

Multiplexor "select"​

Multiplexor (74HC151). Mediante el índice i se selecciona y se reenvía una señal s0, s1, ... Si i es negativo o mayor o igual que el número de entradas (n+1), se emite false. Las señales pueden representar tipos de datos cualesquiera; la salida cambia en consecuencia también de tipo de datos.

y = select(i, s0, s1, ...sn);
is0s1...snSalida
< 0XX...Xfalse
0<var>X...Xsigue a s0
1X<var>...Xsigue a s1
nXX...<var>sigue a sn
> nXX...Xfalse
información

En el lenguaje de programación C, esto correspondería a la siguiente instrucción:

switch(i)
{
case 0: return s0;
case 1: return s1;
// ...
case n: return sn;
default: return false;
}
consejo

Si las distintas señales ya están agrupadas como vector, puede utilizarse más fácilmente la sintaxis de índices para vectores:

VSig = [s0, s1, ...sn]; // eventually result of calculation or buffering
yi = VSig[i];

Sin embargo, entonces debe procurarse que i se mantenga en un rango de valores válido [0 .. n].

Codificador de prioridad "prioEnc"​

Codificador de prioridad (similar a 74HC147 o 74HC148); contando en orden ascendente, se emite el índice de la primera entrada activa. Mediante el objeto de configuración opcional pueden ajustarse variantes de la funcionalidad. Todas las entradas se interpretan como <bool>.

enc1 = prioEnc(e0, e1, ...);
// Optionale Konfiguration
encX = prioEnc(..., { none: <int>
, active: <bool>
, edge: <bool>
, map: [<int>]
, latch: <bool>
, startup: inf|<bool>
});
PropiedadValorDescripción
none<int>Si ninguna entrada está activa, se emite este valor (por defecto: -1)
active<bool>Con esto puede ajustarse el nivel que debe reconocerse como activo (con edge: false) (por defecto: true).
edge<bool>Con true solo se utilizan para el disparo los flancos positivos (active: true) o negativos (active: false).
map[<int>]Tabla de asignación de valores de salida para las entradas de control e0, e1, ... p. ej.
[1, 10, 100, 1000]
latch<bool>Con true se mantiene el índice de la última entrada activa (botón de opción).
startupinf/<bool>Definición de un nivel de referencia para las entradas al arrancar el software

En la tabla siguiente, una entrada está activa cuando se cumple el estado determinado por las propiedades active y edge. En caso contrario, inactiva.

e0e1...enSalida
inactivainactiva...inactivalatch = false: -1 o el valor de la propiedad none
latch = true: el último valor activado (botón de opción)
activaX...X0 o el valor definido con map[0]
inactivaactiva...X1 o el valor definido con map[1]
inactivainactiva...activan o el valor definido con map[n]

Para el arranque del sistema debe establecerse cómo se trata el pasado de las entradas y si, por tanto, deben detectarse flancos inmediatamente al arrancar. Para ello sirve la propiedad startup:

  • inf: la primera muestra de la señal determina el valor en el pasado anterior al arranque del sistema, de modo que con la primera muestra no se dispara ningún flanco.

  • <bool>: se supone que las entradas tenían este valor de señal (true, false) en el pasado anterior al arranque del sistema. Con ello, es posible que se dispare un flanco con la primera muestra de una entrada.

Propiedad startup

información

En el lenguaje de programación C, esto correspondería (sin edge, latch ni startup) a la siguiente instrucción:

if (e0 == active)
return map.size() > 0 ? map[0] : 0;
else if (e1 == active)
return map.size() > 0 ? map[1] : 1;
// ...
else if (en == active)
return map.size() > 0 ? map[n] : n;
else
return none; // by default -1;

Footnotes​

  1. Disponible a partir de la versión 13 del catálogo. ↩