Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Looking for Encoder Ideas

Status
Not open for further replies.

jpanhalt

Well-Known Member
Most Helpful Member
I finally got a replacement for my Bourns 64-pulse per revolution optical encoder and have been playing with it all day. I can read left and right rotations reasonably well using the following look-up table:
upload_2015-11-12_16-39-7.png

The problem is that the zeros mean different things. The first 0 (offset =0) means no change in position. The other 0's are effectively errors, such as skipped reads. The characteristic of which is more than one bit changes in the binary value I am reading. In brief, the +1's and -1's are added to an accumulator to determine the actual number of "clicks."

Since "true" zero should be much more common than the other zeros, I am thinking of using another value for the other zeros, such as "2" that could be easily tested for (e.g., xorlw 0x02, skpnz). Any other ideas?

Thanks, John
 
That is the normal table... Its the one I use...

If 2 or 4 or 11 or 13 CW.
If 1 or 7 or 8 0r 14 CCW.

Some of the decimals are no change.. ie.. 5 or 10 or 0 or 15.
The others are not possible... ie.. 3 or 6 or 9 or 12.

The only part I look for is the CW or the CCW values... Couldn't give a monkeys about the rest!!
 
Interesting. I agree on only looking for the CW or CCW change. I am thinking of an "enhancement." My thought was to use those returns that indicate more than a 1-bit change as flags to change the range. MrAL has a recent thread wherein he uses a switch to do the same thing. My thought was to use a missed read for the same purpose. MrAL used the term acceleration, but I just think of it as velocity.

John
 
If you do not require the high resolution of an incremental encoder, in the past I have used a simple dual opto slot detector to create the quadrature pulses for rpm and direction.
Such as Optek OPB 822S etc.
Max.
 
Last edited:
The way I use it is for winch speed and direction.... I never miss a pulse and that way I can workout speed velocity and acceleration.... We also monitor tension so I can give feedback as well... I know yours is a thumb wheel, but the application is the same..
 
I had spent the morning struggling with Word to make a few tables. It is embarrassing how many hours I spent on such a simple task. Anyway, the experience paralyzed my mind, and I couldn't see the obvious, which was my original purpose in making the tables hours before. Please excuse the mental lapse.

I do have a related question. Do you use edge detection, asynchronous samples, or IOC to test for a change in state?

This excerpt from Gurley ( **broken link removed** ) explains better what I am referring to:
However, modern electronics look not at transitions, but at changes of state. (Yes, a transition is where a state changes, but that's English, not electronics.) Basically, the user's electronics contain a high-speed clock and constantly samples the states of A and B. When it sees a change, it counts up or down based on the following table, where 0,1 represents the states of A and B, respectively.

An IOC method was posted by BobW here last month: https://www.electro-tech-online.com/threads/rotory-encoder-woes.146057/#post-1236122

I am leaning toward multiple sampling or BobW's IOC approach and favoring the latter.

John
 
Last edited:
Interesting. I agree on only looking for the CW or CCW change. I am thinking of an "enhancement." My thought was to use those returns that indicate more than a 1-bit change as flags to change the range. MrAL has a recent thread wherein he uses a switch to do the same thing. My thought was to use a missed read for the same purpose. MrAL used the term acceleration, but I just think of it as velocity.

John


Hi there John,

Yeah i call it acceleration because there is a change in the speed (speed=abs(velocity)) not just a change in the distance or numerical value.

Say we have an encoder that can spit out a number from 1 to 100 when we turn it clockwise. We might see this sequence come out:
1,2,3,4,5,...

Now if we are turning it one click per second we get 1, then a second later 2, then a second later 3, etc. This means we are turning it at the rate of 1 click per second, which is speed (or velocity), and for simplicity the program interprets that as 1 click per second and accumulates that as a total count N. Now if we keep turning it for let's say 5 seconds non stop, the program detects that and starts increasing the value of one click, lets say from 1 (before) to 2 (after). Now still turning it 1 click per second, the program interprets this as 2 clicks per second, and thus increasing the count by 2 per second. That is the same as an increase in the speed itself and that means it is really more like velocity. So the clicks for this example would accumulate as:
1,2,3,4,5,7,9,11,13,15,17
and we can see that we started out as accumulating 1 per second until we got to 5 and then we switched to 2 per second.
If we take the derivative we get the acceleration, so i guess this is why it is actually referred to as acceleration (i didnt make this up, that's what it is actually referred to in literature).

If you feel more comfortable calling it velocity im sure that's not a problem unless you see written somewhere something about an acceleration table or list of accelerators. The list is used to determine the times to change the speed. For example, a list like this:
{{5,2},{7,5},{10,20}}
would mean switch to 2 per second after 5 seconds, then switch to 5 per second after 7 seconds, then switch to 20 per second after 10 seconds.
If the user ever stops rotating the control, the sequence starts all over again at 1 per second, then after 5 seconds it increases again to 2 per second, etc.
 
Do you use edge detection, asynchronous samples, or IOC to test for a change in state?

As I have mentioned... I use a small 8 pin pic12f1840 running at 32Mhz... It permanently reads the RA0 and RA1 pins. Its a state machine and outputs a pulse on RA4 when movement is made and a direction on RA5..

The main micro just see's a count pulse and a direction, so the interrupt is tiny!!

Some applications only need direction so I use a two bit DAC on RA4 and RA5 and supply the main micro with a three level direction sense ( This is to overcome gravity and friction when weighing.. Dynamic weighing so to speak!! )
 
Thanks, Ian. I had forgotten what you did. A little standalone MCU is a good option. For the low speed stuff I am thinking of, a 10F2xx could even be glued to the back of the encoder.

Today, I think I will play with BillW's code on an 16F1829. I am looking to send the output to a 16X2 character LCD and have a parallel version coming Monday.

Just as an FYI for other hobbyists, the 6 pins on the encoder are 50-mil pitch, so I used half of a 16-pin SOIC adapter (Velleman) to make a mount for my breadboard. Sorry for the fuzziness, shaky hands this morning.

upload_2015-11-13_6-12-32.png


John
 
I am thinking of, a 10F2xx could even be glued to the back of the encoder.
Great Idea.... Just remember to put 0.1uF on the little circuit as rotary switches ARE VERY NOISY!!
 
This afternoon, I tried BobW's algorithm. It worked well. So, I modified the standard description for decoding quadrature to show how his method works. It was done in Word with the usual condition that MS knows better than any author how it should be formatted. Only took 1.5 hours to modify an existing format to show this new method. :banghead:

Since that format doesn't even survive saving and re-opening on my own PC, I am attaching it as a pdf, which hopefully is more durable. While a little OT, I hope others will find it useful.

John

BTW: My next DigiKey order will include a 10F3xx .
Edit: Bob, Sorry about getting your name wrong. I have been calling you Bill all afternoon. After all, what's in a name? Please accept my apologies.
 

Attachments

  • Quadrature Analysis 3 BobW.pdf
    37.4 KB · Views: 272
Last edited:
An IOC method was posted by BobW here last month: https://www.electro-tech-online.com/threads/rotory-encoder-woes.146057/#post-1236122

I am leaning toward multiple sampling or BobW's IOC approach and favoring the latter.

Mr Al, If you want to try my code, here is the complete interrupt service routine with all necessary register saving and restoration. Also included is the necessary hardware initialization to go into the main program, to save you a bit of trouble. (I find that I almost always forget to set some obscure register and then end up scratching my head for hours.)
Code:
; Interrupt Service Routine for quadrature Encoder
;
; for midrange PIC 12F, 16F...
; Inputs:
;    PortA,0 - Phase A input (position critical) - IOC
;    PortA,1 - Not used here, available for other functions
;    PortA,2 - Phase B input (position critical) - IOC
;
; Encoder variables:
;    CountH, CountL - High and Low byte of Encoder count
;    LastEnc - Previous state of Phase A input
;
Intservice
;     save w and status registers
     movwf     wsave     ; save w register
     swapf     status,w     ;get current status with nibbles reversed
     movwf     statsave     ; and save it
;     start of interrupt service
     bank0     ; Sel Bank 0
; Start of encoder service code
EncRead
     rrf portA,w
     rlf LastEnc,f
     xorwf LastEnc,w
     andlw 0x02
     subwf CountL,f ;subtract either 0 or 2 depending on encoder change
     btfsc status,c
     incf CountH,f
     incfsz CountL,f     ;then increment regs to correct to +/-1
     decf CountH,f
; Note, if fewer than 16 bits are desired, then insert code
; at this point to mask off the unneeded high bits in CountH
; Eg., for a 0-4095 count use the following additional code:
;     movlw b'00001111'
;     andwf CountH,f
; End of encoder service code
;     Restore saved registers and return to main program
     bcf intcon,raif ; clear the interrupt
     swapf     statsave,w     ; get status back without changing flags
     movwf     status     ; and restore status register
     swapf     wsave,f     ; this reloads w without changing status bits
     swapf     wsave,w     ; w is now restored
     retfie     ; return from interrupt service routine



; Main program hardware initialization for portA digital I/O
; This example is for a 16F630. Some register bits may be different for other MCUs
;   interrupt on change for bits 0 and 2
     clrf intcon
     bank0     ; Select Bank 0
     clrf portA
     movlw 0x07  ;comparator off
     movwf cmcon ;disable comparator, enable digital portA
     clrf option_reg
     bsf option_reg,INTEDG ;set for rising edge interupts
     movlw b'00000000' ; Config port C for all outputs
     movwf TRISC
     movlw b'00000101' ; Config port A bits 0 and 2 as inputs
     movwf TRISA
; Interrupt initialization
     bank1
     clrf pie1   ;Disable all peripheral interrupts
     movlw b'00000101' ;interrupt on change for PortA inputs 0 and 2
     movwf ioca
     movf portA,w ;Read encoder inputs
     movwf LastEnc ;Initialize last encoder value
; Enable or disable the encoder:
     movlw b'10001000'  ;Enable interrupts
;     movlw b'00001000'  ;Disable interrupts
     movwf intcon     ;

Edit note:
Added code to initialize the value of LastEnc in the main program, and to change 'SaveA' to 'LastEnc' in one of the comments. (I'd changed variable names at one point, but missed the comment.)
 
Last edited:
Edit: Bob, Sorry about getting your name wrong. I have been calling you Bill all afternoon. After all, what's in a name? Please accept my apologies.
No problem, considering that I had called you Mr. Al in my last post. :facepalm:
I'm getting my encoder threads mixed up.

BTW, the code that I posted will give a positive or negative increment on every transition. If that's too much resolution, then you can transfer the count value to another register and shift it right once or twice to drop it back down the the 64 ppr.

Also note that I made a minor edit to the above code.
 
Bob,

I just used the meat of your code that was in the other post, and I do want every transition. Haven't decided whether I will do it all in one MCU or a separate little board attached to the encoder as mentioned above. Thanks for tipping us off about the edits.

I used a 12F683, mainly because I was playing that chip for something else. For that chip, it appears that Microchip makes a distinction between other peripheral interrupts and the IOC interrupts in INTCON:
Capture IOC.PNG


I left bit<6> clear and only set GIE and GPIE. In the IOC register (Bank0), it is also necessary to set the appropriate pins. I clear GPIF on exiting the ISR. Perhaps that name (GPIE) is due to calling the 12F683 port "GPIO" instead of a proper port name. In the 12F1840, GPIE is renamed IOCIE, which makes more sense. I am not that familiar with IOC on other chips.

I think I have made all the name corrections for you, including in the diagram I posted.

Thank you again for sharing your algorithm.

John
 
Microchip has inconsistent register naming conventions. If the chip has more than one port then they refer to them as PortA, PortB etc., but if there's only one port, then it's called GPIO, and the associated config registers are also named differently. I don't know why, on single port chips, they can't just refer to the single port as PortA, and keep everything consistent.
 
Microchip has inconsistent register naming conventions. If the chip has more than one port then they refer to them as PortA, PortB etc., but if there's only one port, then it's called GPIO, and the associated config registers are also named differently. I don't know why, on single port chips, they can't just refer to the single port as PortA, and keep everything consistent.
On newer chips (10F320/322, 12F1571/1572, 12F1822, 12F1840, etc.), they do use PORTA... Try to keep up, Bob (grin)...
 
Well that's good to see.
Yeah, I still have a pile of the older chips that I need to use up before I can try these newfangled ones.
 
Here's a little follow-up. My first Bourns encoder died an early death, and DigiKey replaced it. I had seen pictures of how they are made, but I decided to take a look anyway. Here are some pictures. One shows the parts right after popping the back off. There is a little pot accessible from the back, but covered with the label. Then there is the LED and detector and a very nice slotted disk. The rule is in millimeters. One photo shows some silicon. I have no idea what it does except act as the photodetector. Maybe it acts like a comparator to give sharp state changes.

Regards, John

JustOpen Still003.jpg Opened Still004.jpg Silicon Still008.jpgStill010.jpg
 
The pot is often there to adjust the phase angle between the two pulses to exactly quadrature (90°).
The optical/graticule type of encoder starts off as two sine waves, they are then squared up for output, some encoders will retain the sine waves and use the Arctangent function to increase the resolution to much higher than the slot count itself.
Max.
 
Status
Not open for further replies.

New Articles From Microcontroller Tips

Back
Top