-
Can PBP read optical encoder damn fast? :)
Hello.
Say we have optical encoder from inkjet printer. It has 60 pulses per 1cm of movement. So say it is moving with 20cm per second speed, this is 60x20=1200 readings per second. So can be software written in PBP, which will reliably count number of pulses and direction too? Output will be fed into AD9833, chip won't be doing anything else in realtime. So is this task doable with PBP, and which MCU I should consider?
-
Re: Can PBP read optical encoder damn fast? :)
Well a very fast chip at 64MHz may help.
But using another approach I guess it is possible with slower PIC also. You may use the CCP module to capture the rising and falling edge of the pulses in regard with the Timer so the PIC will capture the timer readings. Either just waiting or doing other stuff while the ISR will just transfer the timer value to your variable.
With 1200 readings you will have to count double that. Rising and falling edge so is 2400 reading and I guess double that also, for the quadrature readings. Finally your pulse to pulse time may be about 200usec. Not too demanding but fast.
Ioannis
-
Re: Can PBP read optical encoder damn fast? :)
Yeah, 1200 counts per second really isn't THAT much. How to go about it depends - as always - on what else the PIC is supposed to do while keeping count (ie should it output to the AD9833 and if so, how, while counting pulses or how it's supposed to work) and on what peripherals and interrups sources are available.
If counting is one state and outputting is another then a tight loop polling the inputs will most likely do just fine for 1200 transistions per second.
It's important to determine if the 60 counts are with 4x decoding or not and if that is needed or not. Not doing 4x decoding is a lot easier than doing it.
The 18F2431 family contains a QEI module that will happily keep track of an encoder producing counts up in the MHz
-
Re: Can PBP read optical encoder damn fast? :)
Well the task is as follows. On power up, ribbon is stopped, AD9833 is set to output certain frequency. Depending on ribbon movement direction afterwards, frequency is increased or decreased. Movement can be fast or slow or even non-linear speed.
-
Re: Can PBP read optical encoder damn fast? :)
You may have a timer in counter mode in background; so you can do things in foreground while it counts in background.
-
Re: Can PBP read optical encoder damn fast? :)
I tried to start it at all, even at slow speeds, and looked forum for rotary encoder debug code. Most examples have things like this in it:
OLDR = PORTB & $30 and similar, current hardware config limiting code.
Is there a way to have "universal" rotary encoder code, which will work, if say one pin is going to PORTD.4 and another to PORTA.2 ? I'm not sure how all this XORing and ANDs can be performed across the various ports.
-
Re: Can PBP read optical encoder damn fast? :)
Do you have hardware already on which this has to run? If that's the case then please tell us what that is which PIC and which pins are available.
Having the encoder pins spread across two different port register will slow it down and is not ideal, two adjacent pins on the same port is prefferable. If those pins have IOC capabilities that's one way to skin it.
You say the encoder have 60 pulses, is that 60 pulses per channel (240 edges per cm) or 15 pulses per channel (60 edges)? If it's the former and you're fine with 60 Counts per cm that makes it easier since it's just a mater of sampling channel B on the Rising edge of channel A. No qudrature decoding needed.
I take it you've already figured out how to talk to the AD9833 or is that going to be the follow up question?
-
Re: Can PBP read optical encoder damn fast? :)
I have not went with AD9833 yet, because if I can't run encoder, then there is no need for DDS. And by the way, some DDS code I see around the forum, so I think I can re-use it. For the encoder, this is simple encoder from inkjet printer, HEDS-9730. The ribbon has plain strips, 60 per centimeter (I've counted it under microscope). Before going with this encoder, I want to have some code running with simple, rotary, 3 pin, incremental encoder. My prototyping system has PIC16F886 on it now, and while now I can connect both pins to same port - say PORTA.1 and PORTA.2, if doing own code, I'd like to have a code, which will not be limited by same port.
-
Re: Can PBP read optical encoder damn fast? :)
If on different port, then you will spend time on transferring the data to a temp variable and do the XOR/AND on that temp byte.
Ioannis
-
Re: Can PBP read optical encoder damn fast? :)
While I know how XOR AND and other logical operations work, I can't get idea, how they are used over time based domain, as in case of encoder. I mean, where is that component, which defines the frequency of readout and pulse width and so on.
-
Re: Can PBP read optical encoder damn fast? :)
I came up with this code idea (have not tested it yet)
Code:
STATE: 'WAIT FOR ENCODER TO BE MOVED (STATE CHANGE)
X=PORTB.1
Y=PORTB.2
PAUSE 10
X1=PORTB.1
Y1=PORTB.2
IF X<>X1 OR Y<>Y1 THEN GOTO NEXTSTEP
GOTO STATE
NEXTSTEP:
SOMELOOP: 'COUNTER LOOP FOR PULSE LENGTH COUNTING
IF PORTB.1=1 THEN XIN=XIN+1 'X INCREMENT
IF PORTB.2=1 THEN YIN=YIN+1 'Y INCREMENT
IF PORTB.1=0 OR PORTB.2=0 THEN GOTO ANALYZE 'EXIT AND COMPARE LENGTHS
GOTO SOMELOOP
ANALYZE: 'DETERMINE DIRECTION AND INCREMENT CORRESPONDING VARIABLE
IF XIN>YIN THEN
CCW=CCW+1
ELSE
CW=CW+1
ENDIF
XIN=0 'RESET VARIABLES
YIN=0
GOTO STATE
-
Re: Can PBP read optical encoder damn fast? :)
Check out https://www.microchip.com/wwwproducts/en/PIC18F4431 this series has a hardware quadrature encoder feedback module that runs on it's own in the back ground.
-
Re: Can PBP read optical encoder damn fast? :)
For optical encoder I use this:
Code:
; PIC18F4520
DEFINE OSC 4
INCLUDE "DT_INTS-14.bas" ; Base Interrupt System
INCLUDE "ReEnterPBP.bas" ; Include if using PBP interrupts
TRISA = %00000000 ' Make all PortA pins output
TRISB = %11001000
Define LCD_DREG PORTA
Define LCD_DBIT 0
Define LCD_RSREG PORTA
define LCD_RSBIT 4
define LCD_EREG PORTA
define LCD_EBIT 6
define LCD_BITS 4
define LCD_LINES 2
define LCD_COMMANDUS 2000
define LCD_DATAUS 50
; encoder ch A PortB.6
; encoder ch B PortB.7
wsave VAR BYTE $70 SYSTEM ; alternate save location for W
enc_new VAR BYTE bank0
enc_old VAR BYTE bank0
enc_counter VAR word bank0
Flag var BYTE bank0
asm
INT_LIST macro ; IntSource, Label, Type, Resetflag?
INT_Handler RBC_INT, _enc, ASM, yes
endm
INT_CREATE ; Creates the interrupt processor
endasm
; Set variable value @ startup
enc_new = 0
enc_old= 0
enc_counter = 0
Flag = 0
@ INT_ENABLE RBC_INT ; enable external (INT) interrupts
Main_Loop:
Lcdout $fe, 1
lcdout Dec enc_counter
goto Main_Loop
enc:
asm
;Read latest input from PORTB & put the value in _enc_new.
MOVE?CB 1,_Flag
movf PORTB,W
movwf _enc_new
;Strip off all but the 2 MSBs in _enc_new.
movlw B'11000000' ;Create bit mask (bits 7 & 6).
andwf _enc_new,F ;Zero bits 5 thru 0.
;Determine the direction of the Rotary encoder.
rlcf _enc_old,F ;left shift it into _enc_old to align bit 6 of
;_enc_old with bit 7 of _enc_new.
movf _enc_new,W ;Move the contents of _enc_new to W in order to XOR.
xorwf _enc_old,F ;XOR previous inputs (in _enc_old) with latest
;inputs (in W) to determine CW or CCW.
btfsc _enc_old,7 ;Test bit 7 of result (in _enc_old). Skip next line
;if it is 0 (direction is CCW).
goto Up ;Bit is 1 (direction is CW). Go around Down
;and increment counter.
Down
;Decrements _enc_counter because the rotary encoder moved CCW.
;Decrements _enc_counter (16 bit value), sets Z on exit.
decf _enc_counter,F ; Decrement low byte
incfsz _enc_counter,W ; Check for underflow
incf _enc_counter+1,F ; Update
decf _enc_counter+1,F ; Fixup
movf _enc_counter,W
iorwf _enc_counter+1,W ; Set Z bit
;Add here code for the CCW LED if needed.
goto Continue ;Branch around UP.
Up
;Increments _enc_counter because the rotary encoder moved CW.
;Increments _enc_counter (16 bit value), sets Z on exit.
incfsz _enc_counter,W ; Add one to low byte
decf _enc_counter+1,F ; No carry (negates next step)
incf _enc_counter+1,F ; Add one to high byte
movwf _enc_counter ; Store updated low byte back.
iorwf _enc_counter+1,W ; Set Z flag
;Add here code for the CW LED if needed.
Continue
;Assign the latest encoder inputs (in _enc_new) to _enc_old.
movf _enc_new,W
movwf _enc_old
INT_RETURN
;============ END OF THE ROTARY ENCODER CODE =====
endasm
-
Re: Can PBP read optical encoder damn fast? :)
Yes I checked that PIC datasheet already, but I don't see any ways to implement it in PBP, we don't have statement for encoder reading, like we have for LCDOUT or OWIN.
-
Re: Can PBP read optical encoder damn fast? :)
I've modified my code and it works ok, but sometimes I get false readings too - say for 20 pulses of CW, I will have 2-3 pulses of CCW and vise versa
Code:
STATE: 'WAIT FOR ENCODER TO BE MOVED (STATE CHANGE)
'Lcdout $Fe, $1, "WAIT..." , DEC ENX, " ", DEC ENY
X=ENX
Y=ENY
PAUSE 1
X1=ENX
Y1=ENY
IF X<>X1 OR Y<>Y1 THEN GOTO SOMELOOP
GOTO STATE
SOMELOOP: 'COUNTER LOOP FOR PULSE LENGTH COUNTING
IF ENX=1 THEN X1IN=X1IN+1 'X INCREMENT
IF ENY=1 THEN Y1IN=Y1IN+1 'Y INCREMENT
IF ENX=0 and ENY=0 THEN GOTO ANALYZE 'EXIT AND COMPARE LENGTHS
PAUSE 1
GOTO SOMELOOP
ANALYZE: 'DETERMINE DIRECTION AND INCREMENT CORRESPONDING VARIABLE
IF X1IN>Y1IN THEN
CCW=CCW+1
ELSE
CW=CW+1
ENDIF
LCDOUT $FE, $1, "RAW", DEC Y1IN, " ", DEC X1IN, " "
LCDOUT $FE, $C0, "VAL ", DEC CCW, " ", DEC CW, " "
PAUSE 1
X1IN=0 'RESET VARIABLES
Y1IN=0
GOTO STATE
-
Re: Can PBP read optical encoder damn fast? :)
This is simple 3 pin incremental encoder, middle pin is tied to VCC, A and B are tied to PORTB.3 PORTB.4, which are also pull down with 10K resistors. If I rotate shaft slowly, then no false readings. What can be reason, some wiring issue or code inefficiency?
-
Re: Can PBP read optical encoder damn fast? :)
Quote:
Originally Posted by
CuriousOne
Yes I checked that PIC datasheet already, but I don't see any ways to implement it in PBP, we don't have statement for encoder reading, like we have for LCDOUT or OWIN.
What stops you from writing directly to the registers?
Ioannis
-
Re: Can PBP read optical encoder damn fast? :)
Quote:
Originally Posted by
CuriousOne
This is simple 3 pin incremental encoder, middle pin is tied to VCC, A and B are tied to PORTB.3 PORTB.4, which are also pull down with 10K resistors. If I rotate shaft slowly, then no false readings. What can be reason, some wiring issue or code inefficiency?
Well, your LCD may be slowing down the response. And since you use PAUSE and LCDOUT it is expected that program is not the most efficient. The encoder is best done in ISR and even better using hardware module when available.
Ioannis
-
Re: Can PBP read optical encoder damn fast? :)
I don't see how to avoid use of pause statement. We have time changing, things are happening within time, so how not to consider time? In final device, there will be no LCDOUT, if that is the problem.
-
Re: Can PBP read optical encoder damn fast? :)
-
Re: Can PBP read optical encoder damn fast? :)
If the encoder strip has 60 lines per cm then you can get a resolution of 240 counts per cm by counting all four edges of the quadrature cycle.
If you're OK with 60 it makes it a lot easier (compared to 4x decoding) since, again, all you need to do is poll channel B on the rising edge of channel A and you have your count direction. Using a coupe of external NAND gates (or perhaps the CLC module if your PIC has one) you can decode that into two discrete signals, up & down. Feed those into two counters on they'll count for you while you PAUSE.
If counting with software, polling the inputs, then using PAUSE, LCDOUT or any other command that takes longer to execute than the shortest time between two pulses WILL ruin the day - in which case resorting to interrupts or hardware counter is the only way. This is why I asked if the the counting should go on WHILE outputting to the DDS.
/Henrik.
-
Re: Can PBP read optical encoder damn fast? :)
As said above, there will be no LCDOUT or any other statements in the loop, except DDS updating. Regarding the precision, have not decided it yet, because have not build and have not heard :D maybe 10 readings per CM also will be ok....
-
Re: Can PBP read optical encoder damn fast? :)
I've found this: https://hackaday.io/project/122039-i2c-encoder-v2 - Ready firmware for the above mentioned PIC with I2C output. So what if I use this chip with that firmware to get data from encoder, and then use my PIC to send required data to DDS?
-
Re: Can PBP read optical encoder damn fast? :)
If I get it right, you will use a PIC to read a quadrature encoder, then communicate with I2C to another PIC and the second PIC will send the data to your DDS?
Does this sound logical and efficient?
You have a PIC then just do it! Use some lines in ISR and get the job done.
After all, it is a good programming exercise! And the bonus is that you will be thrilled when finished! Don't be afraid of the ISR. A bit of work but you can do it!
Ioannis
P.S. what is your current PIC?
-
Re: Can PBP read optical encoder damn fast? :)
I'm result-oriented person :D
And knowing my programming skill, literally saying, I'd prefer to buy wheel, instead of inventing it :)
I have many different PICs, but no software knowledge that deep to handle all this stuff :D
-
Re: Can PBP read optical encoder damn fast? :)
Have you read the specs for that HackADay thing?
Quote:
•It's support the standard rotary encoder and the RGB encoder
•It's possible to set all the 7bit of the I2C address trough a SMD jumper
•Dimension of 25x25mm or 0.98x0.98in
•With the castellated holes is possible to connected several boards on the 4 sides
•Possibility to solder the pull-up resistor on the I2C bus
•3 General Purpose pins. (GP pins)
•256byte of internal EEPROM divided in the 2 bank of 128 byte
•Advanced configuration respect the first version
•The maximum frequency of the A/B signal is 150Hz.
Anything that sticks out?
-
Re: Can PBP read optical encoder damn fast? :)
I am a terrible programmer but have done some ISR routines that also do things fast.
If I can do it, everyone can do it! Try it and see how it goes. After all we are still here...
I'd select a PIC of relatively recent 18F series so the famous DT INTS-18 will support it, follow the instructions for the DT INTS and do some test. See here: http://dt.picbasic.co.uk/INT16/DTINTS-18
Nothing to be afraid of.
Ioannis
-
Re: Can PBP read optical encoder damn fast? :)
Yes I see 150Hz limitation. But as said above, I'd like to test idea first, if it is working at all.
-
Re: Can PBP read optical encoder damn fast? :)
I couldn't help myself, had to see what I could do with just some simple, basic (no pun intended) coding. No interrupts, no hardware assist, no inline assembly language, just 33 line loop of straight PBP.
On an 18F4520 running at 20MHz it's seems solid as a rock at 20kHz. Above 20kHz it misses the odd count when subjected to long bursts. This is with a function generetor generating bursts of "perfect" signals with 50% dutycyle so in real life it might be a little less.
Connecting an optical encoder works fine but a mechanical one does not due to contact bounce. Using a 16bit WORD for the position counter and simple 1x decoding, pissing away 3/4 of the resoultion but that was what was asked for.
It bit-bangs SPI data to an AD9833 but there's no math to calculate actual frequency.
The LCD code is there for my debug purposes but I left it there just in case.
Code:
DEFINE LOADER_USED 1
DEFINE OSC 20
DEFINE LCD_DREG PORTD 'LCD data port
DEFINE LCD_DBIT 0 'LCD data starting bit 0 or 4
DEFINE LCD_RSREG PORTA 'LCD register select port
DEFINE LCD_RSBIT 3 'LCD register select bit
DEFINE LCD_EREG PORTA 'LCD enable port
DEFINE LCD_EBIT 1 'LCD enable bit
DEFINE LCD_RWREG PORTA 'LCD read/write port
DEFINE LCD_RWBIT 2 'LCD read/write bit
DEFINE LCD_BITS 8 'LCD bus size 4 or 8
DEFINE LCD_LINES 2 'Number lines on LCD
DEFINE LCD_COMMANDUS 3000 'Command delay time in us
DEFINE LCD_DATAUS 40 'Data delay time in us
FSYNC VAR LATB.3
SCLK VAR LATB.4
SDATA VAR LATB.5
Ch_A VAR PortB.6
Ch_B VAR PortB.7
Position VAR WORD ' Encoder position
Frequency VAR WORD '
AD9833 VAR WORD[5] ' Array for data to be sent to the AD9833
BitsToSend VAR BYTE ' Number of bits -1 to send to the AD9833 (max 127)
Ch_A_Old VAR BIT ' Memory bit for edge-detection
'-------------------------------------------------------------
'------------------------- Init ------------------------------
'-------------------------------------------------------------
CMCON = 7
ADCON1 = %00001111 ' No analog inputs.
TRISB = %11000001
Frequency = 0
Position = 0
BitsToSend = 255
PAUSE 1000
LCDOUT $FE, 1, "AD9833..."
' Initialize the AD9833 as per example in AN-1070.
' Just to verify that we're good to go.
' This should make it output 400Hz with a 25MHz base clock
AD9833[4] = $2100
AD9833[3] = $50C7
AD9833[2] = $4000
AD9833[1] = $C000
AD9833[0] = $2000
FSYNC = 0
For BitsToSend = 79 to 0 Step -1
SDATA = AD9833.0[BitsToSend]
SCLK = 0
PAUSEUS 20
SCLK = 1
PAUSEUS 20
NEXT
FSYNC = 1
Main:
'-------------------------------------------------------------
'--------------Poll encoder and keep count -------------------
'-------------------------------------------------------------
IF Ch_A = 1 THEN
IF Ch_A_Old = 0 THEN
IF Ch_B = 1 THEN
Position = Position + 1
ELSE
Position = Position - 1
ENDIF
Ch_A_Old = 1
ENDIF
ELSE
Ch_A_Old = 0
ENDIF
'-------------------------------------------------------------
'-------------------------------------------------------------
'------------- If needed, prepare to update DDS --------------
'-------------------------------------------------------------
IF Position <> Frequency THEN ' Has the count changed since last update of the DDS?
IF BitsToSend.7 THEN ' Are we free to update?
Frequency = Position
' See datasheet for AD9833, this is just for basic testing.
AD9833[2] = %0010000000000000
AD9833[1] = %0100000000000111
AD9833[0] = Frequency
AD9833.0[15] = 0
AD9833.0[14] = 1
BitsToSend = 47 ' 3*16 = 48 but we're using this variable to index the bits so minus 1
ENDIF
ENDIF
'-------------------------------------------------------------
'-------------------------------------------------------------
'---If DDS is to be updated, do it one bit per loop iteration----
'-------------------------------------------------------------
IF NOT BitsToSend.7 THEN ' Still bits left to send ?
FSYNC = 0 ' Chip select
SDATA = AD9833.0[BitsToSend] ' Setup data
SCLK = 0 ' Clock low
BitsToSend = BitsToSend - 1 ' Index next bit
SCLK = 1 ' Clock high
ELSE
SCLK = 1
FSYNC = 1 ' Chip select
ENDIF
' This is for debugging purposes.
' If button is pressed and LCD updated while the encoder is moved
' counts will obviously be missed.
IF PortB.0 = 0 THEN
LCDOUT $FE, 1, DEC Position, " ", DEC Frequency, " ", DEC BitsToSend
ENDIF
Goto Main
-
Re: Can PBP read optical encoder damn fast? :)
Excellent job Henrik.
At the expense of a little slower response, a couple of 100nF will help a lot debouncing mechanical encoders. I used that as I did not want to make a software debouncing at that time.
Ioannis
-
Re: Can PBP read optical encoder damn fast? :)
IF A=1 or B=1 AND A<>B
Is this proper replacement for XOR statement?
-
Re: Can PBP read optical encoder damn fast? :)
You could always write a little program to test your supposition and find out , you never know you may learn something
Code:
TOUCH var byte
A VAR TOUCH.0
B VAR TOUCH.1
RES var byte
touch = 4
Debug 9,"XOR TRUTH TABLE"
Debug ,13 ,10,"A",9,"B",9,"A^B",9,"CUT",13 ,10
while touch
touch=touch-1
touch=~touch
;CODE UNDER TEST
IF A = 1 or B = 1 AND A <> B THEN
RES=1
ELSE
RES=0
ENDIF
DEBUG #A,9,#B,9," ",#A^B ,9," ",#RES ,13 ,10
touch=~touch
WEND
-
Re: Can PBP read optical encoder damn fast? :)
And although the little debug program of Richard's might not give you a clue, the keyword is "priority".
Machines do not follow your thoughts. Need more detailed explanations, so parenthesis will help. See page 87 of the manual to understand why your expression is way out of what you intended to.
Ioannis
-
Re: Can PBP read optical encoder damn fast? :)
If not pissing away 3/4 of the encoder resolution is something worth doing here's a replacement routine that does 4x decoding. It might not be the most optimized or elegant way but is works. Surprisingly (to me) it seems to work fine up to around 8kHz which means it does 32000 counts per second when being fed "perfect" quadrature signals my function gen.
Code:
' Added variables:
Encoder VAR BYTE
Old_Enc VAR BYTE
Test VAR BYTE
Dir VAR WORD ' Must be same size as Position variable
'-------------------------------------------------------------
'--------------Poll encoder and keep count -------------------
'-------------Alternative routine with 4x decoding------------
'-------------------------------------------------------------
Encoder.0 = Ch_A
Encoder.1 = Ch_B
Test = Encoder ^ Old_Enc
Dir = 0
If Test = 1 THEN
If Old_Enc = 0 THEN Dir = 1
IF Old_Enc = 1 THEN DIR = -1
IF Old_Enc = 2 THEN Dir = -1
If Old_Enc = 3 Then Dir = 1
ENDIF
IF Test = 2 THEN
IF Old_Enc = 0 THEN DIR = -1
IF Old_Enc = 1 THEN Dir = 1
IF Old_Enc = 2 THEN Dir = 1
IF Old_Enc = 3 THEN Dir = -1
ENDIF
Position = Position + Dir
Old_Enc = Encoder
-
Re: Can PBP read optical encoder damn fast? :)
To me looks elegant enough! Wow, 32000 counts/s? I suppose on a fast 18F device, right?
Ioannis
-
Re: Can PBP read optical encoder damn fast? :)
Same setup as before, 18F4520 @20MHz so not really that fast.
I don't know why it seems faster than the 1x version from earlier, perhaps I made a mistake when measuring either one of them.
-
Re: Can PBP read optical encoder damn fast? :)
Henrik assuming i have implemented your ideascorrectly it works not at all well for a ky040 re in real life, i get about 400 counts per indent and rarely does it get direction correct.
my old code previously posted works near perfectly in the same rig either as isr or polled even a couple of .1uf across the pins does not help.
Code:
#CONFIG
__config _CONFIG1, _FOSC_INTOSC & _CP_OFF & _WDTE_ON & _PWRTE_ON & _MCLRE_ON & _CLKOUTEN_OFF
__config _CONFIG2, _PLLEN_ON & _LVP_OFF
#ENDCONFIG
DEFINE OSC 32
OSCCON=$70
ANSELA=0
OPTION_REG.6=0
ENCODER VAR BYTE ;THE STATE OF THE ENCODER
DIR VAR BYTE ;POSN
Old_Enc VAR BYTE ;LAST MOVE
TEST VAR BYTE
Position VAR WORD
TRISA = %11111110
lata.0=1 ;DEBUG
Ch_A VAR PORTA.4
Ch_B VAR PORTA.5
DEFINE DEBUG_REG PORTA
DEFINE DEBUG_BIT 0
DEFINE DEBUG_BAUD 38400
DEFINE DEBUG_MODE 0
pause 2000
Debug "Start",13 ,10
Position =0
Old_Enc=0
mainloop:
' Encoder.0= Ch_A ;WON'T WORK AT ALL MOST TIMES
' Encoder.1= Ch_B
Encoder = (PORTA&48)>>4
Test = Encoder ^ Old_Enc
Dir = 0
If Test = 1 THEN
If Old_Enc = 0 THEN Dir = 1
IF Old_Enc = 1 THEN DIR = -1
IF Old_Enc = 2 THEN Dir = -1
If Old_Enc = 3 Then Dir = 1
ENDIF
IF Test = 2 THEN
IF Old_Enc = 0 THEN DIR = -1
IF Old_Enc = 1 THEN Dir = 1
IF Old_Enc = 2 THEN Dir = 1
IF Old_Enc = 3 THEN Dir = -1
ENDIF
Old_Enc = Encoder
Position = Position + Dir
IF DIR THEN
debug 13,10, "C",SDEC Position
ENDIF
goto mainloop
my take [no pic18 worky or shitty old chips with no wreg access]
Code:
'****************************************************************'* Name : RE16.BAS *
'* Author : RICHARD *
'* Notice : *
'* : All Rights Reserved *
'* Date : 5/06/2020 *
'* Version : 1.0 *
'* Notes : ONLY PIC16'S AND 12'S WITH WREG *
'* : IN THIS INCARNTATION NO SHITTY OLD CHIPS *
'****************************************************************
#CONFIG
__config _CONFIG1, _FOSC_INTOSC & _CP_OFF & _WDTE_ON & _PWRTE_ON & _MCLRE_ON & _CLKOUTEN_OFF
__config _CONFIG2, _PLLEN_ON & _LVP_OFF
#ENDCONFIG
DEFINE OSC 32
OSCCON=$70
ANSELA=0
OPTION_REG.6=0
ev VAR BYTE bank0 ;THE STATE OF THE ENCODER
cnt VAR WORD bank0 ;POSN
TMP VAR BYTE bank0 ;LAST MOVE IS 1, 0, -1
TRISA = %11111110
lata.0=1 ;DEBUG
DEFINE DEBUG_REG PORTA
DEFINE DEBUG_BIT 0
DEFINE DEBUG_BAUD 38400
DEFINE DEBUG_MODE 0
pause 2000
Debug "Start",13 ,10
CNT=0
mainloop:
ASM
bcf STATUS,C
RLF _ev ,f ;shift last reading into position
bcf STATUS,C
RLF _ev ,f
MOVF PORTA,W ;read enc pins 4,5
ANDLW 48 ;mask off others
SWAPF WREG ,w ;shift NEW reading into position
IORWF _ev,F ;combine this read with last read
MOVF _ev,W ;save ev
ANDLW 15
L?CALL enc_lut ; decide to inc , dec or ignore
MOVWF _TMP ;save decision
BTFSC _TMP,7
GOTO myDEC16
BTFSC _TMP,0
GOTO myINC16
enc_exit ; exit
GOTO OUT
myINC16
INCF _cnt ,f
BTFSC STATUS,Z
INCF _cnt +1 ,f
GOTO enc_exit
myDEC16
MOVF _cnt ,w
BTFSC STATUS,Z
DECF _cnt +1, f
DECF _cnt , f
GOTO enc_exit
OUT
ENDASM
IF TMP THEN
debug 13,10,SDEC CNT
ENDIF
goto mainloop
enc:
ASM
enc_lut ; the decision matrix
addwf PCL, F
retlw 0
retlw 255
retlw 1
retlw 0
retlw 1
retlw 0
retlw 0
retlw 255
retlw 255
retlw 0
retlw 0
retlw 1
retlw 0
retlw 1
retlw 255
retlw 0
ENDASM
-
Re: Can PBP read optical encoder damn fast? :)
I have it running on the bench, works perfectly fine with an optical encoder (Scancon 2RMHF-500, 500 lines / 2000 edges per rev) - IRL :-)
Like I said previously I do not expect it to work reliably with a mechanical encoder unless it is properly debounced in hardware. Why your ASM version works with the same encoder I do not know :-(
You have a DEBUG statement within the loop - that will obviously mess up the timing but I know you know that.
-
Re: Can PBP read optical encoder damn fast? :)
silly me i had the dir var as byte, it now works with this added change
' Encoder.0 = Ch_A
' Encoder.1 = Ch_B
encoder =(porta&48)>>4
reading the pins individually wont work for me @32mhz
-
Re: Can PBP read optical encoder damn fast? :)
I made that exact mistake initially, hence the comment where the DIR variable is declared - yet I missed it when looking at you code...
I wonder why reading the pins individually doesn't work in your case. I only did it that way because CuriousOne wanted to be able to have the signals placed arbitrarily. I suspect though that reading them individually might be faster than masking and shifting.
I've been playing around with the math to go from encoder counts to actual frequency and I'm down to 110 cycles for calculating and stuffing the bits into the array. Had to resort to a tiny bit of ASM, getting the high word of a 16*16bit multiplication back from PBP without resorting to actually using LONGs.