Controlling an application with both IR and a rotary encoder
This is code I developed to re-engineer the user input to my amplifier. The idea is that control is either by an amp mounted rotary encoder, or by a infra red remote.
The issue with this is that the IR input routines are blocking so must be run on a separate picaxe and that the encoder debounce routines can be difficult.
The IR input is handled by an 08M2 (08M should work with minor mods)
This just reads the codes off the input and recodes them to standard ascii characters which it sends out on the serial output. I'm using my standard Sony TV remote to control the amplifier. The code includes an "acceleration" algorithm to separate individual button pushes but also allow continuous presses for scrolling up and down the volume.
The main processor listens to the serial port but also handles the encoder totally at the interrupt level. My original routines for this http://www.picaxeforum.co.uk/showthread.php?20634-08M2-interrupt-issue were blocking whilst the encoder completed a cycle but this would have caused inputs from the IR to be delayed if the encoder was left in a mid cycle state rather than at the detent (easy to do) so I have recoded them to exit all interrupts immediately but still only report the user event on cycle completion. The interrupt routine feeds the encoder output into the hardware serial buffer so that the main code only has one place to look for data and doesn't care where it arrives from.
This is code I developed to re-engineer the user input to my amplifier. The idea is that control is either by an amp mounted rotary encoder, or by a infra red remote.
The issue with this is that the IR input routines are blocking so must be run on a separate picaxe and that the encoder debounce routines can be difficult.
The IR input is handled by an 08M2 (08M should work with minor mods)
Code:
#picaxe 08M2
setfreq M8
symbol last=b1
symbol repcount=b2
symbol pauselength=w2
main:
irin c.3,b0
if b0<9 then
b0=b0+49 'convert to an ascci number
gosub rep
sertxd (b0)
b0=255
endif
if b0=9 then
b0=48 'convert to an ascci number
gosub rep
sertxd (b0)
b0=255
endif
if b0>15 and b0<29 then
b0=b0+49 ' convert to capital A to M
if b0="C" then: b0=">" :endif
if b0="D" then: b0="<" :endif
gosub rep
sertxd (b0)
b0=255
endif
if b0>50 and b0<57 then
b0=b0+27 ' convert to capital N to S
gosub rep
sertxd (b0)
b0=255
endif
if b0>75 and b0<83 then
b0=b0+8 ' convert to capital T to Z
gosub rep
sertxd (b0)
b0=255
endif
if b0>115 and b0<118 then
b0=b0-45 ' convert to capital G and H
gosub rep
sertxd (b0)
b0=255
endif
if b0=37 then
gosub rep
sertxd ("P")' convert to capital P
b0=255
endif
if b0=101 then
gosub rep
sertxd ("R")' convert to capital R
b0=255
endif
if b0=96 then
gosub rep
sertxd ("X")' convert to capital X
b0=255
endif
if b0=35 then
gosub rep
sertxd ("Y")' convert to capital Y
b0=255
endif
if b0=99 then
gosub rep
sertxd ("C")' convert to C
b0=255
endif
if b0=40 then
gosub rep
sertxd ("D")' convert to D
b0=255
endif
'sertxd (b0,last,cr,lf)
pauselength=repcount*repcount * 2
pauselength=500-pauselength
pause pauselength
goto main
rep:
if b0<>last then
repcount=0
else
repcount=repcount + 1 max 15
endif
last=b0
return
The main processor listens to the serial port but also handles the encoder totally at the interrupt level. My original routines for this http://www.picaxeforum.co.uk/showthread.php?20634-08M2-interrupt-issue were blocking whilst the encoder completed a cycle but this would have caused inputs from the IR to be delayed if the encoder was left in a mid cycle state rather than at the detent (easy to do) so I have recoded them to exit all interrupts immediately but still only report the user event on cycle completion. The interrupt routine feeds the encoder output into the hardware serial buffer so that the main code only has one place to look for data and doesn't care where it arrives from.
Code:
#picaxe 28X2
setfreq m8
symbol resetenc=bit0
symbol switchison = bit2
symbol rotatedleft=bit3
symbol rotatedright=bit4
symbol scratch=b1
symbol switched = b2
'
'Connections
' Encoder switch pulled high and connected to A.1
' Encoder output1 pulled high and connected to A.2
' Encoder output2 pulled high and connected to A.3
'
'
symbol interruptmask = %00001110 ' allow interrupts on a.3,a.2, a.1
symbol rotated = %00000110
symbol clicked = %00000001 ' mask to test for c.1 high
'
symbol true=1
symbol false=0
'
hsersetup B9600_8,1
dirsa=0
ptr=0
switchison=false
rotatedright=false
rotatedleft=false
resetenc=true
setint OR 0,interruptmask,A
do
do while ptr<>hserptr
b10=@ptrinc
sertxd (b10) 'Do required control actions here
loop
'do required background actions here
loop
interrupt:
switched=pinsa & interruptmask >> 1'look at just the three inputs
on switched goto I0,I1,I2,I3,I4,I5,I6,I7 'whatever the cause set the next interrupt to look for a reverse
I0:
setint OR 14,interruptmask,A
goto proc
I1:
setint OR 12,interruptmask,A
goto proc
I2:
setint OR 10,interruptmask,A
goto proc
I3:
setint OR 8,interruptmask,A
goto proc
I4:
setint OR 6,interruptmask,A
goto proc
I5:
setint OR 4,interruptmask,A
goto proc
I6:
setint OR 2,interruptmask,A
goto proc
I7:
setint OR 0,interruptmask,A
proc:
scratch=switched & clicked
if scratch=0 then
switchison=true
else
if switchison=true then
put hserptr,"A"
hserptr=hserptr+1 & $03FF
switchison=false
endif
endif
'
scratch=switched & rotated >>1
on scratch goto R0,R1,R2,R3
R0:
if rotatedleft=true then
put hserptr,"<"
hserptr=hserptr+1 & $03FF
rotatedleft=false
endif
if rotatedright=true then
put hserptr,">"
hserptr=hserptr+1 & $03FF
rotatedright=false
endif
return
R1:
if resetenc=true then
rotatedleft=true
rotatedright=false
resetenc=false
endif
return
R2:
if resetenc=true then
rotatedright=true
rotatedleft=false
resetenc=false
endif
return
R3:
rotatedleft=false
rotatedright=false
resetenc=true
return
Last edited: