| CODE |
;Copyright 2004 by the Dick Cappels. projects(at)cappels.org www.projects.cappels.org ;Copy and paste this into an assembler file. .include "tn12def.inc";Note that no path is given for this file. ;DOOR BELL TIMER. ;Description: Keeps Portb B bit 1 low for the first 10 hours of each day. Port B bit 0 is a 1 Hz ;pulse to connect to an indicator LED or other monitoring device to indicate that interrupts are ;occuring - mainly to show that oscillator is working because you can't probe it without stopping it. ;Port B bit 2 is low for the first 30 seconds of each minute and high the rest of the time. This is ;for test purposes. ;This runs on an ATtiny12 with a 32768 Hz crystal connected between pins 2 and 3. No phase shift capacitors ;or other components should be connected to these pins. ;When Programming the chip: ;1. Select the Low Freuqency Crystal oscillator 67ms + 32k clock (CKSEL = 1000) ;VERSIONS ; bt040409D Most recent version. ;Define I/O .equ testpin = 2;Port B bit 2 is the test output - low for first 10 seconds. .equ bellpin = 1;Port B bit 1 is the bell relay driver -low for first 10 hours. .equ winkled = 0;Port B bit 0 winks at 1 Hz, changed during interrupt time. ;Contreg (Control Register) bit descriptions and associated constants .equ readclockinh = 1;if 1, inhibits clock from being written to user buffer. Autocleared by write routine .equ readclockinhflag = 2;value ored with contreg to set flag .equ readclockinhmask=$FD;used to clear the falg when task completed .equ writeclock = 2;*if 1, commands user buffer to be written to clock. Autocleared by write routine .equ writelcockorflag= 4;value ored with contreg to set flag. .equ writeclockmask =$FB;used to clear the flag when task completed .equ disableclock = 3;if 1 disables clock and alarm maintenance during interrupt .equ disableclockorflag=8;value ored with contreg to set flag .equ disableclockmask=$F7;used to clear flag by anding with contreg ;intflags Internal Flags register bit assignments and associated constants .equ extintmask =$FE;used to clear flag by anding with contreg .equ rbtorflag = 8;used to set bit ;.equ almaskinitial =$FF;Defaul value of alarm mask loaded at startup .def rectimer= r0;number of t0 interrupts within on second (used to filter attn line) .def sregtemp= r1;temporary storage of status register during interrupt time .def uyear = r5;user accesible year user register 2 .def umonth = r6;user accessible month user register 3 .def uday = r7;user accessible day .def uhour = r8;user accessible hour .def uminute = r9;user accessible minute .def usecond = r10;user accessible second .def ayear = r11;alarm year (user accessible) .def amonth = r12;alarm month (user accessible) .def aday = r13;alarm day (user accessible) .def ahour = r14;alarm hour (user accessible) .def aminute = r15;alarm minute (user accessible) .def asecond = r16;alarm second (user accessible) .def contreg = r17;device control register, user register F ;/////end of user accessible registers .def intflags= r18;internal flags - not user accessible .def second = r19;second .def minute = r20;minute .def hour = r21;hour .def day = r22;day .def month = r23;month .def year = r24;year .def temp = r25;scratch .def tempi = r26;scratch for use during interrupt .ORG $0000 rjmp reset reti ;external interrupt handler reti ;pin change interrupt -return rjmp tovflo ;timer overflow interrupt handler reset:;SET EVERYTING UP TO RUN. ldi contreg,$00 ;Preload conreg flags ldi temp,$80 out ACSR,temp ldi temp,$03 out TCCR0,temp ;Set timer prescaler in intflags,eedr ;Get the data into temp andi intflags,$78 ;MAKE NORMAL STATE "BAILED", only bits 4,5,6 of EEPROM clr second clr minute clr hour clr day clr month clr year ldi temp,$FF ;Pre-load second in user register with $FF so it can mov usecond,temp ;be determined if the reigster was read before ;values are written by clock ldi asecond,$FF ;Similarly, put $FF into the alarm seconds ;so alarm cab't fire until initialized. clr tempi ;presets 500 millisecond counter ldi temp,0 ;preload timer counter out TCNT0,temp ldi temp,$02 ;enable timer overflow interrupts out TIMSK,temp ldi temp,$FF ;load data direction value for PORTB out DDRB,temp ;no pullups on B0 and B1 *** andi intflags,$78 ;MAKE NORMAL STATE "BAILED", only bits 4,5,6 of EEPROM main: ;Main loop - do this after each awakening from sleep. Wakes from sleep 2 times per ;second by timer interrupt. ;Set state of testpin according to number of seconds elapsed within current minute. mov temp,usecond cpi temp,30 brpl havetest cbi PORTB,testpin;Come here if test pin is to be off (low). Set test pin low. rjmp notest havetest: sbi PORTB,testpin;Come here if test pin is to be on (high).Make test pin high. notest: ;Set state of bellpin according to number of hours elapsed within current day. mov temp,uhour cpi temp,10 brpl havebell cbi PORTB,bellpin;Come here if bell pin is to be off (low). Set bell pin low. rjmp nobell havebell: sbi PORTB,bellpin;Come here if bell is to be on (high. Make bell pin high. nobell: ;Go to sleep. ldi temp,$22 ;enable sleep and set T0 to respond to falling edge out MCUCR,temp ;enable sleep mode ldi temp,$40 ;enable external interrupt 0 out GIMSK,temp sei ;assure interrupts are enabled sleep ;good night. Wait for the attention line to go low (interrupt 0) rjmp main ;///////////////////////////////////////////////////////////////////////////////// ;///////////////CODE BELOW IS ONLY TIMER INTERRUPT AND CLOCK CODE///////////////// ;///////////////////////////////////////////////////////////////////////////////// ;///////////////TIMER OVERFLOW SERVICE////////////////// tovflo: ;twice per second timer interrupt (assumes 32678 hz crystal) in sregtemp,SREG ;save the status register contents tst tempi ;Since the interrupt is twice a second, tempi will be used brne even500ms ;to divide by two cbi PORTB,winkled ;Set wink LED output low. ldi tempi,1 rjmp lateExit even500ms: sbi PORTB,winkled ;Set wink LED output high. tst rectimer breq notimeout dec rectimer brne notimeout ori intflags,rbtorflag andi intflags,$7F ;**** possible savings of one word - is this redundant with flag clear in bail? notimeout: ;//////write to clock////// sbrs contreg,writeclock;write user time registers to clock rjmp nowrite mov second,usecond mov minute,uminute mov hour,uhour mov day,uday mov month,umonth mov year,uyear andi contreg,writeclockmask ;clear write flag nowrite: ;/////begin clock/calendar maintenance///// ;Year counter runs to 255 years. Leap test year assumes ;that the year is a leap year if bits 0 and 1 are low. sbrc contreg,disableclock;Skip clock/alarm maintenance if flag is set rjmp skipclocktohere inc second cpi second,60 breq dominute rjmp doneclock dominute:clr second inc minute cpi minute,60 breq dohour rjmp doneclock dohour: clr minute inc hour cpi hour,24 breq doday rjmp doneclock doday: clr hour inc day cpi day,32 breq domonth cpi day,31 brne check30 cpi month,4 breq domonth cpi month,6 breq domonth cpi month,9 breq domonth cpi month,11 breq domonth check30:cpi month,2 brne doneclock cpi day,30 breq domonth cpi day,29 brne doneclock mov tempi,year andi tempi,$03 breq doneclock domonth:ldi day,1 inc month cpi month,13 brne doneclock ldi month,1 inc year doneclock: ;/////end clock/calendar maintenance///// ;//////read from clock to user registers////// sbrc contreg,readclockinh;read from clock to user time registers rjmp noread mov usecond,second mov uminute,minute mov uhour,hour mov uday,day mov umonth,month mov uyear,year noread: skipclocktohere: ;Just skipped the clock and alarm doneint: clr tempi lateExit: andi intflags,extintmask;clear ext interrupt counter **** should move to before lateExit out SREG,sregtemp ;restore the status register contents reti ;end of assembly souce listing .exit |