producing a negative count instaed of 255
gc3076
Posts: 44
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
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
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.
You can use 2-s complement math, but be careful when it comes to a FOR or IF.
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 -->
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
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 -->
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
Your program has an IF-THEN-ELSE statement with nothing in the THEN part. It would be more efficient to write it as,
or you could implement the inner statements as simple math:
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):
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
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
REP 32\5
sends 5 spaces.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
Tracy Allen
www.emesystems.com