ATtiny2313 Timer1 CTC: PB3 PB4 128s, 50% duty, kod C i ASM, kwarc 1MHz lub 1.048576MHz

Pytanie

Jak wygląda kod w j.C i w j.ASM na Attiny 2313 , według poniższej wskazówki , na pinie PB3 i PB4 , 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ść.

Odpowiedź Sztucznej Inteligencji


Bezpośrednia odpowiedź na pytanie

  • Najprościej: użyj Timer1 w trybie CTC i sprzętowego przełączania wyjść (COM1A0 i COM1B0 = 1). Piny PB3=OC1A i PB4=OC1B będą się „toggle’ować” bez udziału CPU co 64 s, czyli okres 128 s z wypełnieniem 50%.
  • Polecany kwarc: 1.048576 MHz (2^20 Hz) lub 1.000000 MHz. Dają „ładne” wartości OCR i pracę z preskalerem 1024.
  • Dla 1.048576 MHz: preskaler 1024, OCR1A = 65535 (ICzasy = 64 s). Dla 1.000 MHz: preskaler 1024, OCR1A = 62499.

Szczegółowa analiza problemu

  • Wymagany półokres: T1/2 = 64 s. Zegar timera po preskalerze fT = F_CPU / 1024.
  • Czas między zdarzeniami Compare w CTC: tCMP = (OCR1A + 1) / fT.
  • Warunek: tCMP = 64 s → OCR1A = 64·F_CPU/1024 − 1.
  • Obliczenia:
    • F_CPU = 1.048576 MHz → fT = 1024 Hz → OCR1A = 64·1024 − 1 = 65535.
    • F_CPU = 1.000000 MHz → fT ≈ 976.5625 Hz → OCR1A = 64·976.5625 − 1 = 62500 − 1 = 62499.
  • Sprzętowe 50%: w trybie CTC (WGM12=1, WGM13:WGM10=0) ustaw:
    • COM1A0=1 (toggle OC1A = PB3 na zgodność z OCR1A),
    • COM1B0=1 (toggle OC1B = PB4 na zgodność z OCR1B).
  • Aby oba piny przełączały się równocześnie, ustaw OCR1B = OCR1A. Timer zlicza do OCR1A i się zeruje; porównania z OCR1A i OCR1B następują w tej samej chwili, więc PB3 i PB4 „idą razem”.
  • Uwaga na fuse CKDIV8: jeśli jest zaprogramowany (domyślnie często tak), F_CPU zostanie podzielone przez 8. Wtedy przelicz OCR1A lub wyłącz CKDIV8.

Aktualne informacje i trendy

  • Dla długich czasów i stabilności częstotliwości praktykuje się częstotliwości „binarnie wygodne” (1.048576 MHz) lub kwarce 1.000 MHz. Wewnętrzny RC można skalibrować (OSCCAL), ale dla 64 s niedokładność RC (±1…10%) może być zauważalna.

Wspierające wyjaśnienia i detale

  • Mapowanie wyjść w ATtiny2313: PB3 = OC1A, PB4 = OC1B. Dzięki temu dokładnie Twoja wskazówka (sprzętowe przełączanie OC1x) działa bez ISR.
  • Alternatywa z ICR1 jako TOP (tryb 12 CTC, WGM13:WGM12=1, WGM11:WGM10=0) też działa: ustaw ICR1 na wartość dla 64 s, a OCR1A/OCR1B na dowolny licznik w zakresie [0..ICR1]; wyjścia będą toggle raz na cykl (również 50%). Tu jednak pokazuję prostszy wariant (TOP = OCR1A).

Aspekty etyczne i prawne

  • Brak szczególnych aspektów; pamiętaj jedynie o zgodności z dokumentacją i ESD.

Praktyczne wskazówki

  • Jeżeli używasz zewnętrznego kwarcu: wyłącz CKDIV8 (albo uwzględnij go w obliczeniach), ustaw CKSEL na „External Crystal/Resonator”.
  • Chcesz przesunąć fazę między PB3 i PB4? Ustaw OCR1B na inny moment (np. OCR1B = OCR1A/2 → sygnał na PB4 przesunięty o 180° względem PB3).
  • Chcesz niższy pobór mocy? Po konfiguracji przejdź w tryb uśpienia (Idle/Power-save); Timer1 dalej pracuje.

Ewentualne zastrzeżenia lub uwagi dodatkowe

  • Przy OCR1A=65535 (dla 1.048576 MHz) jesteś na maksymalnej wartości 16-bit — to poprawne i powtarzalne, ale jeśli planujesz dynamicznie zmieniać częstotliwość, miej na uwadze zakres.
  • Wewnętrzny RC (bez kwarcu) może mieć zauważalny błąd okresu 128 s; dla precyzji stosuj kwarc.

Sugestie dalszych badań

  • Jeśli kiedyś będziesz potrzebował jeszcze dłuższych okresów bez zmiany kwarcu — rozważ kaskadę Timer0→Timer1 (Timer0 generuje przerwanie co N sekund i wymusza „force compare” lub przełącza tylko co pewien licznik przerwań).
  • Dla ultra-niskiej mocy i bardzo długich czasów rozważ mikrokontroler z asynchronicznym timerem zasilanym kwarcem 32.768 kHz.

Kod w C (wariant 1: kwarc 1.048576 MHz, idealne 64 s bez ISR)

#include <avr/io.h>
int main(void)
{
    // PB3 (OC1A) i PB4 (OC1B) jako wyjścia
    DDRB |= _BV(PB3) | _BV(PB4);
    // Timer1: CTC, TOP=OCR1A, preskaler 1024
    TCCR1A = 0;
    TCCR1B = _BV(WGM12) | _BV(CS12) | _BV(CS10);
    // F_CPU = 1.048576 MHz -> fT = 1024 Hz -> 64 s => OCR1A = 65535
    OCR1A = 65535;
    OCR1B = 65535;       // Równoczesne toggle PB3 i PB4
    // Sprzętowe toggle na zgodność
    TCCR1A |= _BV(COM1A0) | _BV(COM1B0);
    while (1) { /* nic, sprzęt działa sam */ }
}

Kod w C (wariant 2: kwarc 1.000000 MHz)

#include <avr/io.h>
int main(void)
{
    DDRB |= _BV(PB3) | _BV(PB4);
    TCCR1A = 0;
    TCCR1B = _BV(WGM12) | _BV(CS12) | _BV(CS10); // CTC, /1024
    // F_CPU = 1 MHz -> fT ≈ 976.5625 Hz -> 64 s => OCR1A = 62499
    OCR1A = 62499;
    OCR1B = 62499;
    TCCR1A |= _BV(COM1A0) | _BV(COM1B0);
    while (1) { }
}

Kod w ASM (wariant 1: kwarc 1.048576 MHz, OCR1A=65535)

; ATtiny2313, PB3=OC1A, PB4=OC1B, T=128 s (64 s/64 s)
.include "tn2313def.inc"
.cseg
.org 0x0000
    rjmp RESET
RESET:
    ; Stos
    ldi  r16, low(RAMEND)
    out  SPL, r16
    ldi  r16, high(RAMEND)
    out  SPH, r16
    ; PB3, PB4 jako wyjścia
    sbi  DDRB, PB3
    sbi  DDRB, PB4
    ; CTC, preskaler 1024
    ldi  r16, 0
    out  TCCR1A, r16
    ldi  r16, (1<<WGM12) | (1<<CS12) | (1<<CS10)
    out  TCCR1B, r16
    ; OCR1A = 65535
    ldi  r16, 0xFF
    out  OCR1AH, r16
    out  OCR1AL, r16
    ; OCR1B = 65535 (równoczesne przełączanie PB3 i PB4)
    out  OCR1BH, r16
    out  OCR1BL, r16
    ; Toggle OC1A i OC1B
    ldi  r16, (1<<COM1A0) | (1<<COM1B0)
    out  TCCR1A, r16
MAIN:
    rjmp MAIN

Kod w ASM (wariant 2: kwarc 1.000000 MHz, OCR1A=62499 = 0xF423)

.include "tn2313def.inc"
.cseg
.org 0x0000
    rjmp RESET
RESET:
    ldi  r16, low(RAMEND)
    out  SPL, r16
    ldi  r16, high(RAMEND)
    out  SPH, r16
    sbi  DDRB, PB3
    sbi  DDRB, PB4
    ldi  r16, 0
    out  TCCR1A, r16
    ldi  r16, (1<<WGM12) | (1<<CS12) | (1<<CS10)
    out  TCCR1B, r16
    ; OCR1A = 62499 (0xF423)
    ldi  r17, high(62499)     ; 0xF4
    ldi  r16, low(62499)      ; 0x23
    out  OCR1AH, r17
    out  OCR1AL, r16
    ; OCR1B = 62499
    out  OCR1BH, r17
    out  OCR1BL, r16
    ; Toggle OC1A/OC1B
    ldi  r16, (1<<COM1A0) | (1<<COM1B0)
    out  TCCR1A, r16
LOOP:
    rjmp LOOP

Podsumowanie

  • Ustaw Timer1 w trybie CTC, preskaler 1024, COM1A0=COM1B0=1, OCR1B=OCR1A.
  • Najprostsze i najdokładniejsze: kwarc 1.048576 MHz (OCR1A=65535) lub 1.000000 MHz (OCR1A=62499).
  • Brak przerwań, idealne 50% wypełnienia, główny program nie wpływa na przebieg na PB3/PB4.

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)...