Butuh bantuan untuk memahami output cermin waktu AVR ATMEGA / ATTINY

10

Saya mencoba menggunakan Timer1 dari mikrokontroler Atmel AVR, baik AtMega328 seperti yang digunakan dalam Arduino, atau ATTiny85, untuk menghasilkan dua sinyal jam yang merupakan gambar cermin satu sama lain. Frekuensi yang saya coba hasilkan adalah variabel 1 MHz hingga 2 MHz atau lebih yang terlalu tinggi untuk melakukan ini menggunakan kode untuk beralih pin output kecuali saya ingin melakukan hampir tidak ada yang lain di controller. Jadi saya ingin menggunakan penghitung waktu langsung pada pin terkait. Saya menggunakan toolchain GCC sehingga tidak dibatasi oleh pustaka arduino atau bahasa.

Timer1 di Atmega328 memiliki dua pin yang terkait dengannya dan saya bisa mendapatkan dua sinyal 1MHz hingga 2MHz yang identik. Meskipun datasheet sepertinya mengatakan saya bisa mendapatkan gelombang terbalik, ini membingungkan saya. Saya juga bisa mendapatkan dua sinyal yang berbeda siklus tugas pada 1 MHz, menggunakan pengaturan PWM dengan Timer1, tetapi kedua sinyal menjadi tinggi pada saat yang sama, yang lebih pendek menjadi rendah sebelumnya. Ini tidak melayani proyek saya. Saya bahkan tidak memerlukan variasi lebar pulsa PWM, saya hanya perlu dua sinyal tipe "jam" identik dari fase berlawanan, itu saja.

Saya tidak meminta siapa pun untuk menulis kode agar saya melakukan ini, saya hanya perlu seseorang untuk memberi tahu saya mode / flag timer mana yang harus memberi saya bentuk gelombang terbalik sederhana pada salah satu dari dua pin yang terkait dengan timer. Jika mungkin saya ingin menghindari menggunakan sirkuit pembalik eksternal untuk salah satu output kecuali itu hanya pilihan.

Jika ini mungkin sama sekali dalam ATTiny, itu akan menjadi lebih baik. ATTiny juga memiliki 2 pin yang terkait dengan satu timer, tetapi saya tidak yakin ia memiliki opsi yang sama dengan ATMega.

Saya sudah memiliki kristal 20 MHz dan kapasitor yang terhubung pada PCB dan jam 20 MHz bekerja dengan andal pada ATMega328. Pada ATTiny85 PCB saya memiliki kristal 8 MHz dan itu juga berfungsi dengan baik.

Tolong bantu. Terima kasih.


UPDATE : Ada beberapa asumsi yang tidak valid dalam jawaban dan komentar sejauh ini jadi mungkin saya harus mengklarifikasi: Perhatikan bahwa dalam posting asli saya, saya telah menyatakan bahwa saya menggunakan jam 20 MHz, bukan 8 MHz , dan juga bahwa saya tidak perlu PWM .

Satu-satunya mode yang memberikan frekuensi output cukup tinggi tampaknya adalah mode CTC karena mode PWM tidak berfungsi untuk output 2 MHz. Apakah ada cara untuk membalikkan Timer 1 output A, atau output B, dalam mode CTC?

Saya sekarang telah beralih ke standar Arduino Uno (ATMega328, 16 MHz) daripada papan 20 MHz saya sendiri untuk memeriksa kode saya, dan ini adalah kode saya untuk jam 2 MHz stabil yang bagus dalam mode CTC dari pin 9 dan 10, Timer 1 pin output:

#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() {
}

Jejak osiloskop untuk kedua pin identik dan sinkron, bagaimana saya bisa mendapatkan salah satu dari dua sinyal terbalik? Mode membalikkan dalam lembar data tampaknya tidak melakukan apa pun dalam mode CTC. Apakah saya salah membaca datasheet, atau apakah saya akan terpaksa menggunakan frekuensi yang lebih rendah dan mode PWM?

Untuk menambahkan pertanyaan "karunia" tertentu ke permintaan asli saya:
Jadi, perubahan apa yang perlu saya lakukan pada kode di atas, untuk membuatnya memberikan sinyal terbalik sempurna pada pin 9 dan 11 pada frekuensi tertinggi yang dimungkinkan untuk jam 16 MHz , apakah itu 2 MHz atau tidak?

Saya akan tetap menggunakan Arduino Uno standar untuk saat ini, sehingga tidak ada mode kesalahan yang diperkenalkan oleh papan tenunan saya, dan agar siapa pun yang menggunakan Arduino dapat mencoba kode saya di atas dan mengonfirmasi bahwa itu berfungsi seperti yang telah saya sebutkan dan bukan seperti yang saya lakukan. perlu!

Proyek yang Menyenangkan
sumber
1
Melihat halaman 97-98 dari ATmega8L datasheet , ada meja dari mode operasi. Menyatakan 108 "COM21: 0 bits mengontrol apakah output PWM yang dihasilkan harus terbalik atau tidak (PWM terbalik atau tidak terbalik)". Buat kami selalu diposting untuk kesuksesan Anda!
Vorac
Mengapa tidak menggunakan inverter transistor sederhana untuk output mirrorred?
Jonny B Baik

Jawaban:

10

Dari Lembar Data ATtiny85:

Mode operasi, yaitu, perilaku Timer / Penghitung dan pin Perbandingan Output, ditentukan oleh kombinasi mode Generasi Bentuk Gelombang (WGM0 [2: 0]) dan Mode Output Perbandingan (COM0x [1: 0]) bit. Bit mode Bandingkan Output tidak mempengaruhi urutan penghitungan, sedangkan bit mode Waveform Generation mempengaruhi. Bit COM0x [1: 0] mengontrol apakah output PWM yang dihasilkan harus terbalik atau tidak (PWM terbalik atau tidak terbalik ).

Tabel 11-5 menunjukkan cara mengatur Mode.

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

Anda menginginkan mode PWM Cepat (jadi mode 3 atau mode 7). Jika Anda ingin memvariasikan siklus tugas, dan sepertinya Anda lakukan, Anda ingin mode 7 dan memvariasikan siklus tugas dengan mengatur OCRA.

Tabel 11-3 menunjukkan cara mengatur mode keluaran perbandingan untuk mode PWM Cepat.

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)

Artinya, Anda dapat mengatur output OC0A menjadi rendah ketika nilai Timer == OCR0A dan tinggi ketika nilai Timer == 0x00 dengan mengatur COM0A1: COM0A0 = 0b10. Atau sebaliknya dengan menetapkan COM0A1: COM0A0 = 0b11. Dan juga untuk OC0B, OCR0B, COM0B0, COM0B1.

Frekuensi PWM ditentukan oleh Jam I / O (8Mhz bagi Anda) dan pengaturan prescaler timer Anda. Dan persamaan diberikan sebagai f_clk_IO / (N * 256) untuk mode PWM Cepat.

Jadi Anda dapat menggunakan OC0A untuk polaritas "normal" dan OC0B untuk polaritas "terbalik" dengan mengatur OCR0A dan OCR0B ke nilai yang sama dan mengatur COM0A1: COM0A0 = 0b10 dan COM0B1: COM0B0 ke 0b11.

MEMPERBARUI

Mengingat Anda ingin beralih output secepat mungkin dan Anda menggunakan Mega328 yang beroperasi pada 16MHz, mode operasi CTC akan memungkinkan Anda untuk mendapatkan frekuensi switching:

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

Mode Fast PWM akan memungkinkan Anda beralih pin di:

f_OCnxPWM = f_clk_IO / (N * [1 + TOP]) = 16e6 / (1 * [1 + 1]) = 8MHz

Jadi saya masih berpikir Anda ingin mode Fast PWM. Khusus Mode 3 dengan OCR0A = OCR0B = 0x80 untuk 50% siklus kerja. Dan atur COM0A bit ke 0x3 dan COM0B bit ke 0x2 untuk membuat dua gelombang pada OC0A dan OC0B inversi satu sama lain.

Perbarui # 2 Lebih banyak lagi Mega328 Cobalah kode Arduino ini:

#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(){

}
vicatcu
sumber
Biarkan saya mengunyah ini sedikit dan melihat apakah itu berhasil. Terima kasih.
Proyek Menyenangkan
Setelah membaca ulang jawaban Anda untuk mencobanya hari ini, saya melihat beberapa asumsi yang tidak valid: Saya menetapkan 20 MHz clock (dan sekarang saya telah beralih ke 16 MHz), bukan "(8MHz kedengarannya seperti untuk Anda)" . Juga saya tentukan bahwa saya tidak perlu variasi lebar pulsa PWM, jadi tidak yakin di mana Anda menduga "Jika Anda ingin memvariasikan siklus tugas, dan sepertinya Anda melakukannya" .
Proyek Menyenangkan
@ExcitingProjects Saya membatalkan pernyataan Anda "Pada ATTiny85 PCB saya memiliki kristal 8 MHz dan itu juga berfungsi dengan baik." dan jawaban saya mengacu pada ATtiny85. Saya akan mencoba dan memperbarui jawaban saya sebagai jawaban atas pertanyaan Anda yang diperbarui.
vicatcu
@vicateu Terima kasih. Saya telah memperbarui pertanyaan, mengingat mode invert tampaknya tidak berpengaruh pada mode CTC kecuali saya kehilangan beberapa langkah.
Proyek Menyenangkan
@ExcitingProjects dari datmeeet ATmega328: "Untuk mode non-PWM, COM0x1: 0 bit mengontrol apakah output harus disetel, dihapus, atau diaktifkan pada pertandingan yang cocok"
vicatcu
1

Keluarga ATtinyX5 memiliki PLL di dalamnya, gunakan anak besar.

Saya menggunakan PLL internal untuk menyalakan jam CPU juga dan memiliki 16Mhz tanpa XTAL. Ini sangat berharga karena Anda hanya memiliki 5 pin. (Saya tidak menghitung pin reset). Juga satu PLL'ed PWM (OCR1B) berjalan pada pin XTAL dengan output gratis opsional. Anda hanya perlu menyesuaikan sekering untuk 16Mhz Xtalless ATtiny ... Atau biarkan CPU berjalan dalam 8Mhz tetapi jalankan PWM dengan clock 64Mhz tanpa mengubah sekering ..

Anda dapat memiliki PWM hingga 64 Mhz clock (tetapi resolusi 1 bit). Atau resolusi 125Khz @ 8 bit. Anda dapat mengurangi resolusi PWM & meningkatkan kecepatan melalui penurunan register OCR1C.

Untuk 1 Mhz Anda perlu mengatur OCR1C ke 63. Untuk 2 Mhz Anda perlu mengatur OCR1C ke 31. Untuk 4 Mhz Anda perlu mengatur OCR1C ke 15. ...

Cukup aktifkan PLL dengan kode ini:

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

Sekarang Anda memiliki jam 64 Mhz pada PWM "OCR1B0 / OCR1A0".

Anda juga dapat menyesuaikan OCR1 [A / B] 0 & XOCR1 [A / B] 0 untuk output yang dicerminkan.

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

Anda perlu tahu, Dead Time Generator akan memakan PWM jika Anda menetapkan OCR1A = 1. Anda membutuhkan nilai yang lebih tinggi daripada waktu mati.

Salam,

Erdem

EUA
sumber