Full Version : Clock/Calendar Tiny12 & Dallas Interface (AVR ASM)
avr >>HOME & TIME & TEMPERATURE PROJECTS >>Clock/Calendar Tiny12 & Dallas Interface (AVR ASM)


AVR_Admin- 05-17-2006
Real Time Clock/Calendar/Alarm with Interpreter for battery backed-up and battery powered operation with DS interface by Dick Cappel

Based on the Atmel ATtiny12L-4PI microcontroller -A real Time Clock/Calendar for less than US$1.50 in moderate quantity.

- Low current operation (chip sleeps most of the time)

- Alarm and external event triggered interpreter operation

- Capable of stand-alone timer and alarm use. No additional processor required once programmed.

- One external input pin and one open drain output pin for interpreter


Link to Site: http://cappels.org//dproj/T12clk/att12clk.htm
CODE

.include "tn12def.inc"

;When Programming the chip:
;1. Select the Low Freuqency Crystal oscillator 67ms + 32k clock
;2. Disable Reset to free up pin 1 as open drain output

;serial version major and minor revision leves.
.equ  version =  $00;0 starting August 20, 2002 (cleaned up terms in notes 040407

;.equ  revision=  5;alarm sets output low
;.equ revision= 6;corrected error in cjump $0D
;.equ revision=  7;saved a byte
;.equ revision= 8;or and and with contreg instructions
;.equ revision= 9;reset alarm via ds port
;.equ revision= $A;consolidate "ACK by pulling attn line low" in receive byte;
;.equ revision= $B;timeout subroutine.
;;equ revision= $C;making attn continuously low not cause restarts
;.equ revision= $D;seems completely funcitonal settle time set to $02
;.equ revision= $F;fast DS input response
.equ revision= $11;Remove C2 and C3 commands, fix EEPROM checksum routines

;I/O pin descriptions
.equ dataline= 0;B0 Data line
.equ attline = 1;B1 Attention line
.equ extinput= 2;B2 External Event Trigger
.equ dout = 5;B5 Data output pin
; **** can use SBR instruction instead of oring with another register -save some bytes
.equ initialddrb = $00; Inital value for DDRB (pin 1 default open)

;Contreg (Control Register) bit descriptions  and associated constants

.equ eepromok =  0;After EPROM checsum check, set to 1 if ok, otherwise 0
.equ eepromokorflag =  1;value ored with contreg to set flag
.equ eepromokmask =$FE;used to clear flag by anding
.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
;note EEPROM Address 4=  4;bits 4 and 5 are used for page address in EEPROM.
;note EEPROM address 5=  5
.equ enablearlarm =  6;if 1 enables alarm maintenance during interrupt
.equ enablealarmorflag=$40;value ored with contreg to set flag
.equ enablealarmmask =$BF;used to clear flag by anding with contreg
.equ eeprominhibit =  7;If 1 EEPROM interpreter will not execute EEPROM code
.equ eeprominhibitor =$80;Ored to set bit

.equ commandmask =$04;used to mask off bits that are not command request flags
; Bits marked with an asterisk, "*", are commands.

; **** note that command mask is not needed if write clock is the only interrupt time task
; commanded by one of these flags.

;intflags Internal Flags register bit assignments and associated constants

.equ extint  =  0;if 1, attention line filtered is disabled. Bit location in contreg.
.equ extintorflag =  1;value ored with contreg to set flag
.equ extintmask =$FE;used to clear flag by anding  with contreg
.equ execeealrm =  1;if 1, requests EEPROM code for alarm be exectued
.equ execeealrmorflag=  2;value ored with contreg to set flag
.equ execeealrmmask =$FD;used to clear the flag by anding
.equ execextevent =  2;if 1, requests external event code be run in EEPROM
.equ execexteventorflag=4;value ored with contreg to set flag.
.equ execexteventmask=$FB;used to clear the flag when task completed
.equ rbt  =  3;if 1, readbyte has timed out
.equ rbtorflag =  8;used to set bit
.equ rbtandmask =$F7;used to clear bit
.equ eepromstart =  4;if 1 idicates that startup code is in eeprom
.equ alrmineeprom =  5;If 1, indicates that alarm handler code is in eeprom
.equ alarmineepromor =$20;used to or with intflags to set flag hit (1=false)
.equ alarmineepromand=$DF;used to and with intflags to clear flag bit (0=true)
.equ extevpres =  6;if 0 indicates that external event eeprom code is present
;note that bits 0,1,2,3 are controlled by the firmware and
; bits 4,5,6,7, are copied from EEPROM

;EEPROM register assignments
.equ eepromflags =00;address in EEPROM that EEPROM flags are kept at
.equ startaddress =01;address in EEPROM that start of start up code is located at
.equ alarmaddress =02;address in EEPROM that start of alarm code is located at
.equ exteventaddress =03;address in EEPROM that start of external event code is located at
.equ checksum =63;address in EEPROM that EEPROM checksum is kept at. this location not in calculation

;note EEPROM flags are low true because erased state of EEPROM is $FF
;note EEPROM flag bit 4 low indicates start up code is present
;note EEPROM flag bit 5 low indicates alarm code is present
;note EEPROM flag bit 6 low indicates external event code is present


;alamask (Alarm Mask Register) bit descriptions  and associated constants
;function bit position description
;second mask 0  if zero, seconds ignored in testing for alarm condition
;minute mask 1  if zero, minutes ignored in testing for alarm condition
;hour mask 2  if zero, hours ignored in testing for alarm condition
;day mask 3  if zero, days ignored in testing for alarm condition
;month mask 4  if zero, months ignored in testing for alarm condition
;year mask 5  if zero, years ignored in testing for alarm condition

.equ  almaskinitial  =$FF;Defaul value of alarm mask loaded at startup

;parameters
.equ setltime  =$01;How long to wait for data and I/O lines to settle
.equ DStimeout =$02;How long to wait for DS Interface transaction to complete

.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
;////start user accessible regisers:
.def datareg =  r2;data register user register
.def regA =  r3;(user accessible register 0)
.def alamask =  r4;alarm mask (user accessible reigster 1)
.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  
.def rxtxbyte= r27;byte to be sent -can be lower register
.def delayc = r28;counter used for timing delay
.def bitcount= r29;counter for number of bits transfered

;note that r30 and r31 used as Z register


.ORG $0000
rjmp reset
rjmp int0handler;external interrupt handler
reti  ;pin change interrupt -return
rjmp tovflo  ;timer overflow interrupt handler

reset:
ldi contreg,$00;Preload conreg flags
sbis PINB,dout
sbr contreg,eeprominhibitor;Inhibit eeprom execution if dout is low
ldi temp,$80
out ACSR,temp
ldi temp,$03
out TCCR0,temp;Set timer prescaler

ldi temp,eepromflags
out eear,temp;move to EEPROM address register
sbi eecr,eere;Trigger the read
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,almaskinitial
mov alamask,temp;Calculate EERPOM checksum at location 63 and set flag




postreset:  ;do some initialization here that can be redone to recover from send error


; ldi contreg,$00;Preload conreg flags
ldi temp,initialddrb;load data direction value for PORTB
out  DDRB,temp;no pullups on B0 and B1 ***
; out PORTB,temp  
; in intflags,eedr;Get the data into temp
andi intflags,$78  ;MAKE NORMAL STATE "BAILED", only bits 4,5,6 of EEPROM




   ;Uses ZL,ZH,temp. Location 63 is not used in the calculation.
clr ZH  ;checksum kept here  
ldi ZL,checksum-1;pointer

wratzD: sbic eecr,eewe; start new;Wait for EEPROM write to not be busy
rjmp wratzD

moretosum1:
out eear,ZL  ;move to EEPROM address register
sbi eecr,eere;Trigger the read
in temp,eedr;Get the data into temp
add ZH,temp
dec ZL
cpi ZL,$FF
brne moretosum1

ldi temp,checksum;Address of checksum stored in memory
out eear,temp  ;move to EEPROM address register
sbi eecr,eere;Trigger the read
in temp,eedr;Get the data into temp
cp ZH,temp  ;compare checksums and set flag if they match

   ;An unprogrammed eerpom (all FFs) will fail.
brne   nomatch
ori contreg,eepromokorflag;Set EEPROM OK flag in internal flags register
nomatch:
   ;DO NOT MOVE THIS ROUTINE -IT MUST BE THE LAST ROUTING IN INITIALIZATION
ldi ZL,startaddress;Address of start code is  stored in here move to ZL in case of execution
   ;Execute startup program from EEPROM of present and checksum ok

sbrs contreg,eepromok; **** chance to reduce code by placing inside eeprom check
rjmp nostartupcode
sbrc intflags,eepromstart
rjmp nostartupcode

rjmp InterpretEEPROM;note that InterpretEEPROM returns to main
nostartupcode:
rjmp main


Seteepromchecsum:  ;Calculate EERPOM checksum and store in location 63.
   ;Uses ZL,ZH,temp. Locatoin 63 is not used in the calculation.
clr ZH  ;checksum kept here  
ldi ZL,checksum-1;pointer
wratzB:
sbic eecr,eewe; new;Wait for EEPROM write to not be busy
rjmp wratzB
moretosum:
out eear,ZL  ;move to EEPROM address register
sbi eecr,eere;Trigger the read
in temp,eedr;Get the data into temp
add ZH,temp
dec ZL
cpi ZL,$FF
brne moretosum
   ;Store checksum stored in ZH into EEPROM location 63
wrat1: sbic eecr,eewe;Wait for EEPROM write to not be busy
rjmp wrat1

ldi ZL,checksum
out eear,ZL    
out eedr,ZH  ;Set up the write data
cli  ;Inhibit interrupts while triggering EPROM write
sbi eecr,eemwe
sbi eecr,eewe;Trigger the write
sei  ;re-enable interrupts now that EEPROM write has been triggered
ori contreg,eepromokorflag;Set EEPROM ok flag true.
rjmp main;


; end of new code

;**** set up a loop to wait until EEPROM is not busy before reading
ReadEEPROM:  ;Read contents of EEPROM register pointed to by ZL to datareg
mov temp,contreg;Set up the write address
andi temp,$30;Bits 4 and 5 of contreg select which of 4 pages are addressed
add ZL,temp
out eear,ZL  ;move to EEPROM address register
sbi eecr,eere;Trigger the read
in rxtxbyte,eedr;Get the data into temp
rcall SendByte
rjmp main  ;This rjmp instruction is being kept incase this routine is relocated

main:
sbrc intflags,$07
rjmp receivebyte

;//////Most routines return here////////
sbrs intflags,execeealrm;Check to see if flag is set requesting EEPROM alarm code be executed
rjmp noalarmexec;If flag is set, reset flag then jump to execution routine
andi intflags,execeealrmmask;Clear flag
ldi ZL,alarmaddress;Load pointer to address of alarm routine
rjmp InterpretEEPROM;Note InterpretEEPROM returns to main
noalarmexec:

   ;See in an external even has occured and execute if code is present in EEPROM
sbic PINB,extinput
rjmp extpinishigh;If the external input is high,skip running code

sbrc intflags,execextevent
rjmp noexeventcode  
ori intflags,execexteventorflag


sbrs contreg,eepromok;Execute startup program from EEPROM of present and checksum ok
rjmp noexeventcode
sbrc intflags,extevpres
rjmp noexeventcode


ldi ZL,exteventaddress;Load pointer to address of alarm routine
rjmp InterpretEEPROM;Note InterpretEEPROM returns to main
 
extpinishigh:
andi intflags,execexteventmask;Set the flag to show input pin was high when looked at last  
 
noexeventcode:


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)

sbrs intflags,extint
 rjmp main
 
andi intflags,extintmask
;
rjmp ReceiveByte
recrtn:
brcc CarryIsClear;if carry is not set, its data, so place in datareg.

;  //////Interpret DataShake input as an instruction//////

   ;If carry is not set, interpret as an instruction.
   ;make lower nybble register pointer just in case its needed
mov ZL,rxtxbyte;move pointer into ZL register
andi ZL,$0F  ;mask off upper nybble
ldi ZH,$00

andi rxtxbyte,$F0;mask off lower nybble in rxtxbyte
   ;and interpret the command
cpi rxtxbyte,$10;test for store instruction
breq storereg

cpi rxtxbyte,$20;test for read instruction
breq readreg

cpi rxtxbyte,$30;test for dump clock command
breq DumpTimenow

cpi rxtxbyte,$40;test for write EEPROM command
breq WriteEEPROM

cpi rxtxbyte,$50;test for read EEPROM command
breq ReadEEPROM

cpi rxtxbyte,$60
brne noeepromexec
mov ZL,datareg;Put start address in ZL as pointer to first instruction
rjmp continueeprom    
noeepromexec:

cpi rxtxbyte,$70;test for generate and write EEPROM checksum and update EEPROM-realted flags
brne dontsetchecksum;Extra byte is because of branch out of range.
ldi temp,eepromflags
out eear,temp;move to EEPROM address register
sbi eecr,eere;Trigger the read
in temp,eedr;Get the data into temp
andi temp,$F0;Only upper 4 bits from EEPROM
or intflags,temp
rjmp Seteepromchecsum
dontsetchecksum:

cpi rxtxbyte,$80
brne noversionno
ldi rxtxbyte,version;READ BYTE FROM REGISTER
clc  ;clear the carry becuase data is being sent
rcall SendByte
ldi rxtxbyte,revision
rcall SendByte
rjmp main
noversionno:

cpi rxtxbyte,$90;Check -reset alarm?
brne noalarmoff
cbi DDRB,dout
rjmp main
noalarmoff:

rjmp main  ;finished fetching and interpreting. go for another byte

storereg:  ;STORE INCOMING BYTE INTO DATAREG
ldi temp,02  ;
add ZL,temp  ;point to registers 2 thrugh 17
st Z,datareg
rjmp main

readreg:
ldi temp,02  ;
add ZL,temp  ;point to registers 2 thrugh 17
ld rxtxbyte,Z;READ BYTE FROM REGISTER
clc  ;clear the carry becuase data is being sent
rcall SendByte
rjmp main

CarryIsClear:  ;If carry is clear, its data -store in data register
mov datareg,rxtxbyte
rjmp  main

DumpTimenow:  ;dump time over DS line    
mov ZH,contreg;save contreg to ZH
ori contreg,$02;inhibit reads from clock to user registers during this process
mov rxtxbyte,uyear;dump the data
rcall SendByte
mov rxtxbyte,umonth  ; **** replace "ori contreg,$02 with equated value
rcall SendByte
mov rxtxbyte,uday
rcall SendByte
mov rxtxbyte,uhour
rcall SendByte
mov rxtxbyte,uminute
rcall SendByte
mov rxtxbyte,usecond
rcall SendByte
mov contreg,ZH
rjmp main

WriteEEPROM:  ;Write contents of datareg into EEPROM register pointed to by ZL
wrat: sbic eecr,eewe;Wait for EEPROM write to not be busy
rjmp wrat
mov temp,contreg;Set up the write address
andi temp,$30;Bits 4 and 5 of contreg select which of 4 pages are addressed
add ZL,temp
out eear,ZL    
out eedr,datareg;Set up the  write data
cli  ;Inhibit interrupts while triggering EPROM write
sbi eecr,eemwe
sbi eecr,eewe;Trigger the write
sei  ;re-enable interrupts now that EEPROM write has been triggered
rjmp main



; //////Interpret EEPROM contents//////
InterpretEEPROM:  ;must enter with ZL set to vector


out eear,ZL  ;move to EEPROM address register
sbi eecr,eere;Trigger the read
in ZL,eedr  ;Get the data into temp

continueeprom:  ;Alternative entry point with Z: already pointing to first instruction

sbrc contreg,eeprominhibit
rjmp eepromstop  

out eear,ZL  ;move pointer to EEPROM address register
sbi eecr,eere;Trigger the read
in temp,eedr;Get the data into temp


cpi temp,$01
breq resetclock

cpi temp,$02
brne nodouthigh
cbi DDRB,dout;Set that output pin high
nodouthigh:


cpi temp,$03
brne nodoutlow
sbi DDRB,dout;Set that output pin low
nodoutlow:



cpi temp,$04;Test for "Or next byte with contreg".
brne notor    
inc ZL  ;Enter with ZL pointing to instruction, extits with ZL poiting to value
out eear,ZL  ;Move pointer to EEPROM address register
sbi eecr,eere;Trigger the read
in temp,eedr;Get next byte into alamask (alarm mask register)
or contreg,temp
notor:


cpi temp,$05;Test for "And next byte with contreg".
brne notand    
inc ZL  ;Enter with ZL pointing to instruction, extits with ZL poiting to value
out eear,ZL  ;Move pointer to EEPROM address register
sbi eecr,eere;Trigger the read
in temp,eedr;Get next byte into alamask (alarm mask register)
and contreg,temp
notand:




cpi temp,$0C
breq Setalarm
 
cpi temp,$0D
brne not0D
inc regA
rjmp executioncomplete
not0D:

 
cpi temp,$FF;if its $FF, then its the end of the string of commands
breq eepromstop

rjmp continueinterpretation;Jump to another part of memory for more commands (branch limitation)
continueinterpretationreturn:


   ;IF NOOP or unrecognized command, falls through to here. DO NOT MOVE
executioncomplete:  ;routines return here -rcall would use stack space
inc ZL
rjmp  continueeprom
eepromstop:
rjmp  main

resetclock:  ;Set clock to Y:M:D:H:M:S = 0:0:0:0:0:0

mov ZH,contreg;save contreg in ZH
ori  contreg,$02;disable clock updates to user resigers
clr usecond
clr uminute  ; repalce "ori contreg,$02 with eauted value ****
clr uhour
clr uday
clr umonth
clr uyear
ori contreg,writelcockorflag;request clock be written with user register values
waitforclockwriting:
sbrc contreg,writeclock;
rjmp waitforclockwriting
mov contreg,ZH  ;restore contreg from ZH
rjmp executioncomplete



Setalarm:  ;Set alarm to [next 6 bytes of EEPROM]
   ;format: [instruction code] [Y] [M] [D] [H] [M] [S]
   ;enters with ZL pointing to the instruction
   ;exits with ZL pointing to last parameter which is [S]
ldi bitcount,11;bitcount indexes the registers
continueawrite:
inc ZL
out eear,ZL  ;move to EEPROM address register
sbi eecr,eere;Trigger the read
in temp,eedr;Get the data into temp
mov delayc,ZL
mov ZL,bitcount
st Z,temp
mov ZL,delayc
inc bitcount
cpi bitcount,17
brne continueawrite
rjmp executioncomplete



;//////////SEND A BYTE
; Send carry bit as first bit, then send rxtxbyte bit-by-bit. rxtxbyte destroyed.

SendByte:

ldi bitcount,$09

ldi temp,DStimeout  
mov rectimer,temp
andi intflags,rbtandmask


S1:
sbrc intflags,rbt  
rjmp cleanandgo
sbis PINB,attline;Wait for Attention line to go high =--SEND A BIT
rjmp S1


   ;Put data on data line
cbi DDRB,dataline
brcs R1
cbi PORTB,dataline
sbi DDRB,dataline
R1:
sbrc intflags,rbt  
rjmp cleanandgo
cbi PORTB,attline;Set Attention line low
sbi DDRB, attline

rcall shortdelay  ;Wait a short time so other chip can see Attnetion line is low
cbi DDRB,attline;Release Attention line for a peak
rcall shortdelay;Short delay to allow settling of lines
sbic PINB,attline  ;If Attention line isn't low, go back and put it low again, else continue
rjmp R1

brcs szero  ;Invert data line
cbi DDRB,dataline
rjmp R3
szero: cbi PORTB,dataline
sbi DDRB,dataline
R3:
sbrc intflags,rbt
rjmp cleanandgo
sbis PINB,attline;Wait for Attention line to go high
rjmp R3

cbi DDRB,dataline;Let data line float
   ;-finished sending a bit
rol rxtxbyte;Shift rxtxbyte through carry
dec bitcount
brne S1  ;Continue until all bits sent

ret

cleanandgo:  
rjmp postreset;Reset a lot of things if send byte fails.

ReceiveByte:
ldi bitcount,$09

ldi temp,DStimeout    
mov rectimer,temp  
andi intflags,rbtandmask

W3A:;    ;Get a bit from the input into the carry


W3:
sbrc intflags,rbt  
rjmp bail

; rcall testtimeout  
sbic PINB,attline;Wait for Attention line to go low
rjmp w3
cbi PORTB,attline;ACK by pulling attention line low
sbi DDRB, attline
; ldi temp,$02    
; mov asecond,temp
; andi intflags,$F7

clc  ;Latch dataline into carry bit
sbis PINB,dataline
rjmp NotaOne
sec

W1: sbrc intflags,rbt;Wait for data line to go low
rjmp bail
sbic PINB,dataline
rjmp W1
rjmp RelesaseAttLineAndGo  
NotaOne:  
W2: sbrc intflags,rbt;Wait for data line to go high
rjmp bail
sbis PINB,dataline
rjmp W2
RelesaseAttLineAndGo:  ;Release attention line
cbi DDRB, attline  
   ;DONE RECEIVING BIT
rol rxtxbyte;Shift rxtxbyte through carry
dec bitcount
brne W3A  ;Continue until all bits received
rjmp recrtn  ;The reason this is looks like a subroutine is to make the
   ;code a little more readable.

shortdelay:
ldi delayc,setltime  
D1: dec delayc
brne D1
ret

   
bail: cbi DDRB, attline
andi intflags,$7F
rjmp main  


;///////////////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
ldi tempi,1
rjmp lateExit
even500ms:

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

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:

;//////Test for alarm condition//////

sbrs contreg,enablearlarm;If the alarm enable flag isnt' set, skip alarm maintenance
rjmp noalarm
     
mov tempi,alamask
ror  tempi

brcc nosecond
cp  second,asecond;compare hours,minutes, seconds
brne noalarm
nosecond:

ror tempi
brcc nominute
cp minute,aminute
brne  noalarm
nominute:

ror tempi
brcc nohour
cp  hour,ahour
brne noalarm
nohour:

ror tempi
brcc noday
cp day,aday
brne noalarm
noday:

ror tempi
brcc nomonth
cp month,amonth
brne noalarm
nomonth:

ror tempi
brcc noyear
cp year,ayear
brne noalarm
noyear:

; mov tempi,intflags;Execute alarm program from EEPROM if present and checksum ok
; andi tempi,$21
; cpi tempi,$01
; brne noalarmcode;set the flag requesting execution

sbrs contreg,eepromok
rjmp noalarmcode
sbrc intflags,alrmineeprom  
rjmp noalarmcode

ori intflags,execeealrmorflag
rjmp noalarm  ;skip ahead and don't set output pin high
noalarmcode:

sbi DDRB,dout;Set that output pin low  

noalarm:


skipclocktohere:  ;Just skipped the clock and alarm



donecontrol:



doneint:
clr tempi
lateExit:

andi intflags,extintmask
; clr t0intcount;clear ext interrupt counter **** should move to before lateExit
out SREG,sregtemp;restore the status register contents
reti

;//////External interrupt handler

int0handler:  ;arrived here because attention line was pulled low  
ori intflags,extintorflag
; ldi temp,$00;disable external interrupt 0
; out GIMSK,temp;*
ori intflags,$80
reti


continueinterpretation:


cpi temp,$0E;Test for "Get next EEPROM byte into alarm mask register".
brne noalarmaks    
inc ZL  ;Enter with ZL pointing to instruction, extits with ZL poiting to value
out eear,ZL  ;Move pointer to EEPROM address register
sbi eecr,eere;Trigger the read
in alamask,eedr;Get next byte into alamask (alarm mask register)
noalarmaks:

cpi temp,$0F;Test for "Get next EEPROM byte into rega".
brne nosetrega    
inc ZL  ;Enter with ZL pointing to instruction, extits with ZL poiting to value
out eear,ZL  ;Move pointer to EEPROM address register
sbi eecr,eere;Trigger the read
in rega,eedr;Get next byte into alamask (alarm mask register)
nosetrega:

cpi temp,$10
brne dontdecrement
dec rega
dontdecrement:

   ;Conditional jumps within EEPROM space. If conditional jump condition
   ;is met the jump address is picked up from the byte following the
   ;instruction. The jump address is an absolute address, valid range is
   ;0..3F but there are not checks here, so illeagal values will warp around.
   ;Handle conditional jumps.

sbrs temp,7  ;If bit 7 is set, its a conditionial jump
rjmp nocjumps
   
inc ZL  ;Fetch jump address. Enter with ZL pointing to instruction.
out eear,ZL  ;Move pointer to EEPROM address register
sbi eecr,eere;Trigger the read
in rxtxbyte,eedr;Get jump address into rxtxbyte


sbrs temp,6  ;If bit 6 is set, a constant is used in the instruction
rjmp noconstant;If a constant is used, it is the third byte of the instructio
inc ZL  ;Fetch constant. Enter with ZL pointing to instruction.
out eear,ZL  ;Move pointer to EEPROM address register
sbi eecr,eere;Trigger the read
in bitcount,eedr;bitcount now contains the constant.
noconstant:
   ;At this point, jump address is in rxtxbyte and constant is in bitcount

cpi temp,$C0
brne notC0  ; $C0 If rega equals constant,jump
cp rega,bitcount
breq dothecjump
notC0:

cpi temp,$C1; $C1. If rega is not equal to the contstant (bitcount) jump
brne notC1
cp rega,bitcount
brne dothecjump
notC1:


cpi temp,$80; $80. Jump unconditionally
brne not80
rjmp dothecjump
not80:

cpi temp,$81; $81. Jumps if rega equals datareg
brne not81
cp rega,datareg
breq dothecjump
not81:


cpi temp,$82; $82. Jumps if rega does not equal datareg
brne not82
cp rega,datareg
brne dothecjump
not82:


cpi temp,$83; $83. Jumps ext input is high
brne not83
sbic PINB,extinput
brpl dothecjump
not83:

cpi temp,$84; $84. Jumps ext input is low
brne not84
sbis PINB,extinput  
brpl dothecjump
not84:

nocjumps:  ;Skipped to here beacuse these aren't jump instructions

rjmp continueinterpretationreturn

dothecjump:  ;rxtxbyte contains jump address
mov ZL,rxtxbyte;Jump
rjmp continueeprom  
 


;end of assembly souce listing



Forumer™ is Voted #1 Free Forum Hosting provider
Build your own community today with the largest message board hosting company.