encoder question

Hello everyone,My name is Tony ,I am a beginner in Python, I would like to ask a question.

How to read the encoder value When I have two motors with encoders?

I have successfully read an encoder value in Pin7 and Pin8 with the “timer.ENC_AB” command.

Sorry for my bad english.

import pyb,time
from pyb import Timer,Pin
timer = pyb.Timer(4,freq=114)
while(True):
    timer.ENC_AB
    print('R_encoder',timer.counter())

Hi, see this example:

You need to change the pin names and verify the right timer/channel for the correct pins but otherwise it should work.

Hi kwagyeman, thank you very much for your reply.

I have seen the examples you provided.However, I have more questions to ask.

Q1.I am a user of openmv m7,I use 4 pins to control 2 motors(P0,P1,P2,P4),2 pins for encoder L(P7,P8),and I don’t know where should encoder R’s two pins connect? The picture below is my current dilemma,and also my code below,I have a record: encoder test - YouTube


Q2.I run encoder.py from the examples,it show"ValueError: Pin(X3) doesn’t exist",so i don’t know which Pin ID should i change to.

Q3.I saw the “Notes for Timer.ENC modes”,it say it only works on CH1 and CH2 (and not on CH1N or CH2N),but in this picture https://cdn.shopify.com/s/files/1/0803/9211/files/cam-v3-pinout.png?6147773140464094715 i just see one CH2 in Tim4, two CH1 in Tim4 and Tim2,so can I use openmv m7 to do what I want to do?(control 2 motors and read their encoder value)

Thank you very much for reading this,and I am sorry for my bad English.

import pyb,time
from pyb import Timer,Pin
tim4 = pyb.Timer(4,prescaler=1, period=65535) #for encoder
tim2 = pyb.Timer(2,freq=10000)
tim1 = pyb.Timer(1,freq=10000)
baseV=6800
p0 = pyb.Pin("P0",pyb.Pin.OUT_PP)
p1 = pyb.Pin("P1",pyb.Pin.OUT_PP)
p2 = pyb.Pin("P2",pyb.Pin.OUT_PP)
p4 = pyb.Pin("P4",pyb.Pin.OUT_PP)
ch1 = tim4.channel(1, Timer.ENC_A, pin=Pin("P7"))
ch2 = tim4.channel(2, Timer.ENC_B, pin=Pin("P8"))
def RIGHT():
    ch2 = tim1.channel(2, Timer.PWM, pin=Pin("P1"), pulse_width=baseV)
    p0.low()
def RIGHTback():
    ch3n = tim1.channel(3, Timer.PWM, pin=Pin("P0"), pulse_width=baseV)
    p1.low()
def LEFT():
    ch3 = tim2.channel(3, Timer.PWM, pin=Pin("P4"), pulse_width=baseV)
    p2.low()
def LEFTback():
    ch1 = tim1.channel(1, Timer.PWM, pin=Pin("P2"), pulse_width=baseV)
    p4.low()
while(True):
    #RIGHT()
    #LEFT()
    encoder=tim4.ENC_AB
    print('encoder',tim4.counter())

It looks like you got the left right. As for the R one.

If you look at this datasheet you can see what the extra functions are on the pins: https://www.st.com/resource/en/datasheet/stm32f765vi.pdf

Anyway, Timer 2, channels 3 and 4 are available on “P4” and “P5”. So, just use that, as for the motor driver pins, just uses pins P0/P1/P2/P3.

Hi kwagyeman,I am sorry for the late reply.

I drew a picture according to your suggestion,I posted my code below,and also got a record this time:encoder test2 - YouTube.

But it didn’t work,I don’t know if I have misunderstood,and how to solve this.


Is my code wrong?

import pyb,time
from pyb import Timer,Pin
tim4 = pyb.Timer(4,prescaler=1, period=65535) #for encoder
tim2 = pyb.Timer(2,prescaler=1, period=65535) #for encoder

ch1 = tim4.channel(1, Timer.ENC_A, pin=Pin("P7"))#LEFT
ch2 = tim4.channel(2, Timer.ENC_B, pin=Pin("P8"))#LEFT
ch3 = tim2.channel(3, Timer.ENC_A, pin=Pin("P4"))#RIGHT
ch4 = tim2.channel(4, Timer.ENC_B, pin=Pin("P5"))#RIGHT

while(True):
    Lencoder=tim2.ENC_AB
    Rencoder=tim4.ENC_AB
    print('L encoder',tim4.counter(),'R encoder',tim2.counter())

The encoder mode only works on CH1 and CH2.

http://docs.micropython.org/en/v1.9.3/pyboard/library/pyb.Timer.html
https://community.st.com/s/question/0D50X00009Xkg1KSAR/stm32-quadrature-encoder

Hi, we never designed the hardware around this feature to use encoders. It’s cool that it works on one side at least.

Um, so, you can use pin interrupts to get an encoder reading on the other side.

It’s pretty easy, just make an interrupt for the rising edge on one of the pins and then in the interrupt method increment or decrement a global var by the state of the other pin. I’ll provide a example in a sec.

Hi iabdalkader,thank you for your reply.

“The encoder mode only works on CH1 and CH2”.I have mentioned this in my reply on Apr 03.

I may be too attached to use encoder mode.There is a mention of using interrupt pins in the links you provide.

Should I refer to this?class ExtInt – configure I/O pins to interrupt on external events — MicroPython 1.9.3 documentation

I hope to learn more here.

And thank you very much for reading this,and my English isn’t very good, please don’t mind. :blush:

Hi kwagyeman,Thank you for the quick reply.

Now I know that encoder mode only works on one side(P7,P8).

So,to the next step,should I use the same connection as in the picture below?


I would be very grateful if there is a sample. :unamused:

And thank you so much for your helping me.

Do something like this:

position = 0

pin4 = pyb.Pin("P4")
pin5 = pyb.Pin("P5")

def callback4(line):
    global position
    if pin4.value(): # rising-edge
        position += 1 if pin5.value() else -1
    else: # falling-edge
        position += -1 if pin5.value() else 1

def callback5(line):
    global position
    if pin5.value(): # rising-edge
        position += -1 if pin4.value() else 1
    else: # falling-edge
        position += 1 if pin4.value() else -1

extint4 = pyb.ExtInt(pin4, pyb.ExtInt.IRQ_RISING_FALLING, pyb.Pin.PULL_UP, callback4)
extint5 = pyb.ExtInt(pin5, pyb.ExtInt.IRQ_RISING_FALLING, pyb.Pin.PULL_UP, callback5)   

while(True):
    print(position)

Don’t do anything else in the interrupt handlers other than the simple pin logic code. Note, I may have messed up the python above. If there’s a compile issue and your system crashes immediately try running each method in the main loop first to see if they are okay before enabling the callback interrupt handler.

Hey, I think using 1 channel (TIM2_CH1) you should be able to count pulses, just not know which direction.

Hi iabdalkader,thanks for your reply.

You’re right.I have tried it.But I want to make it a bit more complete,and I think I will need to know the direction of the motor.

I saw kwagyeman’s suggestion, I think I have made some progress.

And thank you so much for helping me. :smiley:

Hi kwagyeman,I appreciate your prompt response.

I am still working on it,But your advice has helped me a lot.

I will complete a stage in the near future.But maybe I will have some problems again.

Thank you for taking your time to answer my question.I hope my question will not cause you any inconvenience.

Thank You Again. :slight_smile:

Hi kwagyeman

I use 4 pins (P5,P6,P7,P8) for the motor driver,and 4 pins for encoder (P0,P1,P2,P3),just like the picture below.

I am sorry that this painting is not very professional.


And I got a record:encoder test3 - YouTube

it looks pretty good :wink:

Can you post your code for others to use? Thanks,

For what it’s worth, on the H7 the TIM2_CH2 is multiplexed on this pin:


Note: If you use this pin you can NOT use the FLIR module.

Hi kwagyeman,here is my code.I’m sure my coding skill is bad :laughing: ,but hope it helps others.

How to connect:use 4 pins (P5,P6,P7,P8) for the motor driver,and 4 pins for encoder (P0,P1,P2,P3),just like the picture below.


And I got a record:encoder test3 - YouTube

import sensor, image, time, pyb, math
from pyb import Pin, Timer
tim4 = Timer(4, freq=10000)
tim2 = Timer(2, freq=10000)
Lposition = 0
Rposition = 0
baseV=6600
p8 = pyb.Pin("P8",pyb.Pin.OUT_PP) 
p7 = pyb.Pin("P7",pyb.Pin.OUT_PP) 
p6 = pyb.Pin("P6",pyb.Pin.OUT_PP) 
p5 = pyb.Pin("P5",pyb.Pin.OUT_PP) 

pin3 = pyb.Pin("P3") #LencoderA
pin2 = pyb.Pin("P2") #LencoderB
pin1 = pyb.Pin("P1") #RencoderA
pin0 = pyb.Pin("P0") #RencoderB

def callback3(line):
    global Lposition
    if pin3.value(): # rising-edge
       Lposition += 1 if pin2.value() else -1
    else: # falling-edge
        Lposition += -1 if pin2.value() else 1
def callback2(line):
    global Lposition
    if pin2.value(): # rising-edge
        Lposition += -1 if pin3.value() else 1
    else: # falling-edge
        Lposition += 1 if pin3.value() else -1

def callback1(line):
    global Rposition
    if pin1.value(): # rising-edge
        Rposition += -1 if pin0.value() else 1
    else: # falling-edge
        Rposition += 1 if pin0.value() else -1
def callback0(line):
    global Rposition
    if pin0.value(): # rising-edge
       Rposition += 1 if pin1.value() else -1
    else: # falling-edge
        Rposition += -1 if pin1.value() else 1

def R():
    ch4 = tim2.channel(4, Timer.PWM, pin=Pin("P5"), pulse_width=baseV)
    p6.low()
def RB():
    ch1 = tim2.channel(1, Timer.PWM, pin=Pin("P6"), pulse_width=baseV)
    p5.low()
def L():
    ch71 = tim4.channel(1, Timer.PWM, pin=Pin("P7"), pulse_width=baseV)
    p8.low()
def LB():
    ch2 = tim4.channel(2, Timer.PWM, pin=Pin("P8"), pulse_width=baseV)
    p7.low()

extint3 = pyb.ExtInt(pin3, pyb.ExtInt.IRQ_RISING_FALLING, pyb.Pin.PULL_UP, callback3)
extint2 = pyb.ExtInt(pin2, pyb.ExtInt.IRQ_RISING_FALLING, pyb.Pin.PULL_UP, callback2)
extint1 = pyb.ExtInt(pin1, pyb.ExtInt.IRQ_RISING_FALLING, pyb.Pin.PULL_UP, callback1)
extint0 = pyb.ExtInt(pin0, pyb.ExtInt.IRQ_RISING_FALLING, pyb.Pin.PULL_UP, callback0)
while(True):
    Lp=(int(Lposition/4))
    Rp=(int(Rposition/4))
    if Rp>65535:
        Rencoder=Rp-(65536*(int(Rposition/262144)))
    elif Rp<0:
        Rencoder=(65536*(abs(int(Rposition/262144))+1)-abs(Rp))
    else:
        Rencoder=abs(Rp)
    if Lp>65535:
        Lencoder=Lp-(65536*(int(Lposition/262144)))
    elif Lp<0:
        Lencoder=(65536*(abs(int(Lposition/262144))+1)-abs(Lp))
    else:
        Lencoder=abs(Lp)
    #R()
    #L()
    print('Lenc',Lencoder,'Renc',Rencoder)

Hi iabdalkader,i have a record for last time i use Tim2_CH1 to counting pulses:encoder test4 - YouTube

And my code below.

So did you mean openmv H7 can easier use timer’s encoder mode for two motors.Sounds pretty good!

import sensor, image, time, pyb, math
from pyb import Pin, Timer
tim4 = pyb.Timer(4,prescaler=1, period=65535)
tim2 = pyb.Timer(2,prescaler=1, period=65535)
ch1 = tim4.channel(1, Timer.ENC_A, pin=Pin("P7"))
ch2 = tim4.channel(2, Timer.ENC_B, pin=Pin("P8"))
ch21 = tim2.channel(1, Timer.ENC_A, pin=Pin("P6"))

while(True):
    encRencoder=tim4.ENC_AB
    encLencoder=tim2.ENC_AB
    print('LEFT',tim2.counter(),'RIGHT',tim4.counter())