Bascom and AVR, Encoders
Encoders are a special type of rotary switches. Most encoder have an A and B output, that switches as the encoder is
turned:

Encoders come in two variants: contacting and optical. A contacting encoder has switches that close or open as the
encoder is turned. As the switches are contacting, you must consider contact bounce. Read more on
contact bounce
if you need to. Contacting encoders often have detents that 'click' through an entire A/B cycle per detent.
Optical encoders have a slotted disc with two led/photo-transistor combinations. These sensors are arranged around
the disc such that when the disc is turned, the A/B pattern is output. Take an old-fashioned computer mouse apart and
you'll understand.
Contacting encoders usually have three pins: the centre pin goes to Ground, the other two are A and B that switch to
Ground. So, reading the switches involves no more than connecting them to two AT90S2313 inputs. I always use 10k pull-ups
on these input pins.
Optical encoders often have pull-up resistors built-in. (Check the datasheet!) They have a power-supply, a Ground and A/B pins. Sometimes they
have an 'index' output, a pin that switches independently of A/B. Optical encoders have a transistor that does the
switching, so you need not worry about contact bounce.
Both type of encoders sometimes have an extra switch that is operated by pushing the shaft. This can be a nice sort of
'Enter' button.
Let us start with attaching a contacting or optical encoder to the AT90S2313:

And begin with a simple program that continuously reads the A/B switches:
test-encoder.bas
$regfile = "2313def.dat"
$crystal = 4000000
Config Pind.6 = Output
Config Pind.2 = Input
Config Pind.3 = Input
Const Debouncetime = 25
Dim Wtime As Byte
Dim Encounter As Integer
Cls
Wtime = 100
Encounter = 0
Set Portd.2
Set Portd.3
Do
Cls
Lcd Pind.2 ; " " ; Pind.3
Waitms Wtime
Loop
End
In the Do Loop, the state of Pind.2 and Pind.3 are displayed on the LCD.
Using a contacting encoder
I started with a
Bourns
ECW1J-B24-AC0024
contacting encoder. Such an encoder has contact bounce:

although it is not much. The datasheet states a conservative maximum of 5 milliseconds when turning the encoder
at 15 rpm. I used a debounce time of 1 millisecond in the following program:
encoder-bourns-ecw1j.bas
$regfile = "2313def.dat"
$crystal = 4000000
Cha Alias Pind.2
Chb Alias Pind.3
Config Cha = Input
Config Chb = Input
Config Pind.6 = Output
Config Int0 = Falling
Const Debouncetime = 1
Dim Wtime As Byte
Dim Encounter As Integer
Set Chb
On Int0 Getencoder
Cls
Wtime = 100
Encounter = 0
Enable Interrupts
Enable Int0
Do
Set Portd.6
Waitms Wtime
Upperline
Lcd "encounter: " ; Encounter ; " "
Reset Portd.6
Waitms Wtime
Loop
Getencoder:
Waitms Debouncetime
If Cha = 0 Then
If Chb = 0 Then Incr Encounter Else Decr Encounter
End If
Gifr = 64
Return
End
Pin Portd.2 is Alias'ed to Cha, Portd.3 to Chb. Both are configured to Input.
Int0 is configured to occur on trailing edges of Cha input.
Debouncetime is set to 1 millisecond.
In the Do Loop the Led is switched on and off and the value of encounter is put on the Lcd.
In the interrupt routine Getencoder, a debouncetime is executed, a check is done on Cha (must be low) and
if Chb is low, encounter is incremented, else decremented.
Formally, the check on Cha = 0 in the interruptroutine is not necessary; we are in the interrupt routine
>because< Cha went from high to low! I have found this check to be useful however, especially with
contacting encoders that sometimes 'jitter' between two A/B states.
Using an optical encoder
I also tried a
HP, now Agilent
500 cycles-per-revolution, TTL-output, HEDS-5700 optical encoder: (This type is not on Agilent's web-site anymore, try:
HEDS-550 for a similar type)
Optical encoders do not have contact bounce:

(note the time-base setting)
encoder-hp-heds-5700.bas
$regfile = "2313def.dat"
$crystal = 4000000
Cha Alias Pind.2
Chb Alias Pind.3
Config Chb = Input
Config Pind.6 = Output
Config Int0 = Falling
Dim Wtime As Byte
Dim Encounter As Integer
Set Chb
On Int0 Getencoder
Cls
Wtime = 100
Encounter = 0
Enable Interrupts
Enable Int0
Do
Set Portd.6
Waitms Wtime
Upperline
Lcd "encounter: " ; Encounter ; " "
Reset Portd.6
Waitms Wtime
Loop
Getencoder:
If Chb = 0 Then Incr Encounter Else Decr Encounter
Gifr = 64
Return
End
In the interrupt routine, the debounce is omitted as well as the Cha = 0 check.
A 'special' encoder
I have tested an
ALPS
contacting encoder, that does not have an A/B output, but instead an A output that pulses closed when turned left (B is then open)
and a B output that pulses closed when turned right (A is then open). I could not find this type on the ALPS web-site.
This type of encoder is the easiest to use: both A and B output can be connected to an interrupt pin:
encoder-alps-special.bas
$regfile = "2313def.dat"
$crystal = 4000000
Config Pind.6 = Output
Config Int0 = Falling
Config Int1 = Falling
Dim Wtime As Byte
Dim Encounter As Integer
Const Debouncetime = 5
On Int0 Encodera
On Int1 Encoderb
Cls
Wtime = 100
Encounter = 0
Enable Interrupts
Enable Int0
Enable Int1
Do
Set Portd.6
Waitms Wtime
Upperline
Lcd "encounter: " ; Encounter ; " "
Reset Portd.6
Waitms Wtime
Loop
Encodera:
Waitms Debouncetime
Incr Encounter
Gifr = 64
Return
Encoderb:
Waitms Debouncetime
Decr Encounter
Gifr = 128
Return
End
Both Int0 and Int1 is used.
I used a debouncetime of 5 milliseconds.
The interrupt routines only have an increment or decrement, no Cha or Chb testing is required.
Note the Gifr = 64/128. Read
more on this.
TOC