logo elektroda
logo elektroda
X
logo elektroda

TL;DR

  • Pokazano efekt LED na ATtiny13 oraz własną wersję na uniwersalnej płytce z tranzystorem i „gwiazdą” z diodami.
  • Mikrokontroler używa Timer0 w fast PWM z TOP=15, a przerwanie przepełnienia pobiera kolejne wartości z tabel zapisanych w pamięci flash.
  • Przełączniki S1 i S2 zmieniają działanie w locie: S1 obniża jasność do połowy, a S2 przyspiesza przebieg 16 razy.
  • Dostępne są programy migania, liniowego rozjaśniania/ściemniania, efektu sinusoidalnego oraz trybu sekwencyjnego przełączania, z czasami 0.055–0.88 s.
Generated by the language model.
ADVERTISEMENT
Treść została przetłumaczona polish » english Zobacz oryginalną wersję tematu
📢 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 😇

    Cool? Ranking DIY
    About Author
    _ACeK_
    Level 14  
    Offline 
    _ACeK_ wrote 149 posts with rating 140, helped 5 times. Been with us since 2024 year.
  • ADVERTISEMENT
  • #2 21773292
    Urgon
    Level 38  
    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 are easier to port between platforms - in the case of microcontrollers, this is usually limited to renaming registers and sometimes changing the values in those registers. Compilers are now so good that code from C to machine code is efficiently converted. If one wants, one can set the compiler to also generate intermediate ASM source code to see how efficiently the compiler compiles....

    Many old, defunct pages are available via Archive.org. I there a few years ago found a lost page about joule thieves, which hasn't existed for over a decade, and saved it to a PDF for myself....
  • ADVERTISEMENT
  • #3 21773564
    gulson
    System Administrator
    Beautiful times, beautiful code written by a human in assembler and not generated. Thanks for sharing a forgotten solution. May it last forever.
  • ADVERTISEMENT
  • #4 21773896
    robgold
    Level 23  
    @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 and you can't always use a more powerful CPU. At university we wrote almost everything in ASM on a '51 and it worked. Such were the times, I also preferred to write in C in AVR Studio or MPLAB rather than the bloody Platforimio or Arduino, but such were the times.

    @gulson today I think it's getting harder and harder with so much code not to use AI. Especially as with the free ones you need to know what they generate for you anyway, how it works otherwise you get a mass of nonsense. Of course you can say a firm "no" but it's like trying to spell reality that you won't use a smartphone.
  • #5 21773929
    Urgon
    Level 38  
    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, but once or twice I've had to have an ASM insert because a precise sequence of instructions is required to edit the program memory. Generally, however, apart from this particular case, I have not had a situation where assembler programming was needed. And deliberately I usually reach for smaller microcontrollers, like the PIC10F322....
📢 Listen (AI):

FAQ

TL;DR: ATtiny13 ASM LED effect with 293 Hz PWM; “LED effect based on ATtiny13.” Built from a 2012 tutorial, revived with code, HEX, and video. [Elektroda, ACeK, post #21772947]

Why it matters: This FAQ helps hobbyists quickly rebuild, tweak, or port the classic Gerhard Schmidt LED effect using modern tools.

Quick Facts

What is the Gerhard Schmidt LED light project?

A compact ATtiny13 assembly program creates multiple LED effects using Timer0 Fast PWM and a lookup table in flash. The thread revives the 2012 design with source comments, a ready-to-flash HEX, build photos, and a demo video. [Elektroda, ACeK, post #21772947]

Which ATtiny13 pins do I connect for switches and LED output?

Use PB1 (OC0B) for the LED or LED driver. Map switches to PB0 (S1), PB2/SCK (S2), PB3 (S3), and PB4 (S4). VCC, GND, and RESET wire per the ATtiny13 standard. The code defines these bits and enables pull‑ups for the inputs. [Elektroda, ACeK, post #21772947]

How do I change brightness and speed during runtime?

S1 halves LED current by halving the PWM duty. S2 accelerates the effect timing by 16×. S3 and S4 select the effect program.
  1. Hold S3/S4 to pick a mode.
  2. Tap S1 to dim by half.
  3. Tap S2 to speed the sequence. [Elektroda, ACeK, post #21772947]

What LED patterns are included out of the box?

Four programs: 00 toggles LEDs on/off seven times, 01 ramps linearly up/down, 02 generates sine‑like fades, and 03 cycles through all modes automatically. The data tables in flash drive the sequences and end with a zero marker. [Elektroda, ACeK, post #21772947]

What PWM frequency and timing does it use?

Timer0 runs Fast PWM with TOP=15 and prescaler 256, yielding about 293 Hz PWM. The upper nibble sets cycle counts, producing steps from roughly 0.055 to 0.88 seconds per segment. This avoids flicker while keeping soft transitions. [Elektroda, ACeK, post #21772947]

Can I port this to C or other microcontrollers easily?

Yes. One author notes high‑level code ports across MCUs with minor register changes, and modern compilers generate efficient machine code. Quote: “Compilers are now so good that code from C to machine code is efficiently converted.” [Elektroda, Urgon, post #21773292]

Is assembler still useful for time‑critical or cost‑sensitive designs?

Yes. Another contributor argues ASM is still generated or hand‑tuned where every cent or cycle matters. Quote: “Nowadays, time‑critical things are also generated in ASM for a given CPU.” This perspective reflects production constraints on low‑end MCUs. [Elektroda, robgold, post #21773896]

How can I recover the original tutorial if the website is gone?

Try Archive.org’s Wayback Machine. A participant retrieved a long‑lost “joule thief” page years after it vanished and saved it to PDF. Search by the original URL or page title, then export for offline use. [Elektroda, Urgon, post #21773292]

What hardware did the builder use in this thread?

A DIY universal board with an ATtiny13, a discrete transistor on flying leads (“spider”), and a star‑shaped LED assembly. The post includes photos, a HEX file block, and a video link showing the effect. [Elektroda, ACeK, post #21772947]

What fuse/clock assumptions does the code make?

It assumes default fuses: internal RC oscillator divided by 8, giving about 1.2 MHz CPU clock. Timer0 and the ISR are configured for those defaults, so set fuses accordingly if flashing a blank chip. [Elektroda, ACeK, post #21772947]

How does the interrupt routine drive the LED effect?

The Timer0 overflow ISR decrements a cycle counter, then fetches the next table byte via Z from flash. It packs duty (low nibble) to OCR0B and timing (high nibble) to set cycle length, with zero as a table terminator to switch sequences. [Elektroda, ACeK, post #21772947]

Any edge cases or failure modes to watch for?

Programming flash sometimes requires a precise instruction sequence; one author needed small ASM inserts for self‑modifying workflows. While this project does not self‑program, mixing C and ASM may still be necessary for such tasks. [Elektroda, Urgon, post #21773929]
Generated by the language model.
ADVERTISEMENT