AVR ATMEGA / ATTINY zamanlayıcı yansıtılmış çıkışını anlamak için yardıma mı ihtiyacınız var


10

Atmel AVR mikrodenetleyicisinin Timer1'ini, Arduino'da kullanılan AtMega328'i veya ATTiny85'i, birbirinin ayna görüntüsü olan iki saat sinyali çıkışı için kullanmaya çalışıyorum. Oluşturmaya çalıştığım frekans, denetleyicide neredeyse hiçbir şey yapmak istemedikçe çıkış pinlerini değiştirmek için kod kullanarak bunu yapmak için çok yüksek olan 1 MHz ila 2 MHz veya daha fazla bir değişkendir. Bu yüzden zamanlayıcı çıkışını doğrudan ilişkili pinlerde kullanmak istiyorum. Arduino kütüphaneleri veya dili ile sınırlı olmayan GCC araç zincirini kullanıyorum.

Atmega328'deki Timer1'in kendisiyle ilişkili iki pimi vardır ve bunlardan iki özdeş 1MHz ila 2MHz sinyal alabilirim. Veri sayfası ters bir dalga formu alabileceğimi söylese de, bu beni karıştırıyor. Ayrıca Timer1 ile PWM ayarlarını kullanarak 1 MHz'de farklı görev döngüleri olan iki sinyal alabilirim, ancak her iki sinyal de aynı anda yükselir, daha kısa olan daha erken düşer. Bu benim projeme hizmet etmiyor. PWM darbe genişliği varyasyonuna bile ihtiyacım yok, sadece zıt fazın iki özdeş "saat" tipi sinyaline ihtiyacım var, hepsi bu.

Kimsenin bunu yapmak için bana kod yazmasını istemiyorum, sadece zamanlayıcının hangi modunun / bayraklarının bana zamanlayıcı ile ilişkili iki pimden birinde basit bir ters dalga şekli vermesi gerektiğini söylemesi gerekiyor. Mümkünse, tek seçenek olmadığı sürece çıkışlardan biri için harici bir ters çevirme devresi kullanmaktan kaçınmak istiyorum.

ATTiny'de bu mümkün ise, daha da iyi olacaktır. ATTiny ayrıca bir zamanlayıcı ile ilişkili 2 pime sahiptir, ancak ATMega ile aynı seçeneklere sahip olduğundan emin değilim.

Zaten 20 MHz'lik bir kristalim var ve PCB'ye bağlı kapasitörler var ve 20 MHz saat ATMega328'de güvenilir bir şekilde çalışıyor. ATTiny85 PCB'de 8 MHz'lik bir kristal var ve bu da güvenilir bir şekilde çalışıyor.

Lütfen yardım et. Teşekkür ederim.


GÜNCELLEME : Şimdiye kadar cevaplarda ve yorumlarda bazı geçersiz varsayımlar olabilir, belki de açıklığa kavuşturmalıyım: Orijinal yazımda 8 MHz değil 20 MHz saat kullandığımı ve ayrıca PWM'ye ihtiyaç duymadığımı unutmayın. .

Yeterince yüksek bir çıkış frekansı veren tek mod, PTC modları 2 MHz çıkış için çalışmadığından CTC modu gibi görünüyor . CTC modunda Zamanlayıcı 1 çıkışı A veya çıkış B'yi ters çevirmenin bir yolu var mı?

Şimdi kodumu kontrol etmek için kendi 20 MHz kartım yerine standart Arduino Uno'ya (ATMega328, 16 MHz) geçtim ve bu, kod 9 ve 10, Timer'den CTC modunda güzel bir sabit 2 MHz saat için kodum 1 çıkış pini:

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

Her iki pim için osiloskop izleri aynıdır ve senkronize olarak, iki sinyalden nasıl ters çevrilebilirim? Veri sayfasındaki ters çevirme modunun CTC modunda hiçbir şey yapmadığı görülür. Veri sayfasını yanlış mı okuyorum yoksa sonuçta daha düşük bir frekans ve PWM modu kullanmak zorunda kalacak mıyım?

Orijinal sorguma belirli bir "ödül" sorusu eklemek için:
Peki yukarıdaki kodumda , 16 MHz saat için pin 9 ve 11'de mümkün olan en yüksek frekansta mükemmel şekilde tersine çevrilmiş sinyaller vermek için hangi değişiklikleri yapmam gerekir? 2 MHz mi yoksa değil mi?

Şimdilik standart bir Arduino Uno ile sadık kalacağım, böylece ana kartım tarafından tanıtılan bir hata modu yok ve böylece bir arduino olan herkes yukarıdaki kodumu deneyebilir ve bahsettiğim gibi çalıştığını onaylayabilirim ihtiyaç!


1
Atmega8L veri sayfasının 97-98. Sayfalarına bakıldığında, çalışma modlarının bir tablosu vardır. Sayfa 108 "COM21: 0 bitleri, üretilen PWM çıkışının ters çevrilip çevrilmeyeceğini kontrol eder (ters çevrilmiş veya ters çevrilmemiş PWM)". Başarınız bizi haberdar edin!
Vorac

Aynalı çıkışlar için neden basit bir transistör invertörü kullanmıyorsunuz?
Jonny B İyi

Yanıtlar:


10

ATtiny85 Veri Sayfasından:

Çalışma modu, yani Zamanlayıcı / Sayıcı ve Çıktı Karşılaştırma pimlerinin davranışı, Dalga Formu Oluşturma modunun (WGM0 [2: 0]) ve Karşılaştırma Çıkış modunun (COM0x [1: 0]) kombinasyonu ile tanımlanır. bit. Çıktıyı Karşılaştırma modu bitleri sayım sırasını etkilemezken, Dalga Formu Oluşturma modu bitleri de etkiler. COM0x [1: 0] bitleri, oluşturulan PWM çıkışının ters çevrilip çevrilmeyeceğini (ters veya ters çevrilmemiş PWM ) kontrol eder.

Tablo 11-5, Modun nasıl ayarlanacağını gösterir.

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

Hızlı PWM modu istiyorsunuz (mod 3 veya mod 7). Eğer görev döngüsünü değiştirmek istiyorsanız ve bu sizin gibi geliyorsa, mod 7'yi ve OCRA'yı ayarlayarak görev döngüsünü değiştirmek istersiniz.

Tablo 11-3, Hızlı PWM modu için karşılaştırma çıkış modunun nasıl ayarlanacağını gösterir.

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)

Yani, Zamanlayıcı değeri == OCR0A olduğunda OC0A çıkışını alçak ve COM0A1: COM0A0 = 0b10 ayarlayarak Zamanlayıcı değeri == 0x00 olduğunda yüksek olacak şekilde ayarlayabilirsiniz. Ya da tam tersi COM0A1: COM0A0 = 0b11 ayarlayarak. Aynı şekilde OC0B, OCR0B, COM0B0, COM0B1 için.

PWM frekansı, G / Ç Saatine (sizin için duyulan 8MHz) ve zamanlayıcı ön ayar ayarınıza göre belirlenir. Ve denklem Hızlı PWM modu için f_clk_IO / (N * 256) olarak verilir.

Böylece OCR0A ve OCR0B'yi aynı değere ayarlayıp COM0A1: COM0A0 = 0b10 ve COM0B1: COM0B0'ı 0b11 olarak ayarlayarak "normal" polarite için OC0A ve "ters" polarite için OC0B kullanabilirsiniz.

GÜNCELLEME

Çıkışı olabildiğince hızlı değiştirmek istediğinizde ve Mega328'i 16MHz'de kullandığınızda, CTC çalışma modu aşağıdakilerin anahtarlama frekansını elde etmenize izin verecektir:

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

Hızlı PWM modu, pimi şu adreste değiştirmenizi sağlar:

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

Bu yüzden hala Hızlı PWM modunu istediğinizi düşünüyorum. Özellikle% 50 görev döngüsü için OCR0A = OCR0B = 0x80 ile Mod 3. Ve birbirinin OC0A ve OC0B terslemelerinde iki dalga formu yapmak için COM0A bitlerini 0x3 ve COM0B bitlerini 0x2 olarak ayarlayın.

Güncelleme # 2 Daha fazla Mega328 Bu Arduino kodunu deneyin:

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

}

Biraz çiğneme izin verin ve işe yarayıp yaramadığını görün. Teşekkür ederim.
ExcitingProjects

Bugün denemek için cevabınızı tekrar okuduktan sonra birkaç geçersiz varsayım görüyorum: 20 MHz saat belirledim (ve şimdi 16 MHz'e geçtim), "(sizin için 8MHz gibi geliyor)" değil . Ayrıca, PWM darbe genişliği varyasyonuna ihtiyacım olmadığını belirttim, bu yüzden "Görev döngüsünü değiştirmek istiyorsanız ve sizin yaptığınız gibi geliyor" nu nereden bildiğinizden emin değilim .
Heyecan

@ExcitingProjects "ATTiny85 PCB'de 8 MHz'lik bir kristalim var ve bu da güvenilir bir şekilde çalışıyor." ve cevabım ATtiny85'e atıfta bulunuyor. Güncellenmiş sorunuza yanıt olarak cevabımı güncellemeye çalışacağım.
vicatcu

@vicateu Teşekkür ederim. Soruyu güncelledim, bir adımı atlamadığım sürece ters modun CTC modunda herhangi bir etkisi yok gibi görünüyor.
Heyecan

@ExcitingProjects ATmega328 veri sayfasından: "PWM olmayan modlar için COM0x1: 0 bitleri, çıktının bir karşılaştırma maçında ayarlanması, temizlenmesi veya değiştirilmesi gerekip gerekmediğini kontrol eder"
vicatcu

1

ATtinyX5 ailesinin içinde PLL var, büyük çocuk kullan.

CPU saatini de çalıştırmak için dahili PLL kullanıyorum ve XTAL olmadan 16Mhz var. Sadece 5 iğneniz olduğundan bu değerlidir. (Sıfırlama pinini saymıyorum). Ayrıca bir PLL'ed PWM (OCR1B), isteğe bağlı ücretsiz çıkışı ile XTAL pinlerinde çalışır. Sadece 16Mhz Xtalless ATtiny için sigortaları ayarlamanız gerekir ... Veya sadece CPU'nun 8Mhz'de çalışmasına izin verin, ancak sigortaları değiştirmeden 64Mhz saat ile PWM'yi çalıştırın.

64 Mhz saat PWM'ye (ancak 1 bit çözünürlük) sahip olabilirsiniz. Veya 125Khz @ 8 bit çözünürlük. OCR1C kaydını azaltarak PWM çözünürlüğünü azaltabilir ve hızı artırabilirsiniz.

1 Mhz için OCR1C'yi 63'e ayarlamanız gerekir. 2 Mhz için OCR1C'yi 31'e ayarlamanız gerekir. 4 Mhz için OCR1C'yi 15'e ayarlamanız gerekir ...

Bu kod ile PLL'yi etkinleştirmeniz yeterlidir:

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

Şimdi "OCR1B0 / OCR1A0" PWM'lerinde 64 Mhz saat var.

Ayrıca, yansıtılmış çıktı için OCR1 [A / B] 0 ve XOCR1 [A / B] 0 ayarlayabilirsiniz.

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

Bilmeniz gerekir, OCR1A = 1'i ayarlarsanız Dead Time Generator PWM çıkışını yiyecektir. Ölü zamandan daha yüksek değerlere ihtiyacınız var.

Saygılarımızla,

Erdem

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.