24 votos

¿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 todos los proyectos sencillos que he visto, la gente siempre conecta un oscilador externo de 16MHz. Por lo que veo, debería tener un oscilador interno de 8MHz. Mi proyecto no requiere mucho poder de procesamiento, ni la sincronización necesita ser muy precisa (aparte de una UART e I2C). Tambien tengo un programador, asi que no necesito preocuparme por bootloaders.

¿Hay alguna razón para utilizar un oscilador externo?

25voto

lillq Puntos 4161

Lo que no dices es cual es la precisión de este oscilador interno. Me ha costado encontrarlo en el ficha técnica en la página 369.

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

I2C es un síncrono y la precisión de la temporización no es relevante siempre que se respeten los tiempos de impulso mínimo y máximo.
UART por otra parte es asíncrono La precisión de los tiempos es muy importante. La mayoría de las UART permiten un error de medio bit en el último bit (el bit de parada), lo que supone un 5% para una transmisión de 10 bits.

El oscilador calibrado de fábrica no servirá aquí. Tendrás 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.

6voto

Mark Biek Puntos 41769

Como estás utilizando una UART, sería aconsejable un oscilador de cristal. Si no fuera por eso, podrías usar el oscilador interno. Algunos MCUs tienen osciladores internos ajustados de fábrica, que pueden ser adecuados para el funcionamiento de la UART.

3voto

bathMarm0t Puntos 80

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

Opción 1: Utiliza un cristal normal. Cambie el fusible de selección de reloj adecuadamente. La selección del cristal depende de los baudios que quieras usar / lo rápido que quieras que vaya esta cosa. Hay "cristales mágicos" que te darán un 0% de error para velocidades estándar (si están fabricados perfectamente). Mira las tablas en la Sección 20 [USART0] para más información (¿has leído la datasheet.... verdad???) :).

enter image description here

Opción 2: Puedes calibrar el oscilador interno usando un cristal de 32khz si la energía es una preocupación. Con 32khz puedes conseguir corrientes de uA en modo sleep (yo las he bajado a ~2uA). Usted tiene que configurar una rutina de calibración, aunque lo que implica iniciar / detener temporizadores y alternando timer2 al modo asíncrono.

El código 328P puede diferir... esta función funciona actualmente en 48/88 (con las definiciones apropiadas de F_CPU/baudios. Es un poco feo / no refactorizado completamente pero he aprendido mejor que joder con cosas que funcionan cuando estás en una fecha límite. Busca en el foro AVRFreaks "tune 32khz crystal" algo así. Esto es sólo una muestra de lo que te vas a encontrar... 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;
}

2voto

Denis de Bernardy Puntos 175

También hay que tener en cuenta que un cristal tarda mucho en arrancar. En realidad, eso se debe a su precisión: sólo toma energía de una banda de frecuencias muy estrecha. Esto puede ser una carga para las cosas que funcionan con baterías donde se despierta la 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 un oscilador RC interno pero menos que un cristal, y arrancan en consecuencia.

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

1voto

KC Baltz Puntos 655

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

AVR053: Calibración del oscilador RC interno .

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X