Pregunta

Tengo una máquina de estado / tabla de verdad (algo) grande que necesito implementar en mi código (C incrustada). Anticipo la especificación de comportamiento de esta máquina de estado para cambiar en el futuro, por lo que me gustaría mantener esto fácilmente modificable en el futuro.

Mi tabla de verdad tiene 4 entradas y 4 salidas. Lo tengo todo en una hoja de cálculo de Excel, y si pudiera pegarlo en mi código con un poco de formato, sería ideal.

Estaba pensando que me gustaría acceder a mi tabla de verdad así:

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

Y luego podría acceder a los valores de salida con:

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

Pero para conseguir eso, parece que tendría que hacer una tabla bastante confusa como esta:

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 }}}};

Esos corchetes anidados pueden ser algo confusos. ¿Alguien tiene una mejor idea de cómo puedo mantener una tabla de aspecto bonito en mi código?

¡Gracias!

Editar según la respuesta de HUAGHAGUAH:

Usando una amalgama de los comentarios de todos (gracias, me gustaría poder "aceptar" 3 o 4 de estas respuestas), creo que lo intentaré como una matriz bidimensional. Voy a indexar en mi matriz usando una pequeña macro de desplazamiento de bits:

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

Y eso permitirá que la matriz de mi tabla de verdad se vea así:

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 }};

Y luego puedo acceder a mi tabla de verdad así:

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

Le daré una oportunidad y veré cómo funciona. También reemplazaré los 0 y los 1 con #defines más útiles que expresan lo que significa cada estado, junto con / ** / comentarios que explican las entradas para cada línea de salidas. Gracias por la ayuda, todos!

¿Fue útil?

Solución

No es necesaria una tabla multidimensional. Con un bit 4 = > Mapeo de 4 bits, puede tener un solo u8 [16] entradas de mapeo de matrices a salidas. Las búsquedas de estado serán mucho más baratas, y puedes extraer bits individuales con algunas operaciones de cambio y máscara.

Si el algoritmo para completar filas es fácil de codificar, puede # definir una macro para completar cada fila por número de índice.

Otros consejos

Yo sugeriría cualquiera de los dos (los enfoques preferidos primero):

  • Use una macro para inicializar cada fila " " - Esto ocultará las llaves dentro de la llamada a la macro.
  • Usa comentarios para dividir las filas.
  • Use una función de inicio para inicializar el contexto explícitamente, tal vez use funciones para inicializar cada sección. Esto es similar a la primera opción anterior, pero tiene la desventaja de que se debe invocar la función init antes de poder usar la máquina de estado.

Personalmente, lo leí de un archivo de configuración. CSV, tal vez, que es fácil de exportar desde Excel. O simplemente puede copiar y pegar desde Excel en texto sin formato, lo que le brinda valores separados por espacios, lo que es igualmente fácil de importar.

Esto también significa que, dado que está trabajando con C, no tendrá que volver a compilar su código cada vez que cambie la tabla de decisiones.

Si tu tabla de verdad es completamente booleana, simplemente puedes contraerla para formar una lista de pares, por ejemplo

1111,0000
1110,0110
...

para la compresión de datos, represente los valores como bytes (dos nybbles) ...

dónde / cómo almacenarlo para la codificación suave en su configuración particular del sistema incorporado, solo usted puede decir ;-)

Si la tabla de verdad es realmente solo 4x4x4x4, entonces usaría macros. Si alguna vez va a crecer más allá de eso, usaría Ragel . Es probable que produzca un código C más pequeño y más rápido que usted.

No veo ninguna referencia al estado actual para obtener el estado de salida. Esto significa que no es una máquina de estado, sino solo una tabla de verdad. Hay cuatro entradas, por lo que solo hay 16 combinaciones de entradas posibles. Por lo tanto, una tabla con 16 posiciones debería hacerlo.

Generalmente cuando tienes un problema como este, uno trata de reducirlo a una fórmula booleana simple. No veo por qué ese no sería el mejor enfoque aquí. Sería mucho más compacto y más legible, además tiene el potencial de ser más rápido (me imagino que un puñado de AND y OR se ejecutaría más rápidamente que la recopilación de multiplicaciones / desplazamientos + acceso a memoria necesario para el enfoque de la tabla de consulta). La forma más fácil de reducir esta tabla a una fórmula booleana es con un K-Map .

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top