PDA

View Full Version : FOR...NEXT strange counting



flotulopex
- 7th October 2006, 16:58
Hello,

I can't figure out how the FOR...NEXT count works.

First my code, then my question.



...
Duty VAR BYTE
Duty = 0

if duty = 0 then
FOR Duty = 0 TO 254
HPWM 1, Duty, 1000
lcdout Dec Duty 'First read of "Duty"
PAUSE 5
NEXT
lcdout Dec Duty 'Second read of "Duty"
endif
...


At the end of the FOR...NEXT execution, first read of Duty = 254. Right after the "NEXT" command, the second read of the variable Duty = 255.

Why is this!?

mister_e
- 7th October 2006, 17:32
Increse PAUSE 5 to PAUSE 500, it counts perfectly.
Why you have 255 on the second LCDOUT?



1 FOR Duty = 0 TO 254
2 HPWM 1, Duty, 1000
3 lcdout Dec Duty 'First read of "Duty"
4 PAUSE 500
5 NEXT
Incrementation of Duty variable is done @ line #5, The condition to exit the for-next loop is done @ line #1. If >254, exit the loop. 255>254?

flotulopex
- 7th October 2006, 18:58
I'm using this routine to switch ON the backlight of my LCD display, gradually but quite quickly (around 1 second). If I "PAUSE 500", it will takes ages to have the backlight fully on.

As stated in the MicroCode help file, the max "duty" value can be 255. If I want to have the backlight fully ON, I should have 255.

If the condition is "FOR Duty = 0 to 255", Duty will turn back to value 0 (zero) after the "NEXT" since it has been declared as a BYTE variable.

Maybe, the best thing to do is to declare Duty as WORD sized...

Nevertheless, the strange thing is that the Duty variable gets incremented by 1 when it exists the FOR...NEXT cycle.

Darrel Taylor
- 8th October 2006, 09:10
Hi flotul,

It won't matter that the Duty variable ends up at 0 when it wraps around. The HPWM will stay at the last DutyCycle it was set to "Inside" the FOR/Next loop. So you can go the full 0-255.

It appears that you are using the "if duty = 0 then" statement to make the backlight only ramp-up once, when power is applied. Which also means that you have this section of code within the Main Loop of the program.

If you take it out of the main loop and put it up at the top of the program, that section of code will only run once.
<br>

flotulopex
- 8th October 2006, 10:45
I have my LCD-backlight controlled with two buttons; this is why it is in the main loop.

The HPWM command accepts the duty value from 0 to 255.

Actually, when the FOR...NEXT cycle is completed with a count up to 255, the value "wraps" from 255 to 0.

But I track this value to prevent a second press on the same button (it's not nice to see the backlight switched OFF instantaneously and dimm up again when it was already ON - looks like a bug to the user).

To get the HPWM at full range, I would count from 0 to 254 in the FOR...NEXT cycle and, when completed, add one more command to set the duty value to 255. This is not very "clean".

Actually I found another way around. I use REPEAT...UNTIL. Now it works.

I was just suprised to see how the FOR...NEXT cycle affects the count.

Ioannis
- 9th October 2006, 20:10
Since the for-next loop counting from 0 to 255 and the HPWM is inside the loop, where is the problem? At the end HPWM will be at 100% (255), the for-next will wrap to 0 since you have byte variable ant the loop will exit.

Thats how a for-next works in the first place. Always exits when variable will pass the upper limit.

Did I miss anything?

Ioannis

flotulopex
- 10th October 2006, 22:06
I need to get a "HPWM 1, 255, 1000" final command with a Duty value of 255.


...
Duty VAR BYTE
Duty = 0

FOR Duty = 0 TO 255
HPWM 1, Duty, 1000
LCDOUT $FE, 2, DEC Duty 'First read of Duty
NEXT
LCDOUT $FE, $C0, DEC Duty 'Second read of Duty
...

When this FOR...NEXT loop is completed, the HPWM command will be correct ("HPWM 1, 255, 1000" - see first read of Duty) BUT Duty's value will be 0 (see second read of Duty).

Even if the count is completed (Duty has reached 255), passing the last NEXT command will increment Duty by 1 and make it a 0.

This is what happens with my 16F88 programmed with PBP. I never expected such a result.

In my program, I use Duty as a reference to check if my LCD-backlight is fully OFF (Duty = 0) or if it is fully ON (Duty = 255).

If Duty is 0, I'm allowed to press only button 'A'; if Duty's value is 255, I'm allowed to press only button 'B'.

In other words, if Duty is 0, I don't want to allow a second press on button 'A'; I will only accept button 'B' and vice-versa if Duty is 255.

The solution I found now is this one:


...
SUBROUTINE:
REPEAT
Duty = Duty + 1
HPWM 1, Duty, 1000
UNTIL Duty = 255
RETURN
...

keithdoxey
- 10th October 2006, 22:19
Alternatively you could add the following line

FOR Duty = 0 TO 255
HPWM 1, Duty, 1000
LCDOUT $FE, 2, DEC Duty 'First read of Duty
NEXT
Duty = Duty-1
LCDOUT $FE, $C0, DEC Duty 'Second read of Duty

Which would put it back the the final value inside the For/Next loop

If you are also dimming down then do the opposite

FOR Duty = 255 TO 0 STEP -1
HPWM 1, Duty, 1000
LCDOUT $FE, 2, DEC Duty 'First read of Duty
NEXT
Duty = Duty+1
LCDOUT $FE, $C0, DEC Duty 'Second read of Duty

flotulopex
- 11th October 2006, 14:12
Thank you keithdoxey,

It is not about to find a solution to make it work; it is about how the FOR...NEXT loop counts.

There are lots of differents solutions to solve my problem and I wonder how many people noticed this stange loop counting behaviour.

keithdoxey
- 11th October 2006, 16:03
It is not about to find a solution to make it work; it is about how the FOR...NEXT loop counts.


I think it is the same in any language.

you specify the start and end points for the count and optionally the step size.

the count starts at the specified start value then adds (or subtracts) the step value. It is then tested to see if it is within the range specified at which point the actions are executed. Once outside the specfied range it exits the for/next loop. This means that the value has to have changed from the last time the loop code was executed.

Ioannis
- 12th October 2006, 08:01
Hi Flotul

As I stated at #6 there is no strange behaviour. It is just the way for-next loops work in every version of Basic. Inside the loop the result is absolutely correct. Outside is expected to be +1 or -1 depending on the step of counting.

I see nothing strange here.
Other way to make a loop like While-Went or Repeat-Until use different counting methods.

While-wend for example, first checks, then executes. For-Next, first executes then checks.

Ioannis

mister_e
- 12th October 2006, 08:19
OK i'll try another explanation


For Variable=0 to 255
Pouet pouet
next

The test is done at the FOR TO NEXT line, the incrementation is done at NEXT line.
So at the end the value=256... wich is really hard to fit in a BYTE variable. Hence it gives 0

Change your var to a WORD too see what's happen now.



Repeat
Pouet Pouet
Variable = Variable +1
Until Variable = 255

a Repeat Untill loop do the test at the end... so this why it worked

flotulopex
- 13th October 2006, 18:12
Thank you All,

All your explanations are absolutely clear.

peterdeco1
- 13th October 2006, 18:59
Hi Flotulopex. The FOR - NEXT is confusing to me too. I use a different routine from a basic compiler I used a long time ago. This is a snip from a motor speed controller that controls the speed of an electric cart. At the start of the program, LEFTRAMP is made 0. If the speedpot is reduced while running, it will also ramp down.

LEFTON: 'TURNS ON LEFT MOTOR FOR RIGHT TURN
ADCIN 2, SPEEDPOT
IF LEFTRAMP < SPEEDPOT Then LET LEFTRAMP = LEFTRAMP + 1
IF LEFTRAMP > SPEEDPOT Then LET LEFTRAMP = LEFTRAMP - 1
Pause 1 'CONTROLS THE RAMP-UP DELAY
HPwm 1,LEFTRAMP,15000 'PWM OUTPUT DUTYCYCLE LIMITED TO SPEEDPOT
GoTo LEFTON