;Umsetzer Inkrementalgeber auf Hoch/Runter-Tasten
;Zur Nachrüstung eines Inkrementalgebers in Paralleleschaltung
;zu vorhandenen Hoch/Runter-Funktionstasten;
;diese müssen schnell genug reagieren und (hier:) nach Masse schalten
;Eine „nacheilende“ Tastenstimulation (für eine zu lahme Folgeschaltung)
;ist hier nicht implementiert
;Typ des Inkrementalgebers: 4 Pegelwechsel pro Rastung, unsymmetrisch*
;(bspw. ALPS EC20A)
;* Kontakt A (I1) ist derjenige, der in Raststellung stets HIGH ist.
; Kontakt B (I2) hat in den Raststellungen indifferenten Schaltzustand,
; wird durch den Mikrocontroller auf LOW gezogen (da fehlt ein Buskeeper)
;Stromaufnahme: 0,2µA @ 5V, während der Drehung 100 µA (Pull-Up für Kontakt A)
;080708 haftmann#software
;Hardware:
;Pinzuweisung:
#define I1 4 ;(3) Inkrementalgeber Kontakt A (nach Masse)
#define I2 3 ;(2) Inkrementalgeber Kontakt B (nach Masse)
#define frei 0 ;(5) frei (Pull-Up)
#define O2 1 ;(6) Tasten-Stimulusausgang - (nach Masse)
#define O1 2 ;(7) Tasten-Stimulusausgang + (nach Masse)
;Mit ALPS-Geber gibt O1 bei Rechtsdrehung Impulse aus.
;Anschlusslage: +---+
; | O |
;(C = GND) +ACB+
;A und B dürfen nicht vertauscht zum Mikrocontroller verdrahtet werden!
;Zeiten
.equ MAXKEY = 100 ;Maximalzeit Tastendruckstimulation [ms]
.NOLIST
.include "tn12def.inc" ;Ein ATtiny11 würde auch reichen
.LIST
#define CPUCLK 1200000 ;[Hz] - beim ATtiny11 1000000
.def zero = R1 ;immer Null
.def cnt = R15 ;Zählerstand des Gebers (-2..+2, um I1 geshiftet)
.def xorval = R17 ;immer 2<<I1
.def drive = R18 ;Zu treibende Tasten (bei Zweierschritt)
.cseg
rjmp OnReset ;Reset
reti ;IRQ0
rjmp OnPinChange ;Pegelwechsel-Interrupt (aktiv!)
rjmp OnT0Ovl ;Timer0-Überlauf
;reti ;EEPROM fertig (nur ATtiny12)
;reti ;Analogvergleicher
OnPinChange:
in r16,PINB ;hier nur I1 abfragen
mov r0,r16
eor r0,cnt ;cnt.I1 == 1 während Übergang
sbrc r0,I1 ;Wirklich Pegelwechsel an Kontakt A?
reti ;nein, nichts tun
cbi DDRB,I2
sbi PORTB,I2 ;Pull-Up an I2 aktivieren (zum "B" abfragen)
rjmp pc+1 ;warten (6 Takte)
rjmp pc+1
rjmp pc+1
andi r16,1<<I1 ;auch: warten
sbic PINB,I2
or r16,xorval ;Bit B kopieren (A bleibt, nicht neu lesen!)
cbi PORTB,I2 ;Pull-Up ausschalten
sbi DDRB,I2 ;Vagabundierenden Pegel an I2 vermeiden
sbrc r16,I1
eor r16,xorval ;Bit: B ^= A
sbr r16,1<<I1 ;Bit: A = 1, also +1 oder -1
add cnt,r16
sbrc cnt,I1 ;Einerschritt? (A==0)
rjmp OneStep ;ja
sbrs cnt,I1+1 ;Zweierschritt? (A==1)
reti ;nein, nichts tun (Rückdreher)
clr cnt
out DDRB,drive ;Je nach Richtung ausgeben
ldi r16,5 ;Vorteiler 1024 (maximal erreichbare Zeit: 0,2s)
out TCCR0,r16
ldi r16,256-CPUCLK/1024*MAXKEY/1000
out TCNT0,r16
ldi r16,1<<TOIE0
out TIFR,r16 ;Anhängigen Interrupt löschen (falls vorhanden)
out TIMSK,r16
ldi r16,1<<SE ;Sleep = Sleep (Zähler läuft)
out MCUCR,r16
reti
OneStep:
ldi drive,(1<<O2)|(1<<I2)
sbrc cnt,I1+1 ;Je nach Richtung
ldi drive,(1<<O1)|(1<<I2) ;… nächste Tastenstimulation merken
OnT0Ovl:
cbi DDRB,O1 ;Tastenstimulation ausschalten
cbi DDRB,O2
ldi r16,(1<<SE)|(1<<SM)
out MCUCR,r16 ;Sleep = PowerDown
out TCCR0,zero ;Timer0 ausschalten
out TIMSK,zero ;Timer0-Überlaufinterrupt ausschalten
reti
OnReset:
clr zero
clr drive ;Nichts ausgeben bei plötzlichem Zweierschritt
ldi xorval,2<<I1
sbi PORTB,I1 ;1 Pullup am Inkrementalgeber aktivieren
sbi PORTB,frei ;Keine vagabundierenden Ströme
sbi DDRB,I2 ;I2 (B) auf Masse legen
clr cnt
ldi r16,1<<PCIE ;Pegelwechselinterrupt EIN
out GIMSK,r16
ldi r16,(1<<SE)|(1<<SM) ;Sleep = PowerDown
out MCUCR,r16
sei
;Hauptschleife (schläft nur! Deshalb brauchen ISRs nichts retten!)
mainloop:
sleep
rjmp mainloop
.db "haftmann#software",0
Vorgefundene Kodierung: UTF-8 | 0
|