Passa al contenuto principale

Funzioni logiche

Operazioni booleane​

Le variabili o i segnali booleani possono assumere solo 2 stati, che a seconda del contesto possono essere descritti con mnemonici diversi

01
falsetrue
noyes
offon
lowhigh

Di seguito si assume inoltre il simbolo X per "don't care", cioè il valore è irrilevante per il risultato. I fronti sono indicati con la relativa notazione 0->1 o 1->0.

A scopo di confronto, in molti punti viene mostrato il collegamento con i classici circuiti integrati di porte logiche della serie 74 (ad es. 74HC147). Nei componenti complessi, la funzione implementata nel modulo Math offre per lo più ancora più opzioni del modello indicato.

La funzione logica più semplice ed elementare è l'elemento invertente "NOT":

NOT A
A(74HC04)
01
10

Quando due variabili o segnali booleani vengono combinati tra loro, si applicano 2 funzioni logiche elementari, AND e OR:

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

L'elemento XOR (OR esclusivo) può essere realizzato con una combinazione complessa di AND, OR e NOT e viene qui elencato come elemento a sé stante per rendere più semplice la descrizione delle funzioni seguenti.

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

Combinando con uno stadio NOT si ottiene rispettivamente

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

A seconda dei tipi di dati si applicano i seguenti operatori e funzioni logiche, dove i 64 bit del tipo numerico <uint> (unsigned integer) vengono forniti singolarmente alle funzioni logiche:

<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)

Funzioni orientate ai bit​

attenzione

Queste funzioni sui bit non sono operatori logici! Operano sempre sulla rappresentazione interna come <uint> e per questo convertono dapprima tutti i parametri nel tipo <uint>. Lo si vede, ad esempio, nella funzione bNot(), che inverte tutti i bit del valore di ingresso.

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

Anche se nel risultato l'operatore XOR ^^ somiglia a != (diverso), il primo impone ai propri operandi il tipo di dati <bool>, mentre != o == cercano la migliore rappresentazione possibile per entrambi i tipi di dati e quindi, mescolando tipi di dati diversi, di norma convertono l'operando booleano in un valore numerico 0 o 1 (<uint>, <int>, <dbl>) per il confronto.

FunzioneDescrizione
bNot(x)inversione orientata ai bit di x (vedere anche l'operatore ~)
Per un NOT logico su un'espressione <bool> utilizzare l'operatore !.
bAnd(x1, ..., xN)congiunzione bit a bit (AND) di tutte le espressioni x1, ..., xN
bNAnd(x1, ..., xN)congiunzione bit a bit (AND) di tutte le espressioni x1, ..., xN con successiva inversione
bOr(x1, ..., xN)disgiunzione bit a bit (OR) di tutte le espressioni x1, ..., xN
bNOr(x1, ..., xN)disgiunzione bit a bit (OR) di tutte le espressioni x1, ..., xN con successiva inversione
bXor(x1, ..., xN)disgiunzione esclusiva bit a bit (OR) di tutte le espressioni x1, ..., xN
bNXor(x1, ..., xN)disgiunzione esclusiva bit a bit (OR) di tutte le espressioni x1, ..., xN con successiva inversione
bShift(x,n)spostamento bit a bit (SHIFT) di x di n posizioni verso sinistra, con n negativo verso destra
bCount(x)numero di bit impostati in x
bTest(x,n)verifica se in x è impostato l'n-esimo bit, n corrisponde al peso del bit 2n,n∈[0..63]2^n, n \in [0 ..63]
bSet(x,n,v)impostazione (v=true) o cancellazione (v=false) del bit 2n,n∈[0..63]2^n, n \in [0 ..63] in x

Elementi logici​

Rilevamento di fronti "posedge", "negedge", "onchange"​

Per gli elementi di rilevamento dei fronti il segnale di ingresso può essere un qualsiasi valore numerico scalare di tipo <bool>, <uint>, <int> o <dbl>.

FunzioneDescrizione
posedge(x)restituisce true per un nanosecondo se il valore attuale del segnale y è maggiore del valore precedente
negedge(x)restituisce true per un nanosecondo se il valore attuale del segnale y è minore del valore precedente
onchange(x)restituisce true per un nanosecondo se il valore attuale del segnale y è cambiato rispetto al valore precedente

Rilevamento dei fronti

note

A causa della durata estremamente breve del segnale, di soli 1 ns, un segnale di questo tipo viene di regola ignorato dalla trasmissione MQTT. Per il controllo o la visualizzazione sono quindi adatte solo le registrazioni nei file OSF.

Flip-flop RS "rsFF"​

Con true sull'ingresso reset l'uscita passa a false e con true sull'ingresso set l'uscita viene impostata a true. reset ha la priorità.

Gli ingressi reset e set vengono interpretati come <bool>.

Q = rsFF(reset, set);
// Optionale Konfiguration
Qx = rsFF(..., { storage: <str>
});
ProprietàValoreDescrizione
storage<str>Nome di una memoria persistente per lo stato interno. In questo modo, dopo un riavvio del sistema l'uscita assume l'ultimo valore salvato. Il contenuto di questa memoria non è utilizzabile in nessun altro punto di smartCORE.
resetsetUscita
00L'ultimo stato viene mantenuto
011
1X0

Flip-flop JK "jkFF"​

Con un fronte di salita sull'ingresso clock, gli ingressi di preparazione j e k decidono come viene modificata l'uscita (74HC73).

Con true sull'ingresso reset l'uscita passa a false e con true sull'ingresso set l'uscita viene impostata a true. reset ha la priorità.

Tutti gli ingressi vengono interpretati come <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>
});
ProprietàValoreDescrizione
storage<str>Nome di una memoria persistente per lo stato interno. In questo modo, dopo un riavvio del sistema l'uscita assume l'ultimo valore salvato. Il contenuto di questa memoria non è utilizzabile in nessun altro punto di smartCORE.
clockjkresetsetUscita
0XX00L'ultimo stato viene mantenuto
1XX00L'ultimo stato viene mantenuto
0->10000L'ultimo stato viene mantenuto
0->101000
0->110001
0->11100L'uscita cambia stato
XXX1X0
XXX011

Flip-flop D "dFF"​

Con un fronte di salita sull'ingresso clock il valore sull'ingresso data viene memorizzato (74HC74).

Con true sull'ingresso reset l'uscita passa a false e con true sull'ingresso set l'uscita viene impostata a true. reset ha la priorità.

Questo flip-flop può memorizzare tutti i tipi di dati. Ad eccezione di data, tutti gli ingressi vengono interpretati come <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>
});
ProprietàValoreDescrizione
storage<str>Nome di una memoria persistente per lo stato interno. In questo modo, dopo un riavvio del sistema l'uscita assume l'ultimo valore salvato. Il contenuto di questa memoria non è utilizzabile in nessun altro punto di smartCORE.
clockdataresetsetUscita
0X00L'ultimo valore di uscita viene mantenuto
1X00L'ultimo valore di uscita viene mantenuto
0->1<var>00Emissione e memorizzazione del valore su data
XX1XL'uscita viene impostata a <false>
XX01L'uscita viene impostata a <true>

Latch D "dLatch"​

Con true sull'ingresso hold viene memorizzato l'ultimo valore sull'ingresso data, altrimenti l'uscita segue direttamente l'ingresso data (74HC75). Questo flip-flop può memorizzare tutti i tipi di dati. L'ingresso hold viene interpretato come <bool>.

Q = dLatch(hold, data);
// Optionale Konfiguration
Qx = dLatch(..., { storage: <str>
});
ProprietàValoreDescrizione
storage<str>Nome di una memoria persistente per lo stato interno. In questo modo, dopo un riavvio del sistema l'uscita assume l'ultimo valore salvato. Il contenuto di questa memoria non è utilizzabile in nessun altro punto di smartCORE.
holddataUscita
0<var>Segue il valore su data
1XL'ultimo valore di uscita viene mantenuto
informazioni

Se hold e data cambiano contemporaneamente, il nuovo valore di data non viene più utilizzato.

Memoria indicizzata "memory" 1​

La funzione memory rappresenta un dLatch() o dFF() indirizzabile con funzionalità estese. Il valore restituito è il vettore di dati memorizzato. Il tipo di dati viene stabilito tramite il parametro 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>
});
ProprietàValoreDescrizione
mode<enum>latch: con true sull'ingresso control viene memorizzato l'ultimo valore sull'ingresso data nell'elemento index, altrimenti l'elemento segue direttamente l'ingresso data (come dLatch())
set: mem[index] = data, con un fronte di salita sull'ingresso control il valore sull'ingresso data viene memorizzato nell'elemento index (come dFF())
add: mem[index] += data, con un fronte di salita sull'ingresso control il valore sull'ingresso data viene sommato all'elemento index:
mult: mem[index] *= data, con un fronte di salita sull'ingresso control il valore sull'ingresso data viene moltiplicato per l'elemento index
weight: mem[index] = (1-weight)*mem[index] + weight*data, con un fronte di salita sull'ingresso control il valore sull'ingresso data viene moltiplicato per questo fattore di ponderazione e sommato all'elemento index ponderato in modo complementare.
sizeNumero di posizioni di memoria riservate (indicizzate da 0 a size-1) e dimensione del vettore di uscita.
presetInizializzazione della memoria (con reset = true) e definizione del tipo di dati, ad es. 0.0 per <dbl> o 0 per <int>.
weightFattore di ponderazione per la modalità weight, intervallo di valori valido [0..1.0][0 .. 1.0]
storage<str>Nome di una memoria persistente per il vettore di dati. In questo modo, dopo un riavvio del sistema l'uscita assume l'ultimo valore salvato. Il contenuto di questa memoria non è utilizzabile in nessun altro punto di smartCORE.
suggerimento

Un elemento del vettore "memoria" può essere letto tramite la sintassi di indicizzazione [...] o la funzione GetCol(), anche in punti diversi del testo della formula:

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

Un caso d'uso frequente della funzione memory() è, ad esempio, la memorizzazione delle letture dei contatori di energia. In questo caso, nella modalità latch si ricaverebbe l'indice dalla funzione decodeTime(), ad es. come giorno della settimana, e si fornirebbe come data la lettura cumulata del contatore di energia. L'ingresso control è costantemente su false, per seguire i valori del contatore di energia.

Una seconda memoria mantiene in modo analogo i valori del giorno precedente, in modo che il consumo giornaliero risulti dalla differenza dei vettori.

Un'implementazione si trova nell'Esempio 1c).

Multiplexer "select"​

Multiplexer (74HC151). Tramite l'indice i viene selezionato e inoltrato un segnale s0, s1, ... Se i è negativo oppure maggiore o uguale al numero di ingressi (n+1), viene restituito false. I segnali possono rappresentare tipi di dati qualsiasi; l'uscita cambia di conseguenza anche il tipo di dati.

y = select(i, s0, s1, ...sn);
is0s1...snUscita
< 0XX...Xfalse
0<var>X...Xsegue s0
1X<var>...Xsegue s1
nXX...<var>segue sn
> nXX...Xfalse
informazioni

Nel linguaggio di programmazione C ciò corrisponderebbe alla seguente istruzione:

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

Se i singoli segnali sono già raggruppati come vettore, si può utilizzare più semplicemente la sintassi con indici per i vettori:

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

In tal caso occorre tuttavia fare attenzione che i rimanga in un intervallo di valori valido [0 .. n].

Encoder con priorità "prioEnc"​

Encoder con priorità (simile a 74HC147 o 74HC148): contando in ordine crescente, viene restituito l'indice del primo ingresso attivo. Tramite l'oggetto di configurazione opzionale si possono impostare varianti della funzionalità. Tutti gli ingressi vengono interpretati come <bool>.

enc1 = prioEnc(e0, e1, ...);
// Optionale Konfiguration
encX = prioEnc(..., { none: <int>
, active: <bool>
, edge: <bool>
, map: [<int>]
, latch: <bool>
, startup: inf|<bool>
});
ProprietàValoreDescrizione
none<int>Se nessun ingresso è attivo, viene restituito questo valore (def.: -1)
active<bool>Con questa proprietà si può impostare il livello da riconoscere come attivo (con edge: false) (def.: true).
edge<bool>Con true solo i fronti positivi (active: true) o negativi (active: false) vengono utilizzati per l'attivazione.
map[<int>]Tabella per l'assegnazione dei valori di uscita agli ingressi di controllo e0, e1, ... ad es.
[1, 10, 100, 1000]
latch<bool>Con true viene mantenuto l'indice dell'ultimo ingresso attivo (radio button).
startupinf/<bool>Definizione di un livello di riferimento per gli ingressi all'avvio del software

Nella tabella seguente un ingresso è attivo se lo stato definito dalle proprietà active e edge è soddisfatto. Altrimenti è inattivo.

e0e1...enUscita
inattivoinattivo...inattivolatch = false: -1 o valore della proprietà none
latch = true: l'ultimo valore attivato (radio button)
attivoX...X0 o il valore definito con map[0]
inattivoattivo...X1 o il valore definito con map[1]
inattivoinattivo...attivon o il valore definito con map[n]

Per l'avvio del sistema occorre stabilire come trattare lo storico degli ingressi e se all'avvio debbano quindi essere rilevati subito dei fronti. A tale scopo serve la proprietà startup:

  • inf: il primo campione del segnale determina il valore nel passato prima dell'avvio del sistema, quindi con il primo campione non viene generato alcun fronte.

  • <bool>: gli ingressi vengono assunti con questo valore di segnale (true, false) nel passato prima dell'avvio del sistema. In questo modo con il primo campione di un ingresso può eventualmente essere generato un fronte.

Proprietà startup

informazioni

Nel linguaggio di programmazione C ciò corrisponderebbe (senza edge, latch o startup) alla seguente istruzione:

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. Disponibile dalla versione 13 del catalogo. ↩