0

我必须通过轮询 5 个不同的引脚来读取高达 20KHz 的 5 个不同频率(方波)。我只使用一个定时器中断,每 1 毫秒。引脚的轮询将在 ISR 中完成。

到目前为止我想到的算法是:1.Count HIGH 2.Count LOW 3.检查 HIGH+LOW 的总和是否=时间段。这个算法看起来很慢,不实用。

是否有任何过滤器函数可用于检查 pin 处的频率,以便我所要做的就是调用该函数?用于频率检测的任何其他算法都会很好。

我的代码中仅限于 1 个中断(定时器中断)

4

1 回答 1

0

你需要记住输入信号的属性是什么

  • 因为您仅限于单个中断(这很奇怪)
  • 定时器只有 1 KHz
  • 输入信号不得高于 0.5 KHz
  • 如果信号带有噪声,则频率很容易多次超过该限制

速度

  • 您写道,简单的计数期方法很慢
  • 你有什么CPU和IO能力?
  • 我习惯了 Atmel AVR32 AT32UC3 芯片,这是 ARM 皮质芯片之前的 2 代
  • 我有大约 96MIPS 和 2-5 MHz 引脚 R/W 频率,没有 DMA 或中断
  • 那么这种方法到底有什么慢呢?

我会像这样使用您的约束对其进行编码(它只是不使用您的平台的 C++ 伪代码):

const int n=5;
volatile int T[n],t[n],s[n],r[n]; // T last measured period,t counter,s what edge is waitng for?
int T0[n]={?,?,?,...?}; // periods to compare with

void main() // main process
 {
 int i;
 for (i=0;i<n;i++) { T[i]=0; t[i]=0; s[i]=0; r[i]=0; }
 // config pins
 // config and start timer
 for (;;) // inf loop
  {
  for (i=0;i<n;i++)            // test all pins
   if (r[i]>=2)                 // ignore not fully measured pins
    {
    r[i]=2;
    if (abs(T[i]-T[0])>1)     // compare +/- 1T of timer can use even bigger number then 1
     // frequency of pin(i) is not as it should be
    }
  }
 }

void ISR_timer() // timer interrupt
 {
 // test_out_pin=H
 int i;
 bool p;
 for (i=0;i<n;i++)
  {
  p=get_pin_state(i);                                // just read pin as true/false H/L
  t[i]++;                                             // inc period counter
  if (s[i]==0){ if ( p) s[i]=1; }                   // edge L->H
  else         { if (!p) s[i]=0; T[i]=t[i]; t=0; r[i]++; } // edge H->L
  } 
 // test_out_pin=L
 }
  • 您还可以扫描最后一个引脚状态和实际之间的比较
  • 这将消除需要s[]
  • 就像是p0=p1; p1=get_pin_state(i); if ((p1)&&(p0!=p1)) { T[i]=t[i]; t[i]=0; }
  • 这样您还可以更轻松地实现 SW 毛刺滤波器
  • 但我认为他的 MCU 也应该有硬件过滤器(就像大多数 MCU 一样)

如果没有您奇怪的限制,我将如何做到这一点?

  • 我会使用外部中断
  • 通常它们可以配置为在信号的特定边沿触发
  • 还包括噪声的硬件过滤
  • 在每个中断上取内部 CPU 时钟计数器值
  • 如果它不可用,则计时器/计数器状态
  • 减去最后一个测量的
  • 如果发生溢出则从溢出中恢复
  • 更改为sHz如果需要
  • 通过这种方式,我可以使用 30MHz 时钟可靠地扫描 MCU 上的引脚,频率高达 15MHz(将其用于 IRC 解码器)
  • 是的,IRC 有时可以为您提供高于 1 MHz 的频率(在州之间的边缘)
  • 如果你也想要这个比例,你可以:
  • 有 2 个中断,一个用于上升沿,第二个用于下降沿
  • 或者只使用一个并在每次命中后重新配置边缘(我前一段时间使用的 Atmel UC3L 芯片由于内部错误而对这个有问题)

[笔记]

  • 您访问的引脚必须位于同一个 IO 端口
  • 这样您就可以一次全部阅读它们,然后在之后解码引脚
  • GPIO模块通常也是可配置的,所以检查它是用什么时钟供电的
  • 通常有 2 个时钟,一个用于将 GPIO 模块与 CPU 内核连接
  • 第二个用于 GPIO 本身,因此请同时检查
  • 您也可以使用 DMA 代替外部中断
  • 如果您可以配置为通过 DMA 读取 IO 端口...到某处的内存
  • 然后您可以检查独立于 IO 的后台进程
于 2015-06-17T07:34:39.770 回答