; Binaire klok in ASM. Attiny2313 op 4mhz kristal, met ckdiv8 op 0.5mhz ; voor laag stroomgebruik. Processor staat ook grotendeels in SLEEP. ; tijd wordt bijgehouden dmv timer1 interupt. ; Tijd kan worden ingesteld en leds kunnen worden gedimd, geen verdere luxe. ; Gebruikt desondanks +/- 1mA + 1mA per LED die aan is. Gedimde leds vragen minder stroom ; portb.5 (S2) en 6 (S1) zijn schakelaars, portb.4 is secondenled, ; Portd.5 = Minuten.0 ; Portd.4 = Minuten.1 ; Portd.3 = Minuten.2 ; Portd.2 = Minuten.3 ; Portd.1 = Minuten.4 ; Portd.0 = Minuten.5 ; Portd.6 = Uren.0 ; Portb.0 = Uren.1 ; Portb.1 = Uren.2 ; Portb.2 = Uren.3 ; Portb.3 = Uren.4 ; Dat had handiger gekund (led's precies op de juiste bits van een poort ; zodat de tijd er direct heen geschreven kan worden). ; Werking schakelaars: ; S1 indrukken: tijd instellen uren ; interupts uit ; seconden naar 0 ; secondenled aan ; S2 = uren + 1 ; S1 = naar minuteninstellen (dus eerst wachten tot losgelaten) ; secondenled uit ; S2 = minuten + 1 ; S1 is terug naar normaal gebruik ; wachten tot loslaten is niet erg, timer interupts missen tijdens tijd instellen is niet erg. ; S2 indrukken toggled LED's aan / uit. .include "tn2313def.inc" .def temp = r16 .def seconden = r17 .def minuten = r18 .def uren = r19 .def temp2 = r20 .def wait1 = r21 .def wait2 = r22 .org 0x000 rjmp init .org 0x004 ;timer 1 compare A overflow interupt rjmp Timer1_COMPA .org 0x013 ; na alle interupt vectors komt de echte code init: ldi r24,low(RAMEND) ; init stack out SPL,r24 ldi r24,high(RAMEND) ldi temp,0b10011111 ; LED's als output zetten, maar schakelaars als input out DDRB, temp ldi temp,0b0110_0000 ; Pull-ups voor schakelaars out portb, temp ldi temp,0xff ; rest v.d. leds ook output out DDRD,temp ; init timer 1 interupt ; prescale 8, klokken uit de 0.500000Mhz, comparen met 500.000/8= 62500 (F424) ; voor 1 s. En clear on compare match. ; vergeet verder niet om interupts in het algemeen te enablen. (sei) ; stel compare 1a register in ldi temp,0xF4 out OCR1AH,temp ; eerst highbyte schrijven ivm de buffer ldi temp, 0x24 out ocr1al,temp ldi temp, 0b01000000 out TIMSK,temp ; interupt enable voor timer1a compare match (zet oci1a 1) sei ; set global interupt enable ; stel TCCR1B in, zie datasheet: ldi temp,0b00001010 ; clock instellen op clkio/8, CTC mode OCR1A als top. out TCCR1b,temp ; timer loopt nu, omdat er klok wordt aangeboden. main: loop: ; reti heeft i alweer geset ; schakelaars lezen kan in main of in de interupt, of met een eigen interupt. ; Eigen interupt: Kans dat we timerinterupt missen tijdens schakelaars lezen, dus nee ; In de timerinterupt: Interupt wordt te lang ; dus hier lezen. We zouden ook de de interuptvlaggen kunnen gebruiken... (maar dat doen we niet) ; Werking schakelaars: ; S1 indrukken: tijd instellen uren ; interupts uit ; seconden naar 0 ; secondenled aan ; S2 = uren + 1 ; S1 = naar minuteninstellen (dus eerst wachten tot losgelaten) ; secondenled uit ; S2 = minuten + 1 ; S1 is terug naar normaal gebruik ; wachten tot loslaten is niet erg, timer interupts missen tijdens tijd instellen is niet erg. ; S2 indrukken toggled LED's aan / uit. in temp,pinb andi temp,0b0010_0000 ; alleen naar S2 kijken cpi temp,0 ; en als die is ingedrukt dan: brne geens2 ; (of als ie niet is ingedrukt, dan niks doen) rcall laats2los ; wachten tot 'ie wordt losgelaten (Tijd loopt door, interupt driven :)) in temp,DDRB ; ddrb inlezen ori temp,0b01100000 ; zorgen dat schakelaars hoe dan ook input staan com temp ; en inverteren out ddrb, temp ; en weer terugzetten in DDRB, zodoende led aan/uit toggled op portb ; er zitten ook leds op portd: in temp, ddrd com temp out ddrd, temp geens2: in temp, pinb andi temp,0b0100_0000 ; alleen naar S1 kijken cpi temp,0 ; als die niet is ingedrukt naar ookgeens1 springen brne ookgeens1 cli ; interupts uit, we willen de tijd instellen! ldi seconden, 0 ; en dus niet dat 'ie doorloopt. Seconden op 0 in temp, portb ori temp,0b0001_0000; secondenled aanzetten out portb, temp ; waarom kunnen or/and masks niet direct op I/O registers? rcall laats1los ; wachten tot s1 is losgelaten (roept zelf debounce aan) checks2: rcall werkledsbij ; 't is wel zo handig als je ook kan zien wat je doet... in temp,pinb andi temp,0b0010_0000 ; alleen naar S2 kijken cpi temp,0 ; en als die is ingedrukt dan: brne urenerbijklaar rcall laats2los inc uren cpi uren, 24 brne urenerbijklaar ldi uren, 0 urenerbijklaar: in temp,pinb andi temp,0b0100_0000 ; alleen naar S1 kijken cpi temp,0 ; en als die is ingedrukt dan: brne checks2 rcall laats1los in temp, portb andi temp,0b1110_1111; secondenled uitzetten out portb, temp checks2min: ; zelfde voor de minuten rcall werkledsbij in temp,pinb andi temp,0b0010_0000 ; alleen naar S2 kijken cpi temp,0 ; en als die is ingedrukt dan: brne minutenerbijklaar rcall laats2los ; wachten tot 'ie is losgelaten inc minuten ; minuut erbij cpi minuten,60 ; kijken of we er niet teveel krijgen brne minutenerbijklaar ; zonee doorgaan ldi minuten, 0 ; zoja eerst minuten weer op 0 minutenerbijklaar: in temp,pinb andi temp,0b0100_0000 ; alleen naar S1 kijken cpi temp,0 ; en als die is ingedrukt dan: brne checks2min ; als 'ie niet is ingedrukt kijken of er nog minuten bij moeten rcall laats1los ; als 'ie wel is ingedrukt wachten tot 'ie wordt losgelaten ; klaar met tijd instellen sei ; interupts weer aan ookgeens1: sleep ; als we verder toch niks te doen hebben, val dan in slaap. ; (stroomgebruik laag houden) rjmp loop Timer1_COMPA: push temp ; oude temp bewaren in r16, sreg Push r16 ; sla statusreg op ; secondenregister incrementen, en volgende registers bijwerken. inc seconden cpi seconden,60 brne klaar ldi seconden,0 inc minuten cpi minuten,60 brne klaar ldi minuten, 0 inc uren cpi uren, 24 brne klaar ldi uren , 0 klaar: ; klaar met registers comparen in temp, portb ; toggle secondenLED elke keer ldi temp2, 0b0001_0000 eor temp,temp2 ; waarom is er geen eori? out portb, temp rcall werkledsbij pop r16 ; Sreg restoren out sreg, r16 pop temp ; en temp restoren reti ; Return naar je mainloop. laats1los: rcall debounce in temp, pinb andi temp,0b0100_0000 ; alleen naar S1 kijken cpi temp,0 breq laats1los rcall debounce ret laats2los: rcall debounce in temp, pinb andi temp,0b0010_0000 ; alleen naar S1 kijken cpi temp,0 breq laats2los rcall debounce ret debounce: ; wachtlusberekening: ; 2 registers, max 255*255*4= 260100 cycles, op 0.5Mhz is dat langer dan 2 seconden ; we willen 0,1 seconden wachten. ; 500000*0.1=50.000 cycles te verbranden ; 50.000/4=12500 cycles per lus = 0x30D4 ldi wait1, 0xd4 ldi wait2, 0x30 wachtlus: subi wait1,1 sbci wait2,0 brcc wachtlus ret werkledsbij: ; push temp ; misschien nodig. Voorlopig niet doen in temp, portd bst minuten,0 ; minuten naar leds schrijven bld temp,5 ; wegens onhandige ledvolgorde via T bit bst minuten,1 bld temp,4 bst minuten,2 bld temp,3 bst minuten,3 bld temp,2 bst minuten,4 bld temp,1 bst minuten,5 bld temp,0 bst uren,0 ; uren.0 zit ook op portd bld temp,6 out portd,temp in temp, portb ; rest van de uren (en seconden) op portb bst uren,1 bld temp,0 bst uren,2 bld temp,1 bst uren,3 bld temp,2 bst uren,4 bld temp,3 out portb,temp ; pop temp ret ; Dit programma neemt 14,6% van het programmageheugen van de attiny2313 in. ; De BASCOM versie die functioneel gezien hetzelfde doet neemt 34% in. ; (Daar worden wel de schakelaars anders gebruikt)