如何在 Arduino 循环中运行一次状态机

问题描述

我正在尝试使用两个螺线管拍摄水滴碰撞。我使用一个螺线管成功地做到了这一点。这使用了代码中的设置延迟来为相机快门、水滴和闪光灯计时。我想以相同的延迟同时触发两个螺线管,但不确定如何执行此操作。

操作顺序应该是

  1. 打开相机快门(相机处于灯泡模式)
  2. 同时从两个螺线管中滴下两滴水。
  3. 闪光
  4. 关闭相机快门

我的平台是 Atmega 2560。这是我目前拥有的代码

int relayCam=A0;  //pin to relay to trigger camera
int relayFlash=A7 ;  //pin to relay to fire flash
int button1Read;
//button read delays (settling time)
int button1DT=250;
int button1Pin=8;  //pin for 2 drop button read
int DelayCamOpen=100;  //wait time to trigger camera
int DelayCamClose=1000;  //wait time to close camera shutter
//Drop start
int DropStart=500;  //time to start first drop
//Flash timing
int DelayFlashFire1=350;
int DelayFlashOff=50;  //turn flash off

bool runOnce = false;

class Solenoid
{
 int SolenoidPin;
 long OnTime;
 long OffTime;
 int SolenoidState;
 unsigned long prevIoUsMillis;
  
public:
Solenoid(int pin,long on,long off)
{
SolenoidPin = pin;
pinMode(SolenoidPin,OUTPUT);
OnTime = on;
OffTime = off;
SolenoidState = HIGH;
prevIoUsMillis = 0;
}
void update()
{
unsigned long currentMillis = millis();
if((SolenoidState == HIGH) && (currentMillis - prevIoUsMillis >= OnTime))
{
SolenoidState = HIGH;
prevIoUsMillis = currentMillis;
digitalWrite(SolenoidPin,SolenoidState);  
}
else if ((SolenoidState == LOW) && (currentMillis - prevIoUsMillis >= OffTime))
{
SolenoidState = LOW;
prevIoUsMillis = currentMillis;
digitalWrite(SolenoidPin,SolenoidState);  
}
}
};

Solenoid drop1(A1,55,55);
Solenoid drop2(A2,55);

void setup()
{
pinMode(relayCam,OUTPUT);
pinMode(relayFlash,OUTPUT);
pinMode(button1Pin,INPUT);
}
void loop()
{
//This part works
button1Read=digitalRead(button1Pin);
delay (button1DT);
if(button1Read==0) {
delay (DelayCamOpen);  //wait time after button is pushed to start sequence
digitalWrite (relayCam,LOW);  //opens the camera shutter
delay (DropStart);  //wait time after shutter opens ro start first drop
//This part does not execute
if (runOnce == false)
{runOnce = true;
drop1.update();
drop2.update();
}
//This part works
delay (DelayFlashFire1);  //wait time to fire flash
digitalWrite (relayFlash,LOW);  //fire flash
delay (DelayFlashOff);  //time to keep flash open (very short time)
digitalWrite (relayFlash,HIGH);  //close flash relay
delay  (DelayCamClose);  //wait time to close camera shutter
digitalWrite (relayCam,HIGH);  //close camera shutter
} 
else if(button1Read==1) 
{
 digitalWrite (drop1,HIGH);  //no signal to waterdrop
 digitalWrite (drop2,HIGH);  //no signal to waterdrop
 digitalWrite (relayCam,HIGH);  //no signal to camera
 digitalWrite (relayFlash,HIGH);  //no signal to flash
}
}

相机和闪光灯部分工作正常,但螺线管不工作。我不确定我是否正确地解决了这个问题。我确实知道延迟运行两个螺线管并没有给我想要的结果,因此尝试使用状态机方法。非常感谢任何帮助/建议。我是编写代码和 Arduino 的新手。

这是与一个螺线管一起工作的代码

//Pin assignments
int relayCam=A0;  //pin to relay to trigger camera
int relayFlash=A7 ;  //pin to relay to fire flash
int relayWD1=A1;  //pin to relay to trigger water drop 1
int button1Read;
//button read delays (settling time)
int button1DT=250;

int button1Pin=8;  //pin for 2 drop button read
//drop sizes
int dropSize1=55;  //time to hold relay for 1st drop
int dropSize2=45;  //time to hold relay for 2nd drop

//delays betwween drops
int Delay1=45;  //time between 1st and 2nd drops
//camera shutter timings
int DelayCamOpen=100;  //wait time to trigger camera
int DelayCamClose=1000;  //wait time to close camera shutter
//Drop start
int DropStart=500;  //time to start first drop
//Flash timing
int DelayFlashFire1=350;
int DelayFlashOff=50;  //turn flash off

void setup() {
pinMode(relayCam,OUTPUT);  
pinMode(relayWD1,INPUT);
}

void loop() {
button1Read=digitalRead(button1Pin);
delay (button1DT);
if(button1Read==0) {
delay (DelayCamOpen);  //wait time after button is pushed to start sequence
digitalWrite (relayCam,LOW);  //opens the camera shutter
delay (DropStart);  //wait time after shutter opens ro start first drop  
  
digitalWrite (relayWD1,LOW);  //starts first drop
delay (dropSize1);  //duration of water flow
digitalWrite (relayWD1,HIGH);  //stops first drop
  
delay (Delay1);  //wait time for second drop to start
  
digitalWrite (relayWD1,LOW);  //start of second drop
delay (dropSize2);  //duration of waterflow
digitalWrite (relayWD1,HIGH);  //stops second drop

delay (DelayFlashFire1);  //wait time to fire flash
digitalWrite (relayFlash,HIGH);  //close camera shutter
} 
else if(button1Read==1) 
{digitalWrite (relayWD1,HIGH);  //no signal to flash
}
}

解决方法

你的 update() 方法所代表的抽象对我来说是折磨和困惑。我的建议是用两个方法 update()startDrop() 替换 stopDrop()startDrop() 记录一个 startTimestamp(就像您对 currentMillis 所做的那样,但是是一个类成员变量)并打开电磁阀。 stopDrop() 比较经过的时间,如果时间不够且电磁阀保持打开,则返回 false;如果时间足够长且电磁阀关闭,则返回 true。

class Solenoid
{
  ...
  
  private unsigned long startTimestamp;

  void startDrop()
  {
    startTimestamp = millis();
    digitalWrite(SolenoidPin,LOW);  
  }
  
  bool stopDrop()
  {
    if ((millis() - startTimestamp) >= OffTime)
    {
      digitalWrite(SolenoidPin,HIGH);
      return true;
    }
    return false;
  }
  
  ...
}


void loop()
{
  ...
  
  drop1.startDrop();
  drop2.startDrop();
  while (drop1.stopDrop() == false);
  while (drop2.stopDrop() == false);
  
  ...
}

这只是一个草稿。您可能需要添加一些错误检查以确保例如电磁阀在 startDrop() 之前关闭或 startDrop()stopDrop() 之前被调用。