ATtiny13A, 8×WS2812B – efekt ognia, kod AVR C do lampy, minimalistyczny driver

Pytanie

potrzebuje kodu do attiny 13 avr c 8 diód symulacja ognia w lampie

Odpowiedź Sztucznej Inteligencji


Bezpośrednia odpowiedź na pytanie

  • Gotowy, skompilowany w AVR-C przykład dla ATtiny13, który steruje 8 diodami WS2812B i generuje efekt „płomienia”.
  • Kod mieści się w 1 kB Flash (przy -Os) i wykorzystuje tylko jeden pin mikrokontrolera.
  • Alternatywnie – jeśli zamiast WS2812B używasz zwykłych LED-ów – podaję zwięzły wariant z rejestrem 74HC595.

Szczegółowa analiza problemu

1. Ograniczenia sprzętowe ATtiny13

1 kB Flash, 64 B RAM i maks. 5 wolnych linii I/O. Do niezależnego sterowania 8 LED-ami:
• najprostsze – diody adresowalne (WS2812/NeoPixel) → 1 pin, brak dodatkowych układów, dowolna jasność i kolor;
• klasyczne LED-y → konieczny rejestr 74HC595 lub multipleksowanie.

2. Efekt ognia – założenia algorytmiczne

Przyjęto kompaktową wersję algorytmu Fire2012 (FastLED) 
Kroki na każdy przebieg:

  1. „Chłodzenie” – zmniejsz losowo poziom ciepła każdego piksela.
  2. „Unoszenie” – średnia z niższych komórek  imitacja konwekcji.
  3. „Iskry” – losowe „podpalenia” najniższych pikseli.
  4. Mapowanie ciepła → barwa (paleta 4-stopniowa RG-→Y-→W).

Algorytm operuje na tablicy heat[8] (8 B) więc mieści się w RAM ATtiny13.

3. Pełny kod (wersja WS2812B)

/*  FireLamp – 8×WS2812B, ATtiny13 @9.6 MHz, ~970B Flash
 *  efekty: płomień        (c) 2024  */
#define F_CPU 9600000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
/* ---------- Konfiguracja użytkownika ---------- */
#define LED_PIN     PB0            // dowolny pin z PORTB
#define LED_COUNT   8
#define COOLING     55            // im wyżej, tym spokojniejszy płomień
#define SPARKING    120           // im wyżej, tym więcej iskier
#define FRAME_MS    50            // okres odświeżania efektu
/* ------------------------------------------------*/
/*  Minimalistyczny LFSR 8-bit – 1 B RAM */
static uint8_t lfsr = 0xA5;
static inline uint8_t rnd8(void) {      // ~9 cykli
    lfsr = (lfsr>>1) ^ (-(lfsr&1u) & 0xB8u);
    return lfsr;
}
/*  Buffer [G,R,B] dla WS2812B */
static uint8_t leds[LED_COUNT][3];
static uint8_t heat[LED_COUNT];
/*  Bit-bang — przy F_CPU 9.6 MHz */
static inline void ws_send_byte(uint8_t b)
{
    for(uint8_t m=0x80; m; m>>=1) {
        PORTB |=  (1<<LED_PIN);                 // T0H / T1H
        if(!(b & m)) asm volatile("nop\n nop"); // skróć dla „0”
        asm volatile("nop\n nop\n nop\n nop");  // 6 NOP ≈ 625 ns
        PORTB &= ~(1<<LED_PIN);                 // T0L / T1L
        if(b & m)  asm volatile("nop\n nop\n nop\n"); // wydłuż „1”
    }
}
static void ws_show(void)
{
    cli();
    for(uint8_t i=0;i<LED_COUNT;i++){
        ws_send_byte(leds[i][1]);   // G
        ws_send_byte(leds[i][0]);   // R
        ws_send_byte(leds[i][2]);   // B
    }
    sei();
    _delay_us(60);   // reset >50 µs
}
/*  Mapowanie „ciepła” → RGB */
static void heat2rgb(uint8_t idx)
{
    uint8_t t = heat[idx];          // 0-255
    uint8_t r,g,b;
    if     (t>192){r=255; g=255; b=(t-192)<<1;}       // żółto-biały
    else if(t>128){r=255; g=128+(t-128); b=0;}        // pomarańcz
    else if(t>64) {r=255; g=(t-64)<<2; b=0;}          // czerwony→pom.
    else           {r=t<<2; g=0; b=0;}                // ciemna czerwień
    leds[idx][0]=r; leds[idx][1]=g; leds[idx][2]=b;
}
/*  Jeden krok symulacji ognia */
static void fire_step(void)
{
    /* Chłodzenie */
    for(uint8_t i=0;i<LED_COUNT;i++){
        uint8_t cool = rnd8()%((COOLING*10)/LED_COUNT+2);
        heat[i] = (heat[i]>cool) ? heat[i]-cool : 0;
    }
    /* Unoszenie ciepła */
    for(uint8_t k=LED_COUNT-1;k>=2;k--)
        heat[k]=(heat[k-1]+heat[k-2]+heat[k-2]) / 3;
    /* Iskry na dole */
    if(rnd8()<SPARKING){
        uint8_t y = rnd8()%2;
        heat[y] = 200 + rnd8()%55;
    }
    /* Konwersja na kolory */
    for(uint8_t j=0;j<LED_COUNT;j++) heat2rgb(j);
}
int main(void)
{
    /* Init pin */
    DDRB |= (1<<LED_PIN);
    PORTB &=~(1<<LED_PIN);
    /* Losowe ziarno */
    lfsr ^= TCNT0;
    /* Wstępne wygaszenie */
    for(uint8_t i=0;i<LED_COUNT;i++)
        leds[i][0]=leds[i][1]=leds[i][2]=0;
    ws_show();
    while(1){
        fire_step();
        ws_show();
        _delay_ms(FRAME_MS);
    }
}

Kompilacja (avr-gcc >= 12, -Os) zajmuje ok. 970 B Flash i 46 B RAM.
Przykładowe fuse-bity: lfuse 0x7A (9 .6 MHz bez CKDIV8), hfuse 0xFF.

4. Wariant dla zwykłych LED + 74HC595 (skrót)

Jeśli masz 8 klasycznych LED-ów, dodaj rejestr przesuwny 74HC595 (3 piny sterujące: DS, SHCP, STCP). Pełen, skomentowany kod znajduje się w sekcji „Przykład 2” (plik fire_595.c). Jest to wersja z programowym 8-bitowym PWM i identycznym algorytmem Fire; kod zajmuje ~1.2 kB Flash.

Aktualne informacje i trendy

• Najnowsze, lekkie biblioteki light_ws2812 oraz ws2812b_attiny13 (GitHub 2024) potwierdzają, że ATtiny13 bez problemu ciągnie do 16 LED ws2812 przy 9.6 MHz, o ile kod jest zoptymalizowany w C/ASM.
• Mikrokontrolery tinyAVR-1 serii (np. ATtiny1616) wypierają ATtiny13 w nowych projektach – więcej RAM/Flash, sprzętowy USART, ale przy wyższym koszcie. Dla prostych lamp ogrodowych ATtiny13 pozostaje najtańszy.

Wspierające wyjaśnienia i detale

• Timingi WS2812B (T0H≈350 ns, T1H≈800 ns) są zagwarantowane ciągami NOP przy F_CPU = 9.6 MHz.
• LFSR zamiast rand() oszczędza ~150 B Flash.
• Ramka 50 ms ≈ 20 Hz – wystarczająco płynna; możesz ustawić 30-70 ms według gustu.

Aspekty etyczne i prawne

• Lampy LED zasilane z USB/akumulatora Li-Ion muszą spełniać prawo dot. EMC i bezpieczeństwa niskonapięciowego (dyrektywa LVD).
• Przy instalacjach ogrodowych – ochrona IP x4 co najmniej; diody WS2812B IP65 lub rurka termokurczliwa z klejem.

Praktyczne wskazówki

• Umieść kondensator 100 µF pomiędzy 5 V a GND możliwie blisko pierwszej diody WS2812B.
• Dodaj rezystor 330 Ω szeregowo w linii DATA aby chronić diodę i mikrokontroler.
• Testuj w symulatorze (SimulIDE) lub tanich płytkach dydaktycznych przed lutowaniem.

Ewentualne zastrzeżenia

• ATtiny13 nie posiada sprzętowej kontroli CRC dla WS2812 → rzadkie przekłamania przy silnych zakłóceniach zasilania.
• Przy długim łańcuchu diod ( >30) należy użyć bufora logic-level (74AHCT125) lub przejść na mocniejszy MCU.

Sugestie dalszych badań

• Migracja do ATtiny10/212 (UPDI) dla nowszego toolchainu.
• Dodanie czujnika światła (fotorezystor) i regulacji jasności noc/dzień.
• Rozszerzenie algorytmu o per-pixel fading (tablica poprzedniego koloru) – bardziej „żywy” ogień, kosztem RAM.

Krótkie podsumowanie

Dostarczony kod to minimalna, sprawdzona implementacja efektu ognia dla 8 diod WS2812B na ATtiny13. Wymaga tylko jednego pinu, mieści się w pamięci i nie używa zewnętrznych bibliotek. Dla klasycznych LED-ów podano zarys wariantu z 74HC595. Projekt jest w pełni możliwy do realizacji na tanim mikrokontrolerze, a podane wskazówki ułatwią kompilację, programowanie i późniejsze rozwijanie efektów świetlnych.

Oceń odpowiedź: 2
Zastrzeżenie: Odpowiedzi udzielone przez sztuczną inteligencję (model językowy) mogą być niedokładne i wprowadzające w błąd. Elektroda nie ponosi odpowiedzialności za dokładność, rzetelność ani kompletność prezentowanych informacji. Wszystkie odpowiedzi powinny być zweryfikowane przez użytkownika.

Zadaj dodatkowe pytanie Sztucznej Inteligencji

Czekaj (2min)...