ATMega328'i dahili osilatör ile mi kullanıyorsunuz?


18

Bir ATMega328P için en uygun olacağını düşündüğüm bir projem var. Ancak, gördüğüm her basit projede, insanlar her zaman 16MHz harici bir osilatör bağlarlar. Görebildiğim kadarıyla, 8MHz dahili bir osilatöre sahip olmalı. Projem çok fazla işlem gücü gerektirmiyor ve zamanlamanın çok hassas olması gerekmiyor (UART ve I2C dışında). Bir programcım da var, bu yüzden önyükleyiciler hakkında endişelenmem gerekmiyor.

Harici bir osilatör kullanmamın bir sebebi var mı?

Yanıtlar:


20

Söylemediğiniz şey, bu dahili osilatörün doğruluğunun ne olduğudur. Veri sayfasında bulmam biraz zaman aldı , sayfa 369.

% 10. Yüzde on! Ve bu kalibre edilmiş bir osilatör için mi? Bu çok kötü. Bunun için % 1 kadar düşük bir hata beklemek mantıksız değildir . Mikroçip / Atmel , osilatörü kendiniz% 1 hassasiyetle kalibre etmek için bir belge sağlar .

I2C bir olan senkron protokol ve minimum ve maksimum nabız süreleri saygı olarak zamanlama doğruluğu sürece önemli değildir. Öte yandan
UART zaman uyumsuzdur ve zamanlama doğruluğu gerçekten önemlidir. Çoğu UART, son bitte (durdurma biti) yarım bit hataya izin verir, bu da 10 bitlik bir iletim için% 5'tir.

Fabrikada kalibre edilmiş osilatör burada çalışmaz. % 1'e ulaşmak için kalibrasyon prosedüründen geçmeniz gerekir. Bu durumda dahili osilatörü kullanabilirsiniz. Aksi takdirde bir kristal kullanmanız gerekir.


1
Burada söylenenleri pekiştirmeme izin verin. Kendinize zaman ve baş ağrısından tasarruf edin ve sadece bir kristal alın. Güç bir endişe ise, başlangıçta dahili osilatörü ayarlamak için bir 32khz saat kristali (48/88/168 için 6PF ... 328'den emin değilim. Geçiş sayfasını kontrol edin) kullanın. Osilatör kalibrasyon rutini çok titizdir, bu yüzden bu rotaya gidiyorsanız dikkatli olun. Başka bir cevap altında bunun için bazı örnek kod gönderdim.
bathMarm0t

6

Bir UART kullandığınız için, bir kristal osilatör tavsiye edilir. Eğer böyle olmasaydı, dahili osilatörü kullanabilirsiniz. Bazı MCU'larda UART çalışması için uygun fabrikada kesilmiş dahili osilatörler bulunur.


2
Ayrıca UART zamanlamasıyla ilgili bu uygulama notuna bakın: maxim-ic.com/app-notes/index.mvp/id/2141
drxzcl

UART sadece 9600bps'de çalışan süper basit bir seri ekranla iletişim içindir ... Sanırım osilatörü ve her şeyi sipariş edeceğim ama onsuz çalışıp çalışmayacağını göreceğim
Earlz

3

Msgstr "Zaman duyarlı değil". UART zamana çok duyarlıdır. Uygun şekilde senkronize edilmezse tam çöp alırsınız.

Seçenek 1: Normal bir kristal kullanın. Saat seçim sigortasını uygun şekilde değiştirin. Kristal seçimi, kullanmak istediğiniz baud'a / bu şeyin ne kadar hızlı gitmesini istediğinize bağlıdır. Standart oranlar için% 0 hata verecek olan "sihirli kristaller" vardır (eğer bunlar mükemmel şekilde üretildiyse). Daha fazla bilgi için Bölüm 20'deki [USART0] tablolara bakınız (veri sayfasını okudunuz ... doğru ???) :).

resim açıklamasını buraya girin

Seçenek 2: Güç söz konusu olduğunda, 32 khz kristal kullanarak dahili osilatörü kalibre edebilirsiniz. 32khz ile uyku modunda uA akımları alabilirsiniz (onları ~ 2uA'ya indirdim). Zamanlayıcıları başlatmayı / durdurmayı ve zamanlayıcı2'yi eşzamansız moda değiştirmeyi içeren bir kalibrasyon rutini ayarlamanız gerekir.

328P kodu farklı olabilir ... Bu işlev şu anda 48/88 üzerinde çalışır (uygun F_CPU / baud tanımları ile. Biraz çirkin / tamamen yeniden düzenlenmiş değil, ancak çalıştığınız şeylerle uğraşmaktan daha iyi öğrendim AVRFreaks forumunda "tune 32khz crystal" için böyle bir şey arayın. Bu, içine gireceğiniz şeyin sadece bir tadı ... Ne işe yarayacağı kesin değil.

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;
}

2

Bir kristalin başlaması uzun sürdüğü de not edilmelidir. Aslında hassasiyeti nedeniyle: sadece çok dar bir frekans bandından enerji alır. Bu, mcu'yu her seferinde çok kısa bir süre için uyandırdığınız pille çalışan şeyler için bir yük olabilir: daha sonra kristalin başlaması için tam güçte bir ms beklemek net bir kayıptır. Seramik rezonatörler dahili RC osilatörden daha doğrudur, ancak bir kristalden daha azdır ve buna göre başlar.

Tabii ki 16MHz atmega çok daha fazla meyve suyu içer ve 8MHz'den daha yüksek voltaja ihtiyaç duyar, ancak 8MHz (veya daha düşük, 32kHz'e kadar) kristaller mevcuttur; bu sadece seçim bir enerji tasarrufu da olabilir.


0

Çok veya kesin zamanlamaya ihtiyacınız yoksa, harici bir osilatöre gerek yoktur. Bazı eski yazıcıları sökerken, birçok IC görüyorum, ancak tek bir osilatör görmüyorum.


0

Sanırım zaten bu uygulama notunu gördünüz: AVR053: Dahili RC osilatörün kalibrasyonu .

Sanırım ondan ve yukarıdaki @drxzcl yorumundan uygulama notu, teorik olarak neyin doğru olduğuna karar verebilmelisiniz.


Zaten kabul edilmiş bir cevabın olduğu yerde, daha fazla bir şey söylemeye çalışmalısınız, aksi takdirde çok yararlı değildir
clabacchio

@clabacchio - bu cevap iki günlük ve dünden kabul edilen tarihler. Bu yayın gönderildiğinde kabul edilemez.
stevenvh

@stevenvh doğru, bunun sadece bir düzenleme olduğunu fark etmedim; Yine de, bu eksik bir cevap
clabacchio

@clabacchio - "eksik cevap". Kabul! "Karar verebilmelisin" çok yararlı bulamıyorum.
stevenvh

@clabacchio - Hey, benim şimdi "2 gün önce" diyor. Bir dakika önce "dün cevap verdi" dedi. Tam olarak 48 saat olmalı! :-)
stevenvh
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.