Source file: /~heha/Mikrocontroller/InkrTast/Firmware.zip/InkrTast4u.a90

;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
Detected encoding: ANSI (CP1252)4
Wrong umlauts? - Assume file is ANSI (CP1252) encoded