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