Code works when in loop by itself but not when summoned by a button press

Hey guys so I have been working on code to run a camera slider with a pan and tilt head (3 stepper motors) and I am so close to finishing it but I can’t seem to get a piece of the code to work when summoned by a button press. It works perfectly if I just place it in the loop but doesn’t when summoned by the button. When the code is working correctly it moves the motor 500 steps then pauses and outputs to the shutterPIN then moves again and this is repeated the photo int number of times which is currently set to 10. When this code gets summoned by the button it moves the motor once and then outputs to the shutterPIN but does not repeat this the designed number of times which is 10. The code is bellow, any suggestions?
I have included both the code where the [playTimeLapse()] doesn’t work when summoned by the button as well as the code where the [playTimeLapse()] works when in the void loop alone so that you can see how the [playTimeLapse()] is suppose to work. They are attachments otherwise it was too long.
Thanks in advance

Code_where_the_small_piece__playTimeLapse____doesn_t_work_when_.ino (9.06 KB)

Code_where_the_small_piece__playTimeLapse____works_in_void_loop.ino (9.05 KB)

Please post code the way told in topics like "How to use this Forum".
Helpers using smartphones can not read. ino files, so no helo from them.

As I clearly stated above I attached the code as a file because it was too long so I cannot type it in a reply. Sorry for the inconvenience.

brencar12:
As I clearly stated above I attached the code as a file because it was too long so I cannot type it in a reply. Sorry for the inconvenience.

There's a fairly small number of people that answer questions in the forums regularly. In the parts I frequent, I estimate it's a little over fifty, but that number ebbs and flows a bit.

You have a better chance of getting an answer if you can engage all those folks. Can you trim down your two examples a little so they will each just fit in a single post?

You have to start embedding Serial.print() statements to see how far it gets. For example, in read_LCD_buttons() to ensure that it get to this: return SELECT ;

Because loop() calls playTimeLapse() thousands of times, the first ten of which do anything.

The dosentwork calls playTimeLapse() once. Per button push.

At a glance.

a7

alto777:
Because loop() calls playTimeLapse() thousands of times, the first ten of which do anything.

It is in an if statement that ends after the 10 times which is the number of photos and once it ends it will never repeat until you set the number of photos again.

alto777:
The dose'nt work calls playTimeLapse() once. Per button push.

It calls this if statement which the code inside which is suppose to repeat until it has done it the 10 time which is the number of photos

6v6gt:
You have to start embedding Serial.print() statements to see how far it gets. For example, in read_LCD_buttons() to ensure that it get to this: return SELECT ;

I have embedded Serial.println() statements because that is how I know that the button is actually being pressed as well as knowing it only goes through the code in the if statement the 1 time and not 10. This is also how I know the code works when in the loop.

How many times do you see “Bye” on the serial monitor window? Looks like once per button press, right before you call playTimeLapse();

This function

void playTimeLapse()
{
  if (counter < photos)
  {
    xstepsToGo = 500;
    takeNextPhoto();
    xprevStepMicros = micros();
    counter ++;
  }
}

will only take 1 photo each time you call it. If counter < photos.

Sounds like you think it will iterate, for this a while statement would be used. It appears to iterate when called from loop() because loop runs over and over and over, the heartbeat of all Arduino sketches. But it takes ten calls to take ten photos, then the if fails with subsequent calls and it doesn’t. Take a photo.

It looks like you are intending that the code of each case in the switch after read_LCD_buttons() runs once per button press or if you hold the button down the code is repeated at 5 times a second.

What happens if just you hold the button that isn’t working down longer than a stab?

Or it’s tired and I’m getting late and something else is going on.

a7

alto777:
Or it's tired and I'm getting late and something else is going on.

So I understand why it's happening now because the button calls that if statement it runs the code and then leaves the if statement and because the button isn't pressed down anymore it leaves that as well.

alto777:
What happens if just you hold the button that isn't working down longer than a stab?

When the button is held down it runs the whole code like it is suppose to
So looks like the way I am currently doing it isn't going to work. Is there a way to have the code repeated the 10 times after the one button press?

On mobile so can't see the code but it sounds a little as though you just need to look at the StateChangeDetection example in the IDE. I.e. has the button BEEN pressed rather than is it NOW pressed.

Steve

slipstick:
On mobile so can't see the code but it sounds a little as though you just need to look at the StateChangeDetection example in the IDE. I.e. has the button BEEN pressed rather than is it NOW pressed.

The way the button state change is being detected is perfectly fine I can ensure you as the code is straight from a library. It is the way the code needs to be looped the certain number of times that's the issue. I need something that when the button gets pressed it enters the loop of the playTimeLapse() code and doesn't get out untill the playTimeLapse is repeated the set number of times which is currently set to 10 times.

Look into the difference between an if statement and a while statement.

It looks awfully like simply changing the if statement in playTimeLapse to a while statement will fix you up.

Harmless to try it.

Also, the buttons are working the way you like. OK. If you stab a button(quick press and release) you get one action. If you hold a button down, you get that action 5 times a second.

That's fine and depends on the 200 millisecond delay I saw somewhere.

This offends some people variously, but it works, works fine and does what you want. I don't arkue with success.

But there may come a day when you'll wqnt buttons to operate differently. The suggested tutorials are well worth the time when you in the mood to learn into this a bit more.

HTH

a7

alto777:
It looks awfully like simply changing the if statement in playTimeLapse to a while statement will fix you up.

I have done this

void playTimeLapse()
{
  while (counter < photos)
  {
    xstepsToGo = 500;
    takeNextPhoto();
    xprevStepMicros = micros();
    counter ++;
  }
}

After the one press of the button, the code runs 3 times (motor spins 3 times) and then gets stuck in the spot I have indicated in the code below

void takeNextPhoto()  // PERFECT NOW - USE THIS PART!!!!!!!!!
{
  startMoveTime = millis();
  
  while((millis() - startMoveTime) <= 2000)
  {
    movexMotor();
    
    Serial.println("move");
  }
  
  startPhotoTime = millis();
  Serial.println("cheese"); //Gets stuck here
  shutter();
  
  while((millis() - startPhotoTime) <= 5000)
  {
    Serial.println("wait");
  }
  
}

When the code runs properly the first 3 times “cheese” comes up once in the serial monitor per loop and then when it gets stuck “cheese” comes up in the serial monitor the remaining number of times the code needs to run. For example, the playTimeLapse code needs to run 10 times and it only runs 3 and then gets stuck and “cheese” comes up in the serial monitor 7 times in a row.

The same thing happens when I run just the playTimeLapse code in the void loop by itself except it runs the code 5 times before it gets stuck in the same spot

Yeah, so what else did you change?

The “works” version from your original post produced the desired result, but for the not for the reason you thought…

and now it doesn’t.

If the only change you made was to substitute a “while” for an “if”, the external behavior shoukd be identical (works, takes 10 frames), it would just be iterating 10 times in the first call to playTimeLapse instead of once each time playTimeLapse was called the first ten times from loop().

So either magic or you changed something else or you’ve something really weird, in all of which cases it is time to post your current version.

It is possible that you damaged your logic inadvertently when you added printing statements. Have you tried the substitution in the original “works” version you posted?

a7

I just downloaded the file I upload to the forum originally where the if statement worked in the void loop and changed the if to while and it does what I said above where it will only go through the code 5 times.

Code_where_the_small_piece__playTimeLapse____works_in_void_loop.ino (9.05 KB)

First, I can’t find the #include <LiquidCrystal_I2C.h> library you are using. I’ve been going on theory, so I haven’t needed it. Point us to it even if it is right under my nose.

Second, I can verify that you have done as you claimed, the only change is the while/if thing.

Third, this means you cornered you original problem in the wrong corner, that is to say your report is impossible (!) so even though the while / if thing was definitely a problem, it wasn’t the only problem, I think you just got lucky and uncovered another error and seized on it as the problem.

playTimeLapse failed to behave as you expected for the reasons I have described. Changing the if to a while fixes that.

Something else was (also) wrong with your code. Or I am Arnold Palmer.

Here are two sketches that also differ literally by one word. One uses “if”, the other uses “while”. Both take 10 pictures. Uncomment the Serial.println that announces the entrance into the function to see the difference in how this happens.

Please take a few minutes and try them. I happen to have a Nano EVERY hooked up, but this plain vanilla demo should be fine on any Arduino.

Structurally identical to your two versions but isolated to demonstrate the other (if/while) thing you would have gone on to (re)discover as another problem altogether.

So we’ve a mystery. Not playTimeLapse().

a7

IF

int photos;
int counter;

void setup() {
 	Serial.begin(9600);

	photos = 10;
	counter = 0;
}

void aFunction()
{
//	Serial.println("entering aFunction!");
	if (counter < photos) {
		counter++;
		Serial.print("    Taking a photo ");
		Serial.println(counter);
	}
}

int loopLimiter = 15;		// only run the loop N times 

void loop() {

	if (!--loopLimiter) while (1);		// just stalls the loop after the 15 time through

	aFunction();
}

and if you don’t trust yourself to change one statement

WHILE

int photos;
int counter;

void setup() {
 	Serial.begin(9600);

	photos = 10;
	counter = 0;
}

void aFunction()
{
//	Serial.println("entering aFunction!");
	while (counter < photos) {
		counter++;
		Serial.print("    Taking a photo ");
		Serial.println(counter);
	}
}

int loopLimiter = 15;		// only run the loop N times 

void loop() {

	if (!--loopLimiter) while (1);		// just stalls the loop after the 15 time through

	aFunction();
}

alto777:
So we've a mystery. Not playTimeLapse().

I haven't tried what you have suggested above yet but I have made a discovery that the playTimeLapse() code doesn't seem to want to run any longer than 35 seconds.
So currently the block of code that is inside the loop [takeNextPhoto()] has two delays in it, on of 2 seconds and the other of 5 totalling to 7 seconds. In this case, the code only loops 5 times and 5 times 7 seconds is 35. When the delay in the [takeNextPhoto()] code adds up to 5 seconds the code loops 7 times which is a total of 35 seconds.
So the mystery is, why doesn't it want to run any longer than 35 seconds??

A quick extra thing I just found out, I had the startMoveTime be printed in the serial monitor and it gets to 35267 milliseconds and then goes negative. I was thinking it might be an issue with my arduino board but I tested it with another board and it does the same thing

Could you mean 32767?

Sounds like you are using an int where you need a long. Somewhere.

But first, I (still!) can’t find the #include <LiquidCrystal_I2C.h> library you are using. I’ve been going on theory, so I haven’t needed it. Point us to it even if it is right under my nose.

Please?

a7

alto777:
Could you mean 32767?

That is the exact number that it stops at and switches to negative. Does that mean you know what could be the cause of it not working?
I have attached the specific library I used for the display. From memory, it was one I had to download because the common one everyone uses didn’t work with my display.

Arduino-LiquidCrystal-I2C-library-master.zip (8.96 KB)