Verwenden Sie den ATMega328 mit dem internen Oszillator?

17

Ich habe ein Projekt, von dem ich denke, dass es am besten für einen ATMega328P geeignet ist. In jedem einfachen Projekt, das ich gesehen habe, wird jedoch immer ein externer 16-MHz-Oszillator angeschlossen. Soweit ich sehen kann, sollte es einen internen 8-MHz-Oszillator haben. Mein Projekt erfordert weder viel Rechenleistung noch muss das Timing sehr genau sein (außer für UART und I2C). Ich habe auch einen Programmierer, so dass ich mich nicht um Bootloader kümmern muss.

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

Earlz
quelle

Antworten:

19

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, einen Fehler von nur 1% zu erwarten . Microchip / Atmel stellt ein Dokument zur Verfügung, mit dem Sie den Oszillator selbst mit einer Genauigkeit von 1% kalibrieren können.

I2C ist ein synchrones Protokoll, und die Zeitgenauigkeit spielt keine Rolle, solange die minimalen und maximalen Pulszeiten eingehalten werden.
UART hingegen ist asynchron , und dann ist die Genauigkeit der Zeitsteuerung in der Tat wichtig. Die meisten UARTs erlauben einen Halbbitfehler im letzten Bit (dem Stoppbit), das sind also 5% für eine 10-Bit-Übertragung.

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

stevenvh
quelle
1
Lassen Sie mich verstärken, was hier gesagt wird. Sparen Sie sich Zeit und Kopfschmerzen und holen Sie sich einfach einen Kristall. Wenn die Stromversorgung ein Problem darstellt, verwenden Sie einen 32-kHz-Uhrenkristall (6PF für 48/88/168 ... nicht sicher, ob der 328 geeignet ist. Überprüfen Sie das Migrationsblatt), um den internen Oszillator beim Starten abzustimmen. Die Oszillatorkalibrierungsroutine ist sehr aufwändig, seien Sie also vorsichtig, wenn Sie diesen Weg gehen. Ich habe unten eine andere Antwort mit einem Beispielcode veröffentlicht.
bathMarm0t
6

Da Sie einen UART verwenden, ist ein Quarzoszillator empfehlenswert. Wäre das nicht der Fall, könnten Sie den internen Oszillator verwenden. Einige MCUs verfügen über werkseitig getrimmte interne Oszillatoren, die für den UART-Betrieb geeignet sein können.

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

Msgstr "Nicht zeitempfindlich". UART ist sehr zeitkritisch. Sie erhalten vollständigen Müll, wenn er nicht ordnungsgemäß synchronisiert wird.

Option 1: Verwenden Sie einen normalen Kristall. Uhr ändern Sicherung entsprechend auswählen. Die Auswahl des Kristalls hängt davon ab, welchen Baud Sie verwenden möchten und wie schnell Sie möchten, dass das Ding funktioniert. Es gibt "magische Kristalle", die Ihnen 0% Fehler 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 ???) :).

Bildbeschreibung hier eingeben

Option 2: Sie können den internen Oszillator mit einem 32-kHz-Quarz kalibrieren, wenn die Stromversorgung ein Problem darstellt. Mit 32kHz können Sie uA-Ströme im Schlafmodus erhalten (ich habe sie auf ~ 2uA gesenkt). 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 ist derzeit auf 48/88 (mit entsprechenden F_CPU / Baud-Definitionen) verfügbar. Es ist ein wenig hässlich / wird nicht vollständig überarbeitet, aber ich habe gelernt, besser als mit Dingen umzugehen, die funktionieren, wenn Sie sind Suchen Sie im AVRFreaks-Forum nach "tune 32khz crystal" so etwas. Dies ist nur ein Vorgeschmack auf das, worauf Sie sich einlassen ... 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;
}
bathMarm0t
quelle
2

Es sollte auch beachtet werden, dass der Start eines Kristalls lange dauert. Das liegt eigentlich an seiner Präzision: Es wird nur Energie aus einem sehr engen Frequenzband entnommen. Dies kann eine Belastung für batteriebetriebene Geräte sein, bei denen Sie die mcu von Zeit zu Zeit für eine sehr kurze Zeit aufwecken: Das Warten auf eine ms bei voller Leistungsaufnahme, bis der Kristall startet, ist ein Nettoverlust. Keramikresonatoren sind genauer als interne RC-Oszillatoren, aber weniger als ein Kristall und starten dementsprechend.

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

Nicolas D
quelle
0

Wenn Sie nicht viel oder genaues 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.

SetKent
quelle
0

Ich vermute, Sie haben diese App bereits gesehen. Hinweis: AVR053: Kalibrierung des internen RC-Oszillators .

Ich vermute mal, und der App-Hinweis aus dem Kommentar von @drxzcl oben, sollte man theoretisch entscheiden können, was richtig ist.

Vorac
quelle
Wo es bereits eine akzeptierte Antwort gibt, sollten Sie versuchen, etwas mehr zu sagen, sonst ist es nicht sehr nützlich
clabacchio
@clabacchio - diese Antwort ist zwei Tage alt und die akzeptierten Daten stammen von gestern. Es kann nicht akzeptiert worden sein, als dies veröffentlicht wurde.
stevenvh
@stevenvh richtig, ich wusste nicht, dass es nur eine Bearbeitung war; Es ist jedoch eine unvollständige Antwort
Clabacchio
@clabacchio - "unvollständige Antwort". Einverstanden! Ich finde "Sie sollten sich entscheiden können" nicht sehr hilfreich.
stevenvh
@clabacchio - Hey, meins sagt jetzt auch "vor 2 Tagen". Vor einer Minute hieß es "gestern beantwortet". Muss genau 48 Stunden gewesen sein! :-)
stevenvh