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?
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.
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.
"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?) :).
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.
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.
bañoMarm0t