ต้องการความช่วยเหลือในการทำความเข้าใจกับตัวจับเวลามิเรอร์ AVR ATMEGA / ATTINY


10

ฉันพยายามใช้ Timer1 ของไมโครคอนโทรลเลอร์ Atmel AVR ทั้ง AtMega328 ที่ใช้ใน Arduino หรือ ATTiny85 เพื่อส่งสัญญาณนาฬิกาสองสัญญาณซึ่งเป็นภาพสะท้อนของกันและกัน ความถี่ที่ฉันพยายามจะสร้างคือตัวแปร 1 MHz ถึง 2 MHz หรือสูงกว่าซึ่งสูงเกินไปที่จะทำเช่นนี้โดยใช้รหัสเพื่อสลับพินเอาต์พุตหากฉันไม่ต้องการทำสิ่งใดในคอนโทรลเลอร์ ดังนั้นฉันต้องการใช้เอาต์พุตไทม์เมอร์โดยตรงบนพินที่เกี่ยวข้อง ฉันใช้ GCC toolchain ดังนั้นไม่ จำกัด โดย arduino library หรือภาษา

ตัวจับเวลา 1 ใน Atmega328 มีสองพินที่เชื่อมโยงกับมันและฉันสามารถรับสัญญาณ 1MHz ถึง 2MHz เหมือนกันได้ แม้ว่าแผ่นข้อมูลดูเหมือนว่าฉันจะได้รับรูปคลื่นคว่ำ แต่มันทำให้ฉันสับสน ฉันยังสามารถรับสัญญาณสองสัญญาณซึ่งมีวัฏจักรหน้าที่แตกต่างกันที่ 1 MHz โดยใช้การตั้งค่า PWM กับ Timer1 แต่สัญญาณทั้งสองไปสูงในเวลาเดียวกัน นี่ไม่ได้ให้บริการโครงการของฉัน ฉันไม่ต้องการแม้แต่ความผันแปรของความกว้างพัลส์ PWM ฉันแค่ต้องการสัญญาณประเภท "นาฬิกา" ที่เหมือนกันของเฟสตรงกันข้ามนั่นคือทั้งหมด

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

ถ้าเป็นไปได้ใน ATTiny นั่นจะดีกว่า ATTiny ยังมี 2 พินที่เกี่ยวข้องกับการจับเวลาหนึ่งครั้ง แต่ฉันไม่แน่ใจว่ามันมีตัวเลือกเดียวกันกับ ATMega

ฉันมีผลึก 20 MHz และตัวเก็บประจุเชื่อมต่ออยู่บน PCB แล้วและนาฬิกา 20 MHz นั้นทำงานได้อย่างน่าเชื่อถือบน ATMega328 บน ATTiny85 PCB ฉันมีคริสตัลขนาด 8 MHz และนั่นก็ทำงานได้อย่างน่าเชื่อถือ

กรุณาช่วย. ขอบคุณ.


UPDATE : มีข้อสมมติฐานที่ไม่ถูกต้องในคำตอบและความคิดเห็นดังนั้นบางทีฉันควรชี้แจง: โปรดทราบว่าในโพสต์ดั้งเดิมของฉันฉันได้ระบุว่าฉันใช้นาฬิกา 20 MHz ไม่ใช่ 8 MHzและฉันไม่ต้องการ PWM .

โหมดเดียวที่ให้ความถี่เอาต์พุตสูงมากน่าจะเป็นโหมด CTCเนื่องจากโหมด PWM ไม่ทำงานสำหรับเอาต์พุต 2 MHz มีวิธีในการสลับทั้ง Timer 1 output A หรือ Output B ในโหมด CTC หรือไม่?

ตอนนี้ฉันได้เปลี่ยนเป็น Arduino Uno มาตรฐาน (ATMega328, 16 MHz) แทนที่จะเป็นบอร์ด 20 MHz ของฉันเพื่อตรวจสอบรหัสของฉันและนี่คือรหัสสำหรับนาฬิกา 2 MHz ที่เสถียรในโหมด CTC จากหมุด 9 และ 10 ตัวจับเวลา 1 ขาออก:

#define tick 9
#define tock 10

void setup() {
  pinMode(tick, OUTPUT);  
  pinMode(tock, OUTPUT); 

  TCCR1A = _BV(COM1A0) | _BV(COM1B0) ;   // activate both output pins 
  TCCR1B = _BV(WGM12)| 1;                // set CTC mode, prescaler mode 1

  // various frustrating attempts to invert OC1B failed. What do I put here?

  OCR1A = 3;                             // set the counter max for 2 MHz

}

void loop() {
}

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

ในการเพิ่มคำถาม "ความชื่นชอบ" เฉพาะลงในข้อความค้นหาดั้งเดิมของฉัน:
ดังนั้นฉันต้องทำการเปลี่ยนแปลงอะไรกับรหัสของฉันด้านบนเพื่อให้สัญญาณแบบกลับด้านที่ 9 และ 11 ที่ความถี่สูงสุดที่เป็นไปได้สำหรับนาฬิกา 16 MHzไม่ว่าจะเป็น นั่นคือ 2 MHz หรือไม่

ฉันจะติดกับ Arduino Uno มาตรฐานในตอนนี้เพื่อให้ไม่มีโหมดข้อผิดพลาดถูกเปิดตัวโดยคณะกรรมการ homespun ของฉันและเพื่อให้ทุกคนที่มี arduino สามารถลองใช้รหัสของฉันด้านบนและยืนยันว่ามันทำงานตามที่ฉันได้กล่าวไว้ ความต้องการ!


1
ดูที่หน้า 97-98 ของแผ่นข้อมูล atmega8L มีตารางของโหมดการทำงาน หน้า 108 ระบุว่า "บิต COM21: 0 ควบคุมว่าควรจะสร้าง PWM out-put หรือคว่ำ (กลับหัวหรือไม่กลับหัว PWM)" แจ้งให้เราทราบถึงความสำเร็จของคุณ!
Vorac

ทำไมไม่ใช้อินเวอร์เตอร์ทรานซิสเตอร์ธรรมดาสำหรับมิเรอร์เอาท์พุต?
Jonny B Good

คำตอบ:


10

จากแผ่นข้อมูล ATtiny85:

โหมดการทำงานคือพฤติกรรมของตัวจับเวลา / นับและพินเอาท์พุทเปรียบเทียบถูกกำหนดโดยการรวมกันของโหมดการสร้างรูปคลื่น (WGM0 [2: 0]) และเปรียบเทียบโหมดเอาท์พุท (COM0x [1: 0]) เกร็ด บิตโหมดเปรียบเทียบเอาต์พุตไม่ส่งผลกระทบต่อลำดับการนับในขณะที่บิตโหมด Waveform Generation จะทำ บิต COM0x [1: 0] ควบคุมว่าเอาต์พุต PWM ที่สร้างขึ้นควรกลับด้านหรือไม่ (กลับหัวหรือไม่กลับหัว PWM )

ตารางที่ 11-5 แสดงวิธีตั้งค่าโหมด

Mode   WGM  WGM  WGM  Timer/Counter Mode    TOP      Update of    TOV Flag
c0     02   01   00   of Operation                   OCRx at      Set on
==========================================================================
0      0    0    0    Normal                0xFF     Immediate    MAX(1)
1      0    0    1    PWM, Phase Correct    0xFF     TOP          BOTTOM
2      0    1    0    CTC                   OCRA     Immediate    MAX
3      0    1    1    Fast PWM              0xFF     BOTTOM       MAX
4      1    0    0    Reserved                                  
5      1    0    1    PWM, Phase Correct    OCRA     TOP          BOTTOM
6      1    1    0    Reserved                                  
7      1    1    1    Fast PWM              OCRA     BOTTOM       TOP

คุณต้องการโหมด Fast PWM (เช่นโหมด 3 หรือโหมด 7) หากคุณต้องการเปลี่ยนแปลงรอบการทำงานและดูเหมือนว่าคุณทำคุณต้องการโหมด 7 และเปลี่ยนรอบการทำงานโดยการตั้งค่า OCRA

ตารางที่ 11-3 แสดงวิธีตั้งค่าโหมดเปรียบเทียบเอาต์พุตสำหรับโหมด Fast PWM

COM0A1/   COM0A0/
COM0B1    COM0B0     Description
===============================================================================
0         0          Normal port operation, OC0A/OC0B disconnected.
0         1          Reserved
1         0          Clear OC0A/OC0B on Compare Match, set OC0A/OC0B at BOTTOM
                     (non-inverting mode)
1         1          Set OC0A/OC0B on Compare Match, clear OC0A/OC0B at BOTTOM
                     (inverting mode)

กล่าวคือคุณสามารถตั้งค่าเอาต์พุต OC0A ให้ต่ำลงเมื่อค่า Timer == OCR0A และสูงเมื่อค่า Timer == 0x00 โดยการตั้งค่า COM0A1: COM0A0 = 0b10 หรือจับคู่กันโดยการตั้งค่า COM0A1: COM0A0 = 0b11 และในทำนองเดียวกันสำหรับ OC0B, OCR0B, COM0B0, COM0B1

ความถี่ PWM ถูกกำหนดโดยนาฬิกา I / O (8MHz ดูเหมือนกับคุณ) และการตั้งค่าตัวตั้งเวลาล่วงหน้าของคุณ และสมการนี้ให้เป็น f_clk_IO / (N * 256) สำหรับโหมด Fast PWM

ดังนั้นคุณสามารถใช้ OC0A สำหรับขั้ว "ปกติ" และ OC0B สำหรับขั้ว "กลับ" โดยการตั้งค่า OCR0A และ OCR0B เป็นค่าเดียวกันและการตั้งค่า COM0A1: COM0A0 = 0b10 และ COM0B1: COM0B0 ถึง 0b11

UPDATE

เนื่องจากคุณต้องการสลับเอาต์พุตให้เร็วที่สุดและคุณใช้ Mega328 ที่ความเร็ว 16MHz โหมดการทำงาน CTC จะช่วยให้คุณได้รับความถี่การสลับเป็น:

f_OCnA = f_clk_IO / (2 * N * [1 + OCRnA) = 16e6 / (2 * 1 * [1 + 1] 1) = 4MHz

โหมด Fast PWM จะช่วยให้คุณสลับเข็มที่:

f_OCnxPWM = f_clk_IO / (N * [1 + สูงสุด]) = 16e6 / (1 * [1 + 1] 1) = 8MHz

ดังนั้นฉันยังคงคิดว่าคุณต้องการโหมด Fast PWM โหมดเฉพาะ 3 ที่มี OCR0A = OCR0B = 0x80 สำหรับรอบการทำงาน 50% และตั้งค่าบิต COM0A เป็น 0x3 และบิต COM0B เป็น 0x2 เพื่อสร้างรูปคลื่นทั้งสองบน OC0A และ OC0B inversions ของกันและกัน

อัปเดต # 2 เพิ่มเติม Mega328 ลองใช้รหัส Arduino นี้:

#define tick 9
#define tock 10

void setup(){

  pinMode(tick, OUTPUT);  
  pinMode(tock, OUTPUT); 

  // Setup Waveform Generation Mode 15
  // OC1A Compare Output Mode = inverting mode
  // OC1B Compare Output Mode = non-inverting mode
  // Timer Prescaler = 1
  // TOP = OCR1A = 1

  //COM1A[1:0] = 0b11, COM1B[1:0] = 0b10, WGM1[1:0] = 0b11
  TCCR1A = _BV(COM1A1) | _BV(COM1A0) | _BV(COM1B1) | _BV(WGM11) | _BV(WGM10);

  //WGM1[3:2] = 0b11, CS1[2:0] = 0b001
  TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS10);

  OCR1A = 0x0001;
  OCR1B = 0x0001;
}

void loop(){

}

ให้ฉันเคี้ยวเล็กน้อยและดูว่ามันใช้ได้ไหม ขอบคุณ.
น่าตื่นเต้น

อีกครั้งหลังจากที่ได้อ่านคำตอบของคุณพยายามที่จะออกในวันนี้ผมเห็นคู่ของสมมติฐานที่ไม่ถูกต้อง: ผมระบุนาฬิกา 20 MHz (และตอนนี้ผมได้เปลี่ยนถึง 16 MHz) ไม่ได้"(8MHz ดูเหมือนสำหรับคุณ)" นอกจากนี้ผมระบุไว้ว่าฉันไม่จำเป็นต้อง PWM ในรูปแบบกว้างพัลส์จึงไม่แน่ใจว่าที่คุณเดาได้"ถ้าคุณต้องการที่จะแตกต่างกันไปรอบหน้าที่และมันเสียงเหมือนที่คุณทำ"
น่าตื่นเต้น

@ ExcitingProjects ฉันกำลังปิดงบของคุณ "บน ATTiny85 PCB ฉันมีคริสตัล 8 MHz และนั่นก็ทำงานได้อย่างน่าเชื่อถือ" และคำตอบของฉันอ้างอิงถึง ATtiny85 ฉันจะลองและอัปเดตคำตอบของฉันเพื่อตอบคำถามที่อัปเดตของคุณ
vicatcu

@vicateu ขอบคุณ ฉันได้อัปเดตคำถามโดยดูว่าโหมด invert ดูเหมือนว่าจะไม่มีผลในโหมด CTC จนกว่าฉันจะทำบางขั้นตอน
น่าตื่นเต้น

@ ExcitingProjects จากแผ่นข้อมูล ATmega328: "สำหรับโหมดที่ไม่ใช่ PWM COM0x1: 0 บิตจะควบคุมว่าควรจะตั้งค่าส่งออกล้างหรือสลับในการเปรียบเทียบ"
vicatcu

1

ตระกูล ATTinyX5 มี PLL อยู่ด้านในใช้เด็กตัวใหญ่

ฉันใช้ PLL ภายในเพื่อจ่ายพลังงานให้กับนาฬิกา CPU และมี 16 เมกะเฮิร์ตซ์โดยไม่มี XTAL นี่เป็นสิ่งมีค่าเนื่องจากคุณมีเพียง 5 พิน (ฉันไม่นับการรีเซ็ต PIN) อีกหนึ่ง PLL'ed PWM (OCR1B) ทำงานที่หมุด XTAL พร้อมกับเอาต์พุตเสริมฟรี คุณเพียงแค่ต้องปรับฟิวส์สำหรับ 16Mhz Xtalless ATtiny ... หรือปล่อยให้ CPU ทำงานใน 8Mhz แต่ใช้ PWM ด้วยนาฬิกา 64Mhz โดยไม่ต้องเปลี่ยนฟิวส์ ..

คุณสามารถมีนาฬิกา PWM ได้สูงสุด 64 Mhz (แต่ความละเอียด 1 บิต) หรือความละเอียด 125Khz @ 8 บิต คุณสามารถลดความละเอียด PWM และเพิ่มความเร็วด้วยการลดการลงทะเบียน OCR1C

สำหรับ 1 Mhz คุณต้องตั้ง OCR1C เป็น 63 สำหรับ 2 Mhz คุณต้องตั้ง OCR1C เป็น 31 สำหรับ 4 Mhz คุณต้องตั้ง OCR1C เป็น 15 ...

เพียงเปิดใช้งาน PLL ด้วยรหัสนี้:

PLLCSR |= (1 << PLLE);           //Start PLL
while( !(PLLCSR & (1<<PLOCK)) ); //Wait for PLL lock
//PLLCSR |= (1<<LSM );           //Low Speed PLL that clocks 32Mhz, not 64Mhz
PLLCSR |= (1 << PCKE);           //Enable PLL

ตอนนี้คุณมีนาฬิกา 64 Mhz ที่ "OCR1B0 / OCR1A0" PWMs

นอกจากนี้คุณสามารถปรับ OCR1 [A / B] 0 & XOCR1 [A / B] 0 สำหรับเอาต์พุตแบบมิเรอร์

if(0){ //Synch mode
     //OCR1A & XOCR1A enable for Synch operation but not allow odd PWM values!
     TCCR1 |= (1 << PWM1A) | (0 << COM1A1) | (1 << COM1A0); 
     //Also ATtinyX5 has "Dead Time Generator", use it ;)
     DTPS1 = 3;   //8x Prescaler for dead time generator (maximum)
     DT1A = 0xff; //Clk dead on both channels (maximum)
     }
   else
     TCCR1 |= (1 << PWM1A) | (1 << COM1A1) | (0 << COM1A0);  //ONLY OCR1A enabled

คุณจำเป็นต้องรู้ Dead Time Generator จะกิน PWM outout หากคุณตั้งค่า OCR1A = 1 คุณต้องการค่าที่สูงกว่าเวลาที่ตาย

ความนับถือ,

Erdem

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.