Think of it like this. Any time you use a while loop your code has the rains until its done its job.
It's important to remember that the loop() function in Arduino should not be blocked. This line:
while (sensorState == 1)
will block forever. The condition is never changed from within the while loop. Theres a simple way you could fix this which would be to set sensorState and update it inside the while loop. But lets not do that. Because thats inefficient and you'll likely run into this problem again in more complex programs and that solution here won't still be a solution.
What you're trying to do is called concurrency. Your program should have obvious units of execution. Your two units are: "run a buzzer for 5 seconds" and "set off an event when a sensor reads true." where the first is depended on the second. So its conditional. That sounds like a job for if
When you code in { and } it is a block. It's not quite a context but is a distinct mode of execution.
So technically this:
void loop() {
if( ... ) {
...
}
if ( ... ) {
...
}
}
Is two modes of execution. Since loop() is executed repeatedly. With that in mind when you program you can then use a variable to control the what gets executed as needed. So:
void loop() {
int sensorState = digitalRead(lightSensor);
if( sensorState == 1 && buzzer_enabled == 0) { // set off an event when a sensor reads true.
buzzer_enabled = 1;
startTime = millis();
}
if ( buzzer_enabled == 1 ) { // run a buzzer for 5 seconds
endTime = millis();
if(stopTime - startTime <= myDesiredTime) {
runBuzzer();
} else {
buzzer_enabled = 0;
}
}
}
We could stop here. But the use of delay is also blocking in the loop function and it is only for perception. So here's the whole thing without delays using a check against the modulus of diffTime.
int lightSensor = 2;
int buzzer = 3;
long startTime,stopTime;
long myDesiredTime = 5000;
bool buzzer_enabled = false;
bool buzzer_active = false;
int sensorState;
int prevSensorState = 0;
void setup()
{
// put your setup code here, to run once:
Serial.begin(9600);
pinMode(lightSensor, INPUT);
pinMode(buzzer, OUTPUT);
}
void loop() {
sensorState = digitalRead(lightSensor);
if( sensorState == 1 && prevSensorState == 0 ) { // set off an event when a sensor reads true.
buzzer_enabled = true;
startTime = millis();
}
prevSensorState = sensorState;
if ( buzzer_enabled == true ) { // run a buzzer for 5 seconds
stopTime = millis();
long diffTime = stopTime - startTime;
if( (diffTime % 2000) < 1000 ) {
if(buzzer_active == false) {
buzzer_active = true;
//tone(buzzer, 1000);
}
} else {
if(buzzer_active == true) {
buzzer_active = false;
//noTone(buzzer);
}
}
if(diffTime > myDesiredTime) {
buzzer_enabled = false;
}
}
}
No need for delay >:3 And all for free you got a new feature which is that if you set off the event again (the light goes off) the buzzer is extended another 5 seconds. If you don't want that all you have to do is add && buzzer_enabled == false to the first if.