Jak wygląda kod na Attiny 2313A , sprzętowy , PWM , zmiana polaryzacji LOW 64 sekund , HIGH 64 sekund , okres 128 sekund , duty 50% , między pinami PB3 i PB4 , z gołym kwarcem , jakim najlepiej ? ,wedłu poniższych wskazówek : " Cały czas mowa o precyzyjnych częstotliwościach, współczynniku wypełnienia a uczepiłaś się najgorszego z możliwych rozwiązań mając sprzętowe sterowanie GPIO, gdzie trzeba liczyć każdy cykl maszynowy jak w latach 80.
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
DDRB |= _BV(PB4);
}
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."
Tak — da się to zrobić sprzętowo, bez delay(), bez liczenia cykli w pętli i bez przerwań, używając Timer1 w trybie CTC z przełączaniem wyjść OC1A = PB3 i OC1B = PB4. Dla wymaganego przebiegu 64 s LOW, 64 s HIGH, okres 128 s, duty 50% najpraktyczniejszy i jednocześnie dokładny wybór to kwarc 1.048576 MHz. PB3 i PB4 są sprzętowymi wyjściami OC1A/OC1B w ATtiny2313A. (ww1.microchip.com)
Najważniejsza korekta względem części przykładowych odpowiedzi: 32.768 kHz jako “goły kwarc” dla głównego zegara tego układu nie jest dobrym wyborem, bo w dokumentacji ATtiny2313/2313A zakres 0.4–0.9 MHz jest opisany jako nieodpowiedni dla kwarców, a tryb kwarcowy zaczyna się praktycznie od 0.9 MHz. Dla zakresu 0.9–3.0 MHz Microchip podaje też orientacyjnie 12–22 pF dla C1 i C2. (microchip.com)
Masz dwa sensowne podejścia:
Dla Twojego przypadku lepsze jest CTC + toggle, bo wymagany sygnał to w praktyce bardzo wolny prostokąt 50%, a nie szybki PWM z modulacją. Tryb CTC daje tu dokładnie to, czego chcesz: rdzeń nic nie liczy, program główny może robić co chce, a wyjścia zmieniają się wyłącznie sprzętowo. Dokumentacja mówi, że w trybie CTC licznik zeruje się po osiągnięciu TOP, a wyjście OC1x można ustawić na toggle on compare match. (microchip.com)
Przyjmujemy:
Ustawiamy:
Wtedy licznik przechodzi przez:
\[
65536 \text{ taktów}
\]
a więc czas jednego przełączenia wyjścia:
\[
t_{toggle} = \frac{65536}{1024} = 64 \,\text{s}
\]
Ponieważ wyjście jest przełączane co 64 s, pełny okres wynosi:
\[
T = 2 \cdot 64 \,\text{s} = 128 \,\text{s}
\]
czyli:
To wychodzi dokładnie, bez aproksymacji. (microchip.com)
Da się zrobić sygnały komplementarne w Fast PWM na OC1A/OC1B, ale dla dokładnego okresu 128 s przy jednym Timer1 i bez dodatkowego zliczania trzeba dobrać bardzo specyficzny zegar. Matematycznie wychodziłby zegar rzędu 524.288 kHz, ale dokumentacja dla zakresu 0.4–0.9 MHz zaznacza, że ten wariant nie jest przeznaczony dla kwarców, tylko zasadniczo dla rezonatorów ceramicznych / trybów o gorszej stabilności startu. To przeczy założeniu „precyzyjnie i na kwarcu”. Dlatego dla Twojego wymagania CTC jest rozwiązaniem bardziej poprawnym inżyniersko niż “na siłę PWM”. (microchip.com)
Samo ustawienie obu kanałów na toggle spowoduje, że oba będą się przełączać w tych samych chwilach. Aby były komplementarne, trzeba im ustawić przeciwne stany początkowe. Dokumentacja przewiduje to wprost:
Dlatego procedura jest taka:
To jest rozwiązanie całkowicie sprzętowe. (microchip.com)
#define F_CPU 1048576UL
#include <avr/io.h>
static void timer1_init_128s_complementary(void)
{
// 1) Zatrzymaj Timer1
TCCR1A = 0;
TCCR1B = 0;
TCCR1C = 0;
// 2) Tryb CTC, TOP = ICR1 (WGM13:0 = 12 = 1100)
TCCR1B = (1 << WGM13) | (1 << WGM12);
// 3) Dokładnie 64 s do compare przy F_CPU = 1.048576 MHz i preskalerze 1024
TCNT1 = 0x0000;
ICR1 = 0xFFFF; // TOP
OCR1A = 0xFFFF; // Compare dla PB3 / OC1A
OCR1B = 0xFFFF; // Compare dla PB4 / OC1B
// 4) Zainicjalizuj stany wewnętrznych rejestrów OC1A/OC1B:
// OC1A -> LOW
// OC1B -> HIGH
//
// A: Clear on compare
// B: Set on compare
TCCR1A = (1 << COM1A1) | (1 << COM1B1) | (1 << COM1B0);
// Wymuś natychmiastowe wykonanie akcji compare w trybie nie-PWM
TCCR1C = (1 << FOC1A) | (1 << FOC1B);
// 5) Przełącz oba kanały na toggle on compare match
TCCR1A = (1 << COM1A0) | (1 << COM1B0);
// 6) Dopiero teraz włącz wyjścia PB3 i PB4
DDRB |= (1 << PB3) | (1 << PB4);
// 7) Start timera z preskalerem 1024
TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS12) | (1 << CS10);
}
int main(void)
{
timer1_init_128s_complementary();
while (1)
{
// Pętla główna może robić cokolwiek.
// Generacja przebiegu jest całkowicie sprzętowa.
}
}
Po starcie:
czyli dokładnie sygnały komplementarne o okresie 128 s. Jeśli chcesz odwrotny stan początkowy, zamień inicjalizację FOC:
a potem znów wróć oba kanały do toggle. Działa to z tej samej zasady. (microchip.com)
ATtiny2313A jest nadal widoczny u Microchipa jako układ In Production. Jednocześnie jest to już stara rodzina AVR bez dedykowanego RTC, więc dla bardzo długich, precyzyjnych okresów trzeba świadomie wykorzystywać Timer1 i odpowiednio dobrany zegar systemowy. (microchip.com)
W praktyce oznacza to, że dla tego konkretnego zadania ATtiny2313A nadal się nadaje, ale rozwiązanie musi być „zegarowo poprawne”. To właśnie dlatego dobór 1.048576 MHz ma większy sens niż popularne 1 MHz, 4 MHz czy 8 MHz, jeśli wymagasz dokładnie 64/64 s bez ISR. (microchip.com)
Jeżeli przez „goły kwarc” rozumiesz sam rezonator kwarcowy bez C1/C2, to odpowiedź brzmi: nie tak należy to robić. Dokumentacja pokazuje klasyczne połączenie kwarcu do XTAL1/XTAL2 z dwoma kondensatorami do masy i podaje dla zakresu 0.9–3.0 MHz orientacyjnie 12–22 pF jako punkt startowy. (microchip.com)
Praktycznie:
Jeżeli użyjesz aktywnego generatora CMOS, to wtedy nie jest to już „goły kwarc”, tylko zewnętrzny generator zegara i podpinasz go inaczej. To też działa, ale to już inna topologia. (microchip.com)
Dla tego rozwiązania potrzebujesz ustawić źródło zegara na External Crystal / Resonator, zakres 0.9–3.0 MHz. Uwaga praktyczna: układ fabrycznie jest dostarczany z wewnętrznym RC 8 MHz oraz zaprogramowanym CKDIV8, co daje startowo 1 MHz. Jeśli zostawisz niewłaściwe fuse albo dzielnik zegara, wszystkie wyliczenia czasów przestaną się zgadzać. (microchip.com)
W sensie prawnym temat jest neutralny, ale inżyniersko trzeba pamiętać o bezpieczeństwie aplikacji:
Tu szczególnie ważne jest, że po restarcie układu stan wyjść wraca do stanu inicjalizacji programu, więc jeśli sterujesz czymś krytycznym, trzeba jawnie zaprojektować stan bezpieczny.
Idle, jeśli chcesz obniżyć pobór mocy, bo Timer1 nadal może pracować.0xFFFF.Najważniejsze zastrzeżenie: jeśli ktoś upiera się przy „prawdziwym PWM mode” zamiast CTC, to dla ATtiny2313A i wymogu dokładnie 128 s bez ISR i bez dodatkowego dzielenia robi się to dużo mniej elegancko. Właśnie dlatego cytowana przez Ciebie uwaga o „sprzętowym sterowaniu GPIO zamiast liczenia cykli” jest słuszna, ale w tym konkretnym przypadku najlepszą realizacją sprzętową nie jest klasyczny Fast PWM, tylko CTC z toggle. (microchip.com)
Druga ważna korekta: propozycje z 32.768 kHz dla głównego zegara tego układu są mylące. Ten mikrokontroler nie jest tu odpowiednikiem AVR z osobnym oscylatorem zegarkowym RTC; dla jego głównego oscylatora taka sugestia nie wynika z dokumentacji jako poprawny tryb kwarcowy. (microchip.com)
Jeżeli chcesz, mogę od razu przygotować jedną z trzech kolejnych wersji:
avrdude,Mogę też rozpisać wariant z aktywnym generatorem 1.048576 MHz zamiast klasycznego kwarcu.
Najlepsze rozwiązanie dla ATtiny2313A to:
Daje to dokładnie 64 s na każde przełączenie i 128 s pełnego okresu, całkowicie sprzętowo. Dodatkowo PB3 i PB4 można ustawić jako sygnały komplementarne przez jednorazową inicjalizację FOC. To jest rozwiązanie krótkie, precyzyjne i zgodne z duchem cytowanej wskazówki: nie liczyć cykli programowo, skoro timer potrafi zrobić to sprzętowo. (microchip.com)
Jeśli chcesz, w następnym kroku podam Ci dokładne fuse-bity i komendę avrdude dla tego wariantu.