quadrature decoder

Greetings.

In the past I would use a flip flop to interpret the signals from two hall effect sensors to attain a quadrature output but would now like to do the same using a picaxe micro.

I have copied the following from a thread found from searching the subject. I think this will achieve exactly what I want but I am struggling to understand the code.

Can any of you geniuses out there add some clarifying explanation as to what is happening in the example and how this works.

Many thanks...

jg





'================================
'décodeur quadrature Version 03
'PieM 140505
'================================

#picaxe 08M2

symbol InputA = pinc.3
symbol InputB = pinc.4

symbol Comb_act = b0 'combinaison actuelle
symbol Comb_Preced = b1 'combinaison pecédente
symbol Compt = w3 'compteur
'________________________________________________
main:

do
bit0 = InputA
bit1 = InputB

if Comb_act <> Comb_Preced then
Compt = bit1 xor bit8 *2 + compt - 1
Comb_Preced=Comb_act
endif
loop
 
Last edited:

AllyCat

Senior Member
Hi John,

to attain a quadrature output
Sorry, firstly two questions. What do you mean by "attain a quadrature output"? Do you want to detect the sequence in which (and when) two quadrature inputs are changing, or somerthing else? Also, is the speed that your inputs are changing sufficiently slow for PICaxe code to work properly (probably a maximum of a few hundred Hz, even at a raised clock frequency)?

I believe code very similar to that was discussed here a few weeks ago; is that what you found and what don't you understand about it? IMHO the easiest way to understand code like that is by single-stepping with the PICaxe simulator, or even with just a pencil and paper. The key features to understand is that bit0 is the lowest bit of byte b0, bit1 the next etc., and bit8 is the corresponding lowest bit in byte b1, etc.. Multiplying by 2 shifts all the bits left by one (and bit0 becomes zero, bit7 is lost). b0 is the "present state", b1 the "previous state" of the flags (bits) and XOR operates on all 8 bits of two bytes at the same time.

Cheers, Alan.
 

PieM

Senior Member
Hi,

to comp!ete Alan explanation:

Compt = bit1 xor bit8 *2 + compt - 1

case clockwise (or ccw), bit1 xor bit8 =0, Compt = 0 *2 + compt - 1.
Compt =compt - 1
case ccw (or cw), bit1 xor bit8 =1, Compt = 1 *2 + compt - 1.
Compt =compt + 1
 
Thank you both for your comments.

I think I am now grasping the idea although ma pauvre tete is struggling somewhat to really understand the intricacies of the code.

As written (if I got it right!) this is producing a binary addition or subtraction which is not really what I wanted at all.

My desire is to read one of the two pulses from the hall effects to determine a rotational speed (which I can easily manage using a 'count' command) and then secondly, to determine the direction of rotation. It is managing this part that the grey matter is rather failing me.
Using a flip flop, the offset of the pulses as the shaft rotates in opposite directions gives either a 'Q' or 'not Q' to give that indication and that is what I wish to reproduce.

The purpose of this is to monitor and enact a function of a process when it runs forward but to negate the function if the process reverses.

The shaft speed I wish to monitor is not going to exceed a very generously conservative 180 rpm and I anticipate reading a gearwheel of about 50 teeth hence input pulses of max 150 per second or 1 pulse per 6 milli seconds.
To ensure stability, I intend to use a dedicated 08M2 for this part of the device and to feed the output into a 28X2 which is doing the rest of the business most of which is already up and running as desired.


Thanks again.

jg
 

geoff07

Senior Member
From first principles:

If you have two detectors, close by on the shaft

- the rotational speed comes from the interval measured by one detector
- the direction of rotation comes from the interval between the pulses from the two detectors, i.e. which one is seen first. As they are close by on the shaft, you will get A B (gap) A B, or B A (gap) B A
- so the task is to determine which sequence is seen

Personally if I find complex code that I struggle with, I rewrite it so I understand it. Clever coding may save a few bytes but costs far more in misunderstanding.

I would do this (assuming I understand the problem correctly):

1 determine the speed of rotation and thus the interval between pulses from A.
2 determine if the pulse from B was closer to the preceeding A or to the following A
3 that's it
 

g6ejd

Senior Member
All you need to do is use one source as a clock input and the other as a direction indicator. Detect a change of state on the clock input (e.g. 0 to 1) and just after the transition detect the direction input, it will be either 0 or 1 depending on rotation direction. The same technique as using a D-type flip flop with a D and CLK input and Q gives direction of rotation.
 
Thank you both for those suggestions.
I suspect the next couple of evenings will be fully occupied trying alternatives.
Results will posted. Later...

Meanwhile, any further suggestions would be gratefully received

jg
 
Last edited:

PieM

Senior Member
On X2, I use interrupt;
InputA is on Interrupt pin, with hintsetup set for rising edge for example.
In interrupt sub-procedure, InputB state (high or low) is the direction.
 

AllyCat

Senior Member
Hi John,

to determine a rotational speed (which I can easily manage using a 'count' command)
Bear i mind that COUNT is a "blocking" command which may involve significant "lost" time for reasonable resolution. Often it is better to use a PULSIN and calculate the reciprocal value to give rpm. To get the period of the waveform you can add the two "pulse" components, i.e. PULSIN pin,0,variable + PULSIN pin,1,variable.

The shaft speed I wish to monitor is not going to exceed a very generously conservative 180 rpm and I anticipate reading a gearwheel of about 50 teeth hence input pulses of max 150 per second or 1 pulse per 6 milli seconds.
If you're detecting gear teeth then the waveforms probably are a reasonable (symmetrical) "square wave" rather than a "pulse" waveform. In that case, detection of direction should be fairly easy, as described before, your software can just test (or "look for") an edge (i.e. a change) of one of the quadrature waveforms and "immediately" determine the state (logic level) of the other waveform.

Cheers, Alan.
 

g6ejd

Senior Member
On X2, I use interrupt;
InputA is on Interrupt pin, with hintsetup set for rising edge for example.
In interrupt sub-procedure, InputB state (high or low) is the direction.
That's exactly how I would do it
 
All you need to do is use one source as a clock input and the other as a direction indicator. Detect a change of state on the clock input (e.g. 0 to 1) and just after the transition detect the direction input, it will be either 0 or 1 depending on rotation direction. The same technique as using a D-type flip flop with a D and CLK input and Q gives direction of rotation.
This makes perfect sense to me - but could you please explain to my ailing cerebrum which command I should use but cannot find to make an input a clock input... I am using an 08M2 but maybe need something other than this...

Thanks

jg
 

hippy

Ex-Staff (retired)
Either of the two inputs can be used as the clock, so arbitrarily using pinA as the clock, pinB as the other (untested) ...

Code:
#Picaxe 08M2

Symbol Q     = 1         ; Q  output : 1 = Clockwise
Symbol NOT_Q = 2         ; Q/ output : 1 = Anti-Clockwise

Symbol pinA  = pin3      ; Quadrature encoder input
Symbol pinB  = pin4      ; Quadrature encoder input

MainLoop:
  SetFreq M32
  Do
    If pinA = 0 Then
      Do : Loop Until pinA = 1
    Else
      Do : Loop Until pinA = 0
    End If
    If pinB <> pinA Then
      Low NOT_Q : High Q ; Going Clockwise
    Else
      Low Q : High NOT_Q ; Going Anti-Clockwise
    End If
  Loop
If Q is set when anti-clockwise, change "If pinB <> pinA" to "pinB = pinA".
 
Many thanks for the help particularly Hippy's suggestions which I have slightly modified and included my required additions.
This seems to work well even though I think it will be a while yet before I grasp a confident understanding of these loop commands.
Any further suggestions or instructional comments are very welcome

Now for the challenge of putting all the parts together and seeing if anything goes bang....


Code:
main:
        SetFreq M32



        goto Function

Function:

        Do
	  
	  pulsin C.3, 1, w1             ;read and combine both encoder inputs 'on' periods 
	  pulsin C.4, 1, w2             ;divide to generate nominal figure representing 
	  let w3 = w1+ w2 /250          ;rotational speed (higher numerical value = lower            ;
                                      ; speed)
        
        If pin3 = 0   then
        
        Do :  Loop Until pin3 = 1
        
        Else
	  
	  Do : Loop Until pin3 = 0
	  
	  End If                        ;determine direction of rotation and use 'high C.2'   
	                                ;value to inhibit process if CCW
	       
	  If pin4 <> pin3 then high C.2 
	  
	  	   
	  Else low C.2                  ;'low C.2' value cancels inhibit process if rotation is CW
	  
	   
	  
	  if w3 > 95 then high C.2 endif   ;Inhibits process if speed is too low 
	  	  
	  
	  if w3 > 50 and w3 < 95 then low C.2 high C.1 low C.0 endif 
	                                    ;output to instruct low speed process function
	  
	  
	  if w3 < 30 then high C.0 low C.1 endif	  
	                                    ;output to instruct high speed process function
	  
	  
	  if w3 > 30 and w3 < 60 then low C.0 low C.1 low C.2  endif
	                                    ;nul output between low and high speed
	  
	  
	  End If
	  
        
	  loop
 

hippy

Ex-Staff (retired)
In determining the speed, it would generally be better to read both the high and low of the same input pin, rather than just the highs of both. That is, replace -

pulsin C.3, 1, w1
pulsin C.4, 1, w2

With ...

pulsin C.3, 0, w1
pulsin C.3, 1, w2

Or use C.4 if preferred.

Or you could even just do one PULSIN and double its value, or halve the value compared with in the subsequent IF commands.
 
Top