--
-- name : cucu.jal - zero error clock
-- ver : 2.1, with interrupts using Roman's method from:
-- http://www.ezy.net.au/~fastvid/one_sec.htm
-- 4.00MHz quartz, alarm and clock data stored in eeprom
-- author : Vasile Surducan http://www.geocities.com/vsurducan
-- date : december 2001
-- purpose : 4 digit common anodes clock using modified AN615
-- Ra0: minutes, Ra1: tens of minutes, Ra2: hours, Ra3: tens of
-- hours all active in low state, all conected through 5k6 resistor
-- at pnp transistors bases, emiters at +5V, colectors to anodes
-- Rb0...Rb6=a...f segments all active in low state, conected whith
-- 47 ohm resistors to display segments
-- Rb4 button minutes, Rb5 button alarm,
-- Rb6 button hours, all active in low state
-- one buttons pin conected to Rb4, Rb5, Rb6 trough a 3K9 resistor,
-- 10k resistor conected to +5V from same point, another buttons pin
-- conected to ground
-- Rb7 conected to buzzer (50k in base of a npn transistor, colector
-- to buzzer, emiter at ground, another pin of buzzer to +5V)
include 16f84_4
include jpic
include jseven
include jdelay
var byte sel_min_units = 0b_1110
var byte sel_min_tens = 0b_1101
var byte sel_hours_units = 0b_1011
var byte sel_hours_tens = 0b_0111
var byte sel_blank = 0b_1111
port_a_direction = all_output
pin_b7_direction = output
var byte sec = 0
var byte min_units = 0
var byte min_tens = 0
var byte hours_units = 2
var byte hours_tens = 1
var byte amin_units
var byte amin_tens
var byte ahours_units
var byte ahours_tens
var bit but_flag = low
var bit alarm_flag = low
var bit cucu_flag = low
var byte roman_hi = 0x_0f
var byte roman_mid = 0x_43
var byte roman_lo = 0x_40
clear_watchdog
bank_1
option = 0x_88 -- prescaler asigned to watchdog, no pullup
bank_0
tmr0 = 0
asm bsf intcon_gie -- enable interrupts
asm bsf intcon_t0ie -- enable overflow interrupts
procedure time is
asm incf sec, f
if sec == 60 then
asm incf min_units, f
asm clrf sec
end if
if min_units == 10 then
asm clrf min_units
asm incf min_tens, f
end if
if min_tens == 6 then
asm clrf min_tens
asm incf hours_units, f
end if
if hours_units == 10 then
asm clrf hours_units
asm incf hours_tens, f
end if
if hours_tens == 2 then
if hours_units == 4 then
asm clrf hours_tens
asm clrf hours_units
end if
end if
end procedure
procedure isr is
pragma interrupt
assembler
local out
tstf roman_mid -- roman_mid = 0 ?
skpnz
decf roman_hi, f -- yes, roman_mid = 0 so decrement roman_hi
decfsz roman_mid, f -- roman_mid = roman_mid - 256
goto out -- if nz then not one second yet
tstf roman_hi -- test roman_hi
skpz -- if z then roman_hi and roman_mid are 0
goto out -- if nz then not one second yet
movlw 0x_0f
movwf roman_hi -- load msb
movlw 0x_42
movwf roman_mid -- load mid
movlw 0x_40
addwf roman_lo, f -- add to remainder already in lsb
skpnc -- no overflow
incf roman_mid, f -- if c, roman_lo overflowed, increment roman_mid
call time -- call user task
out: bcf intcon_t0if -- reset interrupt flag
end assembler
end procedure
procedure tick ( byte in ton ) is
for 20 loop
pin_b7 = high
delay_200us ( ton )
pin_b7 = low
delay_200us ( ton )
end loop
end procedure
procedure button_minutes is
port_a = sel_blank
pin_b4_direction = input
if ( ! pin_b4 ) then
tick ( 2 )
asm incf min_units, f
if min_units == 10 then
asm clrf min_units
asm incf min_tens, f
end if
if min_tens == 6 then
asm clrf min_tens
asm incf hours_units, f
end if
delay_10mS ( 5 )
end if
pin_b4_direction = output
end procedure
procedure button_hours is
port_a = sel_blank ; display off
pin_b6_direction = input ; enable button
if ( ! pin_b6 ) then ; read button and
tick ( 2 ) ; tick to hear that !
asm incf hours_units, f ; simple clock operations
if hours_units == 10 then
asm clrf hours_units
asm incf hours_tens, f
end if
if hours_tens == 2 then
if hours_units == 4 then
asm clrf hours_tens
asm clrf hours_units
end if
end if
delay_10mS ( 5 ) ; delay required for reading button
end if
pin_b6_direction = output ; disable button
end procedure
procedure button_alarm is
port_a = sel_blank ; display off
pin_b5_direction = input ; enable button
if ( ! pin_b5 ) then ; read button
if ! but_flag then ; if alarm preset,
tick ( 1 )
eeprom_put( 1, min_units ) ; store actual time
eeprom_put( 2, min_tens )
eeprom_put( 3, hours_units )
eeprom_put( 4, hours_tens )
but_flag = ! but_flag
elsif but_flag then ; if time preset/display
tick ( 3 )
eeprom_put( 5, min_units ) ; store alarm time and
eeprom_put( 6, min_tens )
eeprom_put( 7, hours_units )
eeprom_put( 8, hours_tens )
eeprom_get( 1, min_units ) ; load previously saved time, WARNING
eeprom_get( 2, min_tens ) ; this reglage must be done in less
eeprom_get( 3, hours_units ) ; than 1 minute so don't sleep !
eeprom_get( 4, hours_tens )
but_flag = ! but_flag ; reset the flag for next operation
end if
delay_10mS ( 5 ) ; delay required for buttons
pin_b5_direction = output ; disable button
end if
end procedure
procedure display is
port_b_direction = all_output ; prepare displaying
port_a = sel_min_units ; mux min_unit and
port_b = ! seven_from_digit( min_units ) ; display
delay_1ms( 3 ) ; keep it for good visibility
port_a = sel_min_tens ; bla-bla, the same for the rest
port_b = ! seven_from_digit( min_tens )
delay_1ms( 3 )
port_a = sel_hours_units
port_b = ! seven_from_digit( hours_units )
delay_1ms( 3 )
if hours_tens == 0 then
port_a = sel_blank
elsif hours_tens > 0 then
port_a = sel_hours_tens
port_b = ! seven_from_digit( hours_tens)
delay_1ms( 3 )
end if
end procedure
procedure cucu ( byte in cuchours_tens, byte in cuchours_units,
byte in cucmin_tens, byte in cucmin_units ) is
if ( cucmin_units == min_units ) &
( cucmin_tens == min_tens ) &
( cuchours_units == hours_units ) &
( cuchours_tens == hours_tens ) then
if ! cucu_flag then
for 5 loop
tick ( 1 )
tick ( 2 )
end loop
cucu_flag = ! cucu_flag ; stop the noise
end if
end if
if min_units > cucmin_units then ; enable for the next time
cucu_flag = low
end if
end procedure
procedure alarm is
eeprom_get( 5, amin_units ) ; read the stored alarm value
eeprom_get( 6, amin_tens )
eeprom_get( 7, ahours_units )
eeprom_get( 8, ahours_tens )
if ( amin_units == min_units ) & ; and compare with actual one
( amin_tens == min_tens ) &
( ahours_units == hours_units ) &
( ahours_tens == hours_tens) then
port_a = sel_blank ; blank the display
if ! alarm_flag then ; and make noise
for 50 loop
tick ( 1 )
tick ( 2 )
display
tick ( 3 )
end loop
alarm_flag = ! alarm_flag ; stop, oh my ears
end if
end if
if min_units > amin_units then ; enable after one minute
alarm_flag = low
end if
end procedure
forever loop
cucu ( 0, 8, 0, 0 ) ; play cucu every time when I'm sure at the office
button_minutes ; read buttons,
cucu ( 0, 9, 0, 0 )
button_hours
cucu ( 1, 0, 0, 0 )
button_alarm
cucu ( 1, 1, 0, 0 )
cucu ( 1, 2, 0, 0 )
cucu ( 1, 3, 0, 0 )
alarm ; and play alarm
cucu ( 1, 4, 0, 0 )
display ; display something, it's a clock !
cucu ( 1, 5, 0, 0 )
cucu ( 1, 6, 0, 0 )
end loop
               (
geocities.com/vsurducan/electro)                   (
geocities.com/vsurducan)