Go Down

### Topic: Loop problem (Read 549 times)previous topic - next topic

#### nahuelv

##### Jun 12, 2012, 07:32 pm
Hi, I need to control a electrostatic deflector that has a TTL input. I need to send a some number of pulses and the rest of the time the signal must be in HIGH. I want to decide when are going to start my pulses pushing a button, the code is pretty easy but I dont understand why it doesn't made the number of pulses of I write in the for sentence, always send more. The idea is: press the button "play" the pulses and keep in high until the button is pressed again.
Thanks
Code: [Select]
` void loop(){   buttonState = digitalRead(buttonPin);    if (buttonState == HIGH) {            for (int i=0; i <= numberOfPulses; i++){        // set the LED on      delay(10);                    digitalWrite(13, LOW);        delay(10);      digitalWrite(13, HIGH);         }        }  else {       digitalWrite(ledPin, HIGH);   delay(100);  }} `

#### Arrch

#1
##### Jun 12, 2012, 07:39 pm
It sounds like you're problem is that the loop finished before you release the button, so it goes into another loop. Your best bet is to use signal edge detection to detect the instance when the button is being pushed down or released. To do that, you need to keep track of the last state of the button. If the last state was LOW and the current state is HIGH, then the button was just pushed down.

#2
##### Jun 12, 2012, 07:39 pmLast Edit: Jun 12, 2012, 07:41 pm by jraskell Reason: 1
loop is going to execute very fast.  Depending on which block of the if statement gets executed, at least 10 times a second and up to 50 times a second.  In the case of you pushing the button, it's getting executed 5 times a second, so if you hold the button down for longer than about 20ms, it's going to execute that block of code multiple time, and thus send out more pulses.

What you need is some one shot logic.  Keep track of both the previous button state and the current button state, and only execute the block of code when the previous state was low, and the current state is high (so basically creating a rising edge trigger).

To do that, add a second buttonstate variable to your code and name it previousbuttonstate.  Rename your current variable to currentbuttonstate.

Change your if condition to (currentbuttonstate == HIGH && previousbuttonstate == low).

Then at the end of your loop, set previousbuttonstate to currentbuttonstate.

Word of warning though, if you have any bounce in your button, you may still see undesirable pulses, in which case you'll either have to implement some debounce code, or add some debounce circuitry.

#### majenko

#3
##### Jun 12, 2012, 08:09 pmLast Edit: Jun 12, 2012, 08:11 pm by majenko Reason: 1
A simple little cheat way is to wait for button release, then wait for button press at the start of your code:

Code: [Select]
`void loop(){  digitalWrite(ledPin,HIGH); // Set the idle state   while(digitalRead(buttonPin)==HIGH); // Wait for a release, if it is pressed.  while(digitalRead(buttonPin)==LOW); // Wait for button to be pressed.  for (int i=0; i <= numberOfPulses; i++)  {    // set the LED on    delay(10);                  digitalWrite(ledPin, LOW);       delay(10);    digitalWrite(ledPin, HIGH);  }}`

Of course, this doesn't fit well with a state machine if you ever want to expand your code to do other things.  If this is all it will do then this method is fine.

#### nahuelv

#4
##### Jun 13, 2012, 12:53 am
You are AWESOME, I love this forum!

Go Up