2009-03-02 15 views
10

Ho una macchina di tabella/stato di verità (piuttosto) grande che devo implementare nel mio codice (C incorporato). Prevedo che le specifiche di comportamento di questa macchina a stati cambino in futuro e quindi mi piacerebbe mantenerlo facilmente modificabile in futuro.Tabelle di verità nel codice? Come strutturare la macchina a stati?

La mia tabella di verità ha 4 ingressi e 4 uscite. Ho tutto in un foglio di calcolo di Excel, e se potessi semplicemente incollarlo nel mio codice con un po 'di formattazione, sarebbe l'ideale.

pensavo mi piacerebbe accedere al mio tabella di verità in questo modo:

u8 newState[] = decisionTable[input1][input2][input3][input4]; 

E poi ho potuto accedere ai valori di uscita con:

setOutputPin(LINE_0, newState[0]); 
setOutputPin(LINE_1, newState[1]); 
setOutputPin(LINE_2, newState[2]); 
setOutputPin(LINE_3, newState[3]); 

Ma al fine di ottenere ciò, sembra che dovrei fare una tabella abbastanza confusa in questo modo:

static u8 decisionTable[][][][][] = 
{{{{ 0, 0, 0, 0 }, 
    { 0, 0, 0, 0 }}, 
    {{ 0, 0, 0, 0 }, 
    { 0, 0, 0, 0 }}}, 
    {{{ 0, 0, 1, 1 }, 
    { 0, 1, 1, 1 }}, 
    {{ 0, 1, 0, 1 }, 
    { 1, 1, 1, 1 }}}}, 
{{{{ 0, 1, 0, 1 }, 
    { 1, 1, 1, 1 }}, 
    {{ 0, 1, 0, 1 }, 
    { 1, 1, 1, 1 }}}, 
    {{{ 0, 1, 1, 1 }, 
    { 0, 1, 1, 1 }}, 
    {{ 0, 1, 0, 1 }, 
    { 1, 1, 1, 1 }}}}; 

Quelle parentesi annidate n essere un po 'confuso - qualcuno ha un'idea migliore di come posso mantenere una tabella carina nel mio codice?

Grazie!

Edit in base alla risposta del HUAGHAGUAH:

Utilizzando un amalgama di ingresso di tutti (grazie - vorrei poter "accettare" 3 o 4 di queste risposte), penso che ho intenzione di provarlo come una matrice bidimensionale. Io indice nel mio array usando un po 'piccolo-shifting macro:

#define SM_INPUTS(in0, in1, in2, in3) ((in0 << 0) | (in1 << 1) | (in2 << 2) | (in3 << 3)) 

E che lasciare che la mia matrice di tabella verità simile a questa:

static u8 decisionTable[][] = { 
{ 0, 0, 0, 0 }, 
{ 0, 0, 0, 0 }, 
{ 0, 0, 0, 0 }, 
{ 0, 0, 0, 0 }, 
{ 0, 0, 1, 1 }, 
{ 0, 1, 1, 1 }, 
{ 0, 1, 0, 1 }, 
{ 1, 1, 1, 1 }, 
{ 0, 1, 0, 1 }, 
{ 1, 1, 1, 1 }, 
{ 0, 1, 0, 1 }, 
{ 1, 1, 1, 1 }, 
{ 0, 1, 1, 1 }, 
{ 0, 1, 1, 1 }, 
{ 0, 1, 0, 1 }, 
{ 1, 1, 1, 1 }}; 

e posso quindi accedere alla mia tabella di verità come so:

decisionTable[ SM_INPUTS(line1, line2, line3, line4) ] 

Darò uno scatto e vedrò come funziona. Sostituirò anche gli 0 e gli 1 con #defaggi più utili che esprimono ciò che ogni stato significa, insieme a/**/commenti che spiegano gli input per ogni linea di output. Grazie per l'aiuto a tutti!

+0

Dal momento che è incorporato, l'utilizzo della memoria deve essere una limitazione delle risorse? – EvilTeach

+0

@EvilTeach: Grazie per la domanda. Anche se è incorporato, stiamo lavorando su un ferro piuttosto pesante con un sacco di flash e RAM da buttare in giro (entro limiti ragionevoli). La leggibilità del codice è il fattore più importante qui. – HanClinto

+0

Ancora uno. Hai una chiamata API che ti consente di impostare tutti e 4 i pin allo stesso tempo? – EvilTeach

risposta

3

Non c'è bisogno di una tabella multidimensionale. Con una mappatura a 4 bit => 4 bit, è possibile avere un singolo array u8 [16] che associa gli ingressi alle uscite. Le ricerche di stato saranno molto più economiche e puoi estrarre singoli bit con alcune operazioni di spostamento e maschera.

Se l'algoritmo per popolare le righe è facile da codificare, è possibile #definire una macro per popolare ogni riga per numero di indice.

+0

Mi piace questa risposta la migliore. Potrei ancora tenerla come una matrice bidimensionale (per array-ify le mie uscite), ma mi piace molto l'idea di combinare gli input in un singolo indice a 4 bit. Poiché tutti gli input e gli output sono booleani, funzionerà bene. Grazie! – HanClinto

3

Personalmente, l'ho letto da un file di configurazione. CSV, forse, che è facile esportare da Excel. Oppure puoi semplicemente copiare e incollare da Excel in testo semplice, che ti dà valori separati da spazio, che è altrettanto facile da importare.

Ciò significa anche, dato che si sta lavorando con C, che non sarà necessario ricompilare il codice ogni volta che cambia la tabella delle decisioni.

+0

@duffymo che il collegamento è morto ora :( –

+0

La risposta è di quattro anni e il collegamento sembra essere nove, quindi non è una sorpresa – duffymo

4

Io suggerirei di entrambi (approcci preferiti primi):

  • utilizza una macro per inizializzare ogni "riga" - In questo modo nascondere le parentesi all'interno della chiamata di macro.
  • Utilizzare i commenti per suddividere le righe.
  • Utilizzare una funzione di inizializzazione per inizializzare il contesto in modo esplicito - forse utilizzare le funzioni per inizializzare ciascuna sezione. Questo è simile alla prima opzione sopra ma ha uno svantaggio che la funzione init deve essere invocata prima che la macchina di stato possa essere utilizzata.
2

se il tuo tavolo di verità è tutto booleano, puoi semplicemente comprarlo in un elenco di coppie, ad es.

1111,0000 
1110,0110 
... 

per la compressione dei dati, rappresentano i valori come byte (due nybble) ...

dove/come salvarlo per soft-codifica nella particolare configurazione del sistema embedded, solo tu puoi dire; -)

+0

@ [EvilTeach] grazie per la modifica, ma preferisco l'ortografia y (vedi http://en.wikipedia.org/wiki/Nybble) –

+0

@SAL: ottimi suggerimenti, grazie! Questa è davvero una delle idee che ho inserito nella mia soluzione, molto apprezzata. – HanClinto

1

Se la tabella di verità è in realtà solo 4x4x4x4, quindi utilizzerei le macro. Se dovesse mai andare oltre, userei Ragel. È probabile che realizzerà un codice C più piccolo e più veloce di quello che farai.

+0

Strumento accurato! Come diceva gbarry, Immagino che il mio problema sia più mirato a Truth Tables che a State Machine, ma questo è uno strumento eccellente per tenere in una faretra. Grazie! – HanClinto

1

Non vedo alcun riferimento allo stato corrente per ottenere lo stato di output. Ciò significa che non è una macchina di stato, ma solo una tabella di verità. Ci sono quattro ingressi, quindi ci sono solo 16 possibili combinazioni di input. Quindi, un tavolo con 16 posizioni dovrebbe farlo.

+0

Buon punto: una delle cose Non ho detto che il valore futuro di una delle colonne di input è una delle colonne di output, quindi c'è una piccola macchina a stati all'interno della tabella di verità. Ma sì, per semplicità, probabilmente è meglio pensarlo come una macchina a stati puri. Grandi commenti, grazie! – HanClinto

+0

In realtà, per lo più è la macchina di stato che ha una tabella di verità all'interno. Gli stati sono latch che passano dall'output all'input. Quindi penso che vuoi dire che lo tratterai come un puro tavolo di verità.Una volta funzionante, ovviamente, il resto è solo semantica. – gbarry

1

Di solito quando si presenta un problema come questo, si cerca di ridurlo a una semplice formula booleana. Non vedo perché questo non sarebbe l'approccio migliore qui. Sarebbe molto più compatto e più leggibile, in più ha il potenziale per essere più veloce (immagino che una manciata di AND e OR possano essere eseguiti più rapidamente rispetto alla raccolta di multipli/turni + accesso alla memoria necessario per l'approccio alla tabella di ricerca). Il modo più semplice per ridurre questa tabella a una formula booleana è con un K-Map.

+0

@rmeador: Il motivo principale per cui non volevo ridurlo alla logica booleana è perché volevo che fosse facilmente leggibile e facilmente modificabile. Inoltre, non volevo fare ipotesi per ottimizzare la mia logica booleana che richiederebbe la riprogrammazione della mia logica su ogni cambiamento. – HanClinto