PDA

View Full Version : limiting to "no less than" zero



Byte_Butcher
- 17th September 2011, 02:45
Greetings all,

Too many interests and hobbies have kept me away from electronics for a while, but I'm back again and trying to re-learn what little I knew about PICs....

Todays question is how to easily limit a number to "not less than zero".

I have a number... lets call it "volume" and I want to increment or decrement that number by "step", which could be from 1 to 9.
I want to limit "volume" to no more than 350 at the upper end and no "less" than zero at the low end.

So if I press buttonA then volume increments by the step amount, and if I press buttonB then volume decrements by step amount.

Here's a simple example (of what doesn't work):



volume = 100 'set a default level
step = 3 'This could be ANY NUMBER FROM 1 TO 9


main:

if buttonA then volume = (volume + step) min 350 'this works fine to limit the top end to 350

if buttonB then volume= (volume - step) max 0 'but of course THIS fails, because it's hard to go lower than zero

LCDOUT $fe, $c0, dec volume

pause 50
goto main

end



So I'm sure that there must be an easy way to limit a number from decrementing "below" zero... ?
Help please?


Thanks much!

Steve

Charles Linquis
- 17th September 2011, 04:08
if buttonB then
if step > volume then
volume = 0
else
volume= (volume - step)
endif
endif

Heckler
- 17th September 2011, 04:14
This Should (untested as of yet) work...

One thing about programming... there is always more than one way to do the exact same thing... some are more elegant than others... Mine usually falls into the "less elegant, but gets the job done" category:)

The extra "IF" test should eliminate the need to test for below zero or the "max 0" test.



volume = 100 'set a default level
step = 3 'This could be ANY NUMBER FROM 1 TO 9


main:

if buttonA then volume = (volume + step) min 350 'this works fine to limit the top end to 350

if buttonB and (volume < 3) then
volume = 0
goto Skip1
endif

if buttonB then volume= (volume - step) 'but of course THIS fails, because it's hard to go lower than zero

Skip1:
LCDOUT $fe, $c0, dec volume

pause 50
goto main

end

Heckler
- 17th September 2011, 04:24
Hey Charles... you beat me to it :)

When I started my reply, you had not posted yet. I am not sure I like the new code posting window... it gave me fits and I had to start over.

I think I like yours better... but it is fun and informative to try different bits of code and compile each and see how the byte count changes. I have been surprised at times in finding that what you think should be more compact code ends up being more bloated.

Darrel Taylor
- 17th September 2011, 04:43
Yup, there are always lots of ways.



if buttonB then
volume = volume - Vstep ; subtract the step
if volume.15 then volume = 0 ; zero if it went negative
endif

sayzer
- 17th September 2011, 07:45
if buttonB then
if volume - Vstep >= vstep then
volume = volume - Vstep
else
volume = 0
endif
endif

HankMcSpank
- 17th September 2011, 10:00
Straying a little off...

I'm never more than a couple of threads away from having it underlined that I'm still woefully underskilled in this programming melarkey - where's the condition here...

if buttonB then

to my n00b eyes, I'd have thought there should be a condition like "if buttonB = 0 then" or "if buttonB = 1 then"

??

Ioannis
- 17th September 2011, 12:25
If buttonB means If buttonB=1.

Is a default.

A pure boolean logic.

Darrel gets the most elegant so far coding :)

Ioannis

HankMcSpank
- 17th September 2011, 12:32
I'd figured as much (on account everyone was doing it!)....can the default be changed to 0? (I'd imagine that switches get used with weak pullups or external pullups ....so the switch pressed condition would be a 0).

Re Darrel's entry..


if volume.15 then volume = 0 ; zero if it went negative

how does bit 15 of 'volume' being a '1' indicate negative? Can someone shine a little more light on this one please?

Ioannis
- 17th September 2011, 13:02
Related to the "default" just use the ! before your variable:

If !buttonB then.... meaning If buttonB=0 then...

The 15th bit is the sign bit in two's complement. When the most significant bit is 1, it indicates a negative sign. Just Binary maths...

But is relative. If you use 8-bits then the 8th (most significant bit) is considered the sign bit. As long as you are thinking of positive and negative numbers. So at the end you have from -128 to +127 (1000 0000 to 0111 1111).

http://en.wikipedia.org/wiki/Two's_complement

Ioannis

Byte_Butcher
- 17th September 2011, 17:42
Thanks guys!

Well... I guess the answer to my question is that there isn't really a way that's as easy as using "min" to limit the upper end.

The method that Charles posted is what I've been using. But I was hoping for something that was... simpler.
I guess I'd hoped there was some way as clean and easy as "MAX" but that worked all the way down to zero.

Darrels method using volume.15 is great, but it "wastes" half of a variable.
Most of the variables that I need to limit are declared as bytes, and I need the full 255 step range for some of them.
I *can* use it for my temperature setpoint because that needs a word anyway and I can afford to "lose" part of it.

I'm starting to run low on code space on this project so hoping to find more efficient ways to do a few things...

Thanks for the input!

Steve

Darrel Taylor
- 17th September 2011, 20:06
Darrels method using volume.15 is great, but it "wastes" half of a variable.
Most of the variables that I need to limit are declared as bytes, and I need the full 255 step range for some of them.
With 8-bit values, the CARRY flag is valid after addition or subtraction.

So it can be ...

if buttonB then
Volume = Volume - Vstep
IF !STATUS.0 THEN Volume = 0 ; Zero if BORROWED
endif

Byte_Butcher
- 17th September 2011, 20:27
STATUS ?
STATUS.0 ?

Ahhh, Darrel, you confuseth me. From whence comes... STATUS ?

steve

Darrel Taylor
- 17th September 2011, 21:19
STATUS is a register in the PIC that contains the results (status) of arithmetic operations.
Depening on the chip family, it may also have Watchdog Timer status and FSR/page bits.

STATUS.0 is the CARRY flag.
After an addition, if the result is larger than 255 the carry bit will be set (1).
After a subtraction, if the result is less than 0 (BORROW), the carry bit will be cleared (0).

The carry bit is only valid after addition/subtraction with 8-bit values.
After math with WORD values, the carry bit cannot be used because not all of the math is done by the hardware.

Ioannis
- 17th September 2011, 21:26
If the previous subtraction produced negative results, bit 0 of STATUS is set (to 1). Then you check this condition and if true, set Volume to 0.

By the way which chip are you controlling?

Ioannis

Byte_Butcher
- 17th September 2011, 22:18
Wow... thanks Darrel. THAT is an interesting item to know about.
I'm sure I can make good use of that!

Ioannis, I'm using a 16F887. And thanks for helping explain the STATUS thing!


steve

Heckler
- 17th September 2011, 23:48
Darrel = After a subtraction, if the result is less than 0 (BORROW), the carry bit will be cleared (0).
Ioannis = If the previous subtraction produced negative results, bit 0 of STATUS is set (to 1)

OK guys(gals?)
if I read those two statements correctly... they are contradictory. You can't have it both ways... which is it??

Darrel Taylor
- 18th September 2011, 01:11
Don't believe anything just because somebody said so.
Especially when there's conflicting information.

Check the datasheet, and test it for yourself. Then you will know the truth.

This program will help with the testing part.


Volume VAR BYTE
Vstep VAR BYTE
Result VAR BYTE
Carry VAR BIT
HIGH PORTD.0 ; initialize serial line
PAUSE 100
FOR Volume = 5 TO 0 STEP -1
FOR Vstep = 5 TO 0 STEP - 1
Result = Volume - Vstep
Carry = STATUS.0
SEROUT2 PORTD.0,84,[DEC Volume," - ",DEC Vstep," = ",DEC Result," C = ",DEC Carry,13,10]
NEXT Vstep
NEXT Volume
STOP

Byte_Butcher
- 18th September 2011, 01:43
IF !STATUS.0 THEN Volume = 0

Darrels way works with a 16F887.
Can't vouch for any other chips...

aratti
- 18th September 2011, 01:48
Darrel, what is the value of STATUS.0 at start up? I assume it should be zero (no borrow no carry) , are you going to set it at start up, in order to have your snippet @ post #12 working?
Cheers

Al.

cncmachineguy
- 18th September 2011, 02:21
Not that Darrell needs it, but I feel compelled to jump in here and row his boat. To my knowledge, borrow/carry flag in the status reg is the same across ALL PIC's. It is not a compilier thing. It is a basic hardware reg no different then any other. It exists the same as W. That said, I believe it is cleared at POR, but it doesn't matter. it only has value directly after an addition or subtraction. Well it is also used on rotate R/L through carry, but PBP doesn't support that. Some devices even have 1 for borrow or carry between nibbles, but again only used during math.

So startup value makes no difference for the snippet in post 12 as it follows a math operation.

Heckler
- 18th September 2011, 03:23
Here is my test code and the debug results below...


DEFINE DEBUG_REGG PORTA 'set debug port to porta
DEFINE DEBUG_BIT 0 'use pin a0 of porta for debug
DEFINE DEBUG_BAUD 2400 'set baud rate to 2400
DEFINE DEBUG_MODE 0 'communicate in true mode
valA var byte
valB var byte
resultA var byte
resultB var byte
resultC var byte
resultD var byte
Carry var bit
vala=51
valb=50

resulta=vala-valb
Carry = STATUS.0
debug "resultA : 51-50=",dec resulta," Carry=",dec carry,13,10

resultb=valb-vala
Carry = STATUS.0
debug "resultB : 50-51=",dec resultb," Carry=",dec carry,13,10

resultC=vala+valb
Carry = STATUS.0
debug "resultC : 51+50=",dec resultc," Carry=",dec carry,13,10

vala=55
valb=201

resultD=vala+valb
Carry = STATUS.0
debug "resultD : 55+201=",dec resultd," Carry=",dec carry,13,10
end

and the Debug results...


resultA : 51-50=1 Carry=1
resultB : 50-51=255 Carry=0
resultC : 51+50=101 Carry=0
resultD : 55+201=0 Carry=1

Heckler
- 18th September 2011, 03:43
DANG EDIT TIMER...

Therefore
If you subtract two BYTE variables and the result is NEGATIVE, the Carry Bit will be Cleared (0)
If you add two Byte variables and the result is >255 then the Carry Bit will be SET (1)

HEY!! I think that's what Darrel said earlier.:eek:

Darrel Taylor
- 18th September 2011, 03:53
Sweet!
And you made your own test program ... Perfect!

I'm sure it all seems much clearer now.

http://www.pbpgroup.com/files/SIGIMG/understand.gif

Ioannis
- 18th September 2011, 11:21
Oops, sorry. I should have said borrow...

Darrel was too polite! Thanks.

@ Steve: I meant which audio chip are you controlling with the PICİ

Ioannis

Byte_Butcher
- 18th September 2011, 19:33
@ Steve: I meant which audio chip are you controlling with the PICİ

Audio chip? LM380 :)

Ah, you asked because I used "volume" as a variable in my question...

Actually it's not an audio project. It's for FrankenGriddle.

http://www.weirdstuffwemake.com/blackhole/images/frankengriddle_1450.jpg

If anyone is really curious I guess I could start a thread about "The FrankenGriddle Project" in the OT forum.

Hmmmm... is there a forum specifically for showcasing "Projects" that use PICs?



Steve

mister_e
- 18th September 2011, 19:39
The Wiki could be a nice place. You can even start your personnal group in your own profile... not sure how it works though.

Byte_Butcher
- 19th September 2011, 00:55
The carry bit is only valid after addition/subtraction with 8-bit values.
After math with WORD values, the carry bit cannot be used because not all of the math is done by the hardware.

OK, curiosity got me so I tried it with WORD values and it still seems to work...


x = 32768
Y = 32769
x = x + y
Result: X = 1, STATUS.0 = 1
'--------------------------------

x = 32768
Y = 32765
x = x + y
Result: X = 65533, STATUS.0 = 0
'-------------------------------------

x = 32768
Y = 32765
x = x - y
Result: X = 3, STATUS.0 = 1
'--------------------------------------

x = 32765
Y = 32771
x = x - y
Result: X = 65530, STATUS.0 = 0
'------------------------------------

I thought it was only 'sposed to work with 8 bit numbers?


Steve

Darrel Taylor
- 19th September 2011, 02:46
Try it with ...

X = 32768
Y = 65523

Byte_Butcher
- 19th September 2011, 05:15
Try it with ...

X = 32768
Y = 65523

Nope, that didn't work.
OK, 8 bit math then....

Thanks!

Charles Linquis
- 19th September 2011, 13:44
Since PBP handles the 16 (31) bit math, and certainly knows the results of the 8 bit operation, the writers of PBP *could* provide us with an overflow/underflow flag (PSTATUS?). If they really wanted to.