Alternating between 2 Outputs

I am using an Arduino Mega to alternate outputs that feed a clock pin on a 4553 IC. When the start button is pushed, the "Timer" output pin goes HIGH. This pin starts a 555 astable circuit designed for a total Time of 1 sec. It is actually a touch over 1 sec, but this project is for kids so it won't hurt. One other note, based on a previous suggestion, I am using a 1N4148 Diode across R2 on the astable so I have a Duty Cycle of approx. 22%. The thinking was to keep High(time) as low as possible compared to the total Time - just to minimize the possibility of double signals.

This project is a laser maze so if someone is good enough, they would complete the maze without blocking any lasers - the game clock would simply count at a 1-sec pace until the stop button is pressed.

BUT, if/when a laser is blocked, I have a Penalty Circuit designed to add 5 seconds to the total time. My current design uses a 0.1 sec 555 One Shot circuit feeding a second 555 astable designed to approx. 5 "highs" in the 0.1 sec from the One Shot. The Penalty astable output also feeds into the 4553 clock pin.

During the debugging process, I can get the 1-sec 555 to count great. And, if I block the laser and keep it blocked, I can watch the penalty time start running up. In fact, if I stay in the beam, the timer keeps the hyperspeed rate.

But, if I just block the laser for a split second, the penalty time is not added. I do know that the LDR is going dark, because I also have a siren circuit that sounds for 2 secs. The siren sounds for the entire 2 secs (yep, another 555 circuit) even if I run through the laser.

Here is the section of the program that I have been messing with. I only have 2 ldr's/lasers setup now so that is why I have the 3-6 commented out.

if (easyMode == 1 && startMode == 1){
     digitalWrite(timer, HIGH);
       ldr1Read = analogRead(ldr1);
       ldr2Read = analogRead(ldr2);
     //ldr3Read = analogRead(ldr3);
     //ldr4Read = analogRead(ldr4);
     // ldr5Read = analogRead(ldr5);
     // ldr6Read = analogRead(ldr6);
       if (ldr1Read > 900){
         digitalWrite(timer, LOW);
         delay(30);
         digitalWrite(penalty, HIGH);
         delay(110);
         digitalWrite(siren, HIGH);
         digitalWrite(penalty, LOW);
         digitalWrite(siren, LOW);         
         digitalWrite(timer, HIGH);
        }
    
       if (ldr2Read > 850){
         digitalWrite(timer, LOW);
         delay(30);
         digitalWrite(penalty, HIGH);
         delay(110);
         digitalWrite(siren, HIGH);
         digitalWrite(penalty, LOW);
         digitalWrite(siren, LOW);         
         digitalWrite(timer, HIGH);
        }

I have tried several ways - no delays, more delays. My thinking for using the 110 delay after the penalty is set High is to allow the penalty cycle to do its damage, but to be honest I have tried several variations and this may be the one that caused the penalty not to show up at all - would that be because the arduino is basically paused during the penalty portion?

This is my first time programming and I have only been doing it for a couple of weeks so go easy and what seems obvious to you is def. not to me.

Thanks in advance for any help provided.

I know it's not answering your question, but I'm intrigued to know why you're doing all this timing stuffin hardware. You've got an Arduino sitting there - doesn't it make sense to use your microcontroller to control whatever it is you're doing?

PeterH:
I know it's not answering your question, but I'm intrigued to know why you're doing all this timing stuffin hardware. You've got an Arduino sitting there - doesn't it make sense to use your microcontroller to control whatever it is you're doing?

It's more of an issue of me just learning the programming (just 2 weeks into owning an arduino) and being slightly more familiar with 555's. I would be willing to investigate what topics to look into if the arduino could directly feed the clock pin for my 5" 7 seg display circuit at 1-sec intervals and then switch to a quick 5 sec penalty if a laser is blocked. To be honest, I looked around the playground area and the options I found seemed a bit overwhelming and I was not even sure what I was looking at would give me what I needed.

I do realize I have an awesome tool (arduino) available to me, but I am trying to take baby steps.

You can run things in loops and the penalty comes when a count exceeds some chosen value -

the ball blocks a sensor and stays there, the program continues to run and each time through a counter is updated. When the count exceeds a certain amount that counts as an error. when the sensor clears the count is reset.

The 555 would work, but it would use an input, or inputs that you could be using for reading the switch directly.

Instead of having to do the 555 in hardware, you can now do it in software.

Look at the blink without delay example - it shows you how to toggle an output at a fixed period.

wildbill:
Look at the blink without delay example - it shows you how to toggle an output at a fixed period.

Thank you for the lead to follow. I checked out the example you suggested and I think I understand the process. In the posted example, the interval is set at 1000. That will produce a 1 second on 1 second blink, blink correct?

So, if I shamefully copy the code in the example and change the interval to 500, the timerState would then toggle back and forth every .5 seconds for a total cycle of 1 second?

If that is the case, my 1-sec 555 circuit could be retired. I could then just start the "if" statement to get the process started when the start button is pressed. Of course, that is assuming my timer output pin can feed directly to the 4553 clock pin.

But, I am not sure how to use the example to handle the penalty portion. I currently have an "if" statement to check when the ldrRead value goes above the trigger value. The length of time the ldrRead value stays above the trigger value can be quite small, but I still want a full 5 seconds added to the timer (through the same 4553 clock pin mentioned above). Other than digitally writing the timerState to LOW when that happens, I am not sure how to stop the intitial toggling loop.

Even if I assigned a separate interval (faster toggle rate) for the penalty portion, to be called when the ldrRead value goes above the target value, I am not sure how to deal with the problem of the ldrRead value spiking above the target value, then going back down. How can I keep the faster toggle rate going until the full penalty is added? Another penaltyLength interval variable?

So, if I shamefully copy the code in the example and change the interval to 500, the timerState would then toggle back and forth every .5 seconds for a total cycle of 1 second?

Yes. No shame in it though - that's what they're for.

As to the penalty, when you detect that one has been incurred, just run a for loop for the number of seconds to penalize, toggling the clock pin with the smallest delay between that you can get away with. You probably want to keep a boolean for each laser that tells whether the penalty has been triggered so that it only applies once.

OK, this is my first attempt at using the millis() feature to avoid using delays. I tried to follow the blinkwithoutdelay example, but I did change a few things - probably incorrectly.

Here is what I was thinking ...

the first part is copied right from the example with my specific variable names. If there is an error here, it is probably because I suck at typing.

If the ldrRead value triggers the "if", my thought process was/is this:

  1. Get the siren on and off at the start just to get it out of the way. This siren 555 has actually been working as planned so I just left it as is.
  2. I use a variable to grab the current time to use in the for loop (I just read the info page on the for loop so it may be a complete cluster).
  3. I have the blockInterval set at 1000, so the for loop will run until 1 sec has elapsed?
  4. During the for loop, I just copied the example again, but with a faster toggle rate.
  5. After the for loop times out, the 1-sec toggle portion will kick back in?

So let me have it - how off is my thinking ... be gentle ...

 if (easyMode == 1 && startMode == 1){
     //start the 1 sec toggle after both easy and start PB's are pressed
     unsigned long currentTimerMillis = millis();
           if(currentTimerMillis - previousTimerMillis > timerInterval) {
           // save the last time you changed the timer 
              previousTimerMillis = currentTimerMillis;   

             // if the timer is off turn it on and vice-versa:
                if (timerState == LOW)
                    timerState = HIGH;
                    else
                      timerState = LOW;
 
             // set the timer with the timerState of the variable:
           digitalWrite(timer, timerState);
           } 
     
     ldr1Read = analogRead(ldr1);
      if (ldr1Read > 900){
        digitalWrite(siren, HIGH);
        delay(10);
        digitalWrite(siren, LOW);
       
        for (unsigned long currentBlockMillis = millis();millis() - currentBlockMillis < blockInterval;)
            unsigned long currentPenaltyMillis = millis();
            if(currentPenaltyMillis - previousPenaltyMillis > penaltyInterval) {
            // save the last time you triggered the penalty 
               previousPenaltyMillis = currentPenaltyMillis; 
                  digitalWrite(timer, LOW);  //turn timer off - clear clock pin for penalty
                  delay(10);     
                      // if the penalty is off turn it on and vice-versa:
                      if (penaltyState == LOW)
                          penaltyState = HIGH;
                          else
                              penaltyState = LOW;
 
                       // set the timer with the timerState of the variable:
                      digitalWrite(penalty, penaltyState);
                 }
              }
        }