Forum - MCS Electronics

 

FAQFAQ SearchSearch RegisterRegister Log inLog in

Problema con Encoder

 
Post new topic   Reply to topic    www.mcselec.com Forum Index -> BASCOM-AVR
View previous topic :: View next topic  
Author Message
sielcon

Bascom Member



Joined: 16 Mar 2006
Posts: 82
Location: Argentina

argentina.gif
PostPosted: Wed Mar 12, 2025 9:13 pm    Post subject: Problema con Encoder Reply with quote

Hello everyone, how are you? I'm bothering you to see if any of you with experience using encoders can help me with the problem I'm having. Here's a simple code that reads the encoder through the ISR of timer1 set to 20mS. As you can see, I added an additional timer to read every 100mS to avoid mechanical bounces. I'm attaching the example with the terminal having turned the encoder five times to the right and then five times to the left. As you can see, 7 RIGHT, 2 LEFT, and 2 RIGHT were printed instead of 5 and 5.

Code:

$regfile = "m2560def.dat"
$crystal = 16000000
$hwstack = 128
$swstack = 128
$framesize = 128
$baud = 9600
Config Submode = New
Print "Test encoder"

Dim B , Tim_encoder As Byte
Carga_t1 Alias 312
Config Portk = Input
Portk = &B11
Rota Alias Pink.0                                           'clk encoder
Rotb Alias Pink.1                                           'dt encoder

Config Timer1 = Timer , Prescale = 1024                     ' 20 mS
On Timer1 Int_t1
Timer1 = Carga_t1
Enable Timer1
Start Timer1
Enable Interrupts

Do
Loop
'======================================================
'ISR timer1 - 20mS
'======================================================
Sub Int_t1
Load Timer1 , Carga_t1
Start Timer1
   If Tim_encoder = 0 Then
      B = Encoder(rota , Rotb , Izquierda , Derecha , 0)
      Tim_encoder = 5                                       '100mS
   Else
      Decr Tim_encoder
   End If
End Sub

Derecha:
   Print "Right"
Return

Izquierda:
   Print "Left"
Return
 



[/img]


Then I tried without the additional timer (reading every 20mS) and the result was as follows: I turned five times to the right again and then five times to the left, and 10 RIGHT and 10 LEFT were printed. In other words, the direction was correct for both sides, but the printout is duplicated.

[/img]

I've run several tests with different timers, including within a loop, and even using PCINT and 100nF capacitors between the pins and GND, but nothing makes it work properly. I've attached a photo of the encoder used.
Thank you very much for your attention.
Best regards.



(BASCOM-AVR version : 2.0.8.6 )
Back to top
View user's profile Visit poster's website
programmista123

Bascom Member



Joined: 31 Jan 2018
Posts: 184

poland.gif
PostPosted: Thu Mar 13, 2025 6:37 am    Post subject: Reply with quote

Hello,

The capacitor itself may not bring any improvement - on the contrary - it may accelerate the degradation of the encoder connectors. Are you able to add a resistor in series (for example 100 Ohm) to create an RC filter?

Regards,
Przemek
Back to top
View user's profile
laborratte

Bascom Expert



Joined: 27 Jul 2005
Posts: 305
Location: Berlin

germany.gif
PostPosted: Thu Mar 13, 2025 11:13 am    Post subject: Reply with quote

These type of encoders have a typical bounce time of 2ms, 5ms max. So 100ms is way too much, you probably will miss steps.
In addition: with every indent "click" you get two impulses on A+B (a "full" cycle - see datasheets). So your second attempt with 20ms is the correct behaviour.
Back to top
View user's profile
sielcon

Bascom Member



Joined: 16 Mar 2006
Posts: 82
Location: Argentina

argentina.gif
PostPosted: Thu Mar 13, 2025 7:31 pm    Post subject: Reply with quote

Thank you so much for the replies. I used the 100nF capacitors just for testing, but nothing seems to work as expected.
Back to top
View user's profile Visit poster's website
laborratte

Bascom Expert



Joined: 27 Jul 2005
Posts: 305
Location: Berlin

germany.gif
PostPosted: Thu Mar 13, 2025 10:50 pm    Post subject: Reply with quote

Sorry if I didn't make it clear what I meant.

Here is a waveform of a typical encoder (ALPS EC11 series):



Between two clicks of the encoder (green arrows) you have 2 changes of A/B lines (red arrows) so your program recognises two pulse per click -> 2x left or 2x right.
This is what I called "correct behaviour".

A solution could be: implement a flag or counter in the "Derecha:" and "Izquierda:" routines to suppress every 2nd pulse.

A different approach is to have line A on an INT input and look for a rising edge. On interrupt check in the interrupt service routine the B line state: if B = 0 than CW, if B = 1 than CCW. Of course you have to implement a "debouncing" algorithm which suppresses for 2..5 ms further interrupts.
Back to top
View user's profile
EDC

Bascom Expert



Joined: 26 Mar 2014
Posts: 1131

poland.gif
PostPosted: Fri Mar 14, 2025 3:55 pm    Post subject: Reply with quote

Dont miss any step Very Happy https://www.youtube.com/watch?v=VTA-Wkj9Yv0
Code is available. I can post it again.
Im using a PCINT here. They are available on anypin on Mega2560, so applicable here.

_________________
Check B-Flash -my MCS bootloader app for Android (updated)
Back to top
View user's profile Visit poster's website
murmel

Bascom Member



Joined: 13 Oct 2014
Posts: 19

germany.gif
PostPosted: Sun Mar 16, 2025 7:06 am    Post subject: Reply with quote

Hello EDC,
I would be interested in the code, please upload.
Back to top
View user's profile
EDC

Bascom Expert



Joined: 26 Mar 2014
Posts: 1131

poland.gif
PostPosted: Mon Mar 17, 2025 8:01 am    Post subject: Reply with quote

It is somehow old code so maybe not best possible efficient but this is exactly the code from the video.

Code:
    $regfile = "m644pdef.dat"
    $crystal = 11059200
    $hwstack = 64
    $swstack = 32
    $framesize = 128
     
    ' Cheap encoder PCINT FULLSTEP (one step per click)
    ' 2017/01/02 by BARTek EDC
     
    Config Submode = New
     
    Config Lcdpin = Pin , Rs = Portc.7 , E = Portc.6 , Db4 = Portc.5 , Db5 = Portc.4 , Db6 = Portc.3 , Db7 = Portc.2
    Config Lcd = 16x2
    Cursor Off , Noblink
    Cls
     
    Dim Turn_l As Byte , Turn_r As Byte , Steps As Integer , Milis As Byte
    Dim Enc_new As Byte , Steps_old As Integer , State As Byte
     
     
    Config Portd.0 = Output : Led_a Alias Portd.0
    Config Portd.1 = Output : Led_b Alias Portd.1
     
    Config Portd.2 = Input : Encoder_a Alias Pind.2 : Set Portd.2
    Config Portd.3 = Input : Encoder_b Alias Pind.3 : Set Portd.3
     
    Config Timer2 = Timer , Prescale = 1024 , Compare_a = Disconnect , Clear_timer = 1
     Compare2a = 215                                            '20ms @11MHz/1024
     
    Pcmsk3 = &B00001100
    Enable Pcint3 : On Pcint3 Encoder_isr Nosave
     
    Locate 1 , 6 : : Lcd "Full step"
     
    Sub Show_steps()
     Locate 2 , 9 : If Steps > 0 Then Lcd "+" : Lcd Steps ; "    "
    End Sub
     
     
    Call Show_steps()
     
    Enable Interrupts
     
    Do
     
     If Turn_l > 0 Then
      Decr Turn_l
       Incr Steps
     End If
     
     If Turn_r > 0 Then
      Decr Turn_r
       Decr Steps
     End If
     
     If Tifr2.ocf2a = 1 Then
      Tifr2.ocf2a = 1
      Incr Milis
       If Milis > 4 Then                                        '5x20ms
        Milis = 0
        If Steps_old <> Steps Then
     
         Call Show_steps()
     
         Steps_old = Steps
        End If
       End If
     End If
     
     Led_a = Encoder_a
     Led_b = Encoder_b
     
    Loop
    End
     
     
    Encoder_isr:
     
      $asm
      !PUSH R16
      !PUSH R24
      !PUSH R26
      !PUSH R27
      !in R24, sreg
      !PUSH  R24
      $end Asm
     
       Enc_new.0 = Encoder_a
       Enc_new.1 = Encoder_b
     
       Select Case Enc_new
     
        Case 1
         Select Case State
          Case 0 : State = 1                                    'pocz L krok 1
          Case 3 : State = 1                                    'revers z 2xHI
          Case 4 : State = 5                                    'progress w prawo krok 3 (bo opadaja naprzemian)
         End Select
     
        Case 2
         Select Case State
          Case 0 : State = 2                                    'pocz R krok 1
          Case 4 : State = 2                                    'revers z 2xHI
          Case 3 : State = 6                                    'progress w lewo krok 3 (bo opadaja naprzemian)
         End Select
     
        Case 0                                                  '2xHI
         Select Case State
          Case 1 : State = 3                                    'byl pocz L krok 1 ->L krok 2 S3
          Case 2 : State = 4                                    'byl pocz R krok 1 ->R krok 2 S4
     
          Case 5 : State = 4                                    'revers
          Case 6 : State = 3                                    'revers
         End Select
     
        Case 3
         Select Case State
          Case 5 : Incr Turn_l
          Case 6 : Incr Turn_r
         End Select
          State = 0
     
       End Select
      '          Tuned with NoSave Tool
     
      $asm
      !POP  R24
      !out sreg, r24
      !POP R27
      !POP R26
      !POP R24
      !POP R16
      $end Asm
     
    Return


Code:
    $regfile = "m644pdef.dat"
    $crystal = 11059200
    $hwstack = 64
    $swstack = 32
    $framesize = 128
     
    ' Cheap encoder PCINT 4xSTEP (four step per click)
    ' 2017/01/02 by BARTek EDC
     
    Config Submode = New
     
    Config Lcdpin = Pin , Rs = Portc.7 , E = Portc.6 , Db4 = Portc.5 , Db5 = Portc.4 , Db6 = Portc.3 , Db7 = Portc.2
    Config Lcd = 16x2
    Cursor Off , Noblink
    Cls
     
    Dim Turn_l As Byte , Turn_r As Byte , Steps As Integer , Milis As Byte
    Dim Enc_new As Byte , Steps_old As Integer , State As Byte
     
     
    Config Portd.0 = Output : Led_a Alias Portd.0
    Config Portd.1 = Output : Led_b Alias Portd.1
     
    Config Portd.2 = Input : Encoder_a Alias Pind.2 : Set Portd.2
    Config Portd.3 = Input : Encoder_b Alias Pind.3 : Set Portd.3
     
    Config Timer2 = Timer , Prescale = 1024 , Compare_a = Disconnect , Clear_timer = 1
     Compare2a = 215                                            '20ms @11MHz/1024
     
    Pcmsk3 = &B00001100
    Enable Pcint3 : On Pcint3 Encoder_isr Nosave
     
     
    Sub Show_steps()
     Locate 2 , 9 : If Steps > 0 Then Lcd "+" : Lcd Steps ; "    "
    End Sub
     
    Locate 1 , 5 : : Lcd "Every step"
     
    Call Show_steps()
     
    Enable Interrupts
     
    Do
     
     If Turn_l > 0 Then
      Decr Turn_l
       Incr Steps
     End If
     
     If Turn_r > 0 Then
      Decr Turn_r
       Decr Steps
     End If
     
     If Tifr2.ocf2a = 1 Then
      Tifr2.ocf2a = 1
      Incr Milis
       If Milis > 4 Then                                        '5x20ms
        Milis = 0
        If Steps_old <> Steps Then
     
          Call Show_steps()
     
          Steps_old = Steps
     
        End If
       End If
     End If
     
     Led_a = Encoder_a
     Led_b = Encoder_b
     
    Loop
    End
     
     
    Encoder_isr:
     
      $asm
      !PUSH R16
      !PUSH R24
      !PUSH R26
      !PUSH R27
      !PUSH R30
      !PUSH R31
      !in R24, sreg
      !PUSH  R24
      $end Asm
     
       Enc_new.0 = Encoder_a
       Enc_new.1 = Encoder_b
     
       Select Case Enc_new
     
        Case 1
         Select Case State
          Case 0 : State = 1 : Decr Steps                       'pocz L krok 1
          Case 3 : State = 1 : Incr Steps                       'revers z 2xHI
          Case 4 : State = 5 : Incr Steps                       'progress w prawo krok 3 (bo opadaja naprzemian)
         End Select
     
        Case 2
         Select Case State
          Case 0 : State = 2 : Incr Steps                       'pocz R krok 1
          Case 4 : State = 2 : Decr Steps                       'revers z 2xHI
          Case 3 : State = 6 : Decr Steps                       'progress w lewo krok 3 (bo opadaja naprzemian)
         End Select
     
        Case 0                                                  '2xHI
         Select Case State
          Case 1 : State = 3 : Decr Steps                       'byl pocz L krok 1 ->L krok 2 S3
          Case 2 : State = 4 : Incr Steps                       'byl pocz R krok 1 ->R krok 2 S4
     
          Case 5 : State = 4 : Decr Steps                       'revers
          Case 6 : State = 3 : Incr Steps                       'revers
         End Select
     
        Case 3
         Select Case State
          Case 1 : State = 0 : Incr Steps
          Case 2 : State = 0 : Decr Steps
     
          Case 5 : Incr Steps
          Case 6 : Decr Steps
         End Select
          State = 0
     
       End Select
      '          Tuned with NoSave Tool
     
      $asm
      !POP  R24
      !out sreg, r24
      !POP R31
      !POP R30
      !POP R27
      !POP R26
      !POP R24
      !POP R16
      $end Asm
     
    Return


Here is this code implemented for three encoders. WOrks well with some CNC machine.
Some optical encoders have Push-Pull outputs so they have intermediate point with two HI-state not regular LO-state. So here I have Const Intermediate to deal with such option.
Code:
$regfile = "m644pdef.dat"                                   '64K FLASH, 4K SRAM, 2K EEPROM, 2xUSART
$crystal = 16000000
$hwstack = 128
$swstack = 64
$framesize = 128
 
$baud1 = 115200
 Open "COM2:" For Binary As #2
  Debug Off
 
Config Submode = New
 
Const Intermediate = 1                                      'przy przej&#347;ciu obydwa plus=1  obydwa minus=0
 
 
'*********************************************************
'*                                                       *
'*********************************************************
  Dim Enc_new As Byte
  Dim Steps(3) As Long , Old_steps(3) As Long , Sign(3) As Long
 
'-----------------------------------[ENC X]---------------
  Dim State1 As Byte
 
  Config Portb.0 = Input : Encoder1_a Alias Pinb.0 : Set Portb.0       'PCINT8
  Config Portb.1 = Input : Encoder1_b Alias Pinb.1 : Set Portb.1       'PCINT9
 
   Pcmsk1 = &B0000_0011
   Enable Pcint1 : On Pcint1 Encoder1_isr Nosave
 
'-----------------------------------[ENC Y]---------------
  Dim State2 As Byte
 
  Config Portc.0 = Input : Encoder2_a Alias Pinc.0 : Set Portc.0       'PCINT16
  Config Portc.1 = Input : Encoder2_b Alias Pinc.1 : Set Portc.1       'PCINT17
 
   Pcmsk2 = &B0000_0011
   Enable Pcint2 : On Pcint2 Encoder2_isr Nosave
 
'-----------------------------------[ENC Z]---------------
  Dim State3 As Byte
 
  Config Portd.0 = Input : Encoder3_a Alias Pind.0 : Set Portd.0       'PCINT24
  Config Portd.1 = Input : Encoder3_b Alias Pind.1 : Set Portd.1       'PCINT25
 
   Pcmsk3 = &B0000_0011
   Enable Pcint3 : On Pcint3 Encoder3_isr Nosave
 
 
Enable Interrupts
 
 
Do
 
 If Old_steps(1) <> Steps(1) Then
  Old_steps(1) = Steps(1)
 
 End If
 
 If Old_steps(2) <> Steps(2) Then
  Old_steps(2) = Steps(2)
 
 End If
 
 If Old_steps(3) <> Steps(3) Then
  Old_steps(3) = Steps(3)
 
 End If
 
 
Loop
End
 
Encoder1_isr:
 
  $asm
  !PUSH R16
  !PUSH R17
  !PUSH R18
  !PUSH R19
  !PUSH R20
  !PUSH R24
  !PUSH R26
  !PUSH R27
  !IN R24, SREG
  !PUSH  R24
  $end Asm
 
   Enc_new = Pinb And &B0000_0011
 
      Select Case Enc_new
 
       Case 1
        Select Case State1
         Case 0 : State1 = 1
         Case 3 : State1 = 1
         Case 4 : State1 = 5
        End Select
 
       Case 2
        Select Case State1
         Case 0 : State1 = 2
         Case 4 : State1 = 2
         Case 3 : State1 = 6
        End Select
 
       #if Intermediate = 1
        Case 3
       #else
        Case 0
       #endif
 
        Select Case State1
         Case 1 : State1 = 3
         Case 2 : State1 = 4
 
         Case 5 : State1 = 4
         Case 6 : State1 = 3
        End Select
 
       #if Intermediate = 1
        Case 0
       #else
        Case 3
       #endif
 
        Select Case State1
         Case 5 : Incr Steps(1)                             ': Set L_led : Reset R_led
         Case 6 : Decr Steps(1)                             ': Set R_led : Reset L_led
        End Select
         State1 = 0
 
      End Select
 
 
  '#  PUT YOUR ISR ROUTINES HERE   #
  '          Tuned with NoSave Tool 1.10
 
  $asm
  !POP  R24
  !OUT SREG, R24
  !POP R27
  !POP R26
  !POP R24
  !POP R20
  !POP R19
  !POP R18
  !POP R17
  !POP R16
  $end Asm
 
Return
 
Encoder2_isr:
 
  $asm
  !PUSH R16
  !PUSH R17
  !PUSH R18
  !PUSH R19
  !PUSH R20
  !PUSH R24
  !PUSH R26
  !PUSH R27
  !IN R24, SREG
  !PUSH  R24
  $end Asm
 
   Enc_new = Pinc And &B0000_0011
 
      Select Case Enc_new
 
       Case 1
        Select Case State2
         Case 0 : State2 = 1
         Case 3 : State2 = 1
         Case 4 : State2 = 5
        End Select
 
       Case 2
        Select Case State2
         Case 0 : State2 = 2
         Case 4 : State2 = 2
         Case 3 : State2 = 6
        End Select
 
       #if Intermediate = 1
        Case 3
       #else
        Case 0
       #endif
 
        Select Case State2
         Case 1 : State2 = 3
         Case 2 : State2 = 4
 
         Case 5 : State2 = 4
         Case 6 : State2 = 3
        End Select
 
       #if Intermediate = 1
        Case 0
       #else
        Case 3
       #endif
 
        Select Case State2
         Case 5 : Incr Steps(3)                             ': Set L_led : Reset R_led
         Case 6 : Decr Steps(3)                             ': Set R_led : Reset L_led
        End Select
         State2 = 0
 
      End Select
 
 
  '#  PUT YOUR ISR ROUTINES HERE   #
  '          Tuned with NoSave Tool 1.10
 
  $asm
  !POP  R24
  !OUT SREG, R24
  !POP R27
  !POP R26
  !POP R24
  !POP R20
  !POP R19
  !POP R18
  !POP R17
  !POP R16
  $end Asm
 
Return
 
Encoder3_isr:
 
  $asm
  !PUSH R16
  !PUSH R17
  !PUSH R18
  !PUSH R19
  !PUSH R20
  !PUSH R24
  !PUSH R26
  !PUSH R27
  !IN R24, SREG
  !PUSH  R24
  $end Asm
 
   Enc_new = Pind And &B0000_0011
 
      Select Case Enc_new
 
       Case 1
        Select Case State3
         Case 0 : State3 = 1
         Case 3 : State3 = 1
         Case 4 : State3 = 5
        End Select
 
       Case 2
        Select Case State3
         Case 0 : State3 = 2
         Case 4 : State3 = 2
         Case 3 : State3 = 6
        End Select
 
       #if Intermediate = 1
        Case 3
       #else
        Case 0
       #endif
 
        Select Case State3
         Case 1 : State3 = 3
         Case 2 : State3 = 4
 
         Case 5 : State3 = 4
         Case 6 : State3 = 3
        End Select
 
       #if Intermediate = 1
        Case 0
       #else
        Case 3
       #endif
 
        Select Case State3
         Case 5 : Incr Steps(2)                             ': Set L_led : Reset R_led
         Case 6 : Decr Steps(2)                             ': Set R_led : Reset L_led
        End Select
         State3 = 0
 
      End Select
 
 
  '#  PUT YOUR ISR ROUTINES HERE   #
  '          Tuned with NoSave Tool 1.10
 
  $asm
  !POP  R24
  !OUT SREG, R24
  !POP R27
  !POP R26
  !POP R24
  !POP R20
  !POP R19
  !POP R18
  !POP R17
  !POP R16
  $end Asm
 
Return

_________________
Check B-Flash -my MCS bootloader app for Android (updated)
Back to top
View user's profile Visit poster's website
Display posts from previous:   
Post new topic   Reply to topic    www.mcselec.com Forum Index -> BASCOM-AVR All times are GMT + 1 Hour
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You cannot download files in this forum