Shop OBEX P1 Docs P2 Docs Learn Events
My binary math skills end at 1+1=10; want cleaner code — Parallax Forums

My binary math skills end at 1+1=10; want cleaner code

cicacica Posts: 11
edited 2006-06-01 16:28 in BASIC Stamp
Hi-

I'm in the process of building a console to be used as part of a geocaching game. Upon the successful entry of a 4-digit code by a player, the console will display the longitude and latitude of the next location in their hunt.

The code as attached allows a 4-digit code on a 4-digit keypad to store the result in a byte VAR. There are 256 possible combinations, so the result will be in the range of 0-255. I should probably leave well enough alone, but always strive to write tighter code. I'm most concerned by the way I convert a binary number into a variable. I was wondering if there is a cleaner way through binary math to store the 256 possiblilities. As written, the first digit will store from {0-3}; the second will then add {0-3}*4; the third adds {0-3}*16; and the fourth adds {0-3}*16. I also don't allow multiple presses and require the button to be released (press=0) before accepting the next button. Also, I have a timer that puts the whole thing to sleep if nothing is pressed for an extended period of time. The console will be activated by a button causing a reset to the BS2.

Any help would be appreciated.

Thanks,
-Tom

Comments

  • Mike GreenMike Green Posts: 23,101
    edited 2006-05-31 19:15
    Your program is pretty reasonable. The main issue for me is the mismatch between displaying the entry code in decimal while entering it using only 4 buttons. Does it make sense to allow the user to see what was actually entered? (like 0010 or 3312?) You could store the 0-3 values in a nibble array declared as "site var nib(4)" that only takes 2 bytes and use "keypos" as an index like "site(keypos)=btns-1". In your display routine, you could use HEX instead of the DEC formatter as "HEX site(0),HEX site(1),HEX site(2),HEX site(3)" to display all 4 digits. If you also want the decimal equivalent, you could add a new byte value "result" and do "result=(site(0) << 6) | (site(1) << 4) | (site(2) << 2) | site(0)".
  • Paul BakerPaul Baker Posts: 6,351
    edited 2006-05-31 19:22
    I love geocaching, great excuse to go places you've never been.
    Not quite sure what your project does (perhaps you're not done yet), but I can help you a bit (pun intended).
    Multiplying by 4 is the same as shifting left by two, but faster. This can be implemented 1 of 2 ways, first is storing the digits in reverse order where the line:
    site = site + ((btns-1)*keypos) would be replaced with site = site << 2 + (btns-1).
    or If you want to preserve the kepress order you can do site = site + (btns-1) << keypos
    where keypos would start at 0 and be incremented by 2 each iteration.

    I can see this project turning into something really cool, you could make maybe a dozen of these, scout out locations to hide the boxes and mark the GPS coordinates. Program these coordinates into UTM tables within the boxes and create randomized sequences (order in which the boxes are to be visited, each team having a different order)·for however many teams would be participating. Each team would have an iButton and each box would have an iButton receiver. The box upon receiving the iButton code would look up and display the GPS coordinates for the team's next box to visit and record the time at which the iButton was placed in the receiver. The team to make contact with all boxes in the proper sequence first wins. You could even weight determine the paths to make them as close to equidistant as possible (each team's total distance to travel is roughly equal).

    You could also use RFID instead of iButtons, however if you employ iButtons which have storage capability and store the box numbers in sequence in the iButtons, you could determine the winner without having to collect the boxes and retrieve the data from each.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    1+1=10

    Post Edited (Paul Baker) : 5/31/2006 7:32:27 PM GMT
  • cicacica Posts: 11
    edited 2006-05-31 19:42
    Mike-

    I posted a stripped down version of the current program to make it easier to follow the logic. The actual console will have 4 buttons that correspond to the four symbols on www.geocaching.com's logo. I have these symbols load as custom LCD characters. The actual program displays these symbols as they are being entered. I am in decimal mode because it is easier for me to code in decimal. After I have recognized the 4-digit code, I'm going to use a SELECT...CASE statement like:

    SELECT site
    CASE = 15
    GOTO Result0
    CASE = 75
    GOTO Result0
    CASE = 125
    GOTO Result0
    CASE = 202
    GOTO Result0
    CASE ELSE
    ' Return bogus long/lat coordinates
    ENDSELECT

    Paul-
    The order pressed is what is allowing me to have 256 possiblities. That's why I'm using the multiplier. I'll definitely give these ideas a shot. While iButtons sound cool, they might be cost prohibitive, as would building a dozen of these. As it stands, after adding an LCD, a battery with a solar charger, some lexan, blue LEDs and a speaker, I'm going to be into this "small project" for about $200.

    My idea is a little more cost effective where the player will have to "tag back" at the console. Each destination will have a new code to enter at the base. And there will be bogus locations if a person just randomly enters a code. The person will have enough information after visiting 4 sites to locate a fifth site where I will hide the geocache.

    I could forsee having this console used for more than one geocache location. All I need are a few more CASE statements to return valid coordinates.
  • Mike GreenMike Green Posts: 23,101
    edited 2006-05-31 20:01
    Consider using the DATA and READ statements for long tables. You can store groups of 2 or 3 bytes with the first byte containing the code to be entered by the user and the other bytes containing a lat/long or similar info. Set X to the start of the table, then do "Read X,code,result1,result2:X=X+3", see if the code is what you want, if not, try again, and use zero or 255 as an end of table marker. I've used such tables for state machines, sound sequencers, and the like because it's simple, easy to change and expand.
  • cicacica Posts: 11
    edited 2006-05-31 20:20
    Mike-

    I think you just touched upon my second question[noparse]:)[/noparse] I don't need to calculate anything with respect to the long/lat data. I just need the result to cause the LCD to display the corresponding longitude/latitude. My program currently has the following statements:


    NDeg            VAR     Byte            ' North degrees of destination
    NMin            VAR     Byte            ' North minutes of destination
    NSec            VAR     Word            ' North seconds of destination
    WDeg            VAR     Byte            ' West degrees of destination
    WMin            VAR     Byte            ' West minutes of destination
    WSec            VAR     Word            ' West seconds of destination
    
      NDeg=42:NMin=27:NSec=718:WDeg=71:WMin=05:WSec=858 ' used for debugging only
    
      SEROUT TX, LcdBaud, [noparse][[/noparse]LCDLine1, 1 ,2, "  N  ",DEC2 NDeg, 0, DEC2 NMin,".",DEC3 NSec]
      SEROUT TX, LcdBaud, [noparse][[/noparse]LCDLine2, 3, 4, "  W 0",DEC2 WDeg, 0, DEC2 WMin,".",DEC3 WSec]
    
    



    As I mentioned before, I have enough room on the stamp to be a little sloppy with the code, but is there a way to store this long/lat data more compactly? My initial plan is to have a subroutine that would assign these values then call the display routine that contains the two SEROUT commands. I could also simply write a single SEROUT command that wraps and displays all of the data and do away with these variables entirely. Thinking long term, I might want to store quite a few coordinates.

    What do you think?
    -Tom
  • Mike GreenMike Green Posts: 23,101
    edited 2006-05-31 21:10
    I would store the data using the DATA statements as a table. If you're using a Stamp with bank storage (anything except a BS2), you can use a whole bank for your table. You could store the information a little more compactly in that the minutes only requires 6 bits. I don't know how big the seconds value has to be, but it may not need a whole 16 bit word. If it's less than 1000, you could store the extra 2 bits in the minutes byte. (value = extra << 2 | minutes) to pack it together and (minutes = value & %111111: extra = value >> 6) to unpack it.
  • Mike GreenMike Green Posts: 23,101
    edited 2006-05-31 21:13
    OOps, I meant (value = extra << 6 | minutes)
  • Mike GreenMike Green Posts: 23,101
    edited 2006-05-31 21:21
    For example ...
    - READ X,A,B,C
    - X = X + 3
    - SEROUT TX,LcdBaud,[noparse][[/noparse] ... ,DEC2 A,0,DEC2 B&%111111,".",DEC3 (B<<2)|C]
    Then repeat for the next line
  • cicacica Posts: 11
    edited 2006-06-01 13:28
    Mike-

    First of all, thanks for all your help. I did some further research and discovered that:

    NDeg can be in the range of 0-90 (in the northern hemisphere)
    NMin can be in the range of 0-59
    NSec can be in the range of 0-999
    WDeg can be in the range of 0-180 (west of the meridian)
    WMin can be in the range of 0-59
    WSec can be in the range of 0-999

    For all intensive purposes, a change of 1 degree is about 67 miles. For my purposes, 42N and 71W degrees covers Eastern Massachusetts. So, I don't really need to store these. However, in the interest of portability and readability, I probably will anyway. Also, WDeg will not hit 100 until I go west to Nebraska. That being said, I tried the following code and could easily fit 100 DATA statements as follows:

    'name                          NDeg  NMin  NSec  WDeg  WMin  WSec
    Site000            DATA    42,     27,    718,    71,      05,     858
    Site001            DATA    42,     27,    718,    71,      05,     858
    Site002            DATA    42,     27,    718,    71,      05,     858
    Site003            DATA    42,     27,    718,    71,      05,     858
    
    



    I would never need more than 30 site codes, so I can afford to be inefficient code-wise, but would like to learn more about compacting data. Knowing the possible ranges, what would be a more compact way to store this data? I know I could set NDeg and WDeg as offset numbers from a constant, but I'want to try to retain readability.

    Thanks
    -Tom

    Thanks
  • Mike GreenMike Green Posts: 23,101
    edited 2006-06-01 13:40
    Use my previous suggestion (pack upper 2 bits from each Seconds into upper 2 bits of each Minutes byte). That gets you a 6 byte DATA entry. The DATA statement allows expressions, so you can let the compiler do the packing as:
    - Site000 DATA 42,((718>>2)&%11000000)|27,718,71,((858>>2)&%11000000)|05,858
    Note that the DATA statement normally only stores the least significant byte of any value greater than 255 (see the Stamp Basic manual) unless you prefix the value with "WORD".
  • cicacica Posts: 11
    edited 2006-06-01 14:49
    One last question:

    I tried to use your DATA statement:

    Site000 DATA 42,((718>>2)&%11000000)|27,718,71,((858>>2)&%11000000)|05,858
    
    



    but it errors out at the second parenthesis with an "Expected a constant" error.
  • Mike GreenMike Green Posts: 23,101
    edited 2006-06-01 15:37
    I keep forgetting that the editor doesn't allow parentheses in constant expressions. In this case, everything evaluates just fine from left to right without the parentheses, so just remove them:
    - Site00 DATA 42, 718>>2 & %11000000 | 27, 718, 71, 858>>2 & %11000000 | 05, 858
  • cicacica Posts: 11
    edited 2006-06-01 16:28
    Thanks Mike-

    By comparing your DATA statement with mine (using WORD) I can see you are able to compact the data to 6 bytes while I end up using 8 bytes. I can also see if I had used a B2e, I could have just filled one bank with 256 8-byte values and maintained readability. While this is a great lesson, I might just limit my usage to about 30 values and sacrifice eprom space for readability.

    Thanks again. I actually learned something. smile.gif

    -Tom
Sign In or Register to comment.