¿Usando el ATMega328 con el oscilador interno?

Tengo un proyecto que creo que sería el más adecuado para un ATMega328P. Sin embargo, en cada proyecto simple que he visto, la gente siempre conecta un oscilador externo de 16 MHz. Por lo que puedo ver, debería tener un oscilador interno de 8MHz. Mi proyecto no requiere mucha potencia de procesamiento, ni el tiempo debe ser muy preciso (aparte de UART e I2C). También tengo un programador, así que no necesito preocuparme por los gestores de arranque.

¿Hay alguna razón para que use un oscilador externo?

Respuestas (6)

Lo que no dice es cuál es la precisión de este oscilador interno. Me tomó un tiempo encontrarlo en la hoja de datos , en la página 369.

10%. ¡Diez porciento! ¿Y eso para un oscilador calibrado? esto es horrible No es irrazonable esperar un error tan bajo como el 1% para esto . Microchip/Atmel proporciona un documento para calibrar el oscilador usted mismo con una precisión del 1%.

I2C es un protocolo síncrono , y la precisión de tiempo no es relevante siempre que se respeten los tiempos de pulso mínimos y máximos.
UART , por otro lado, es asíncrono , y luego la precisión de tiempo es realmente importante. La mayoría de los UART permiten un error de medio bit en el último bit (el bit de parada), por lo que es un 5 % para una transmisión de 10 bits.

El oscilador calibrado de fábrica no funcionará aquí. Tendrá que pasar por el procedimiento de calibración para llegar al 1%. En ese caso puedes usar el oscilador interno. De lo contrario, tendrás que usar un cristal.

Permítanme reforzar lo que se dice aquí. Ahórrese el tiempo y el dolor de cabeza y solo obtenga un cristal. Si le preocupa la energía, use un cristal de reloj de 32 khz (6PF para 48/88/168... no estoy seguro sobre el 328. Consulte la hoja de migración) para ajustar el oscilador interno al inicio. La rutina de calibración del oscilador es muy delicada, así que tenga cuidado si sigue esa ruta. He publicado un código de ejemplo debajo de otra respuesta.

Como está utilizando un UART, sería recomendable un oscilador de cristal. Si no fuera por eso, podrías usar el oscilador interno. Algunas MCU tienen osciladores internos recortados de fábrica, que pueden ser adecuados para la operación UART.

Consulte también esta nota de aplicación sobre la sincronización de UART: maxim-ic.com/app-notes/index.mvp/id/2141
Bueno, el UART es solo para comunicación con una pantalla serial súper simple que funciona a 9600bps... Creo que terminaré ordenando el oscilador y todo, pero ver si funciona sin él.

"No sensible al tiempo". UART es muy sensible al tiempo. Obtendrá basura completa si no está sincronizado adecuadamente.

Opción 1: Usa un cristal normal. Cambie el fusible de selección de reloj de forma adecuada. La selección de cristal depende de qué baudios desea usar / qué tan rápido desea que vaya. Hay "cristales mágicos" que le darán un error del 0% para las tasas estándar (si se fabrican perfectamente). Consulte las tablas en la Sección 20 [USART0] para obtener más información (ha leído la hoja de datos... ¿verdad?) :).

ingrese la descripción de la imagen aquí

Opción 2: puede calibrar el oscilador interno con un cristal de 32 khz si le preocupa la potencia. Con 32khz puede obtener corrientes de uA en modo de suspensión (las he reducido a ~ 2uA). Sin embargo, debe configurar una rutina de calibración que implique iniciar / detener los temporizadores y alternar el temporizador 2 al modo asíncrono.

El código 328P puede diferir... esta función actualmente funciona en 48/88 (con las definiciones de F_CPU/baudios apropiadas. Es un poco feo/no se ha refactorizado por completo, pero he aprendido que es mejor no jugar con cosas que funcionan cuando estás en una fecha límite. Busque en el foro de AVRFreaks "tune 32khz crystal" algo así. Esto es solo una muestra de lo que se estará metiendo... No necesariamente lo que va a funcionar.

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

También se debe tener en cuenta que un cristal tarda mucho en comenzar. En realidad, eso se debe a su precisión: solo toma energía de una banda de frecuencia muy estrecha. Esto puede ser una carga para las cosas que funcionan con batería en las que despierta el mcu por un tiempo muy corto de vez en cuando: esperar un ms a máxima potencia para que el cristal se inicie es una pérdida neta. Los resonadores cerámicos son más precisos que el oscilador RC interno pero menos que un cristal, y comienzan en consecuencia.

Por supuesto, un atmega de 16 MHz consume mucho más jugo y necesita un voltaje más alto que uno de 8 MHz, pero hay disponibles cristales de 8 MHz (o menos, hasta 32 kHz); esta mera elección también puede ser un ahorro de energía.

Esta nota de aplicación documenta la precisión del oscilador RC interno. Su frecuencia es bastante estable pero desconocida; se puede calibrar; la calibración no es necesaria para el funcionamiento normal.

AVR053: Calibración del oscilador RC interno .

Donde ya hay una respuesta aceptada, debe intentar decir algo más, de lo contrario no es muy útil
@clabacchio: esta respuesta tiene dos días de antigüedad y las fechas aceptadas son de ayer. No puede haber sido aceptado cuando se publicó.
@stevenvh cierto, no me di cuenta de que era solo una edición; aunque es una respuesta incompleta
@clabacchio - "respuesta incompleta". ¡Acordado! No puedo encontrar "usted debe ser capaz de decidir" muy útil.
@clabacchio - Oye, el mío también dice "hace 2 días" ahora. Hace un minuto decía "respondió ayer". Debe haber sido exactamente 48 horas! :-)
@stevenvh fue el 23 de mayo, 12:11:12 :)

Si no necesita mucho o una sincronización precisa, no hay necesidad de un oscilador externo. Al desmontar algunas impresoras antiguas, veo muchos circuitos integrados pero ni un solo oscilador a bordo.