;AntiKippenLights-Mini (AKL-Mini) - 18 animated LEDs on a microcontroller ;ATtiny24 @ 1 MHz (internal R/C oscillator), BOD disabled to save power ;Fuses: lfuse=0x62, hfuse=0xDF, efuse=0xFF (factory defaults) ; ;Based on "KippenLights special edition with PIC16C54" version 0.2, 2005-01-01 ;by Stefan Schuermans <1stein@schuermans.info> ;GNU public license - http://www.gnu.org/copyleft/gpl.html ; ;To disable auto-power-off function, bridge PA0 to ground (J1). This ;configuration is read at power-on (by applying power or pressing the button). ; ;To enable always-on mode, bridge PA0 to PA2 (J2). This configuration is only ;read once after applying power. ; ;PORTS ; PA0 = No off-timer detect (connect to GND) - disables auto-power-off, ; Always on detect (connect to PA2) - disables auto-power-off & button ; PA1 = push-button input (internal pull-up) ; PA2-7 = LED anodes 1~6 ; PB0-2 = LED group cathodes A~C (A: LEDs 1~6, B: LEDs 7~12, C: LEDs 13~18) ; PB3 = [Reset] ; ;LED ARRANGEMENT ; 15 ; 12 08 16 ; 13 11 09 07 11 12 13 14 17 ; 14 10 06 18 ; 15 05 10 01 ; 16 04 02 ; 17 03 09 08 07 06 03 ; 18 02 04 ; 01 05 ; ; (for the heart arrangement, directions of clockwise ; and counter-clockwise animations are reversed) ; ;VERSIONS ; 2017-11-09 - Version 1.0.0 - Arne Rossius ; * complete re-write ; 2019-02-27 - Version 2.0.0 - Arne Rossius ; * changed from ATtiny2313 to ATtiny24 ; * corrected conflicting use of 'value' register ;button hold-down delay before power-on (1 ms units) .equ POWER_ON_DELAY = 50 ;50 ms ;auto-power-off timeout (~8.4 kHz units) .equ AUTO_POWER_OFF = 8400 * 60 * 60 * 2 ;approx. 2 hours ;.equ AUTO_POWER_OFF = 8400 * 5 ;approx. 5 seconds ;=============================================================================== .include "../include/tn24def.inc" .undef XL .undef XH .undef YH .undef ZL .undef ZH .def temp = R16 .def count = R17 .def repeat = R18 .def value = R19 .def leds = R20 .def pwm = R21 .def button_cnt = R22 .def timeout1 = R23 .def timeout2 = R24 .def timeout3 = R25 .def timeout4 = R26 .def flags = R27 .equ fAlwaysOn = 0 .equ fNoAutoOff = 1 ;=============================================================================== .dseg RAM_Frame: .byte 18 ;one frame of LED data (brightness values 0~63) ;=============================================================================== .cseg .org 0x000 rjmp reset .org PCI0addr ;pin change interrupt: button pressed reti ;=============================================================================== reset: ;init ports ldi temp, 0xFC ;PORTA out DDRA, temp ldi temp, 0x03 out PORTA, temp ldi temp, 0x07 ;PORTB out DDRB, temp ldi temp, 0x0F out PORTB, temp ;disable analog comparator (to save power) ldi temp, 0x80 out ACSR, temp ;init stackpointer ldi temp, RAMEND out SPL, temp ;configure pin change interrupt on PA1 (push-button inut) ldi temp, 0x02 ;detect pin change on PA1 only out PCMSK0, temp ldi temp, 1< ~7.5 ms ;running from 62 to 0: LED on if pwm < value, 100% on for value = 63 ldi pwm, 62 pwm_loop: ;total loop cycles: 25+3+25+5+25+5+25+2+4 = 119 cycles ;(1 MHz / 119) = ~8.4 kHz loop frequency ;calculate data for LED group A (25 cycles) ldi leds, 0xC0 ;pull-ups enabled for PA1 and PA0 lds temp, RAM_Frame+0 cp pwm, temp ;carry set (LED on) if pwm < temp ror leds lds temp, RAM_Frame+1 cp pwm, temp ror leds lds temp, RAM_Frame+2 cp pwm, temp ror leds lds temp, RAM_Frame+3 cp pwm, temp ror leds lds temp, RAM_Frame+4 cp pwm, temp ror leds lds temp, RAM_Frame+5 cp pwm, temp ror leds ;output (3 cycles) out PORTA, leds ;output LED data for group A cbi PORTB, 0 ;enable LED group A ;calculate data for LED group B (25 cycles) ldi leds, 0xC0 lds temp, RAM_Frame+6 cp pwm, temp ror leds lds temp, RAM_Frame+7 cp pwm, temp ror leds lds temp, RAM_Frame+8 cp pwm, temp ror leds lds temp, RAM_Frame+9 cp pwm, temp ror leds lds temp, RAM_Frame+10 cp pwm, temp ror leds lds temp, RAM_Frame+11 cp pwm, temp ror leds ;output (5 cycles) sbi PORTB, 0 ;disable LED group A out PORTA, leds ;output LED data for group B cbi PORTB, 1 ;enable LED group B ;calculate data for LED group C (25 cycles) ldi leds, 0xC0 lds temp, RAM_Frame+12 cp pwm, temp ror leds lds temp, RAM_Frame+13 cp pwm, temp ror leds lds temp, RAM_Frame+14 cp pwm, temp ror leds lds temp, RAM_Frame+15 cp pwm, temp ror leds lds temp, RAM_Frame+16 cp pwm, temp ror leds lds temp, RAM_Frame+17 cp pwm, temp ror leds ;output (5 cycles) sbi PORTB, 1 ;disable LED group B out PORTA, leds ;output LED data for group C cbi PORTB, 2 ;enable LED group C ;poll push-button (7 cycles) sbic PINA, 1 rjmp button_released ;button pressed sbrs button_cnt, 7 ;prevent overflow inc button_cnt cpi button_cnt, 127 ;pressed for (127 / 8.4 kHz) = ~15 ms brne button_end sbrs flags, fAlwaysOn rcall power_off rjmp button_end button_released: clr button_cnt rjmp PC+1 ;2 cycles nop ;1 cycle button_end: ;auto-power-off timeout counter (8 cycles) clc ;clear carry sbrs flags, fNoAutoOff subi timeout1, 1 sbci timeout2, 0 sbci timeout3, 0 sbci timeout4, 0 brne PC+2 rcall power_off ;extra delay (10 cycles) - button (7) + timeout (8) + 10 = 25 cycles rcall return ;7 cycles rjmp PC+1 ;2 cycles nop ;1 cycle ;output (2 cycles) sbi PORTB, 2 ;disable LED group C ;end of PWM loop (4 cycles when looping, 3 when exiting loop) subi pwm, 1 brcs PC+2 rjmp pwm_loop return: ret ;-------------------- power_off: ;button pressed or auto-power-off timeout elapsed: turn off ;disable LED group C sbi PORTB, 2 ;set all LED cathodes low (turn on LEDs installed in reverse) ldi temp, 0x03 out PORTA, temp ;wait until button released power_off_wait: sbis PINA, 1 rjmp power_off_wait ;pull PA0 low (avoid pull-up current) cbi PORTA, 0 sbi DDRA, 0 ;enable interrupts (use pin change interrupt for wake-up) ldi temp, 1<