.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
|
|