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
条件)?
- 我需要一些延迟吗?
- 是否可以计算这些脉冲?
这是微波传感器的逻辑分析器输出:
编辑:如果我在 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.
我正在尝试计算 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
条件)? - 我需要一些延迟吗?
- 是否可以计算这些脉冲?
这是微波传感器的逻辑分析器输出:
编辑:如果我在 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.