¿Usando el ATMega328 con el oscilador interno?

18

Tengo un proyecto que creo que sería el más adecuado para un ATMega328P. Sin embargo, en cada proyecto simple que he visto, las personas siempre conectan un oscilador externo de 16MHz. 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 un 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?

Earlz
fuente

Respuestas:

20

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 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 del tiempo no es relevante siempre que se respeten los tiempos de pulso mínimo y máximo.
UART por otro lado es asíncrono , y luego la precisión del tiempo es 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 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, puede usar el oscilador interno. De lo contrario, tendrás que usar un cristal.

stevenvh
fuente
1
Permítanme reforzar lo que se dice aquí. Ahórrate el tiempo y el dolor de cabeza y solo consigue 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. verifique 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.
bathMarm0t
6

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

Leon Heller
fuente
2
Consulte también esta nota de aplicación sobre el tiempo UART: maxim-ic.com/app-notes/index.mvp/id/2141
drxzcl
Bueno, el UART es solo para la comunicación con una pantalla en serie súper simple que funciona a 9600bps ... Creo que terminaré ordenando el oscilador y todo, pero viendo si funcionará sin él
Earlz
3

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

Opción 1: usar un cristal normal. Cambie el fusible de selección de reloj adecuadamente. La selección de cristal depende de qué baudios desea usar / qué tan rápido desea que vaya esto. Hay "cristales mágicos" que le darán un 0% de error 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 ... ¿¿¿¿¿¿¿¿¿¿¿¿¿¿¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡¡

ingrese la descripción de la imagen aquí

Opción 2: puede calibrar el oscilador interno utilizando un cristal de 32 kHz si la potencia es un problema. Con 32khz puede obtener corrientes uA en modo de suspensión (las he reducido a ~ 2uA). Sin embargo, debe configurar una rutina de calibración que implica 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 apropiadas de F_CPU / baudios. Es un poco feo / no refactorizado por completo, pero he aprendido mejor que perder el tiempo con cosas que funcionan cuando estás en una fecha límite. Busque en el foro AVRFreaks "tune 32khz crystal" algo así. Esto es solo una muestra de lo que se va a meter ... 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;
}
bathMarm0t
fuente
2

También debe tenerse en cuenta que un cristal tarda mucho en iniciarse. 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, donde se activa el mcu por un tiempo muy corto de vez en cuando: esperar un ms a plena 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 16MHz bebe mucho más jugo y necesita un voltaje más alto que uno de 8MHz, pero hay disponibles cristales de 8MHz (o más bajos, hasta 32kHz); Esta mera elección también puede ser un ahorro de energía.

Nicolas D
fuente
0

Si no necesita mucho tiempo o precisión, no hay necesidad de un oscilador externo. Al desmontar algunas impresoras antiguas, veo muchos IC pero no un solo oscilador a bordo.

SetKent
fuente
0

Supongo que ya has visto esta nota de aplicación: AVR053: Calibración del oscilador RC interno .

Supongo que, y la nota de la aplicación del comentario de @drxzcl anterior, debería ser capaz de decidir teóricamente qué es lo correcto.

Vorac
fuente
Cuando ya hay una respuesta aceptada, debe intentar decir algo más, de lo contrario no es muy útil
clabacchio
@clabacchio: esta respuesta tiene dos días y las fechas aceptadas de ayer. No puede haber sido aceptado cuando esto fue publicado.
stevenvh
@stevenvh bien, no me di cuenta de que era solo una edición; sin embargo, es una respuesta incompleta
clabacchio
@clabacchio - "respuesta incompleta". ¡Convenido! No encuentro muy útil "deberías poder decidir".
stevenvh
@clabacchio - Hola, 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