View previous topic :: View next topic |
Author |
Message |
sielcon
Joined: 16 Mar 2006 Posts: 82 Location: Argentina

|
Posted: Wed Mar 12, 2025 9:13 pm Post subject: Problema con Encoder |
|
|
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 |
|
 |
programmista123
Joined: 31 Jan 2018 Posts: 184

|
Posted: Thu Mar 13, 2025 6:37 am Post subject: |
|
|
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 |
|
 |
laborratte
Joined: 27 Jul 2005 Posts: 305 Location: Berlin

|
Posted: Thu Mar 13, 2025 11:13 am Post subject: |
|
|
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 |
|
 |
sielcon
Joined: 16 Mar 2006 Posts: 82 Location: Argentina

|
Posted: Thu Mar 13, 2025 7:31 pm Post subject: |
|
|
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 |
|
 |
laborratte
Joined: 27 Jul 2005 Posts: 305 Location: Berlin

|
Posted: Thu Mar 13, 2025 10:50 pm Post subject: |
|
|
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 |
|
 |
EDC
Joined: 26 Mar 2014 Posts: 1131

|
|
Back to top |
|
 |
murmel
Joined: 13 Oct 2014 Posts: 19

|
Posted: Sun Mar 16, 2025 7:06 am Post subject: |
|
|
Hello EDC,
I would be interested in the code, please upload. |
|
Back to top |
|
 |
EDC
Joined: 26 Mar 2014 Posts: 1131

|
Posted: Mon Mar 17, 2025 8:01 am Post subject: |
|
|
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ś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 |
|
 |
|
|
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
|
|