;DG75 Clock - 4-digit clock using Japanese-style 9-segment displays ;ATtiny214 @ 2 MHz (internal osc.) + 32 KiHz backup crystal ;Fuses: factory defaults ; ;PORTS ; PA0 = [UPDI] / Debug output (needs FUSE[5] = 0xC0 for GPIO + 12V UPDI) ; PA1 = Colon (active low) ; PA2 = Segment shift register clock ; PA3 = Segment shift register data / Segment i ; PA4 = Digit 1 (left) ; PA5 = Digit 2 ; PA6 = Digit 3 ; PA7 = Digit 4 (right) ; PB0 = mains frequency input (50 Hz or 60 Hz) ; PB1 = Push button (active low, int. pull-up) ; PB2-3 = [32 KiHz XTAL] ; ;SHIFT REGISTER ; DATA IN = Segment i ; Q1 (shifted last) = Segment h ; Q2 = Segment g ; Q3 = Segment f ; Q4 = Segment e ; Q5 = Segment d ; Q6 = Segment c ; Q7 = Segment b ; Q8 (shifted first) = Segment a ; ;DISPLAY ; aaaaaaa ; a h b ; f hh b ; f h b ; f h b ; fff b gg ; e cc ; e i c ; e i c ; e i c ; d i d ; ddddddd ; ;VERSIONS ; 2024-08-11 Arne Rossius ; * first version .include "../include/tn214def.inc" .undef XL .undef XH .undef YL .undef YH ;R1:R0 = multiplication result (used in interrupt) .def dim_cnt = R2 .def ac_restore_cnt = R3 .def last_ac_l = R4 .def last_ac_h = R5 .def zero = R6 .def mux = R7 .def intdiv = R8 .def sreg_backup = R9 .def digit1 = R10 .def digit2 = R11 .def digit3 = R12 .def digit4 = R13 .def set_timeoutL = R14 .def set_timeoutH = R15 .def temp = R16 .def temp2 = R17 .def count = R18 .def subsec = R19 .def second = R20 .def minute = R21 .def hour = R22 .def button_cnt = R23 .def inttmp = R24 .def inttmp2 = R25 .def timeout = R26 .def set_digit = R27 .def flash = R28 .def flags = R29 .equ fButtonShort = 0 .equ fButtonLong = 1 .equ fTimeSet = 2 .equ fAcState = 3 .equ fAcFailDetected = 4 .equ fAcEdgesDetected = 5 .equ fAcRestored = 6 .equ fDST = 7 ;R31:R30 used for Z pointer ;user settings .equ F_MAINS = 50 ;mains frequency (time base): 50 Hz or 60 Hz .equ ZERO_BLANKING = 0 ;blank 1st digit zero (0 = no, 1 = yes) .equ FLASHING_COLON = 0 ;colon frequency (0 = static, 1 = 1 Hz, 2 = 0.5 Hz) .equ FLASH_SPEED = 100 ;Display flashing period (10 ms units), max. 255 .equ BUTTON_SHORT_TIME = 2 ;Short button press (10 ms units), max. 255 .equ BUTTON_LONG_TIME = 100 ;Long button press (10 ms units), max. 255 .equ SET_TIMEOUT = 5*60*100 ;Timeout for set mode (10 ms units), max. 65535 ;other settings .equ DIMMING = 1 ;display dimming (0=100%, 1=50%, 2=25%, 3=12.5%) .equ F_MUX = 500 ;display multiplexing frequency .equ F_CPU = 2000000 ;20 MHz / 10 = 2 MHz ;debug options .equ CRYSTAL_CHECK = 0 ;output F_XTAL / 64 on PA2 (display will be blank) ;PORTA .equ COLON = 1 .equ SR_CK = 2 .equ SR_D = 3 .equ COM1 = 4 .equ COM2 = 5 .equ COM3 = 6 .equ COM4 = 7 ;PORTB .equ AC_IN = 0 .equ BUTTON = 1 ;=============================================================================== .macro shift_clock sbi VPORTA_OUT, SR_CK cbi VPORTA_OUT, SR_CK .endmacro .macro shift_bit sbrc inttmp, @0 sbi VPORTA_OUT, SR_D sbrs inttmp, @0 cbi VPORTA_OUT, SR_D shift_clock .endmacro ;=============================================================================== .cseg .org 0x000 rjmp reset .org PORTB_PORT_vect ;input edge interrupt (mains frequency input) rjmp port_b .org RTC_CNT_vect ;RTC interrupt: AC fail detection & backup clock rjmp rtc .org TCA0_OVF_vect ;TCA0 overflow (multiplexing) rjmp ovf_a ;-------------------- port_b: in sreg_backup, CPU_SREG sbrs flags, fAcFailDetected rjmp port_b_end sbis VPORTB_IN, AC_IN rjmp port_b_end ;AC fail mode, rising edge port_b_cnt: lds inttmp, RTC_STATUS ;wait until CNT register has been updated sbrc inttmp, RTC_CNTBUSY_bp rjmp port_b_cnt movw inttmp2:inttmp, last_ac_h:last_ac_l lds last_ac_l, RTC_CNTL lds last_ac_h, RTC_CNTH ;out16 com inttmp2 ;subtract previous value from new value neg inttmp brne PC+2 inc inttmp2 add inttmp, last_ac_l adc inttmp2, last_ac_h tst inttmp2 brne port_b_fail ;way too much time between edges cpi inttmp, 32768/8 * 5/4 / F_MAINS ;1.25 * T_AC brsh port_b_fail ;too much time between edges cpi inttmp, 32768/8 * 3/4 / F_MAINS ;0.75 * T_AC brlo port_b_fail ;not enough time between edges ;valid time between AC edges sbrs ac_restore_cnt, 4 ;stop counting at 16 inc ac_restore_cnt sbrc ac_restore_cnt, 4 ;consider AC restored after 16 edges ori flags, 1< set fAcState=1 andi flags, ~(1< summer: increment hour ;summer -> winter: decrement hour subi hour, 1 brcs dst_h23 ;hour wrapped around from 0 to 23 brhc PC+2 subi hour, 6 ret dst_h23: ldi hour, 0x23 ret adj_h1: subi hour, -7 brhc PC+2 subi hour, 6 cpi hour, 0x24 brlo PC+2 clr hour rjmp restart_set_timeout adj_m10: clr subsec clr second mov temp, minute andi temp, 0xF0 subi temp, -0x10 cpi temp, 0x60 brlo PC+2 clr temp andi minute, 0x0F or minute, temp rjmp restart_set_timeout adj_m1: clr subsec clr second mov temp, minute andi temp, 0x0F inc temp cpi temp, 0x0A brlo PC+2 clr temp andi minute, 0xF0 or minute, temp rjmp restart_set_timeout ;-------------------- button_long: ;long button press andi flags, ~(1<