Korzystasz z ATMega328 z wewnętrznym oscylatorem?


18

Mam projekt, który moim zdaniem najlepiej pasuje do ATMega328P. Jednak w każdym prostym projekcie, który widziałem, ludzie zawsze podłączają zewnętrzny oscylator 16 MHz. Z tego, co widzę, powinien mieć wewnętrzny oscylator 8 MHz. Mój projekt nie wymaga dużej mocy obliczeniowej, taktowanie nie musi być bardzo precyzyjne (inne niż dla UART i I2C). Mam również programistę, więc nie muszę się martwić o programy ładujące.

Czy jest jakiś powód, dla którego używam zewnętrznego oscylatora?

Odpowiedzi:


20

Nie mówisz, jaka jest dokładność tego wewnętrznego oscylatora. Znalezienie go w arkuszu danych na stronie 369 zajęło mi trochę czasu .

10% Dziesięć procent! A to dla skalibrowanego oscylatora? To okropne. Nie jest nieuzasadnione oczekiwanie na błąd tak niski jak 1% . Microchip / Atmel udostępnia dokument do samodzielnej kalibracji oscylatora z dokładnością 1%.

I2C jest protokołem synchronicznym , a dokładność taktowania nie ma znaczenia, o ile przestrzegane są minimalne i maksymalne czasy impulsu. Z drugiej strony
UART jest asynchroniczny , dlatego dokładność taktowania jest istotna. Większość UART pozwala na błąd o wartości pół bitów w ostatnim bicie (bit stopu), więc jest to 5% dla transmisji 10-bitowej.

Fabrycznie skalibrowany oscylator nie zrobi tego. Musisz przejść procedurę kalibracji, aby uzyskać 1%. W takim przypadku możesz użyć wewnętrznego oscylatora. W przeciwnym razie będziesz musiał użyć kryształu.


1
Pozwólcie, że wzmocnię to, co tu powiedziane. Zaoszczędź sobie czasu i bólu głowy i po prostu zdobądź kryształ. Jeśli problem dotyczy zasilania, użyj kryształu zegarka 32khz (6PF dla 48/88/168 ... nie jestem pewien co do 328. sprawdź arkusz migracji), aby dostroić wewnętrzny oscylator podczas uruchamiania. Procedura kalibracji oscylatora jest bardzo skomplikowana, więc uważaj, jeśli wybierzesz tę trasę. Umieściłem dla niego przykładowy kod pod inną odpowiedzią.
bathMarm0t,

6

Podczas korzystania z UART wskazany byłby oscylator kwarcowy. Gdyby tak nie było, można użyć wewnętrznego oscylatora. Niektóre MCU mają fabrycznie przycięte wewnętrzne oscylatory, które mogą być odpowiednie do pracy UART.


2
Zobacz także tę notatkę aplikacji dotyczącą czasu UART: maxim-ic.com/app-notes/index.mvp/id/2141
drxzcl

Cóż, UART służy tylko do komunikacji z bardzo prostym wyświetlaczem szeregowym, który działa z prędkością
9600 bps

3

„Niewrażliwy na czas”. UART jest bardzo wrażliwy na czas. Dostaniesz pełne śmieci, jeśli nie zostaną odpowiednio zsynchronizowane.

Opcja 1: Użyj normalnego kryształu. Zmień odpowiednio bezpiecznik wyboru zegara. Wybór kryształów zależy od tego, jakiej prędkości transmisji chcesz użyć / od tego, jak szybko chcesz to zrobić. Są „magiczne kryształy”, które dadzą ci 0% błędu dla standardowych stawek (jeśli są wyprodukowane idealnie). Aby uzyskać więcej informacji, zobacz tabele w sekcji 20 [USART0] (przeczytałeś arkusz danych .... prawda ???) :).

wprowadź opis zdjęcia tutaj

Opcja 2: Możesz skalibrować wewnętrzny oscylator za pomocą kryształu 32 khz, jeśli występuje problem z mocą. Przy 32kHz możesz uzyskać prądy UA w trybie uśpienia (zredukowałem je do ~ 2uA). Musisz jednak skonfigurować procedurę kalibracji, która obejmuje uruchamianie / zatrzymywanie timerów i przełączanie timera 2 w tryb asynchroniczny.

Kod 328P może się różnić ... ta funkcja działa obecnie na 48/88 (z odpowiednimi definicjami F_CPU / baud. Jest trochę brzydka / nie została całkowicie zrefaktoryzowana, ale nauczyłem się lepiej, niż błądzić z rzeczami, które działają, gdy jesteś w wyznaczonym terminie. Wyszukaj na forum AVRFreaks „dostroić kryształ 32kHz” coś takiego. To tylko smak tego, w co się pakujesz ... Niekoniecznie to, co zadziała.

char OSCCAL_calibration(char starting_cal, int cal_value){
//Function calibrates the internal oscillator so usart comms go through.
//Works by continually checking two different timers:
//   (0 -> tied to internal, and 2 -> async to crystal).
//  Recommended cal_value = 5900 for the crystals we're using.
//  Must be running 8MHZ with clkdiv8 fuse enabled.
//  TODO: Make sure to check all the math on this later.
unsigned char calibrate = FALSE;
int temp;
unsigned char tempL;
volatile char osccal_temp=starting_cal;
int cal_bandwidth = 50;

//int cal_value = 6250;
//int cal_value = 5900; //Works.  Need to find out why.

//Dont use clock prescalers.  We're already div8ing.
//CLKPR = (1<<CLKPCE);        // set Clock Prescaler Change Enable
// set prescaler = 8, Inter RC 8Mhz / 8 = 1Mhz
//CLKPR = (1<<CLKPS1) | (1<<CLKPS0);

TIMSK2 = 0;             //disable OCIE2A and TOIE2
ASSR = (1<<AS2);        //select asynchronous operation of timer2 (32,768kHz)

OCR2B = 200;            // set timer2 compare value.  We probably only need to compare A
OCR2A = 200;

TIMSK0 = 0;             // delete any interrupt sources

TCCR2A = (1<<WGM21);    //Normal operation.  Reset timer on hitting TOP (ocr2a).
TCCR2B = (1<<CS20);     // start timer2 with no prescaling

TCCR1B = (1<<CS10);     // start timer1 with no prescaling

//wait for everythnig to mellow out.
while((ASSR & (1<<TCN2UB)) | (ASSR & (1<<OCR2BUB)) | (ASSR & (1<<TCR2BUB)) | (ASSR & (1<<OCR2AUB)) | (ASSR & (TCR2AUB)));       //wait for TCN2UB and TCR2UB to be cleared

//This is specifically for the crystal to stabilize.  Check for better times.
_delay_ms(1000);

while(!calibrate){
    cli();  // disable global interrupt

    TIFR1 = 0xFF;   // delete TIFR1 flags
    TIFR2 = 0xFF;   // delete TIFR2 flags

    TCNT1H = 0;     // clear timer1 counter
    TCNT1L = 0;
    TCNT2 = 0;      // clear timer2 counter

    //Stop timer on compare match.
    while ( !(TIFR2 & (1<<OCF2A)) );
    TCCR1B = 0;

    //Check for overflows (useless if it happens).
    sei();
    if ( (TIFR1 & (1<<TOV1)) ){
        temp = 0xFFFF;      // if timer1 overflows, set the temp to 0xFFFF
    }else{   // read out the timer1 counter value
        tempL = TCNT1L;
        temp = TCNT1H;
        temp = (temp << 8);
        temp += tempL;
        }

    //Check timer value against calculated value.           
    if (temp > (cal_value+(cal_bandwidth/2))){
        //Oscillator is too fast.
        osccal_temp--;
        OSCCAL=osccal_temp;
    }else if (temp < (cal_value-(cal_bandwidth/2))){
        //Oscillator is too slow.
        osccal_temp++;
        OSCCAL=osccal_temp;
    }else{
        //Just right.
        calibrate = TRUE;
        }

    TCCR1B = (1<<CS10); // start timer1
    }

//TODO: Stop timers, ya?
//Now setup timer2 to run "normally" aka async+interrupts.
//Disable interrupt source. Set mask.  Wait for registers to clear.
TIFR2 = (1<<TOV2);
TIMSK2 = (1<<TOIE2);
ASSR = (1<<AS2);        //select asynchronous operation of timer2 (32,768kHz)
TIMSK0 = 0;             // delete any interrupt sources

//Normal Op. 256 prescale.
TCCR2A = 0x00;
TCCR2B = (1<<CS22) | (1<<CS21);

TCCR1B = 0x00;     // turn off timer1

//wait for everythnig to mellow out.
while((ASSR & (1<<TCN2UB)) | (ASSR & (1<<OCR2BUB)) | (ASSR & (1<<TCR2BUB)) | (ASSR & (1<<OCR2AUB)) | (ASSR & (TCR2AUB)));       //wait for TCN2UB and TCR2UB to be cleared

//This is specifically for the crystal to stabilize.  Check for better times.
_delay_ms(1000);
return osccal_temp;
}

2

Należy również zauważyć, że uruchomienie kryształu zajmuje dużo czasu. Wynika to z jego precyzji: pobiera energię tylko z bardzo wąskiego pasma częstotliwości. Może to stanowić obciążenie dla urządzeń zasilanych bateryjnie, w których od czasu do czasu budzisz MCU: czekanie na ms przy pełnym poborze mocy do uruchomienia kryształu jest stratą netto. Rezonatory ceramiczne są dokładniejsze niż wewnętrzny oscylator RC, ale mniej niż kryształ, i zaczynają odpowiednio.

Oczywiście atmega 16 MHz pije dużo więcej soku i potrzebuje wyższego napięcia niż 8 MHz, ale dostępne są kryształy 8 MHz (lub niższe, aż do 32 kHz); ten sam wybór może być również oszczędnością energii.


0

Jeśli nie potrzebujesz dużo lub precyzyjnego pomiaru czasu, nie potrzebujesz zewnętrznego oscylatora. Podczas demontażu starych drukarek zdarza mi się widzieć wiele układów scalonych, ale nie ma na nich ani jednego oscylatora.


0

Chyba już widziałeś tę notatkę aplikacji: AVR053: Kalibracja wewnętrznego oscylatora RC .

Myślę, że z tego, a notatka aplikacji z komentarza @drxzcl powyżej, powinieneś być w stanie teoretycznie zdecydować, co jest właściwe.


Tam, gdzie jest już zaakceptowana odpowiedź, powinieneś spróbować powiedzieć coś więcej, w przeciwnym razie nie jest to bardzo przydatne
clabacchio

@clabacchio - ta odpowiedź ma dwa dni, a przyjęte daty pochodzą z wczoraj. Nie można go zaakceptować, gdy został opublikowany.
stevenvh

@stevenvh racja, nie zdawałem sobie sprawy, że to tylko edycja; jest to jednak niepełna odpowiedź
clabacchio

@clabacchio - „niepełna odpowiedź”. Zgoda! Nie uważam, że „powinieneś być w stanie zdecydować” bardzo pomocne.
stevenvh

@clabacchio - Hej, mój mówi teraz „2 dni temu”. Przed chwilą było napisane „odpowiedział wczoraj”. To musiało być dokładnie 48 godzin! :-)
stevenvh
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.