"ไม่ไวต่อเวลา" UART นั้นไวต่อเวลามาก คุณจะได้รับขยะโดยสมบูรณ์หากไม่ได้ซิงค์อย่างเหมาะสม
ตัวเลือกที่ 1: ใช้คริสตัลปกติ เปลี่ยนนาฬิกาเลือกฟิวส์อย่างเหมาะสม การเลือก Crystal ขึ้นอยู่กับว่าคุณต้องการใช้อะไร / คุณต้องการให้มันเร็วขนาดไหน มี "ผลึกวิเศษ" ที่จะทำให้คุณเกิดข้อผิดพลาด 0% สำหรับอัตรามาตรฐาน (หากผลิตขึ้นอย่างสมบูรณ์) ดูตารางในส่วนที่ 20 [USART0] สำหรับข้อมูลเพิ่มเติม (คุณได้อ่านแผ่นข้อมูล .... ถูกต้อง ???) :)
ตัวเลือกที่ 2: คุณสามารถปรับออสซิลเลเตอร์ภายในโดยใช้คริสตัลขนาด 32 กิโลเฮิร์ตซ์หากมีปัญหาเกี่ยวกับกำลังไฟ ด้วย 32khz คุณสามารถรับกระแส uA ในโหมด sleep (ฉันได้รับพวกเขาลงไป ~ 2uA) คุณต้องตั้งค่ารูทีนการสอบเทียบซึ่งเกี่ยวข้องกับการเริ่ม / หยุดตัวจับเวลาและการสลับ timer2 เป็นโหมดอะซิงโครนัส
รหัส 328P อาจแตกต่างกันไป ... ฟังก์ชั่นนี้ใช้งานได้ใน 48/88 (ด้วยคำจำกัดความ F_CPU / baud ที่เหมาะสมมันน่าเกลียดเล็กน้อย / ไม่ได้รับการปรับโครงสร้างใหม่อย่างสมบูรณ์ แต่ฉันได้เรียนรู้ที่ดีกว่า ตามกำหนดเวลาค้นหาฟอรัม AVRFreaks เพื่อหา "จูน 32 กิโลเฮิร์ตซ์คริสตัล" แบบนี้นี่เป็นเพียงรสชาติสำหรับสิ่งที่คุณจะได้รับ ... ไม่จำเป็นต้องเป็นอะไร
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;
}