【问题标题】:Best practice to detect two simultaneous signals on two input pins在两个输入引脚上检测两个同时信号的最佳实践
【发布时间】:2011-08-26 06:40:58
【问题描述】:

我需要执行以下操作:我在微控制器上有 2 个输入引脚,并且有可能在一个或另一个上接收到信号,但也有可能这两个将在外部物理连接, 信号同时到达。

问题:如果我使用类似的东西

if (PINB.1 && PINB.2)
{
  // ...
}

有百万分之一的机会,信号在两个值被加载到寄存器以执行逻辑与运算之间到达。当我离开if时,两个引脚都是高电平,但我仍然检测到只有第二个引脚是高电平。

我尝试了不同的解决方案,到目前为止,最好的方法似乎是在任何一个输入为高时开始一个非常短的倒计时,并且当计时器(最多几毫秒)耗尽时,我再次检查。

有人知道更简单或更好的解决方案吗?我认为这个问题很常见,但到目前为止我找不到任何“经过验证的”方法。

编辑:我从硬件上知道,在一个边缘之后,引脚将保持其值至少几十毫秒。噪音已经处理好了。

PINB.1 和 PINB.2 只是示例。它们可能位于不同的端口上,因此对整个端口进行位掩码可能会带来不够灵活的风险。

【问题讨论】:

  • 您到底在关注什么情况?您是否只想响应任一引脚上的每个上升沿?
  • 我必须注意很多不同的条件(边沿、特定时隙中的信号数量、信号长度等),但我从硬件中知道,在上升沿之后pin 将在合理的时间内保持高电平:至少几十毫秒。
  • 您问题中的if 在寻找什么条件?
  • 可以更换硬件吗?输入端口是否在同一个寄存器中?最好的解决方案是将所有输入放在 PIN 中,以便共享相同的 I/O 寄存器,也就是说,当您读取寄存器时,您将同时读取所有输入。要测试输入,简单的 OR/AND 掩码将解决您的所有问题。再想一想,我真的怀疑您的微控制器速度如此之慢会干扰结果。你说输入信号已经被毫秒阻尼了,哪种处理器会花这么多时间来做一对比较指令???

标签: c concurrency embedded polling


【解决方案1】:

您已经回答了自己的问题:只需使用计时器并再次检查引脚,这是您可以使用的最简单的数字滤波器形式。但是当您检测到引脚电平变化时,您必须启动定时器。如果您有一个非常陡峭的上升沿,即引脚连接到某个数字 IC,那么只需读取两次引脚甚至可能就足够了,具体取决于您的 CPU 时钟与上升沿相比有多快。

如果 MCU 具有此功能,另一种解决方案是使用边缘敏感中断。然后,您可以保证在更改后立即读取引脚。每个引脚都有一个中断,您的程序可以存储引脚的最新值以进行 == 比较。您必须确保在中断和“主”之间使用信号量保护这些值,否则您将回到开始的地方。

【讨论】:

    【解决方案2】:

    当它们都被断言时,你想寻找条件吗?如果是这样,只需对它们进行采样,如果两者都没有断言,则不要打扰。如果这是一个中断事件并且您可能正在使用 C 代码?即使汇编程序只是采样了两三次,如果中断后两者都没有断言,那么这是一个错误的交易并忽略它。

    如果您将这些视为两个独立的事件,并担心您读取端口的次数很少,并且它们都被断言。您可能应该已经将读取端口和处理您发现的内容分开了。如果位 0 则读取端口,然后执行位 1 的内容(从存储的值而不是重新读取端口)然后执行位 1 的内容。

    除了“做你的系统工程”(因为使用类似硬件的不同行业的设计目标不同)之外,没有什么是最佳实践。所有这些问题和解决方案都包含在系统工程中。您的系统工程将准确地告诉您您所关心的事件的余量是多少,并了解控制器/处理器的属性,您知道中断系统在使用时如何响应,或者您的执行和采样率是多少,以了解微控制器的属性与所讨论的事件有关。我愿意打赌快速执行并保存两次读取,然后说如果这些读取中的任何一个都断言了两个位,则声明事件已经发生。您应该已经根据预期/设计的信号对输入进行过采样,因此您可能会丢弃处于输入状态变化边缘的样本。

    【讨论】:

    • +1 表示“做你的系统工程”。如果不确切知道您的系统限制是什么,这个问题是无法回答的。也就是说,鉴于您描述的时间,我想这不是问题。与连接到同一源的 2 个引脚可能给出不同读数的窗口相比,“几毫秒”是永恒的。如果您错过了“检测事件”,因为您碰巧在一次通过此代码时点击了该窗口,那么只要您在下一次通过时检测到它就可以了。
    【解决方案3】:

    我认为你是在追鬼,或者你没有很好地说明你的问题。

    例如,假设您在位测试之间设置了一个 1 毫秒的计时器 - 您所做的只是为比赛“移动杆”。如果在 1 ms 计时器到期后第二个位在 1 皮秒变高,那么让代码表现得好像只设置了一个位是否可以?如果是这样,您为什么希望该行为与当前代码的行为不同。

    这并不是说它不正确,只是如果这是您的断言,您应该理解为什么会这样。这完全取决于问题所在。

    【讨论】:

    • 这就是为什么我说我只需要在两条输入线物理焊接在一起时处理同时信号。这意味着唯一的问题是我的if 中的条件不是原子的,因此在评估条件时可能会发生信号到达。如果我在引脚为高电平后稍微延迟检查条件,我可以确定两者都设置正确。
    • 需要注意的一点是,如果您将引脚连接到单独的输入端,但它们恰好同时处于高电平(或足够接近同一时间),请不要上当。在一般情况下,这不是一个容易解决的问题,但您的情况可能具有某些特性,可以在某些方面使其更容易或减少问题。
    • 如果由于晶体管开关时间的微小差异而在一个端口上更快地检测到同时信号,那么这个小计时器对于极其罕见的情况很有用,但更常见的是出现错误,因为条件不是原子的。
    • @vsz:我想我想说的是,您需要非常明确地定义“同时”的含义,并且应该知道如果输入连接到不同的信号可能会发生什么但两者都是“同时”断言的。这可能没问题,但你应该考虑到这种意外情况。
    【解决方案4】:

    为避免难以重复的错误,嵌入式固件应遵循以下架构:

    1. 输入读取和缓冲
    2. 从缓冲输入计算缓冲输出
    3. 缓冲输出写入

    换句话说,您正在从一个连续的时域转移到一个离散的时域。这就像精心制作真实连续世界的快照。如果不这样做,您最终会得到输入信号,这些信号在计算过程中会发生变化,产生不可预测和不可重复的结果。

    话虽如此,如果您阅读[0 1][1 0],那是后续计算的输入。您将在下次运行时看到 [1 1]

    即使您将相同的信号连接到同一端口的两个引脚,您也不能确定对[1 1] 进行采样:存在硬件公差,这使得它不可能。

    【讨论】:

    • 这些硬件容差(以及不以原子方式处理条件的更大问题)使我使用了那么小的延迟。我意识到这些问题,我只是在寻找更好/更优雅的解决方案。
    【解决方案5】:

    在现实世界中,很少有两个输入“同时”变化。如果您知道两个输入将在彼此的几个指令时间内激活,或者在彼此附近的任何地方都不会激活,您可以执行以下操作:

    如果(输入1) { 如果(输入 2 || 输入 2 || 输入 2 || 输入 2) 处理双输入(); 别的 handle_input_1_only(); } 否则如果(输入2) { 如果(输入 1 || 输入 1 || 输入 1 || 输入 1) 处理双输入(); 别的 handle_input_2_only(); }

    INPUT1 和 INPUT2 都应该是定义的宏,它们使用 volatile 限定符来确保实际轮询输入而不是缓存输入。当检测到一个输入时,“if”测试中的重复项应该允许另一个输入也有时间切换。所需的重复次数可能会因最大输入偏差和控制器的执行速度而异。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-04-11
      • 2013-06-17
      • 2020-03-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多