"Không nhạy cảm với thời gian". UART rất nhạy cảm về thời gian. Bạn sẽ nhận được rác hoàn chỉnh nếu nó không được đồng bộ hóa một cách thích hợp.
Cách 1: Sử dụng một tinh thể bình thường. Thay đổi đồng hồ chọn cầu chì thích hợp. Lựa chọn tinh thể phụ thuộc vào những gì bạn muốn sử dụng / tốc độ bạn muốn điều này đi. Có "tinh thể ma thuật" sẽ cung cấp cho bạn 0% lỗi cho tỷ lệ tiêu chuẩn (nếu chúng được sản xuất hoàn hảo). Xem các bảng trong Phần 20 [USART0] để biết thêm thông tin (bạn đã đọc biểu dữ liệu .... đúng ???) :).
Tùy chọn 2: Bạn có thể hiệu chỉnh bộ dao động bên trong bằng tinh thể 32khz nếu công suất là một mối quan tâm. Với 32khz, bạn có thể nhận được dòng uA ở chế độ ngủ (Tôi đã giảm xuống còn ~ 2uA). Bạn phải thiết lập một thói quen hiệu chuẩn mặc dù bao gồm bắt đầu / dừng bộ hẹn giờ và xen kẽ timer2 sang chế độ không đồng bộ.
Mã 328P có thể khác nhau ... chức năng này hiện đang hoạt động trên 48/88 (với các định nghĩa phù hợp với IFCPU / baud. Nó hơi xấu / không được tái cấu trúc hoàn toàn nhưng tôi đã học tốt hơn là xoay quanh những thứ hoạt động khi bạn làm việc trên một thời hạn. Tìm kiếm trên diễn đàn AVRFreaks để "điều chỉnh tinh thể 32khz" tương tự như vậy. Đây chỉ là một hương vị cho những gì bạn sẽ tham gia ... Không nhất thiết là những gì sẽ hoạt động.
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;
}