所以我重写了我的代码。当我按下连接在引脚 2 上的按钮时,引脚 13 会变为高电平,并通过收发器向接收器发送信号(收发器和接收器的类型无关)。我将一根电线从接收器(其中引脚 13 使其变为高电平)连接到 arduino 上的引脚 7。我还将 LED 连接到引脚 8,以指示引脚 7 何时处于高电平。
我的主要关注点是计算从按下按钮到 Arduino 上的引脚 7 变为高电平所需的时间。我正在使用 Arduino Leonardo(也是不相关的信息)。
这是我的代码:
int buttonState;
int buttonPin = 2;
int LbuttonState; // last button state
int pin13 = 13;
int pin7state;
int pin7 = 7;
int Lpin7state; // last pin 7 state
int pin8 = 8;
long startTimeKeeper;
long endTimeKeeper;
long elapsedTime;
void setup() {
Serial.begin(9600);
pinMode(buttonPin, INPUT);
pinMode(pin13, OUTPUT);
pinMode(pin7, INPUT);
pinMode(pin8, OUTPUT);
}
void loop() {
buttonState = digitalRead(buttonPin);
if(buttonState == HIGH && LbuttonState == LOW) {
startTime(); // start the time
digitalWrite(pin13, HIGH);
LbuttonState = buttonState;
} else if(buttonState == HIGH && LbuttonState == LOW) {
digitalWrite(pin13, LOW);
} else if(buttonState == LOW && LbuttonState == HIGH) {
digitalWrite(pin13, LOW);
LbuttonState = buttonState;
} else//(buttonState == LOW && LbuttonState == LOW)
digitalWrite(pin13, LOW);
pin7state = digitalRead(pin7);
if(pin7state == HIGH && Lpin7state == LOW) {
stopTime(); // stop the time
digitalWrite(pin8, HIGH);
Lpin7state = pin7state;
} else if(pin7state == HIGH && Lpin7state == HIGH) {
digitalWrite(pin8, HIGH);
} else if(pin7state == LOW && Lpin7state == HIGH) {
digitalWrite(pin8, LOW);
Lpin7state = pin7state;
} else//(pin7state == LOW && Lpin7state == LOW)
digitalWrite(pin8, LOW);
}
void startTime() {
startTimeKeeper = millis();
}
void stopTime() {
endTimeKeeper = millis();`enter code here`
elapsedTime = endTimeKeeper - startTimeKeeper;
Serial.print(elapsedTime);
}
最佳答案
我建议使用 interrupts ,特别是因为 Leonardo 支持在您选择的两个引脚的状态更改时触发中断。
如果我正确理解问题的核心,您需要从引脚 2 上的按钮按下的下降沿(高到低)到引脚 7 上的上升沿(低到高)之间耗时。如果我误解了并且您的按钮实际上是高电平有效,只需将 attachInterrupt(interrupt, ISR, mode)
的最终参数更改为 RISING
。
这些设置完成后,只要指定的状态或状态发生变化,就会调用我们指定的中断服务例程(ISR)函数。我们希望在这些 ISR 中做最少的工作,因为当其中一个 ISR 运行时,无法触发其他 ISR。记录开始或停止时间就可以了。
但是,中断不能直接使用 millis()
或 micros()
,因为这些函数本身就使用中断。为了解决这个限制,我们将在每个 ISR 中切换我们自己的一个简单标志——以指示它已被触发——然后在主循环中轮询该标志值,我们将在主循环中启动/停止计时器行动。我添加了 micros()
以获得更高的准确性,因为按下按钮和收到信号之间的时间应该很短(无论如何,永远不会是分钟的数量级)。
#define ULONG_MAX 0xFFFFFFFFUL
unsigned long startTimeKeeper, stopTimeKeeper, elapsedTime;
volatile boolean buttonFlag = false, signalFlag = false;
void setup() {
Serial.begin(9600);
pinMode(2, INPUT);
pinMode(7, INPUT);
pinMode(13, OUTPUT);
pinMode(8, OUTPUT);
// Int.2 corresponds to pin 2
attachInterrupt(2, buttonPressed, FALLING);
// Int.4 corresponds to pin 7
attachInterrupt(4, signalReceived, RISING);
}
void loop() {
// Loop until the buttonPressed ISR sets this flag
if (buttonFlag) {
// Record the start time
startTimeKeeper = micros();
// Do nothing until the signal flag is set by the ISR
while (!signalFlag);
// Record the end time
stopTimeKeeper = micros();
// Normal case - stop time is apparently after start time
if (stopTimeKeeper > startTimeKeeper)
elapsedTime = stopTimeKeeper - startTimeKeeper;
// Overflow case - stop time is apparently before start time
else
elapsedTime = stopTimeKeeper + (ULONG_MAX - startTimeKeeper);
Serial.print(elapsedTime);
signalFlag = buttonFlag = false;
}
}
// Very lightweight ISRs
void buttonPressed() {
buttonFlag = true;
}
void signalReceived() {
signalFlag = true;
}
由于我们在注册按钮按下后立即开始等待 signalReceived()
ISR 激活 signalFlag
,因此我们不必太担心去抖在这种情况下切换。
一般来说,您需要使用物理电路或软件计数器来消除开关的抖动。查看this tutorial要开始使用软件,或查看 here有关构建去抖电路的信息。
关于计算信号时间,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26712701/