¿Usando el ATMega328 con el oscilador interno?

15

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 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 (excepto para un UART e I2C). También tengo un programador, así que no necesito preocuparme por los cargadores de arranque.

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

    
pregunta Earlz

6 respuestas

17

Lo que no dices es cuál es la precisión de este oscilador interno. Me tomó algo de tiempo encontrarlo en 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 de la temporización no es relevante mientras se respeten los tiempos de pulso mínimos y máximos.
UART por otra parte es asíncrono , y entonces la precisión de la temporización 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 funciona aquí. Tendrás que pasar por el procedimiento de calibración para llegar al 1%. En ese caso puedes usar el oscilador interno. Otherwize tendrás que usar un cristal.

    
respondido por el stevenvh
6

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 ajustados de fábrica, que pueden ser adecuados para la operación UART.

    
respondido por el Leon Heller
3

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

Opción 1: Usa un cristal normal. Cambie el reloj seleccione fusible adecuadamente. La selección de cristales depende de qué baudios desea usar / qué tan rápido quiere que vaya esta cosa. Hay "cristales mágicos" que le darán un error del 0% para las tarifas 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?) :).

Opción2:puedecalibrarelosciladorinternousandouncristalde32kHzsilaenergíaesunapreocupación.Con32khzpuedeobtenerlascorrientesdeuAenmododesuspensión(lashereducidoa~2uA).Debeconfigurarunarutinadecalibración,loqueimplicainiciar/detenerlostemporizadoresyalternareltemporizador2almodoasíncrono.

Elcódigo328Ppuedediferir...estafunciónactualmentefuncionaen48/88(conlasdefinicionesF_CPU/baudadecuadas.Esunpocofeo/noseharefaccionadocompletamente,peroheaprendidomejorqueajoderconcosasquefuncionancuandoestásenunafechalímite.BuscaenelforodeAVRFreaks"sintonizar 32khz crystal" algo así. Esto es solo un gusto por lo que te va a gustar ... 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;
}
    
respondido por el bathMarm0t
2

También se debe tener en cuenta que un cristal tarda mucho tiempo en comenzar. Esto se debe en realidad 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ías en las que despiertas el mcu por un tiempo muy corto de vez en cuando: esperar un ms a plena potencia para que el cristal comience 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 toma mucho más jugo y necesita mayor voltaje que uno de 8MHz, pero hay disponibles cristales de 8MHz (o menos, hasta 32kHz); Esta mera elección también puede ser un ahorro de energía.

    
respondido por el Nicolas D
0

Si no necesita mucha o una sincronización precisa, no hay necesidad de un oscilador externo. Al desmontar algunas impresoras antiguas, veo muchos IC's pero no un solo oscilador a bordo.

    
respondido por el SetKent
0

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

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

    
respondido por el Vorac

Lea otras preguntas en las etiquetas

Comentarios Recientes

¡No es tan fácil! Primero debe determinar cuándo detener la programación, ya que el código a veces se vuelve defectuoso al hacerlo. De manera automatizada, como pirata informático, el software escribe un número aleatorio en una EEPROM externa de 16 KB. Dado que estamos en la gente de GDC con herramientas sofisticadas, el recolector de basura continúa donde lo dejó, por lo general, toma alrededor de media hora para que termine el código Cyclone. Sin embargo, si hay varias entradas en el código, en lugar de... Lees verder