logo elektroda
logo elektroda
X
logo elektroda

Led Light by Gerhard Schmidt

_ACeK_  4 1365 Cool? (+5)
📢 Listen (AI):
:smile: Over 10 years ago Gerhard Schmidt DG4FAC on avr asm tutorial.net (site already not exists) :cry: presented such a circuit :idea: LED effect based on ATtiny13

LED schematic with ATtiny13 microcontroller and 4-bit switch interface


;
; ***********************************
; *    Ledlight with an ATtiny13    *
; * (C)2012 by avr-asm-tutorial.net *
; ***********************************
;
.nolist
.include "tn13def.inc"
.list
;
; *******************
;   H A R D W A R E
; *******************
;
;          ____________
;         /            |
; RES o--|             |--o VCC
;        |     AT      |
;  S3 o--|             |--o S2/SCK
;        |    tiny     |
;  S4 o--|             |--o OUT/MISO
;        |     13      |
; GND o--|             |--o S1/MOSI
;        |_____________|
;
; Input port bits
.equ bS1In = 0
.equ bS2In = 2
.equ bS3In = 3
.equ bS4In = 4
;
; Output port bit
.equ bOut = 1
;
; *******************************
;  H O W   T H I N G S   W O R K
; *******************************
;
; Processor:
;   Operates with 1.2 Mcs/s clock
;   Default R/C oscillator dived by 8
;   Default fuse settings
; Timer 0:
;   Operates as fast PWM with TOP=15
;   System clock prescaled by 256
;   f(PWM) = 293 c/s
;   OC0B controls PWM ratio (0 .. 15)
;     OCR0B set by lower nibble of control byte
;     sets OC0B output on restart,
;     clears output on compare match
;   OC0A sets TOP and interrupts
; Timing of cycles:
;   Upper nibble of control byte sets number
;     of PWM cycles (16 to 256)
;   Results in times between 0.055 and 0.88 seconds
; Input switches:
;   S1: if set dims down LED by half current (PWM / 2)
;   S2: accelerates speed by 16 (cycle duration / 16)
;   S3, S4: selects program
;     00: LEDs on and off seven times
;     01: linear up and down of LEDs
;     02: sinewave-type LEDs
;     03: anything from 00 to 03 in sequence
;
; *********************
;   R E G I S T E R S
; *********************
;
; Free: R0..R14
.def rSreg = R15       ; for saving and restoring SREG
.def rmp   = R16       ; multipurpose outside ints
.def rimp  = R17       ; multipurpose inside ints
.def rCnt  = R18       ; count register for PWM cycles
.def rC3   = R19       ; counter for cycles in all-mode
; Free: R20 .. R29
; Used: ZH:ZL as Pointer to table in flash
;
; *******************************************
;  R E S E T   A N D   I N T - V E C T O R S
; *******************************************
;
      rjmp    main                   ; Reset vector
      reti                        ; INT0
       reti                         ; PCINT0
       rjmp    Tc0Int                   ; TIM0_OVF
       reti                         ; EE_RDY
       reti                         ; ANA_COMP
       reti                         ; TIM0_COMPA
       reti                         ; TIM0_COMPB
       reti                         ; WDT
       reti                         ; ADC
;
; Interrupt vector TIM0_OVF
;
Tc0Int:
       in       rSreg,   SREG             ; save SREG
       dec    rCnt                   ; next PWM cycle
       brne    Tc0IntRet                ; if not zero, continue
       lpm    rCnt,   Z+                ; read from table in flash
       mov    rimp,   rCnt             ; copy byte to rimp
       andi    rimp,   0x0F             ; mask upper nibble
       sbis    PINB,   bS1In             ; half intensity?
       lsr    rimp                   ; half PWM cycle
       out    OCR0B,   rimp             ; write to PWM compare
       andi    rCnt,   0xF0             ; mask lower nibble
       sbis    PINB,   bS2In             ; double speed?
       swap    rCnt                   ; 16 times faster
Tc0Int1:
       lpm    rimp,   Z                ; read next table value
       tst    rimp                   ; zero?
       brne    Tc0IntRet                ; not zero
       out    SREG,   rSreg             ; restore SREG
       set                         ; set T-flag
       reti                         ; return from int 
Tc0IntRet:
       out    SREG,   rSreg             ; restore SREG
       reti                         ; return from int
;
; *************************************
;  M A I N   P R O G R A M   S T A R T
; *************************************
;
Main:
 ; Init stack
       ldi    rmp,   LOW(RAMEND)       ; RAMEND to SPL
       out    SPL,   rmp
 ; Init ports
       ldi    rmp,   1<<bOut          ; Output port as output
       out    DDRB,   rmp
       ldi    rmp,   0x1F-(1<<bOut)       ; Switches pull-up, LEDs on
       out    PORTB,   rmp
 ; init Z-Pointer
       ldi    ZH,      HIGH(2*Tab1)       ; Point Z to Tab1
       ldi    ZL,      LOW (2*Tab1)
       ldi    rCnt,   1                ; counter stage 1
 ; init Timer 0, Fast PWM, COMPB as positive PWM 
       ldi    rmp,   0x0F             ; Compare A sets TOP
       out    OCR0A,   rmp
       ldi    rmp,   0x00             ; Compare B to LED off
       out    OCR0B,   rmp
       ldi    rmp,   (1<<COM0B1)|(1<<WGM01)|(1<<WGM00) ; Fast PWM
       out    TCCR0A,   rmp
       ldi    rmp,   (1<<WGM02)|(1<<CS02); Presc=256
       out    TCCR0B,   rmp
       ldi    rmp,   1<<TOIE0          ; int on TOP
       out    TIMSK0,   rmp
 ; init sleep and interrupts
       ldi    rmp,   1<<SE             ; enable sleep mode idle
       out    MCUCR,   rmp
       sei                         ; enable interrupts
;
; *******************
;  M A I N   L O O P
; *******************
;
Loop:
       sleep                         ; go to sleep
       nop
       brtc    Loop                   ; nothing to do, go to sleep again
       clt                         ; clear flag
       in       rmp,   PINB             ; read switches
       andi    rmp,   0x18             ; mask all switches other than S3+S4
       brne    Loop2                  ; program is 4
      inc    rC3
      inc    rC3
      cpi    rC3,   7                ; beyound limit
      brcs    Loop1
      clr    rC3
Loop1:
      ldi    ZH,      HIGH(2*TabPtr)       ; point to pointer table
      ldi    ZL,      LOW (2*TabPtr)
      add    ZL,      rC3             ; add displacement
      ldi    rmp,   0                ; MSB correct? 
      adc    ZH,      rmp
      lpm    rmp,   Z+                ; Read table address
      lpm    ZH,      Z
      mov    ZL,      rmp
      rjmp    Loop
Loop2:                               ; read switches
      lsr    rmp                   ; divide by 2
      lsr    rmp                   ; divide by 4
      ldi    ZH,      HIGH(2*TabPtr)       ; pointer to pointer table
      ldi    ZL,      LOW (2*TabPtr)
      add    ZL,      rmp             ; add displacement
      ldi    rmp,   0                ; MSB correct?
      adc    ZH,      rmp
      lpm    rmp,   Z+
      lpm    ZH,      Z
      mov    ZL,      rmp
      rjmp    Loop
;
; Table pointers
;
TabPtr: 
 .dw 2*Tab1                         ; program 4, start with program 1
 .dw 2*Tab3                         ; dto., program 3
 .dw 2*Tab2                         ; dto., program 2
 .dw 2*Tab1                         ; point to table of program 1
;
; Tables for programs
;
Tab1:
 .dw 0xFFF0                         ; off and on
 .dw 0xFFF0
 .dw 0xFFF0
 .dw 0xFFF0
 .dw 0xFFF0
 .dw 0xFFF0
 .dw 0xFFF0
 .dw 0xFFF0
 .dw 0xFFF0
 .dw 0x0000                         ; end
Tab2:                               ; Modulated Up/Down
 .dw 0xA0C1
 .dw 0xA1C2
 .dw 0xA2C3
 .dw 0xA3C4
 .dw 0xA4C5
 .dw 0xA5C6
 .dw 0xA6C7
 .dw 0xA7C8
 .dw 0xA8C9
 .dw 0xA9CA
 .dw 0xAACB
 .dw 0xABCC
 .dw 0xACCD
 .dw 0xADCE
 .dw 0xAECF
 .dw 0xAFCE
 .dw 0xAECD
 .dw 0xADCC
 .dw 0xACCB
 .dw 0xABCA
 .dw 0xAAC9
 .dw 0xA9C8
 .dw 0xA8C7
 .dw 0xA7C6
 .dw 0xA6C5
 .dw 0xA5C4
 .dw 0xA4C3
 .dw 0xA3C2
 .dw 0xA2C1
 .dw 0xA1C0
 .dw 0xA0C1
 .dw 0xA1C2
 .dw 0xA2C3
 .dw 0xA3C4
 .dw 0xA4C5
 .dw 0xA5C6
 .dw 0xA6C7
 .dw 0xA7C8
 .dw 0xA8C9
 .dw 0xA9CA
 .dw 0xAACB
 .dw 0xABCC
 .dw 0xACCD
 .dw 0xADCE
 .dw 0xAECF
 .dw 0xAFCE
 .dw 0xAECD
 .dw 0xADCC
 .dw 0xACCB
 .dw 0xABCA
 .dw 0xAAC9
 .dw 0xA9C8
 .dw 0xA8C7
 .dw 0xA7C6
 .dw 0xA6C5
 .dw 0xA5C4
 .dw 0xA4C3
 .dw 0xA3C2
 .dw 0xA2C1
 .dw 0xA1C0
 .dw 0x0000
Tab3:
 .dw 0xC1C0                         ; linear up/down
 .dw 0xC3C2
 .dw 0xC5C4
 .dw 0xC7C6
 .dw 0xC9C8
 .dw 0xCBCA
 .dw 0xCDCC
 .dw 0xCFCE
 .dw 0xCDCE
 .dw 0xCBCC
 .dw 0xC9CA
 .dw 0xC7C8
 .dw 0xC5C6
 .dw 0xC3C4
 .dw 0xC1C2
 .dw 0xC1C0                         ; restart
 .dw 0xC3C2
 .dw 0xC5C4
 .dw 0xC7C6
 .dw 0xC9C8
 .dw 0xCBCA
 .dw 0xCDCC
 .dw 0xCFCE
 .dw 0xCDCE
 .dw 0xCBCC
 .dw 0xC9CA
 .dw 0xC7C8
 .dw 0xC5C6
 .dw 0xC3C4
 .dw 0xC1C2
 .dw 0x00C0
TabEnd:
;
; End of source code
;
.db "(C)2012 by Gerhard Schmidt",0x00,0x00
.db "C(2)10 2ybG reahdrS hcimtd",0x00,0x00


😊 Taking inspiration from it I made my version from a universal board (my DIY) with attiny13 , a traistor on a spider and a star with diodes 🛠️

Close-up of DIY circuit with wires and ATtiny13 board

DIY board with ATTiny13 microcontroller and Li-Po battery on a work surface


:020000020000FC
:100000001DC01895189506C018951895189518953F
:1000100018951895FFB62A9579F42591122F1F701F
:10002000B09B169519BD207FB29B22951491112388
:1000300019F4FFBE68941895FFBE18950FE90DBF1F
:1000400002E007BB0DE108BBF0E0E0EB21E00FE0D0
:1000500006BF00E009BD03E20FBD0CE003BF02E0F4
:1000600009BF00E205BF789488950000EEF7E89498
:1000700006B3087171F433953395373008F03327A0
:10008000F0E0E8EAE30F00E0F01F0591F491E02FC3
:10009000EBCF06950695F0E0E8EAE00F00E0F01FF0
:1000A0000591F491E02FE0CFB0003E01C400B00014
:1000B000F0FFF0FFF0FFF0FFF0FFF0FFF0FFF0FFC8
:1000C000F0FF0000C1A0C2A1C3A2C4A3C5A4C6A5DD
:1000D000C7A6C8A7C9A8CAA9CBAACCABCDACCEAD80
:1000E000CFAECEAFCDAECCADCBACCAABC9AAC8A952
:1000F000C7A8C6A7C5A6C4A5C3A4C2A3C1A2C0A1C0
:10010000C1A0C2A1C3A2C4A3C5A4C6A5C7A6C8A7AF
:10011000C9A8CAA9CBAACCABCDACCEADCFAECEAF21
:10012000CDAECCADCBACCAABC9AAC8A9C7A8C6A72F
:10013000C5A6C4A5C3A4C2A3C1A2C0A10000C0C1DA
:10014000C2C3C4C5C6C7C8C9CACBCCCDCECFCECD1D
:10015000CCCBCAC9C8C7C6C5C4C3C2C1C0C1C2C34B
:10016000C4C5C6C7C8C9CACBCCCDCECFCECDCCCBEB
:10017000CAC9C8C7C6C5C4C3C2C1C0002843293242
:100180003031322062792047657268617264205391
:1001900063686D696474000043283229313020326D
:1001A0007962472072656168647253206863696D83
:0401B0007464000073
:00000001FF

🎥



🎅 Btw It's a shame the sites are disappearing from the net :cry: :cry: :cry: :cry: Recently also disappeared khoam 👀 I hope it has a chance to come back to us yet 😇

About Author
_ACeK_
_ACeK_ wrote 129 posts with rating 121 , helped 3 times. Been with us since 2024 year.

Comments

Urgon 06 Dec 2025 21:06

AVE... I used to do such things in C, in a few lines of code. Generally the assembler is ok, if you need to count every clock cycle. But in general you should write in C, for example. High-level languages... [Read more]

gulson 07 Dec 2025 10:14

Beautiful times, beautiful code written by a human in assembler and not generated. Thanks for sharing a forgotten solution. May it last forever. [Read more]

robgold 07 Dec 2025 15:42

@urgon let me disagree with you. Nowadays, time-critical things are also generated in ASM for a given CPU and this is not a problem. I'm not talking about low-volume projects, but where every cent counts... [Read more]

Urgon 07 Dec 2025 16:10

AVE... Well, but nowadays in college you rather learn ARM programming in C++, not '51 in ASM. As I wrote earlier, ASM is good where you need to count every clock cycle. I generally program in C myself,... [Read more]

%}