ATtiny2313: Timer1 CTC, PB4 OC1B sprzętowy przebieg 128s, kwarc 1MHz lub 32,768kHz, kod

Pytanie

Jak wygląda kod na Attiny 2313 według tych wskazówek na pinie PB4 i PB5 , o okresie 128 sekund ,64 sekund stan niski , i 64 sekund stan wysoki , jaki kwarc dać najlepiej.
Wskazówka :
W Generatorze DDS z EP 6/2018 jest sprzętowe sterowanie wyjściem:
void Timer1_Start(uint8_t dzielnik)
{
// OCR1B=dzielnik;
OCR1B=dzielnik;

//Output compare toggles OC1A pin
// TCCR1A |= 0x40; // COM1A = 1
TCCR1A |= 0x10; // COM1B = 1
//start timer without prescaler
TCCR1B = 0b00001001; // WGM 12=1, CS=1

DDRD |= _BV(PD4);
}

Uzyskasz DOKŁADNIE 50% bez liczenia cykli. Nie muszą być włączone przerwania ale mogą. Program główny może robić co chce a nie wpłynie to na generowany przebieg bez względu na to, czy przerwania będą włączone czy nie. Max częstotliwość to Fclk/2, uzyskaj taką przez delay. Taki program jest krótszy niż z delay. Jeśli częstotliwość jest zbyt duża należy timery połączyć w kaskadę.
Można także użyć timera w trybie PWM. Używając OCRxA można ustawić próg zliczania a co za tym idzie, precyzyjnie regulować częstotliwość.

Głupotą jest, mając możliwości sprzętowe, rozwiązywać problem w sposób programowy.

Odpowiedź Sztucznej Inteligencji


Bezpośrednia odpowiedź na pytanie

  • Najprościej i „sprzętowo” uzyskasz 128 s (64 s niski + 64 s wysoki) wykorzystując Timer1 w trybie CTC i sprzętowe przełączanie wyjścia (toggle) na pinie OC1B.
  • Na ATtiny2313 pin PB4 = OC1B (sprzętowe wyjście timera). Pin PB5 nie jest wyjściem OC1x, więc identyczny sygnał na PB5 uzyskasz wygodnie przez jednorazowe przerwanie co 64 s (zerowe obciążenie CPU).
  • Jaki kwarc? Dwie praktyczne opcje:
    • 1,000 MHz (albo wewnętrzny 8 MHz z CKDIV8 → 1 MHz): daje idealnie całkowitą wartość OCR1A = 62499 (preskaler 1024), więc 64,000 s bez błędu zaokrągleń.
    • 32,768 kHz (zegarkowy): najlepszy dla stabilności długoterminowej; z preskalerem 1024 wystarczy OCR1A = 2047.

Szczegółowa analiza problemu

  • Cel: T = 128 s, wypełnienie 50% → półokres = 64 s.

  • Tryb: CTC (WGM12=1) z „toggle on compare match” (COM1Bx0=1) daje idealne 50% bez liczenia cykli i bez jitteru na kanale sprzętowym.

  • Wzór: t_half = (OCR1A + 1) · preskaler / Fclk.

  • Warianty:

    1. Fclk = 1 MHz, preskaler = 1024:
      • (OCR1A + 1) = 64 · 1 000 000 / 1024 = 62500 → OCR1A = 62499 (dokładnie 64,000 s).
      • Ustaw OCR1B = OCR1A, aby sprzętowo przełączać PB4 (OC1B) w tym samym momencie „szczytu”.
      • PB5: jedyne przerwanie COMPA co 64 s do „zlustrowania” stanu (praktycznie bezkosztowe).
    2. Fclk = 32,768 kHz, preskaler = 1024:
      • Ftimer = 32 Hz; 64 s · 32 Hz = 2048 → OCR1A = 2047.
      • Identycznie: COM1B0=1 dla PB4, a PB5 przełączany w ISR od COMPA co 64 s.
  • Mapowanie pinów (istotne): w ATtiny2313 sprzętowe wyjścia Timer1 to OC1A oraz OC1B. OC1B jest na PB4. PB5 nie jest linią OC1x, więc nie da się go przełączać w 100% sprzętowo Timerem1 bez ISR albo logiki zewnętrznej. Jeśli możesz zmienić wymagania pinów, najczyściej jest użyć PB3 (OC1A) + PB4 (OC1B) i wtedy oba kanały będą w pełni sprzętowe.

Aktualne informacje i trendy

  • Do odmierzania długich odcinków czasu w prostych AVR nadal często wybiera się:
    • niską Fclk (np. 32,768 kHz) dla stabilności temperaturowej,
    • albo „całkowite” rozwiązanie przy 1 MHz z preskalerem = 1024 dla prostych, dokładnych nastaw bez błędu dzielenia.
  • Dla najwyższej precyzji czasowej w aplikacjach długookresowych coraz częściej stosuje się zewnętrzne RTC (np. TCXO/DS3231) jako wzorzec czasu.

Wspierające wyjaśnienia i detale

  • Dlaczego OCR1B = OCR1A? W trybie CTC „TOP” to OCR1A. Gdy TCNT1 == OCR1A, następuje Compare Match A oraz reset licznika. Jeśli jednocześnie OCR1B ma taką samą wartość, uzyskasz Compare Match B w tym samym takcie i sprzętowy „toggle” na OC1B (PB4) dokładnie co 64 s.
  • Dlaczego PB5 w ISR? Bo nie ma tam sprzętowego powiązania z Timer1. ISR wywoływane raz na 64 s ma znikome obciążenie i nie wprowadza mierzalnych zakłóceń.

Aspekty etyczne i prawne

  • Brak szczególnych implikacji. Upewnij się, że konfiguracja fuse nie zablokuje możliwości programowania układu (ostrożnie z RSTDISBL).

Praktyczne wskazówki

  • Jeśli nie potrzebujesz dokładności „zegarkowej”, użyj wewnętrznego 8 MHz z CKDIV8 (1 MHz) – prostsze uruchomienie, zero elementów zewnętrznych.
  • Jeśli ważna jest stabilność i niewielki dryft, użyj kwarcu 32,768 kHz i ustaw odpowiednie fuse dla oscylatora niskoczęstotliwościowego.
  • Dodaj kondensatory przy kwarcu wg noty katalogowej.
  • Test: podepnij LED + 1 kΩ do PB4/PB5 i obserwuj zmianę co ~64 s.

Ewentualne zastrzeżenia lub uwagi dodatkowe

  • Jeśli w kodzie głównym wyłączysz globalne przerwania na dłużej niż kilkadziesiąt ms akurat w chwili Compare Match, zbocze na PB5 może się opóźnić – PB4 (sprzętowe) pozostanie idealne.
  • Pełne sprzętowe wyjście na dwóch pinach bez ISR wymagałoby użycia dwóch linii OC (np. PB3+PB4) lub dodatkowej logiki zewnętrznej.

Sugestie dalszych badań

  • Zastosowanie zewnętrznego RTC jako wzorca i synchronizacja timera.
  • Analiza błędu temperaturowego dla wewnętrznego RC vs kwarc 32,768 kHz.
  • Minimalizacja poboru prądu (tryby uśpienia z aktywnym Timer1).

Kod – wariant 1 (Fclk = 1 MHz, preskaler 1024; PB4 sprzętowo, PB5 w ISR)

#define F_CPU 1000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
static inline void timer1_init_64s(void)
{
    // PB4 (OC1B) i PB5 jako wyjścia
    DDRB |= _BV(PB4) | _BV(PB5);
    // Timer1: CTC, TOP=OCR1A, preskaler=1024
    TCCR1A = 0;
    TCCR1B = 0;
    TCNT1  = 0;
    // 64 s = (OCR1A+1)*1024 / 1e6  => OCR1A = 62499
    OCR1A = 62499;
    OCR1B = 62499;        // toggle OC1B dokładnie przy TOP
    // Toggle na OC1B (PB4) przy Compare Match B
    TCCR1A = (1<<COM1B0); // COM1B1=0, COM1B0=1 (toggle)
    // CTC + preskaler 1024
    TCCR1B = (1<<WGM12) | (1<<CS12) | (1<<CS10);
    // Jedno przerwanie co 64 s – do lustrzanego przełączania PB5
    TIMSK |= (1<<OCIE1A);
    sei();
}
ISR(TIMER1_COMPA_vect)
{
    // Lustrzane przełączenie PB5 co 64 s
    PORTB ^= _BV(PB5);
}
int main(void)
{
    timer1_init_64s();
    for (;;)
    {
        // pętla główna może robić cokolwiek; PB4 generuje się sprzętowo
    }
}

Kod – wariant 2 (Fclk = 32,768 kHz, preskaler 1024; PB4 sprzętowo, PB5 w ISR)

#define F_CPU 32768UL
#include <avr/io.h>
#include <avr/interrupt.h>
static inline void timer1_init_64s_32k(void)
{
    DDRB |= _BV(PB4) | _BV(PB5);
    TCCR1A = 0;
    TCCR1B = 0;
    TCNT1  = 0;
    // Ftimer = 32768/1024 = 32 Hz; 64 s * 32 = 2048 => OCR1A = 2047
    OCR1A = 2047;
    OCR1B = 2047;
    TCCR1A = (1<<COM1B0);                     // toggle OC1B
    TCCR1B = (1<<WGM12) | (1<<CS12) | (1<<CS10); // CTC, /1024
    TIMSK |= (1<<OCIE1A); // jednorazowe ISR co 64 s dla PB5
    sei();
}
ISR(TIMER1_COMPA_vect)
{
    PORTB ^= _BV(PB5);
}
int main(void)
{
    timer1_init_64s_32k();
    for(;;) { }
}

Uwaga do fuse:

  • Dla 1 MHz z wewnętrznego RC: włącz CKDIV8 lub ustaw preskaler systemowy tak, by Fclk=1 MHz.
  • Dla 32,768 kHz: ustaw tryb oscylatora niskoczęstotliwościowego zgodnie z dokumentacją ATtiny2313 (czas startu i CKSEL).

Krótkie podsumowanie

  • PB4 (OC1B) można przełączać w 100% sprzętowo co 64 s wykorzystując Timer1 w trybie CTC i „toggle on compare”.
  • PB5 nie jest wyjściem OC1x w ATtiny2313 – najpraktyczniej zlustrować stan PB4 w ISR od COMPA wywoływanym co 64 s (brak wpływu na dokładność PB4, minimalne obciążenie).
  • Kwarc: 1 MHz (idealne „całkowite” wyliczenie) lub 32,768 kHz (najlepsza długoterminowa stabilność). Jeśli możesz zmienić piny, użyj PB3 (OC1A) + PB4 (OC1B), wtedy oba kanały będą w 100% sprzętowe bez ISR.

Oceń odpowiedź:
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)...