CPU Arduino uno 中用于数字读取和计数脉冲的周期

CPU cycles in Arduino uno for Digital read and counting pulses

我正在尝试计算 200ms 时间量内的 HB100 microwave sensor 脉冲数。

代码如下:

#include <SoftwareSerial.h>
#include <elapsedMillis.h>
elapsedMillis ElapsedTime;

#define Sensor A0
#define TimeQuanta 200

int Counter = 0;
boolean LastState;

void setup()
{
  Serial.begin(250000);
  pinMode(Sensor, INPUT);  
}

void loop()
{
  Counter = 0;
  ElapsedTime = 0;
  while (ElapsedTime < TimeQuanta ){
    LastState = digitalRead(Sensor);
    if (LastState == LOW && digitalRead(Sensor) == HIGH ){
      Counter += 1;  //Compare Last state with current state 
    }
  }
  Serial.print(digitalRead(Sensor));
  Serial.print("\t");
  Serial.println(Counter);
}

我需要知道数字读取周期。 我正在将传感器的最后状态与当前状态进行比较,如果进行了更改(从低到高),则计数器会增加。但是,我的计数器总是 0!

这是微波传感器逻辑分析器输出:


编辑:如果我在 if 之前添加 delay(1);,则计数器不再为 0。

由于这些脉冲似乎比微秒更短,所以您不能使用需要大约 80 个机器周期(大约 5us @16MHz)的 digitalRead 函数。

更不用说在每个循环迭代中打印这么多数据了!!!!

所以你的频率超过 1MHz,你的代码可能能够计算出大约 10kHz(最多,可能更少)

无论如何,您应该在 T1 输入上使用带有时钟源的 HW Timer/Counter 1。这个能够以主时钟速率的一半(50% 脉冲宽度)计算脉冲

使用 Timer/Counter 1 非常简单:

TCCR1A = 0; // default mode, no output compare modes
TCCR1B = _BV(CS10) | _BV(CS11) | _BV(CS12); // clock select mode 7 - External clock source on T1 pin. Clock on rising edge.

并且每 200 毫秒只读取 TCNT1 并最终重置为 0 或者只记住最后一个值并有所不同(不要忘记它只是 16b 数字)。

KIIV 很好地解释了为什么您的代码不起作用,在这里我想建议一种实现相同目标的替代方法。


代码:

const byte interruptPin = 2;
volatile unsigned long counter = 0;                // overflow after 2^32-1 pulses

void setup() {
  pinMode(interruptPin, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(interruptPin), count, RISING);
  Serial.begin(19200);
}

void loop() {
  Serial.print("No. pulses: ");
  Serial.println(counter);
  delay(1000);
}

void count() {
  counter++;                                       // never use print() in an ISR!
}

请注意我更改了输入引脚,因为引脚上有一些restrictions可以用于此技术,具体取决于您使用的电路板:

Board                                Digital Pins Usable For Interrupts
Uno, Nano, Mini, other               2, 3
Mega, Mega2560, MegaADK              2, 3, 18, 19, 20, 21
Micro, Leonardo, other 32u4-based    0, 1, 2, 3, 7
Zero                                 all digital pins, except 4
MKR1000 Rev.1                        0, 1, 4, 5, 6, 7, 8, 9, A1, A2
Due, 101                             all digital pins

您可以使用 timer1 来计算经过的时间。

// Set Timer1 without prescaler at CPU frequency
TCCR1A = 0; // TCCRx - Timer/Counter Control Register. The pre-scaler can be configured here. 
TCCR1B = 1;

noInterrupts ();  // Disable interrupts.

uint16_t  StartTime = TCNT1;  // TCNTx - Timer/Counter Register. The actual timer value is stored here.
digitalRead(pin); // your code.
uint16_t EndTime = TCNT1
uint16_t ElapsedTime = EndTime - StartTime;

interrupts (); //Enable interrupts.

作为第二种解决方案,您可以设置和取消设置引脚并使用逻辑分析仪计算时间。

DDRD = DDRD | B10000000; // Set digital pin 7 as output.
PORTD = PORTD | B10000000; // Set digital pin 7.
digitalRead(pin); // your code.
PORTD = PORTD & B01111111; // Unset digital pin 7.