Shop OBEX P1 Docs P2 Docs Learn Events
producing a negative count instaed of 255 — Parallax Forums

producing a negative count instaed of 255

gc3076gc3076 Posts: 44
edited 2006-02-24 19:54 in BASIC Stamp
With the help of this form I have finally got my optical encoder working, incrementing and decrementing counts as desired. My next hurtle is to produce a negative number when the encoder goes CCW and counts down through zero. Instead of going to 255 I would like to display negative counts.

i.e. CCW 4, 3, 2, 1, 0, -1, -2, -3, -4

There must be a trick to this ?

My code to date:

' encoder counting

' {$STAMP BS2}
' {$PBASIC 2.5}
LcdPin················ PIN···· 14
INPUT_FR_PIN_A········ PIN···· 5
INPUT_FR_PIN_B········ PIN···· 4

'
[noparse][[/noparse] Constants ]

LcdBaud············· CON···· 84
LcdCls················ CON···· $0C
LCD_display_CC0·· CON···· 0
LCD_display_CC1·· CON···· 1
LcdBaudMode······ ·CON···· 84
AdcBaudMode······ CON···· 84
LcdStart············ ·CON····· 22
LcdOn················ CON····· 17
Line0················· CON····· 128
Line1················· CON····· 148
T9600··············· ·CON····· 84

'
[noparse][[/noparse] Variables ]

cnt················ VAR···· Byte ' encoder count
pinStates········ VAR··· Nib ' combines the BIT0 and BIT1
pinA·············· ·VAR··· pinStates.BIT0 '·· pin state on input A on encoder
pinB··············· VAR··· pinStates.BIT1 '·· pin state on input B on encoder
NEW············· ·VAR···· Byte········· '·· stores current state of encoder pins
OLD··············· VAR···· Byte········· '
dirtn···············VAR···· Bit·········· '·· direction Bit to indicate CW OR CCW

'
[noparse][[/noparse]main]

SEROUT LcdPin, LcdBaudMode, [noparse][[/noparse]LcdStart, LcdCls, LcdOn] 'values are from the constants heading number
DO
start:
pinA = INPUT_FR_PIN_A
pinB = INPUT_FR_PIN_B

'DEBUG "pinstates ", BIN PINstates, CR

NEW = pinstates & %00000011········ '· AND pinstates and creates the NEW value
dirtn = new.BIT0 ^ old.BIT1········ '· OR's new.BIT0 with old.BIT1 creating a dirtn VAR
IF (old· = new) THEN
ELSE
· IF dirtn=1 THEN Cnt = cnt +1 ' starts the incremented count
· IF dirtn=0 THEN Cnt = cnt -1 ' starts the decremented count
ENDIF
old=new

'DEBUG DEC dirtn,· CR
'DEBUG DEC cnt,· CR

SEROUT LcdPin, LcdBaudMode, [noparse][[/noparse]line1, "AZ count ", DEC cnt]

'PAUSE 1000

LOOP

Comments

  • gc3076gc3076 Posts: 44
    edited 2006-02-24 14:08
    I have also noticed that when I go CW to +10 and go CCW to 9 my value goes to 90, not clearing the 0. Another coding problem ?
  • PJAllenPJAllen Banned Posts: 5,065
    edited 2006-02-24 14:11
    First, I think that this should have stayed in/with your original subject -- Creating Single VAR(nib) with a 2 Bit input

    Second, what's it supposed to do at, say,·-255?· I don't get it.

    You might consider a separate counter that would indicate how far you've back-tracked.
  • allanlane5allanlane5 Posts: 3,815
    edited 2006-02-24 14:12
    I believe that PBasic really only works on positive numbers, especially in its FOR loops and IF checks.

    You can use 2-s complement math, but be careful when it comes to a FOR or IF.
  • Bruce BatesBruce Bates Posts: 3,045
    edited 2006-02-24 14:14
    gc3076 -

    The easiest way to keep accurate encoder counts is the way most quasi-intelligent hardware encoder chips do it. Two counts are maintained internally: UPCOUNT and DOWNCOUNT. Each of these counts are always positive and if you need to know the net difference, one just subtracts one counter from the other counter. To use your program code as an example:

    IF dirtn=1 THEN UPCnt = UPCnt +1 ' starts the incremented count
    IF dirtn=0 THEN DNCnt = DNCnt + 1 ' starts the decremented count
    NETCnt = ABS(UPCnt - DnCnt) 'Determine the net difference

    Regards,

    Bruce Bates

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    <!--StartFragment -->
  • gc3076gc3076 Posts: 44
    edited 2006-02-24 14:26
    Iam displaying this on a serial LCD.

    It should say -1 not 255

    i.e.
    actual CCW encoder movment 1, 0, 255
    desired CCW encoder movement 1, 0, -1

    Also

    i.e.
    actual CCW encoder movment 11, 10, 90, 80
    desired CCW encoder movment 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, -1, -2
  • PJAllenPJAllen Banned Posts: 5,065
    edited 2006-02-24 14:35
    It's showing "90", "80"... because after you print a "10" it's not erasing that trailing "0" from the ten and just writing the single digit, resulting in "90", "80",...
  • Bruce BatesBruce Bates Posts: 3,045
    edited 2006-02-24 14:46
    gc3076 -

    If you insist on using just one count, change the following line of code in your program:

    From:
    SEROUT LcdPin, LcdBaudMode, [noparse][[/noparse]line1, "AZ count ", DEC cnt]

    To:
    SEROUT LcdPin, LcdBaudMode, [noparse][[/noparse]line1, "AZ count ", SDEC cnt]

    Now the sign will be considered.

    Regards,

    Bruce Bates

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    <!--StartFragment -->
  • Chris SavageChris Savage Parallax Engineering Posts: 14,406
    edited 2006-02-24 14:57
    As an addendum to what Bruce said, to clear the previous garbage after your readings use CLREOL at the end of your DEBUG statements.· This will clear from the cursor until the end of the current line.· Or you could just print 3 padding spaces after each DEBUG.

    On the note of counting in negative numbers, SDEC will show you the negative values (signed) but if you need to go down to -255 and up to 255 you will need a WORD variable.· A BYTE just won't suffice for that range.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Chris Savage
    Parallax Tech Support
    csavage@parallax.com
  • Tracy AllenTracy Allen Posts: 6,658
    edited 2006-02-24 17:08
    Hi gc,

    Your program has an IF-THEN-ELSE statement with nothing in the THEN part. It would be more efficient to write it as,
    IF (old  <> new) THEN
      IF dirtn=1 THEN Cnt = cnt +1 ' starts the incremented count
      IF dirtn=0 THEN Cnt = cnt -1 ' starts the decremented count
    ENDIF
    



    or you could implement the inner statements as simple math:


    IF (old  <> new) THEN
      Cnt = Cnt -1 + (dirtn*2)  
     ENDIF
    



    Or, you could implement the whole thing as a math statement (which wouldn't run faster, but I just like to explore different ways of doing things):

    cnt = cnt + (new ^ old max 1) * (-1 + (dirtn*2))
    



    The statement (new ^ old max 1) is zero if no change, 1 if change.

    In any case, with cnt declared as a word, and SDEC instead of DEC, you should be good to go.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Tracy Allen
    www.emesystems.com
  • gc3076gc3076 Posts: 44
    edited 2006-02-24 18:13
    Thanks, great information. It is amazing how the same result can be attained by such a wide variety of code.

    I have changed the LCD SEROUT, to erase the varible trailing. However I don't like the way it makes the variable flash on the screen, especially when the variable is display farther to the right side of the LCD. Is there a trick just to clear the varible location and not the whole LCD ?




    SEROUT LcdPin, LcdBaudMode, [noparse][[/noparse]LcdStart, LcdCls, LcdOn] 'values are from the constants heading number
    DO
    start:
    pinA = INPUT_FR_PIN_A
    pinB = INPUT_FR_PIN_B
    NEW = pinstates & %00000011········ '· AND pinstates and creates the NEW value
    dirtn = new.BIT0 ^ old.BIT1········ '· OR's new.BIT0 with old.BIT1 creating a dirtn VAR
    · IF (old· <> new) THEN
    · Cnt = Cnt -1 + (dirtn*2)
    ·ENDIF
    · old=new

    SEROUT LcdPin,LcdBaudMode, [noparse][[/noparse]Line1, "AZ···· "]
    SEROUT LcdPin,LcdBaudMode, [noparse][[/noparse]SDEC Cnt, "··· ",· LcdCls ]

    ·LOOP
  • Tracy AllenTracy Allen Posts: 6,658
    edited 2006-02-24 19:54
    Put the cursor where you want to clear, and then write spaces. You can use the REP modifier.

    REP 32\5

    sends 5 spaces.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Tracy Allen
    www.emesystems.com
Sign In or Register to comment.