Source file: /~heha/Mikrocontroller/LED-PWM.zip/3pwm.a90

.nolist
.include "m8def.inc"
.include "makros.i90"
.list
// Port B
// PB0		(14)	SLEEP-Anzeige
// PB1	OC1A	(15)
// PB2	OC1B	(16)	PWM-Ausgänge für LEDs
// PB3	OC2	(17)

// Register R8..R15 sowie R23 für ISR erforderlich
.def	ZERO	=r8	// immer 0x00
.def	ONES	=r9	// immer 0xFF
.def	LEN2L	=r10	// gepuffert (Pulslänge, von außen zu setzen)
.def	LEN2H	=r11
.def	isrt1	=r12	// ISR-Register (SREG-Backup)
.def	TCNT2H	=r13	// High-Teil Zählerstand
.def	OCR2L	=r14	// ungepuffert
.def	OCR2H	=r15

.def	r	=r4	// 0=AUS, 255=voll, logarithmisch skaliert
.def	g	=r5
.def	b	=r6
.def	isrt0	=r23	// ISR-Register, muss >= R16 sein

.org 0
	rjmp	Init
	reti
	reti
	reti
// Timer2-Überlauf-ISR (darf sich [255 Takte minus CLI-Zeit] Zeit gönnen)
// Erzeugt CPU-Last, da Aufruf alle 256 Takte (32 µs @ F_CPU == 8 MHz)!
	in	isrt1,SREG
	inc	TCNT2H			// High-Teil in Software
	brne	t2a
	 movw	OCR2H:OCR2L,LEN2H:LEN2L	// Bei Null Wert übernehmen (Doppel-Puffer)
	 in	isrt0,TCCR2
	 sbr	isrt0,1<<WGM21|1<<WGM20	// PWM EIN: WGM=3
	 out	TCCR2,isrt0
	 out	OCR2,ONES		// startet erst wenn TCNT2H == 1
t2a:	cp	OCR2H,TCNT2H
	brne	t2b
	 out	OCR2,OCR2L		// LOW-Zeit setzen
t2b:	mov	isrt0,OCR2H
	inc	isrt0			// Sonderfall OCR2H == 0xFF?
	breq	t2c
	cp	isrt0,TCNT2H		// Wenn  TCNT2H == OCR2H+1 ...
	brne	t2c
	 in	isrt0,TCCR2
	 cbr	isrt0,1<<WGM21|1<<WGM20	// PWM AUS: WGM=0
	 out	TCCR2,isrt0		// (COM2 bleibt 2! Löscht OC2 später)
t2c:	out	SREG,isrt1
	reti				// max. 26 Takte (inkl. Aufruf + RETI)
	
WaitT1:	// Wartet auf Timer1-Überlauf (bei F_CPU == 8 MHz ca. alle 8 ms)
w1:	sbi	PORTB,0			// SLEEP-Kontrollausgabe an Pin 14
	sleep				// Strom sparen
	cbi	PORTB,0
	in	r16,TIFR
	jbrc	r16,2,w1
	outi	TIFR,	0b00000100	// EOI
	ret

Init:	clr	ZERO
	clr	ONES
	dec	ONES
	outihl	SP,RAMEND		// Stackpointer initialisieren
	outi	TIMSK,	0b01000000	// Timer2: Interrupt aktivieren
	outi	TCCR2,	0b01101001	// Timer2: VT1, schnelle nichtinv. PWM
	outi	TCCR1A,	0b10100010	// Timer1: schnelle nichtinv. PWM
	outi	TCCR1B,	0b00011001	// Timer1: VT1
	outhl	ICR1,ONES,ONES		// Timer1: Volle 16 bit Zählumfang
	
	mov	r,ZERO
	mov	g,ZERO
	mov	b,ONES			// Start mit 100 % Blau
	
	outi	DDRB,	0b00011111	// Ausgabeports
	outi	MCUCR,	0b10000000	// SLEEP aktivieren, nur IDLE
	sei
MainLoop:
p1:	rcall	WaitT1
	dec	b
	rcall	SetPwmB
	inc	r
	rcall	SetPwmR
	cp	r,ONES
	brne	p1
p2:	rcall	WaitT1
	dec	r
	rcall	SetPwmR
	inc	g
	rcall	SetPwmG
	cp	g,ONES
	brne	p2
p3:	rcall	WaitT1
	dec	g
	rcall	SetPwmG
	inc	b
	rcall	SetPwmB
	cp	b,ONES
	brne	p3
	rjmp	MainLoop
	
SetPwmR:
	mov	ZL,r
	rcall	getexp
	outhl	OCR1A, r17,r16
	in	r16,TCCR1A
	tst	r
	breq	ppr1
	sbr	r16,1<<COM1A1
	rjmp	ppr2
ppr1:	cbr	r16,1<<COM1A1
ppr2:	out	TCCR1A,r16
	ret
	
SetPwmG:
	mov	ZL,g
	rcall	getexp
	outhl	OCR1B, r17,r16
	in	r16,TCCR1A
	tst	g
	breq	ppg1
	sbr	r16,1<<COM1B1
	rjmp	ppg2
ppg1:	cbr	r16,1<<COM1B1
ppg2:	out	TCCR1A,r16
	ret
	
SetPwmB:
	mov	ZL,b
	rcall	getexp
	movw	LEN2H:LEN2L,r17:r16
	in	r16,TCCR2
	tst	b
	breq	ppb1
	sbr	r16,1<<COM21
	rjmp	ppb2
ppb1:	cbr	r16,1<<COM21
ppb2:	out	TCCR2,r16
	ret
	
getexp:
// PE: ZL = Index 0..255
// PA: R17:R16 = logarithmischer OCR-Wert mit der Eigenschaft:
//	Y[ZL=0] = egal (PWM-Länge 0, ganz AUS)
//	Y[ZL=1] = 0 (PWM-Länge 1, minimal)
//	Y[ZL=255] = 65535 (PWM-Länge 65536, ganz EIN)
// Die PWM des ATtiny/ATmega hat die innewohnende Eigenschaft der
// Impulsausgabe: 1 Takt länger als der OCR-Wert
	clr	ZH
	lsl	ZL			// WORD-Adresse generieren (0..510)
	rol	ZH
	subi	ZL,LOW(-exptab*2)	// Anfangsadresse der Tabelle "addieren"
	sbci	ZH,HIGH(-exptab*2)
	lpm	r16,Z+			// Tabellenwert lesen
	lpm	r17,Z+
	ret
exptab:
.nolist
.dw	0,0,1,2,3,4,5,7,8,9,10,12,13,15,16,18
.dw	19,21,22,24,26,28,30,32,34,36,38,40,42,44,47,49
.dw	52,54,57,60,63,65,68,72,75,78,81,85,89,92,96,100
.dw	104,108,113,117,122,126,131,136,141,146,152,158,163,169,175,182
.dw	188,195,202,209,216,224,232,240,248,257,265,275,284,293,303,314
.dw	324,335,346,358,369,382,394,407,420,434,448,463,478,493,509,526
.dw	543,560,578,596,616,635,655,676,698,720,743,766,790,815,841,867
.dw	894,923,951,981,1012,1044,1076,1110,1144,1180,1216,1254,1293,1333,1375,1417
.dw	1461,1506,1553,1601,1650,1701,1753,1807,1863,1920,1980,2040,2103,2168,2234,2303
.dw	2373,2446,2521,2598,2678,2760,2844,2931,3021,3113,3208,3306,3407,3511,3618,3729
.dw	3842,3959,4080,4204,4332,4464,4600,4740,4885,5033,5186,5344,5507,5674,5847,6024
.dw	6207,6396,6590,6790,6997,7209,7428,7654,7886,8125,8372,8626,8887,9157,9435,9721
.dw	10016,10319,10632,10954,11287,11629,11981,12344,12718,13104,13501,13910,14331,14765,15212,15673
.dw	16148,16637,17140,17659,18194,18745,19312,19897,20499,21120,21759,22417,23096,23795,24515,25257
.dw	26021,26808,27619,28455,29316,30203,31117,32058,33028,34027,35056,36116,37209,38334,39494,40688
.dw	41919,43186,44492,45838,47224,48652,50123,51639,53201,54809,56467,58174,59933,61745,63612,65535
Detected encoding: ANSI (CP1252)4
Wrong umlauts? - Assume file is ANSI (CP1252) encoded