10

我有一个(有点)大的真值表/状态机,需要在我的代码(嵌入式 C)中实现。我预计此状态机的行为规范将来会发生变化,因此我希望将来可以轻松修改它。

我的真值表有 4 个输入和 4 个输出。我将所有内容都保存在 Excel 电子表格中,如果我可以将其粘贴到我的代码中并进行一些格式化,那将是理想的选择。

我在想我想像这样访问我的真值表:

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

然后我可以通过以下方式访问输出值:

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

但为了得到它,看起来我必须做一个相当混乱的表,如下所示:

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

那些嵌套的括号可能有点令人困惑——有没有人对如何在我的代码中保持漂亮的表格有更好的想法?

谢谢!

根据 HUAGHAGUAH 的回答进行编辑:

结合每个人的输入(谢谢——我希望我能“接受”这些答案中的 3 个或 4 个),我想我会尝试将它作为一个二维数组。我将使用一个小的位移宏来索引我的数组:

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

这将使我的真值表数组看起来像这样:

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

然后我可以像这样访问我的真值表:

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

我会试一试,看看效果如何。我还将用更有用的 #defines 替换 0 和 1,这些 #defines 表达了每个状态的含义,以及解释每行输出的输入的 /**/ 注释。谢谢大家的帮助!

4

7 回答 7

4

我建议(首选方法优先):

  • 使用宏初始化每个“行” - 这将隐藏宏调用中的大括号。
  • 使用注释来拆分行。
  • 使用 init 函数显式初始化上下文 - 可能使用函数来初始化每个部分。这类似于上面的第一个选项,但缺点是必须在使用状态机之前调用 init 函数。
于 2009-03-02T16:53:32.550 回答
3

就个人而言,我会从配置文件中读取它。也许是 CSV,它很容易从 Excel 导出。或者,您可以从 Excel 中复制并粘贴到纯文本中,从而为您提供以空格分隔的值,这同样易于导入。

这也意味着,鉴于您正在使用 C,您不必在每次决策表更改时重新编译代码。

于 2009-03-02T16:47:31.173 回答
3

不需要多维表。使用 4 位 => 4 位映射,您可以有一个 u8[16] 数组将输入映射到输出。状态查找会便宜得多,并且您可以使用一些移位和掩码操作来提取单个位。

如果填充行的算法易于编码,您可以#define 一个宏来按索引号填充每一行。

于 2009-03-02T17:10:21.510 回答
2

如果你的真值表都是布尔值,你可以把它折叠成一个对列表,例如

1111,0000
1110,0110
...

对于数据压缩,将值表示为字节(两个 nybbles)...

在哪里/如何存储它以在您的特定嵌入式系统配置中进行软编码,只有您可以说;-)

于 2009-03-02T17:03:38.000 回答
1

如果真值表真的只有 4x4x4x4,那么我会使用宏。如果它要超过那个,我会使用Ragel。很有可能它会比你编写更小、更快的 C 代码。

于 2009-03-02T17:10:08.110 回答
1

为了获取您的输出状态,我没有看到对当前状态的任何引用。这意味着它不是一个状态机,而只是一个真值表。有四个输入,因此只有 16 种可能的输入组合。所以,一张有 16 个位置的桌子应该可以做到。

于 2009-03-02T17:12:31.207 回答
1

通常当你遇到这样的问题时,人们会尝试将其简化为一个简单的布尔公式。我不明白为什么这不是最好的方法。它会更紧凑,更易读,而且它有可能更快(我想少数 AND 和 OR 将比查找表方法所需的乘法/移位 + 内存访问的集合执行得更快)。将此表简化为布尔公式的最简单方法是使用K-Map

于 2009-03-02T17:43:38.497 回答