Shop OBEX P1 Docs P2 Docs Learn Events
BS2sx, Keypad data entry, Parallax Serial LCD, display question — Parallax Forums

BS2sx, Keypad data entry, Parallax Serial LCD, display question

xanatosxanatos Posts: 1,120
edited 2011-10-24 08:19 in BASIC Stamp
I have a 4 x 4 keypad, encoded with a 74C922, hooked up to a BS2sx. To the same BS2sx I have a Parallax Serial LCD attached.

I am adapting code I found from N&V #97 (Keyboard Entry and Display). Code as follows:
    keyCount = 0
    DO : LOOP UNTIL (kbdDA = 1)  ' Wait until Data Available from 74C922

    keyIn = INB
    LOOKUP keyIn, [ 1, 2, 3, 10,
                    4, 5, 6, 11,
                    7, 8, 9, 12,
                    14, 0, 15, 13 ], keyIn ' translate kbd matrix

    LOOKUP keyIn, ["0123456789ABCD*#"], dispChar ' translate key to ASCII

    SEROUT LCD, LcdBaud, [LcdCls]
    PAUSE 5
    SEROUT LCD, LcdBaud, [dispChar, "  "]

    IF (keyIn = 14) THEN  ' 14 = * (Abort and go to beginning)
      keyCount = 0
      GOTO Main
    ELSEIF (keyIn = 15) THEN  '15 = # (Accept entry and go to next op)
      keyCount = 0
      EXIT
    ENDIF


My issue stems from the fact that the LCD display I am using seems to only display two digits when I send the data to it. The VAR 'dispChar' is a Word.

I would normally use the raw keyIn value and multiply it by 10 with each iteration of the keyCount to allow for multiple key entries, but the result of the LOOKUP is - I believe - ASCII, so I can't multiply that. When I've tried using teh raw keyIn value and the *10 thing, I can SEROUT to the LCD and get the single digit on the first keypress, two digits on the second... and two digits on every subsequent keypress.

So - and I know this is a simple thing - but I seem stuck between being unable to shift the decimal place with an ASCII word, or something I am doing wrong trying to send (up to 5) characters to the LCD.

Any help greatly appreciated. Feeling very dumb at the moment.

Thanks,

Dave

Comments

  • Chris SavageChris Savage Parallax Engineering Posts: 14,406
    edited 2011-10-17 10:23
    Dave,

    This will be difficult to determine without seeing the rest of the code. Can you attach the entire program as a file?
  • xanatosxanatos Posts: 1,120
    edited 2011-10-18 08:42
    Hi Chris,

    Thanks for your assistance here. I have edited my code down to only the LCD parts (there are a lot of things hanging off of my BS2 here - printers, solenoids, dataloggers, RTC, odd switches... so here's the code less about 300 lines in two slots:
    
    '  {$STAMP BS2sx}
    '  {$PBASIC 2.5}
    '
    ' =========================================================================
    
    ' -----[ I/O Definitions ]-------------------------------------------------
    
    kbdDA           PIN     3                ' Keyboard Data Available line from 74C922
    kbd0            PIN     4                ' Keyboard bit 0 from 74C922
    kbd1            PIN     5                ' Keyboard bit 1 from 74C922
    kbd2            PIN     6                ' Keyboard bit 2 from 74C922
    kbd3            PIN     7                ' Keyboard bit 3 from 74C922   These are all now on INB
    
    LCD             PIN     14               ' Parallax Serial LCD Display
    
    ' -----[ Constants ]-------------------------------------------------------
    
    LcdBaud         CON     110             ' LCD Baud derp
    LcdBkSpc        CON     $08             ' move cursor left
    LcdRt           CON     $09             ' move cursor right
    LcdLF           CON     $0A             ' move cursor down 1 line
    LcdCls          CON     $0C             ' clear LCD (use PAUSE 5 after)
    LcdCR           CON     $0D             ' move pos 0 of next line
    LcdBLon         CON     $11             ' backlight on
    LcdBLoff        CON     $12             ' backlight off
    LcdOff          CON     $15             ' LCD off
    LcdOn1          CON     $16             ' LCD on; cursor off, blink off
    LcdOn2          CON     $17             ' LCD on; cursor off, blink on
    LcdOn3          CON     $18             ' LCD on; cursor on, blink off
    LcdOn4          CON     $19             ' LCD on; cursor on, blink on
    LcdLine1        CON     $80             ' move to line 1, column 0
    LcdLine2        CON     $94             ' move to line 2, column 0
    
    ' -----[ Variables ]-------------------------------------------------------
    
    keyIn           VAR     Byte            ' Holds translated keypad value
    char            VAR     Byte            ' ASCII char to display
    dispChar        VAR     Word            ' Display holder for multiple key presses
    keyCount        VAR     Nib             ' Number of key presses per cycle
    passCode        VAR     Word
    result          VAR     Byte
    
    
    ' -----[ Initialization ]--------------------------------------------------
    
    Reset_LCD:
      HIGH LCD                              ' setup serial output pin
      PAUSE 100                             ' allow LCD to initialize
      SEROUT LCD, LcdBaud, [LcdBLon, LcdOn1, LcdCls]  'LcdBLoff/LcdBLon
      PAUSE 250
      SEROUT LCD, LcdBaud, ["  XANATRONICS"]
      SEROUT LCD, LcdBaud, [LcdLine2, "Fuel Management"]
      PAUSE 1000
    
    ' -----[ Program Code ]----------------------------------------------------
    
    Main:
    
    ' Ask for data DI, TR#, TRKMLG,
    
      SEROUT LCD, LcdBaud, [LcdCls]
      PAUSE 5
      SEROUT LCD, LcdBaud, ["Driver ID & #:      "]
    
      keyCount = 0
      dispChar = 0
      DO ' Routine to accept keyboard data (and then store it in eeprom)
    
        DO : LOOP UNTIL (kbdDA = 1)  ' Wait until Data Available from 74C922
    
        keyIn = INB
        LOOKUP keyIn, [ 1, 2, 3, 10,
                        4, 5, 6, 11,
                        7, 8, 9, 12,
                        14, 0, 15, 13 ], keyIn ' translate kbd matrix
    
        LOOKUP keyIn, ["0123456789ABCD*#"], dispChar ' translate key to ASCII
    
        SEROUT LCD, LcdBaud, [LcdCls]
        PAUSE 5
        SEROUT LCD, LcdBaud, [LcdLine2, dispChar, "       "]
    
        IF (keyIn = 14) THEN  ' 14 = * (Abort and go to beginning)
          keyCount = 0
          GOTO Main
        ELSEIF (keyIn = 15) THEN  '15 = # (Accept entry and go to next op)
          keyCount = 0
          EXIT
        ENDIF
    
        PAUSE 5
        DO : LOOP UNTIL (kbdDA = 0)
        keyCount = keyCount + 1
    
      LOOP
      PAUSE 2000   ' Replace this with routine to accept keyboard data and PUT to eeprom
    
    
    GOTO Main
    

    In looking at the code you'll see that there are two values I have available for the keyboard's input - the raw keyIn value that I get after the first LOOKUP, and the dispChar value that comes from the second LOOKUP of the keyIn value. I can get the LCD to display either properly as a single digit. When I use the keyIn value, I can do the * 10 trick to move the first digit to the left one space and then add the next incoming digit to display two characters on the LCD. I have also done this by using dispChar and subtracting 48 which gives me the same number. But multiplying the dispChar value by 10 does not work - I get very odd characters (looks like japanese symbols). When I use keyIn I sepcify DEC. dispChar displays without needing to specify DEC or anything.

    I've been using KeyCount to determine where in the loop the number should be. While it's not in the code above (since it didn't work), what I was using is something along these lines (code paraphrased):
    if keyCount = 0 THEN
         SEROUT dispChar to LCD
    ELSE
         dispChar = (old dispChar * 10) + new dispChar
         SEROUT dispChar to LCD
    ENDIF
    
    

    Back to the (last keyIn * 10) + new keyIn method... This works for up to two characters. The third never shows up, I only get two characters. So if I type 3, it displays 3. Then I push 6, and I get 36. Then I push 9 and I get 69. Push 9 again and I get 99. Push 3 again, I get 93.

    I've even tried setting it to DEC3, and I get 000, 003, 036, 069, 099, and 093 respectively.

    Ultimately, my app will need to take a three digit number, followed by #, another 3 dig + #, a 6 digit + # (which will be very interesting because I will need to capture this number and store it in a datalogger, but the number will always exceed 65535... so there's probably another plea for help in the future)... anyway, I need to be able to display, and capture all these entries so I can store them on a datalogger. That part I already have working just fine - it seems to only be the display parts that are stumping me. Shouldn't it be possible for me to just keep typing numbers across the LCD screen until I finally enter the special character that makes it store the number and move on?

    I've read N&V #97 several times and I can't seem to see why that code works on that display but not on my regular old Parallax Serial LCD.

    So I appreciate your help quite a bit. My brain is fried at this point! :-)

    Thanks very much,

    Dave
  • xanatosxanatos Posts: 1,120
    edited 2011-10-18 10:37
    OK, I've got it working... sort of. My intuition is telling me that I am not doing this in the most efficient manner. But I am getting the characters to print across up to five digits:
    
    '  {$STAMP BS2sx}
    '  {$PBASIC 2.5}
    '
    ' =========================================================================
    
    ' -----[ I/O Definitions ]-------------------------------------------------
    
    kbdDA           PIN     3                ' Keyboard Data Available line from 74C922
    kbd0            PIN     4                ' Keyboard bit 0 from 74C922
    kbd1            PIN     5                ' Keyboard bit 1 from 74C922
    kbd2            PIN     6                ' Keyboard bit 2 from 74C922
    kbd3            PIN     7                ' Keyboard bit 3 from 74C922   These are all now on INB
    
    LCD             PIN     14               ' Parallax Serial LCD Display
    
    ' -----[ Constants ]-------------------------------------------------------
    
    LcdBaud         CON     110             ' LCD Baud derp
    LcdBkSpc        CON     $08             ' move cursor left
    LcdRt           CON     $09             ' move cursor right
    LcdLF           CON     $0A             ' move cursor down 1 line
    LcdCls          CON     $0C             ' clear LCD (use PAUSE 5 after)
    LcdCR           CON     $0D             ' move pos 0 of next line
    LcdBLon         CON     $11             ' backlight on
    LcdBLoff        CON     $12             ' backlight off
    LcdOff          CON     $15             ' LCD off
    LcdOn1          CON     $16             ' LCD on; cursor off, blink off
    LcdOn2          CON     $17             ' LCD on; cursor off, blink on
    LcdOn3          CON     $18             ' LCD on; cursor on, blink off
    LcdOn4          CON     $19             ' LCD on; cursor on, blink on
    LcdLine1        CON     $80             ' move to line 1, column 0
    LcdLine2        CON     $94             ' move to line 2, column 0
    
    ' -----[ Variables ]-------------------------------------------------------
    
    keyIn           VAR     Word            ' Holds translated keypad value
    charHold        VAR     Word            ' Holds multiplied values
    dispChar        VAR     Word            ' Display holder for multiple key presses
    keyCount        VAR     Nib             ' Number of key presses per cycle
    passCode        VAR     Word
    result          VAR     Byte
    
    
    ' -----[ Initialization ]--------------------------------------------------
    
    Reset_LCD:
      HIGH LCD                              ' setup serial output pin
      PAUSE 100                             ' allow LCD to initialize
      SEROUT LCD, LcdBaud, [LcdBLon, LcdOn1, LcdCls]  'LcdBLoff/LcdBLon
      PAUSE 250
      SEROUT LCD, LcdBaud, ["  XANATRONICS"]
      SEROUT LCD, LcdBaud, [LcdLine2, "Fuel Management"]
      PAUSE 1000
    
    ' -----[ Program Code ]----------------------------------------------------
    
    Main:
    
    ' Ask for data DI, TR#, TRKMLG,
    
      SEROUT LCD, LcdBaud, [LcdCls]
      PAUSE 5
      SEROUT LCD, LcdBaud, ["Driver ID & #:      "]
    
      keyCount = 0
      dispChar = 0
      DO ' Routine to accept keyboard data (and then store it in eeprom)
    
        DO : LOOP UNTIL (kbdDA = 1)  ' Wait until Data Available from 74C922
    
        keyIn = INB
        LOOKUP keyIn, [ 1, 2, 3, 10,
                        4, 5, 6, 11,
                        7, 8, 9, 12,
                        14, 0, 15, 13 ], keyIn ' translate kbd matrix
    
        LOOKUP keyIn, ["0123456789ABCD*#"], dispChar ' translate key to ASCII
    
    
        IF (keyCount = 0) THEN
          IF (keyIn < 10) THEN
            SEROUT LCD, LcdBaud, [LcdLine2, DEC keyIn, "       "]
            charHold = keyIn * 10
          ENDIF
          IF (keyIn = 14) THEN  ' 14 = * (Abort and go to beginning)
            SEROUT LCD, LcdBaud, [LcdLine2, dispChar, "       "]
            PAUSE 100
            keyCount = 0
            GOTO Main
          ENDIF
        ELSEIF (keyCount > 0 AND keyCount < 5) THEN
          IF (keyIn < 10) THEN
            charHold = charHold + keyIn
            SEROUT LCD, LcdBaud, [LcdLine2, DEC charHold, "       "]
            charHold = charHold * 10
          ENDIF
          IF (keyIn = 14) THEN  ' 14 = * (Abort and go to beginning)
            charHold = charHold/10
            SEROUT LCD, LcdBaud, [LcdLine2, DEC charHold, dispChar, "       "]
            PAUSE 500
            keyCount = 0
            GOTO Main
          ELSEIF (keyIn = 15) THEN  '15 = # (Accept entry and go to next op)
            charHold = charHold/10
            SEROUT LCD, LcdBaud, [LcdLine2, DEC charHold, dispChar, "       "]
            PAUSE 500
            keyCount = 0
            EXIT
          ENDIF
        ELSEIF (keyCount > 5) THEN
          IF (keyIn = 14) THEN  ' 14 = * (Abort and go to beginning)
            charHold = charHold/10
            SEROUT LCD, LcdBaud, [LcdLine2, DEC charHold, dispChar, "       "]
            PAUSE 500
            keyCount = 0
            GOTO Main
          ELSEIF (keyIn = 15) THEN  '15 = # (Accept entry and go to next op)
            charHold = charHold/10
            SEROUT LCD, LcdBaud, [LcdLine2, DEC charHold, dispChar, "       "]
            PAUSE 500
            keyCount = 0
            EXIT
          ENDIF
    
        ENDIF
    
    
    
        PAUSE 5
        DO : LOOP UNTIL (kbdDA = 0)
        keyCount = keyCount + 1
    
    
      LOOP
      SEROUT LCD, LcdBaud, [LcdCls]
      PAUSE 5
      SEROUT LCD, LcdBaud, ["Next task ....         "]
      PAUSE 2000   ' Replace this with routine to accept keyboard data and PUT to eeprom
    
    
    GOTO Main
    
    

    Am I on the right track, or am I doing something far more convoluted here than I really need to be?

    Thanks,

    Dave
  • Chris SavageChris Savage Parallax Engineering Posts: 14,406
    edited 2011-10-18 12:12
    Dave,

    I have two suggestions and that's all they are, but they may or may not make things easier in the long run. The first is you're doing two LOOKUP commands when all you need is one. In your case it seems as if in the first one you're trying to get you ducks in a row, so to speak, in order to make the second LOOKUP be in alphabetical order. You don't need to do this...instead just order the ASCII values in the second lookup in order that the codes are returned by the 74C922.

    The second thing is that I would deal with the raw values and only format the data going to the LCD. This will make your dealing with the values much easier. If you use a fixed length field you can simplify printing to the LCD as values are added since it will reprint the entire field (3 characters?).
  • xanatosxanatos Posts: 1,120
    edited 2011-10-18 14:13
    Hi Chris,

    I concur re: the double lookup. I really only need to set the displayed char to # or * under those specific circumstances. The raw keyIn values are fine elsewise.

    I'm not sure what you mean by a "fixed length field". How do I go about specifying this and does this replace all my *10 math stuff?

    Thanks!

    Dave
  • Chris SavageChris Savage Parallax Engineering Posts: 14,406
    edited 2011-10-18 15:04
    Dave,

    Fixed length field is when using formatters to send the data to the LCD. It would not interfere with your math because you're formated the output of the data only. In fact, done right you would not need a separate variable for what goes on the display.
  • xanatosxanatos Posts: 1,120
    edited 2011-10-19 08:27
    Hi Chris,

    I'm only partially following you here.... You're referring to formatters like DEC3, for example, to send a fixed-length (in this case, 3 digit), correct? I guess I'm not seeing how I could eliminate the need for a separate variable for what goes to the display. Also - when I specify DEC3, or DEC5, I get a bunch of leading zeros. Is there any sort of Leading Zero Suppression function available? :-)

    Thanks,

    Dave
  • Mike GreenMike Green Posts: 23,101
    edited 2011-10-19 09:17
    "Leading Zero Suppression" ... No. If you use the fixed width formatters, you get leading zeroes. You can use the DEC formatter and provide your own leading blanks if you still need a fixed format like

    IF value < 10000 THEN SEROUT LCD, LCDBAUD, [" "]
    IF value < 1000 THEN SEROUT LCD, LCDBAUD, [" "]
    IF value < 100 THEN SEROUT LCD, LCDBAUD, [" "]
    IF value < 10 THEN SEROUT LCD, LCDBAUD, [" "]
    SEROUT LCD, LCDBAUD, [DEC value]
  • xanatosxanatos Posts: 1,120
    edited 2011-10-19 10:54
    Thanks Chris & Mike. It's doing basically what I need now, although that means I'm up against the task of trying to display (and hold in some sort of variable array) a six-digit number... without making the operator separate the values into two separate numbers.... ah, challenges... :-)

    Thanks again guys!

    Dave
  • Mike GreenMike Green Posts: 23,101
    edited 2011-10-19 11:42
    I'd suggest using two words with each holding a number from 0 to 999. One word would hold the most significant 3 digits and the other word the least significant 3 digits. You can easily do multiple precision addition and subtraction as well as multiplication and division by a constant. General multiplication and division is more complicated, but you'd essentially use the same technique you'd used by hand for decimal digits, just with each digit being from 0-999.

    For output, you'd use a variation on what I showed above with one sequence handling 1000-999999 and the other sequence handling 0-999.
  • xanatosxanatos Posts: 1,120
    edited 2011-10-19 12:13
    Hmmm... so I'd have the stamp watch the key count, and when the first three digits were entered, it would assign that value to the first word and start recording the remaining digits into the second word. Is my thinking correct on this? So all of this could be transparent to the user... they could just punch in their keys without having to do anything differently, correct?

    Thanks.
  • Mike GreenMike Green Posts: 23,101
    edited 2011-10-19 12:56
    That's the idea. A word could hold up to 4 digits this way (0-9999) and you can use as many words as you want to hold the whole number. I suggested 3 digits per word only because you've got 6 digits total and that divides them up evenly. It also makes it easier to do multiplication and division by small constants up to 2 digits. You don't have to do a key count. You could just start with a zero value and, for each digit entered, multiply what you have by 10, then add the value of the new digit. You'd check for overflow (most significant 3 digits have to be < 99 before allowing a new digit). You could also divide the whole value by 10 to throw away the last digit entered. Remember that you're carrying a decimal digit (0-9) back and forth between the two parts when you multiply or divide by 10 (just like if you did it by hand).
  • Chris SavageChris Savage Parallax Engineering Posts: 14,406
    edited 2011-10-19 13:57
    Dave,

    I apologize for the confusion. If your numbers are only ever 1 to 3 digits you can use the modifiers and/or a position change when printing which can be done in a SELECT...CASE statement only for display purposes. So when you type in a single decimal number it appears right-justified (calculator style) and as you type each digit the current value is multiplied by 10, but the display routine checks to see if the value is a single, double or triple digit value and positions/formats the value accordingly.

    By the way...in response to your signature tag line...I can count to 32 (0-31) on one hand. =)
  • Chris SavageChris Savage Parallax Engineering Posts: 14,406
    edited 2011-10-19 14:09
    Whoa! In the time (a few hours, sorry) between hiting reply and sending the response I missed a bunch, so my reply is somewhat late. I was thinking similar to what Mike posted but using the SELECT...CASE (instead of several IF...THEN) to set the position for the DEC to print to as one way of doing it.

    So, using your variable as an example:
    SELECT keyIn
      CASE 0 TO 9
        SEROUT LCD, LcdBaud, [LcdLine2 + 2, DEC inKey]
      CASE 10 TO 99
        SEROUT LCD, LcdBaud, [LcdLine2 + 1, DEC inKey]
      CASE 100 TO 999
        SEROUT LCD, LcdBaud, [LcdLine2, DEC inKey]
    ENDSELECT
    

    This is on the assumption that you want the text right-justified (calculator style) as I thought originally, though after looking at your more complete code I am not sure that's what you wanted.

    Also this code takes up more memory than what is necessary to get the point across. It could be simplified by replacing each SEROUT in the CASE evals with a position/offset aded to the LcdLine2 location for positioning.

    I don't have any 74C922 chips anymore or I would write you some example code. I now use the EDE1144 and have plenty of examples for them, but since they have the ability to send the code parallel or serial I use the serial method to save three I/O pins and therefore my examples would look a bit different on the receiving end.
  • xanatosxanatos Posts: 1,120
    edited 2011-10-20 11:13
    Hi Chris,

    Yes, things move swiftly because I obsess over any oddity in code or function! I'm quite happy with the characters filling in from L to R as I have it now, and I am doing both that and successfully capturing the data that's entered, having converted the keyboard reader section into a subroutine.

    Thanks very much to all of you who helped me here. You are a huge part of what makes Parallax such a fantastic organization.

    Dave
  • Chris SavageChris Savage Parallax Engineering Posts: 14,406
    edited 2011-10-20 12:05
    If you need further assistance on keypad entry and LCD display formatting, just follow up in the future and I will set up a test ficture, though it will use the EDE1144, I can always use the 4-bit parallel output as you are on your project.
  • xanatosxanatos Posts: 1,120
    edited 2011-10-20 12:17
    OH YES!!! THANK YOU for that EDE1144 reference! That thing looks awesome! The 74C922/3 is listed as obsolete and not recommended for new projects at Mouser, and I was wondering what would be a good replacement. The EDE looks very simple to use and offers me the choice of serial or parallel, plus several other nice features. A bonus! Thanks again!

    Dave

    PS., I don't consider my thumb a finger I guess! :-)
  • Chris SavageChris Savage Parallax Engineering Posts: 14,406
    edited 2011-10-21 12:50
    Dave,

    No problem...they even have an EDE1188 I believe which is 8x8 Matrix. As for the thumb...you could always think of it as a sign bit, giving you +/- counts! =)
  • xanatosxanatos Posts: 1,120
    edited 2011-10-22 17:24
    The EDE1188 would give me some tremendous possibilities for interfacing a custom keymatrix - thanks again. I'm putting a few of each of these on order to play around when I get my current project shipped.

    There's so much cool stuff out there... I wish I had the time to find out about them all! :-)

    Thanks again,

    Dave
  • Chris SavageChris Savage Parallax Engineering Posts: 14,406
    edited 2011-10-24 08:19
    Dave,

    That's the great thing about these forums. With so many people there's alway a good pool of information. I myself have learned about things I didn't know via these forums. As always, if you like you can always post projects in the projects forum. Take care.
Sign In or Register to comment.