답변:
당신이 말하지 않는 것은이 내부 발진기의 정확성입니다. 데이터 시트 , 369 페이지 에서 그것을 찾는 데 시간이 걸렸습니다 .
10 % 10! 그리고 교정 된 발진기의 경우? 이것은 끔찍하다. 이것에 대해 1 %의 낮은 오류를 예상하는 것은 무리가 없습니다 . Microchip / Atmel은 발진기를 직접 1 % 정확도로 교정하기위한 문서 를 제공합니다 .
I2C 는 동기식 프로토콜이며 최소 및 최대 펄스 시간이 고려되는 한 타이밍 정확도는 관련이 없습니다. 반면에
UART 는 비동기식 이므로 타이밍 정확도가 중요합니다. 대부분의 UART는 마지막 비트 (정지 비트)에서 반 비트 오류를 허용하므로 10 비트 전송의 경우 5 %입니다.
출고시 교정 된 발진기는 여기에서 수행되지 않습니다. 1 %에 도달하려면 교정 절차를 거쳐야합니다. 이 경우 내부 발진기를 사용할 수 있습니다. 그렇지 않으면 크리스탈을 사용해야합니다.
UART를 사용함에 따라 수정 발진기가 권장됩니다. 그렇지 않은 경우 내부 발진기를 사용할 수 있습니다. 일부 MCU에는 공장 트리밍 된 내부 발진기가 있으며 UART 작동에 적합합니다.
"시간에 민감하지 않다". UART는 시간에 매우 민감합니다. 적절하게 동기화되지 않으면 완전한 쓰레기를 얻게됩니다.
옵션 1 : 일반 크리스탈을 사용하십시오. 시계 선택 퓨즈를 적절히 변경하십시오. 크리스탈 선택은 사용하려는 보드 /이 속도를 얼마나 빨리 원하는지에 따라 다릅니다. 표준 속도 (완벽하게 제조 된 경우)에 대해 0 %의 오차를주는 "마법의 결정"이 있습니다. 자세한 정보는 섹션 20 [USART0]의 표를 참조하십시오 (데이터 시트를 읽었습니다 .... right ???) :).
옵션 2 : 전력이 중요한 경우 32khz 크리스털을 사용하여 내부 발진기를 교정 할 수 있습니다. 32khz를 사용하면 휴면 모드에서 uA 전류를 얻을 수 있습니다 (~ 2uA로 낮춤). 타이머를 시작 / 중지하고 timer2를 비동기 모드로 교체하는 교정 루틴을 설정해야합니다.
328P 코드는 다를 수 있습니다 ...이 기능은 현재 48/88에서 작동합니다 (적절한 F_CPU / baud 정의 사용) AVRFreaks 포럼에서 "tune 32khz crystal"같은 것을 검색하십시오. 이것은 당신이 겪을 내용에 대한 맛일뿐입니다.
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;
}
또한 결정을 시작하는 데 시간이 오래 걸린다는 점에 유의해야합니다. 그것은 실제로 정밀도 때문입니다. 매우 좁은 주파수 대역에서만 에너지를 가져옵니다. 이것은 배터리 작동 재료에 부담이 될 수 있습니다. 매번 매우 짧은 시간 동안 MCU를 깨운 다음 결정을 시작하기 위해 최대 전력 소비에서 ms를 기다리는 것은 순 손실입니다. 세라믹 공진기는 내부 RC 발진기보다 정확하지만 크리스털보다는 적으며 그에 따라 시작됩니다.
물론 16MHz atmega는 훨씬 더 많은 주스를 마시고 8MHz 주스보다 높은 전압을 필요로하지만 8MHz (또는 32kHz 이하) 결정을 사용할 수 있습니다. 이 단순한 선택은 또한 에너지 절약이 될 수 있습니다.
당신은 이미이 응용 프로그램 노트를 본 것 같아요 : AVR053 : 내부 RC 발진기의 교정 .
나는 그것을 추측하고 위의 @ drxzcl의 의견에서 나온 응용 프로그램 노트에서 이론적으로 옳은 것을 결정할 수 있어야합니다.