ใช้ ATMega328 กับ oscillator ภายในหรือไม่


18

ฉันมีโครงการที่ฉันคิดว่าเหมาะสมที่สุดสำหรับ ATMega328P อย่างไรก็ตามในทุก ๆ โครงการที่ฉันเคยเห็นผู้คนมักจะเชื่อมต่อกับออสซิลเลเตอร์ภายนอก 16MHz จากสิ่งที่ฉันเห็นมันควรมีออสซิลเลเตอร์ภายใน 8MHz โครงการของฉันไม่ต้องการพลังการประมวลผลจำนวนมากและเวลาไม่จำเป็นต้องแม่นยำมาก (นอกเหนือจาก UART และ I2C) ฉันมีโปรแกรมเมอร์ด้วยดังนั้นฉันไม่ต้องกังวลกับ bootloaders

มีเหตุผลใดที่ฉันจะใช้ออสซิลเลเตอร์ภายนอก?

คำตอบ:


20

สิ่งที่คุณไม่ได้พูดคือความแม่นยำของออสซิลเลเตอร์ภายในคืออะไร ฉันใช้เวลาพอสมควรในการค้นหาในแผ่นข้อมูลหน้า 369

10% สิบเปอร์เซ็นต์! และสำหรับออสซิลเลเตอร์ที่ได้รับการสอบเทียบแล้ว? อันนี้แย่มาก มันไม่ได้เป็นเหตุผลที่จะคาดหวังว่าข้อผิดพลาดที่ต่ำเป็น1% สำหรับการนี้ Microchip / Atmel จัดทำเอกสารสำหรับการสอบเทียบ oscillator ด้วยตนเองเพื่อความแม่นยำ 1%

I2Cเป็นโปรโตคอลแบบซิงโครนัสและความแม่นยำในการกำหนดเวลาไม่เกี่ยวข้องตราบใดที่มีการเคารพเวลาพัลส์ขั้นต่ำและสูงสุด ในทางกลับกัน
UARTนั้นมีความไม่ตรงกันและความแม่นยำของเวลานั้นมีความสำคัญอย่างยิ่ง UART ส่วนใหญ่อนุญาตให้มีข้อผิดพลาดครึ่งบิตในบิตสุดท้าย (บิตหยุด) ดังนั้นนั่นคือ 5% สำหรับการส่ง 10 บิต

ออสซิลเลเตอร์ที่ปรับเทียบจากโรงงานจะไม่ทำที่นี่ คุณจะต้องทำตามขั้นตอนการปรับเทียบเพื่อให้ได้ 1% ในกรณีนี้คุณสามารถใช้ตัวกำเนิดสัญญาณภายใน อย่างอื่นคุณจะต้องใช้คริสตัล


1
ให้ฉันเสริมสิ่งที่กำลังพูดอยู่ที่นี่ ช่วยประหยัดเวลาและอาการปวดหัวและเพียงแค่ได้รับคริสตัล หากปัญหาเกี่ยวกับกำลังไฟให้ใช้นาฬิกาคริสตัลขนาด 32 กิโลเฮิร์ตซ์ (6PF สำหรับ 48/88/168 ... ไม่แน่ใจเกี่ยวกับรุ่น 328 ตรวจสอบแผ่นการโยกย้าย) เพื่อปรับออสซิลเลเตอร์ภายในเมื่อเริ่มต้น รูทีนการสอบเทียบของออสซิลเลเตอร์นั้นค่อนข้างดีดังนั้นโปรดระมัดระวังหากคุณไปเส้นทางนั้น ฉันโพสต์โค้ดตัวอย่างไว้ด้านล่างคำตอบอื่น
bathMarm0t

6

ในขณะที่คุณใช้งาน UART ผู้แนะนำคริสตัลออสซิลเลเตอร์จะแนะนำให้เลือก หากไม่ใช่สำหรับสิ่งนั้นคุณสามารถใช้ออสซิลเลเตอร์ภายในได้ MCU บางตัวมีออสซิลเลเตอร์ภายในที่ถูกตัดแต่งจากโรงงานซึ่งเหมาะสำหรับการใช้งาน UART


2
ดูเพิ่มเติมที่หมายเหตุแอพนี้ในการกำหนดเวลาของ UART: maxim-ic.com/app-notes/index.mvp/id/2141
drxzcl

UART นั้นใช้สำหรับการสื่อสารกับจอแสดงผลแบบอนุกรมที่เรียบง่ายที่สุดที่ทำงานที่ 9600bps ... ฉันคิดว่าฉันจะสั่งออสซิลเลเตอร์และทุกอย่าง แต่ดูว่ามันจะใช้งานได้หรือไม่
Earlz

3

"ไม่ไวต่อเวลา" 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;
}

2

ควรสังเกตว่าคริสตัลใช้เวลานานในการเริ่มต้น นั่นเป็นเพราะความแม่นยำ: ใช้พลังงานจากคลื่นความถี่ที่แคบมากเท่านั้น นี่อาจเป็นภาระสำหรับสิ่งที่ใช้แบตเตอรี่ซึ่งคุณตื่น mcu เป็นระยะเวลาสั้น ๆ ทุกขณะนี้: การรอ ms ที่กำลังไฟเต็มเพื่อให้คริสตัลเริ่มต้นคือการสูญเสียสุทธิ ตัวสะท้อนแสงแบบเซรามิกนั้นมีความแม่นยำมากกว่าออสซิลเลเตอร์ RC ภายใน แต่น้อยกว่าคริสตัลและเริ่มต้นตามลำดับ

แน่นอนว่าเครื่องดื่มขนาด 16MHz atmega จะมีน้ำผลไม้มากขึ้นและต้องการแรงดันไฟฟ้าที่สูงกว่า 8MHz หนึ่งเครื่อง แต่จะมีคริสตัล 8MHz (หรือต่ำกว่าจนถึง 32kHz); ทางเลือกนี้เป็นเพียงตัวช่วยประหยัดพลังงาน


0

หากคุณไม่ต้องการเวลามากหรือแม่นยำไม่จำเป็นต้องมีออสซิลเลเตอร์ภายนอก ในขณะที่ถอดแยกชิ้นส่วนเครื่องพิมพ์เก่าบางรุ่นฉันบังเอิญเห็น IC จำนวนมาก แต่ไม่ใช่ oscillator ตัวเดียวบนเครื่อง


0

ฉันเดาว่าคุณเคยเห็นแอพนี้แล้ว: AVR053: การสอบเทียบของ RC oscillatorภายใน

ฉันเดาจากมันและบันทึกย่อของแอพจากความคิดเห็นของ @drxzcl ด้านบนคุณควรจะสามารถตัดสินใจในทางทฤษฎีในสิ่งที่ถูกต้อง


หากมีคำตอบที่ยอมรับแล้วคุณควรพยายามพูดอะไรมากกว่านี้มิฉะนั้นมันจะไม่มีประโยชน์มากนัก
clabacchio

@clabacchio - คำตอบนี้มีอายุสองวันและวันที่ที่ยอมรับจากเมื่อวาน ไม่สามารถยอมรับได้เมื่อโพสต์สิ่งนี้
stevenvh

@stevenvh ถูกต้องฉันไม่ได้ตระหนักว่ามันเป็นแค่การแก้ไข แม้ว่ามันจะเป็นคำตอบที่ไม่สมบูรณ์
clabacchio

@clabacchio - "คำตอบไม่สมบูรณ์" ตกลงกัน! ฉันไม่พบ "คุณควรตัดสินใจได้" มีประโยชน์มาก
stevenvh

@clabacchio - เฮ้ฉันก็บอกว่า "2 วันก่อน" ตอนนี้ หนึ่งนาทีก่อนมันพูดว่า "ตอบเมื่อวานนี้" ต้องผ่านไปอย่างแน่นอน 48 ชั่วโมง! :-)
stevenvh
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.