Shop OBEX P1 Docs P2 Docs Learn Events
#select #case — Parallax Forums

#select #case

NewzedNewzed Posts: 2,503
edited 2006-02-27 23:39 in BASIC Stamp
I have a program for my bar graph that uses a lot of IF-THEN statements, and the program works fine.

I would like to use #SELECT #CASE insted of the IF-THEN statements.· For a starter I wrote:

AD0 var word
a = word
b = word

start:
SERIN 16, baud, [noparse][[/noparse]DEC AD0]
#DEFINE cnt =· AD0

#SELECT cnt
#CASE cnt>4000
a =0
b = 0

#CASE cnt>3750
a = 255
b = 255
#ENDSELECT

When I try to run it I get an error that the AD0 in the DEFINE statement is an illegal symbol.· Am I doing something wrong, or is this an improper use of SELECT-CASE?

Thanks

Sid

Comments

  • NewzedNewzed Posts: 2,503
    edited 2006-02-26 15:51
    Never mind - I deleted all the # symbols and now it is apparently working OK.· Live and learn.· yeah.gif

    Sid
  • Jon WilliamsJon Williams Posts: 6,491
    edited 2006-02-26 16:08
    See this thread for information on using conditional compilation constructs: http://forums.parallax.com/showthread.php?p=568694

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Jon Williams
    Applications Engineer, Parallax
  • Tracy AllenTracy Allen Posts: 6,662
    edited 2006-02-26 20:20
    Hi Sid,

    AD0 is a run time variable, and as you already found out, your program works when you use the run time versions of the command, without the "#".

    With the "#" is is evaluated at compile time. Jon uses that very effectively to make code that will run on different Stamps by using the #SELECT $STAMP directive with a #CASE for each Stamp. The compiler knows which stamp it needs to compile for, because in PBASIC 2.5, that is stated in the ' $STAMP directive.

    I use the #SELECT directive when I want to have different versions of code that I can have compiled by number, for exaample as shown here emesystems.com/BS2pbasic25.htm. The one I want is defined at compile time, not a run-time variable.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Tracy Allen
    www.emesystems.com
  • NewzedNewzed Posts: 2,503
    edited 2006-02-27 14:33
    Thanks, Tracy -· have that pretty clear now.

    I converted all my IF/THEN statements to SELECT/CASE.· There were 17 so I got an error "Only 16 CASE Statements are allowed."· So I ended it at 16, then added one more SELECT/CASE in order to get my 17 statements in.· The program compiled OK - is this method legal?

    Thanks

    Sid
  • Tracy AllenTracy Allen Posts: 6,662
    edited 2006-02-27 16:47
    Newzed said...
    Thanks, Tracy - have that pretty clear now.

    I converted all my IF/THEN statements to SELECT/CASE. There were 17 so I got an error "Only 16 CASE Statements are allowed." So I ended it at 16, then added one more SELECT/CASE in order to get my 17 statements in. The program compiled OK - is this method legal?

    Thanks

    Sid

    Hi Sid, I didn't realize there was a limit of 16, and it kind of surprises me. If you got your workaround to compile, and it works, then it's legal! Here is the program from the URL mentioned above, that explores the microcoding of the CASE-SELECT statement in PBASIC 2.5, translated to old PBASIC 2.0. This also shows one way to take advantage of #DEFINE/#SELECT/#CASE/#ENDSELECT. First put example=10 in the #DEFINE part, and then hit CTRL-M, scroll down and take a screen shot of the tokens produced by the program. Then put example =11 after the #DEFINE, hit CTRL-M again, and take a second screen shot. The #SELECT allows you to change which of the two code examples gets compiled. Now compare the two sets of tokens. You will see that they are identical. That shows that PBASIC 2.5 takes care of the work and the spagetti of a series of IF-THEN statements for you behind the scenes, when you use the nice, clean, efficient SELECT/CASE/ENDSELECT. Since it is resolved to a chain of IF/THEN GOTO statements in the native PBASIC 2.0, I don't see why the limit of 16. Maybe that is imposed by the compiler.

    ' from [url=http://www.emesystems.com/BS2pbasic25.htm]www.emesystems.com/BS2pbasic25.htm[/url]
    ' where there is more explanation
    '{$STAMP BS2pe}
    '{$PBASIC 2.5}
    
    #DEFINE example=10
    
    '  10  SELECT - CASE - CASE - CASE ELSE - ENDSELECT
    '  11  same tokens as 10, but using IF - GOTOs in old PBASIC
    
    #SELECT  example
    
    #CASE 10        ' SELECT CASE construct
    x VAR Byte
    SELECT x
    CASE 1
      HIGH 0: LOW 1
    CASE 2
      HIGH 1:LOW 0
    CASE ELSE
      LOW 1:LOW 0
    ENDSELECT
    END
    
    
    #CASE 11        ' same tokens as 10, very efficient
    x VAR Byte 
    IF x=1 THEN lab1   ' test for case 1
     GOTO lab2         ' case 1 false, try case 2
    lab1:              ' case 1 true, do this... 
     HIGH 0:LOW 1
     GOTO lab5         ' done with case 1, exit
    lab2: 
    IF x=2 THEN lab3   ' test for case 2 
      GOTO lab4        ' case 2 false, try next case
    lab3:              ' case 2 true, do this...
      HIGH 1: LOW 0
      GOTO lab5        ' done with case 2, exit
    lab4:              ' this is case else
      LOW 1: LOW 0     ' do this...
    lab5:              ' point of exit
      END
    
    #ENDSELECT
    
    

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Tracy Allen
    www.emesystems.com
  • Jon WilliamsJon Williams Posts: 6,491
    edited 2006-02-27 17:33
    SELECT-CASE, by it's flexible nature, generates a lot of internal code for some setups -- a few customers notice this code growth doing complex SELECT-CASE statements. There may in fact be other PBASIC structures that can be used effeciently, things like LOOKDOWN compbined with BRANCH or ON-GOTO/GOSUB.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Jon Williams
    Applications Engineer, Parallax
  • Tracy AllenTracy Allen Posts: 6,662
    edited 2006-02-27 17:44
    Yes, I wonder it what Sid observed came from the SELECT/CASE itself, or from code within it. I know it is important from the standpoint of speed and code space to evaluate expressions before using the result in a SELECT. For example,
    SELECT mydata /50 - 48
    ...
    would lead to code that repeats the expression evaluation for each subsequent CASE. ...Better use,
    x = mydata/50-48
    SELECT x
    ...

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Tracy Allen
    www.emesystems.com
  • NewzedNewzed Posts: 2,503
    edited 2006-02-27 18:29
    Maybe I should go back to the IF/THEN version.· The IF/THEN version takes 24 percent of memory, while the SELECT/CASE only takes 20 percent; however, memory is not an issue in this case.· So.........should I stick with the SELECT/CASE or go back to the IF/THEN?

    Sid
  • Jon WilliamsJon Williams Posts: 6,491
    edited 2006-02-27 18:35
    Do what works best -- generally multiple IF-THEN statements make a program difficult to follow. Still, I'd like to see all these IF-THENs you're using to see if there is another technique that is more effective in PBASIC.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Jon Williams
    Applications Engineer, Parallax
  • NewzedNewzed Posts: 2,503
    edited 2006-02-27 18:41
    OK, Jon.· Here's the program.· Any kmprovements would be most welcome.

    Sid
  • Jon WilliamsJon Williams Posts: 6,491
    edited 2006-02-27 19:27
    You can trim that program pretty easily.· Notice how the end value of all of your IF-THENs is an even multiple of 250?· Why not do this:

    Start:
    · AD0 = AD0 + 240
    · IF (AD0 > 3999) THEN
    ··· AD0 = 240
    · ENDIF
    · idx = AD0 / 250
    · READ (ALevel + idx), a
    · READ (BLevel + idx), b
    ·
    Cont:


    Of course you have to put the list of 'a' and 'b' values into a couple DATA tables, but that would be easy to do an make modifying the program simpler.

    A couple more notes: You might consider using meaningful variable names -- meaningful for you AND other programmers that is; I have no idea what a and b are for, and wouldn't without a lot of detailed analysis.· You're also using OUTPUT in the program; it is probably better to use HIGH or LOW as this sets the pin to an output and to a known level.


    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Jon Williams
    Applications Engineer, Parallax
  • Bruce BatesBruce Bates Posts: 3,045
    edited 2006-02-27 19:33
    Tracy -

    Just as a general matter, the redundant code issue caused by inline mathematical calculations is by no means unique to PBASIC. I honestly can't think of an interpretive Basic Language variant that DOESN'T have that same "problem" and which always benefits from the pre-calculation step you indicated.

    Regards,

    Bruce Bates

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    <!--StartFragment -->
  • Jon WilliamsJon Williams Posts: 6,491
    edited 2006-02-27 19:52
    Sid,

    It turns out there's an even simpler solution:

    Main:
    · IF (ad0 > 249) THEN
    ··· GOSUB Set_Display
    · ELSE
    ··· GOSUB Clear_Display
    · ENDIF
    · END

    Set_Display:
    · idx = (ad0 / 250) - 1········ ' determine left-most bit
    · leds =·0····················· '·clear old value
    · FOR idx = idx TO 0············' light appropriate bits
    ··· leds.LOWBIT(idx) = 1
    · NEXT
    · GOTO Update_Leds

    Clear_Display:
    · leds = $0000

    Update_Leds:
    · SHIFTOUT SData, Clock, MSBFIRST, [noparse][[/noparse]leds.BYTE0, leds.BYTE1]
    · PULSOUT Latch, 5
    · RETURN

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Jon Williams
    Applications Engineer, Parallax
  • NewzedNewzed Posts: 2,503
    edited 2006-02-27 22:54
    Jon, your "even simpler" program works beautifully.
    ·
    Eventually, AD0 will be serined, but for the moment I had to generate a changing AD0.· I made a couple of other small changes just to make things easier.· The whole program only takes 6 percent of memory so I will be able to·incorporate it into any program I like.

    I have attached a copy of Rev. A so you can see exactly what I did.

    Thanks again - I'll have to remember about augmenting the bits of leds -
    that's very neat.

    Sid
  • Jon WilliamsJon Williams Posts: 6,491
    edited 2006-02-27 23:39
    Actually, the code can be even simpler -- I was originally using the DCD operator but that became redundant.

    Set_Display:
    · leds =·0····················· '·clear old value
    ··idx = (ad0 / 250)···· ······· ' determine left-most bit
    · IF (idx > 0) THEN
    ····
    FOR idx = (idx-1) TO 0······' light appropriate bits
    ····· leds.LOWBIT(idx) = 1
    ··· NEXT
    · ENDIF
    · GOTO Update_Leds


    You can send any value (0·- 4000)·to this subroutine -- you don't have to filter values less than 250.· Also, you've added redundant SHIFTOUT code at Clear_Display in your new program.· You can simply set leds to zero at this point and let it drop through to Update_Leds; this gives your program the same operation and cuts down on space.· If you want to keep the redundant code, then it makes more sense to move the code from Update_Leds up to the end of Set_Display.· The only reason I crafted the code as I did was to optimize code space by removing redundancies.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Jon Williams
    Applications Engineer, Parallax
Sign In or Register to comment.