tabelas de verdade no código? Como estruturar máquina de estado?
-
03-07-2019 - |
Pergunta
Eu tenho uma máquina (um pouco) a tabela grande verdade / estado que eu preciso para implementar no meu código (C incorporado). Eu antecipo a especificação comportamento desta máquina de estado para a mudança no futuro, e por isso eu gostaria de manter isso facilmente modificável no futuro.
Meu tabela verdade tem 4 entradas e 4 saídas. Eu tenho tudo em uma planilha do Excel, e se eu pudesse colar isso em meu código com um pouco de formatação, que seria o ideal.
Eu estava pensando que eu gostaria de acessar minha tabela de verdade assim:
u8 newState[] = decisionTable[input1][input2][input3][input4];
E então eu poderia acessar os valores de saída com:
setOutputPin( LINE_0, newState[0] );
setOutputPin( LINE_1, newState[1] );
setOutputPin( LINE_2, newState[2] );
setOutputPin( LINE_3, newState[3] );
Mas para conseguir isso, parece que eu teria que fazer uma tabela bastante confuso assim:
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 }}}};
Os colchetes aninhados pode ser um pouco confuso? - alguém tem uma idéia melhor de como eu posso manter uma tabela bonita olhando no meu código
Obrigado!
Editar com base na resposta do HUAGHAGUAH:
Usando uma amálgama de entrada de todos (graças - Eu gostaria de poder "aceitar" 3 ou 4 destas respostas), eu acho que eu vou experimentá-lo como uma matriz bidimensional. Vou índice em minha matriz usando uma macro-deslocando pouco pequeno:
#define SM_INPUTS( in0, in1, in2, in3 ) ((in0 << 0) | (in1 << 1) | (in2 << 2) | (in3 << 3))
E isso vai deixar a minha verdade matriz da tabela semelhante a este:
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 eu posso acessar minha tabela de verdade assim:
decisionTable[ SM_INPUTS( line1, line2, line3, line4 ) ]
Vou dar que um tiro e ver como ele funciona. Eu também vou estar substituindo os 0 e 1 do com #defines mais votos que expressam o que cada um dos meios do Estado, juntamente com / ** / comentários que explicam as entradas para cada linha de saídas. Obrigado pela ajuda, todos!
Solução
Não há necessidade de uma tabela multidimensional. Com um mapeamento => 4 bit de 4 bits, você pode ter um único u8 [16] entradas de mapeamento de matriz para saídas. pesquisas estaduais será muito mais barato, e você pode extrair bits individuais com alguns ops de deslocamento e máscara.
Se o algoritmo para linhas Preencher é fácil de codificar, você poderia #define uma macro para preencher cada linha pelo número de índice.
Outras dicas
Eu sugiro qualquer um (preferido se aproxima primeiro):
- Use uma macro para intialize cada "linha" -. Isso irá esconder as chaves dentro da chamada de macro
- Use comentários para romper as linhas.
- Use uma função init para inicializar o contexto explicitamente - talvez usar funções para inicializar cada seção. Isto é semelhante à primeira opção acima, mas tem uma desvantagem que a função init deve ser chamado antes da máquina de estado pode ser usado.
Pessoalmente, eu lê-lo a partir de um arquivo de configuração. CSV, talvez, que é fácil de exportação para a partir do Excel. Ou você pode simplesmente copiar e colar a partir de Excel em texto simples, que lhe dá valores separados por espaços, que é igualmente fácil de importação.
Isto também significa, uma vez que você está trabalhando com C, que você não vai ter que recompilar seu código de cada vez que a tabela de decisão alterações.
Se a sua tabela de verdade é todos booleans, você poderia apenas reduzi-la a uma lista de pares, por exemplo.
1111,0000
1110,0110
...
para compressão de dados, representam os valores como bytes (dois nybbles) ...
onde / como armazená-la para codificação suave em sua configuração de sistema embarcado particular, só você pode dizer; -)
Se a tabela de verdade é realmente só 4x4x4x4, então eu usar macros. Se ele nunca vai crescer além disso, eu usaria Ragel . As chances são de que vai fazer menor mais rápido código, C do que você.
Não vejo qualquer referência ao estado atual, a fim de obter o seu estado de saída. Isso significa que ele não é uma máquina de estado, mas apenas uma tabela verdade. Existem quatro entradas, de modo que há apenas 16 combinações possíveis de entrada. Assim, uma tabela com 16 posições deve fazê-lo.
Normalmente, quando você tem um problema como este, tenta-se reduzi-la a uma fórmula booleana simples. Eu não vejo por que não seria a melhor abordagem aqui. Seria muito mais compacto e mais legível, mais ele tem o potencial para ser mais rápido (eu imagino um punhado de ANDs e ORs iria executar mais rapidamente do que a coleção de multiplica / turnos + acesso à memória necessária para a abordagem tabela de pesquisa). A maneira mais fácil de reduzir essa tabela para uma fórmula booleana é com um K-Map.