Verwenden Sie den ATMega328 mit dem internen Oszillator?

Ich habe ein Projekt, das meiner Meinung nach am besten für einen ATMega328P geeignet wäre. In jedem einfachen Projekt, das ich gesehen habe, schließen die Leute jedoch immer einen externen 16-MHz-Oszillator an. Soweit ich sehen kann, sollte es einen internen 8-MHz-Oszillator haben. Mein Projekt erfordert weder viel Rechenleistung noch muss das Timing sehr präzise sein (außer für einen UART und I2C). Ich habe auch einen Programmierer, also brauche ich mir keine Gedanken über Bootloader zu machen.

Gibt es einen Grund für mich, einen externen Oszillator zu verwenden?

Antworten (6)

Was Sie nicht sagen, ist die Genauigkeit dieses internen Oszillators. Ich habe einige Zeit gebraucht, um es im Datenblatt auf Seite 369 zu finden.

10%. Zehn Prozent! Und das für einen kalibrierten Oszillator? Das ist schrecklich. Es ist nicht unangemessen, dafür einen Fehler von nur 1 % zu erwarten . Microchip/Atmel stellt ein Dokument zur Verfügung, um den Oszillator selbst auf 1 % Genauigkeit zu kalibrieren.

I2C ist ein synchrones Protokoll, und die Zeitgenauigkeit ist nicht relevant, solange minimale und maximale Impulszeiten eingehalten werden.
UART hingegen ist asynchron , und dann ist die Zeitgenauigkeit in der Tat wichtig. Die meisten UARTs erlauben einen halben Bitfehler im letzten Bit (dem Stoppbit), das sind also 5 % für eine 10-Bit-Übertragung.

Der werkseitig kalibrierte Oszillator reicht hier nicht aus. Sie müssen das Kalibrierungsverfahren durchlaufen, um 1 % zu erreichen. In diesem Fall können Sie den internen Oszillator verwenden. Andernfalls müssen Sie einen Kristall verwenden.

Lassen Sie mich das, was hier gesagt wurde, bekräftigen. Sparen Sie sich Zeit und Kopfschmerzen und holen Sie sich einfach einen Kristall. Wenn die Stromversorgung ein Problem darstellt, verwenden Sie einen 32-kHz-Uhrquarz (6PF für 48/88/168 ... nicht sicher über den 328. Überprüfen Sie das Migrationsblatt), um den internen Oszillator beim Start abzustimmen. Die Oszillatorkalibrierungsroutine ist sehr pingelig, also seien Sie vorsichtig, wenn Sie diesen Weg gehen. Ich habe einen Beispielcode dafür unter einer anderen Antwort gepostet.

Da Sie einen UART verwenden, wäre ein Quarzoszillator ratsam. Wenn das nicht wäre, könnten Sie den internen Oszillator verwenden. Einige MCUs haben werkseitig getrimmte interne Oszillatoren, die für den UART-Betrieb geeignet sein können.

Siehe auch diesen App-Hinweis zum UART-Timing: maxim-ic.com/app-notes/index.mvp/id/2141
Nun, der UART ist nur für die Kommunikation mit einem supereinfachen seriellen Display, das mit 9600 bps läuft ... Ich denke, ich werde am Ende den Oszillator und alles bestellen, aber sehen, ob es ohne ihn funktioniert

"Nicht zeitkritisch". UART ist sehr zeitkritisch. Sie erhalten kompletten Müll, wenn es nicht richtig synchronisiert wird.

Option 1: Verwenden Sie einen normalen Kristall. Wechseln Sie die Uhrauswahlsicherung entsprechend aus. Die Kristallauswahl hängt davon ab, welche Baud Sie verwenden möchten / wie schnell Sie möchten, dass dieses Ding geht. Es gibt "magische Kristalle", die Ihnen einen Fehler von 0 % für Standardraten geben (wenn sie perfekt hergestellt sind). Weitere Informationen finden Sie in den Tabellen in Abschnitt 20 [USART0] (Sie haben das Datenblatt gelesen ... richtig???) :).

Geben Sie hier die Bildbeschreibung ein

Option 2: Sie können den internen Oszillator mit einem 32-kHz-Quarz kalibrieren, wenn die Leistung ein Problem darstellt. Mit 32 kHz können Sie im Ruhemodus uA-Ströme erhalten (ich habe sie auf ~ 2 uA heruntergebracht). Sie müssen jedoch eine Kalibrierungsroutine einrichten, die das Starten / Stoppen von Timern und das Wechseln von Timer2 in den asynchronen Modus umfasst.

Der 328P-Code kann abweichen ... diese Funktion funktioniert derzeit auf 48/88 (mit entsprechenden F_CPU/Baud-Definitionen. Es ist ein wenig hässlich / nicht vollständig umgestaltet, aber ich habe gelernt, besser als mit Dingen herumzuspielen, die funktionieren, wenn Sie es sind Suchen Sie im AVRFreaks-Forum nach "tune 32khz crystal" oder so ähnlich. Dies ist nur ein Vorgeschmack auf das, worauf Sie sich einlassen werden ... Nicht unbedingt, was funktionieren wird.

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;
}

Es sollte auch beachtet werden, dass ein Kristall lange braucht, um zu starten. Das liegt eigentlich an seiner Präzision: Es nimmt nur Energie aus einem sehr schmalen Frequenzband auf. Dies kann eine Belastung für batteriebetriebene Geräte sein, bei denen Sie die MCU hin und wieder für sehr kurze Zeit aufwecken: Das Warten auf eine ms bei voller Leistungsaufnahme, damit der Kristall startet, ist ein Nettoverlust. Keramische Resonatoren sind genauer als interne RC-Oszillatoren, aber weniger als ein Kristall, und starten entsprechend.

Natürlich trinkt ein 16-MHz-Atmega viel mehr Saft und benötigt eine höhere Spannung als ein 8-MHz-Atmega, aber Kristalle mit 8 MHz (oder niedriger, bis zu 32 kHz) sind verfügbar. Diese bloße Wahl kann auch ein Energiesparer sein.

Dieser Anwendungshinweis dokumentiert die Genauigkeit des internen RC-Oszillators. Seine Frequenz ist ziemlich stabil, aber unbekannt; kann kalibriert werden; Eine Kalibrierung ist für den normalen Betrieb nicht erforderlich.

AVR053: Kalibrierung des internen RC-Oszillators .

Wo es bereits eine akzeptierte Antwort gibt, sollten Sie versuchen, etwas mehr zu sagen, sonst ist es nicht sehr nützlich
@clabacchio - diese Antwort ist zwei Tage alt und die akzeptierten Daten von gestern. Es kann nicht akzeptiert worden sein, als dies gepostet wurde.
@stevenvh richtig, ich wusste nicht, dass es nur eine Bearbeitung war; Es ist jedoch eine unvollständige Antwort
@clabacchio - "unvollständige Antwort". Einverstanden! Ich kann "Sie sollten in der Lage sein zu entscheiden" nicht sehr hilfreich finden.
@clabacchio - Hey, bei mir steht jetzt auch "vor 2 Tagen". Vor einer Minute hieß es "gestern beantwortet". Es müssen genau 48 Stunden gewesen sein! :-)
@stevenvh es war der 23. Mai, 12:11:12 :)

Wenn Sie nicht viel oder präzises Timing benötigen, ist kein externer Oszillator erforderlich. Beim Zerlegen einiger alter Drucker sehe ich zufällig viele ICs, aber keinen einzigen Oszillator an Bord.