;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

Liability Disclaimer and intellectual property notice (Summary: No warranties, use these pages at your own risk. You may use the information provided here for personal and educational purposes but you may not republish or use this information for any commercial purpose without explicit permission.)

I neither express nor imply any warranty for the quality, fitness for any particular purpose or user, or freedom from patents or other restrictions on the rights of use of any software, firmware, hardware, design, service,information, or advice provided, mentioned,or made reference to in these pages. By utilizing or relying on software, firmware, hardware, design, service,information, or advice provided, mentioned, or made reference to in these pages, the user takes responsibility to assume all risk and associated with said activity and hold Richard Cappels harmless in the event of any loss or expense associated with said activity. The contents of this web site, unless otherwise noted, is copyrighted by Richard Cappels. Use of information presented on this site for personal, nonprofit educational and noncommercial use is encouraged, but unless explicitly stated with respect to particular material, the material itself may not be republished or used directly for commercial purposes. For the purposes of this notice, copying binary data resulting from program files, including assembly source code and object (hex) files into semiconductor memories for personal, nonprofit educational or other noncommercial use is not considered republishing. Entities desiring to use any material published in this pages for commercial purposes should contact the respective copyright holder(s).