Usi ATMega328 con l'oscillatore interno?


18

Ho un progetto che penso sarebbe più adatto per un ATMega328P. Tuttavia, in ogni semplice progetto che ho visto, le persone collegano sempre un oscillatore esterno a 16 MHz. Da quello che posso vedere, dovrebbe avere un oscillatore interno da 8 MHz. Il mio progetto non richiede molta potenza di elaborazione, né i tempi devono essere molto precisi (tranne che per un UART e I2C). Ho anche un programmatore, quindi non devo preoccuparmi dei bootloader.

C'è qualche motivo per usare un oscillatore esterno?

Risposte:


20

Quello che non dici è l'accuratezza di questo oscillatore interno. Mi ci è voluto del tempo per trovarlo nel foglio dati , a pagina 369.

10%. Dieci per cento! E quello per un oscillatore calibrato? Questo è terribile. Non è irragionevole aspettarsi un errore dell'1% per questo . Microchip / Atmel fornisce un documento per calibrare l'oscillatore da solo con una precisione dell'1%.

I2C è un protocollo sincrono e la precisione della temporizzazione non è rilevante fintanto che vengono rispettati i tempi di impulso minimo e massimo.
UART d'altra parte è asincrono e quindi l'accuratezza dei tempi è davvero importante. La maggior parte degli UART consente un errore di mezzo bit nell'ultimo bit (il bit di stop), quindi questo è del 5% per una trasmissione a 10 bit.

L'oscillatore calibrato in fabbrica non funziona qui. Dovrai seguire la procedura di calibrazione per arrivare all'1%. In tal caso è possibile utilizzare l'oscillatore interno. Altrimenti dovrai usare un cristallo.


1
Consentitemi di rafforzare ciò che viene detto qui. Risparmia tempo e mal di testa e ricevi un cristallo. Se l'alimentazione è un problema, utilizzare un cristallo dell'orologio da 32 kHz (6PF per 48/88/168 ... non sono sicuro del 328. controllare il foglio di migrazione) per sintonizzare l'oscillatore interno all'avvio. La routine di calibrazione dell'oscillatore è molto delicata, quindi fai attenzione se segui questa strada. Ho pubblicato un codice di esempio per questo sotto un'altra risposta.
bathMarm0t,

6

Quando si utilizza un UART, è consigliabile un oscillatore a cristallo. Se non fosse per quello, potresti usare l'oscillatore interno. Alcuni MCU hanno oscillatori interni tagliati in fabbrica, che possono essere adatti per il funzionamento UART.


2
Vedi anche questa nota dell'app sui tempi UART: maxim-ic.com/app-notes/index.mvp/id/2141
drxzcl

Bene, l'UART è solo per la comunicazione con un display seriale super semplice che funziona a 9600bps ... Penso che
finirò

3

"Non sensibile al tempo". UART è molto sensibile al tempo. Otterrai la spazzatura completa se non viene sincronizzata in modo appropriato.

Opzione 1: utilizzare un cristallo normale. Cambia orologio seleziona il fusibile in modo appropriato. La selezione dei cristalli dipende da quale baud vuoi usare / quanto velocemente vuoi che vada avanti. Ci sono "cristalli magici" che ti daranno un errore dello 0% per le tariffe standard (se sono prodotte perfettamente). Vedi le tabelle nella Sezione 20 [USART0] per maggiori informazioni (hai letto la scheda tecnica .... giusto ???) :).

inserisci qui la descrizione dell'immagine

Opzione 2: è possibile calibrare l'oscillatore interno utilizzando un cristallo da 32 kHz se la potenza è un problema. Con 32 khz puoi ottenere le correnti u in modalità sleep (le ho portate a ~ 2uA). Tuttavia, è necessario impostare una routine di calibrazione che prevede l'avvio / l'arresto dei timer e l'alternanza del timer2 alla modalità asincrona.

Il codice 328P potrebbe differire ... questa funzione attualmente funziona su 48/88 (con le definizioni F_CPU / baud appropriate. È un po 'brutta / non completamente rifattorizzata ma ho imparato meglio che a rovinare cose che funzionano quando sei entro una scadenza. Cerca nel forum AVRFreaks "sintonizza il cristallo 32khz" qualcosa del genere. Questo è solo un assaggio di quello che ti farà entrare ... Non necessariamente quello che funzionerà.

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

Va inoltre notato che l'avvio di un cristallo richiede molto tempo. Questo è in realtà a causa della sua precisione: prende energia solo da una banda di frequenza molto stretta. Questo può essere un peso per le cose alimentate a batteria in cui si sveglia la MCU per un tempo molto breve di tanto in tanto: aspettare un ms a piena potenza per l'avvio del cristallo è una perdita netta. I risuonatori ceramici sono più precisi dell'oscillatore RC interno ma meno di un cristallo e si avviano di conseguenza.

Ovviamente un atmega da 16 MHz beve molto più succo e necessita di una tensione superiore a quella di 8 MHz, ma sono disponibili cristalli da 8 MHz (o inferiore, fino a 32 kHz); questa semplice scelta può anche essere un risparmio energetico.


0

Se non hai bisogno di tempi molto o precisi, non è necessario un oscillatore esterno. Durante lo smontaggio di alcune vecchie stampanti, mi capita di vedere molti circuiti integrati, ma non un singolo oscillatore a bordo.


0

Immagino che tu abbia già visto questa nota dell'app: AVR053: calibrazione dell'oscillatore RC interno .

Immagino da questo, e la nota dell'app dal commento di @drxzcl sopra, dovresti essere in grado di decidere teoricamente cosa è giusto.


Dove c'è già una risposta accettata, dovresti provare a dire qualcosa di più, altrimenti non è molto utile
clabacchio

@clabacchio - questa risposta ha due giorni e le date accettate da ieri. Non può essere stato accettato quando questo è stato pubblicato.
Stevenvh,

@stevenvh, non mi ero reso conto che fosse solo una modifica; tuttavia, è una risposta incompleta
clabacchio

@clabacchio - "risposta incompleta". Concordato! Non riesco a trovare "dovresti essere in grado di decidere" molto utile.
Stevenvh,

@clabacchio - Ehi, il mio dice anche "2 giorni fa" ora. Un minuto fa diceva "ha risposto ieri". Devono essere state esattamente 48 ore! :-)
stevenvh
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.