- Delay () varken neden Timer?
- PIC mikrodenetleyici Zamanlayıcıları:
- Programlama ve Çalışma Açıklaması:
- Devre Şeması ve Proteus Simülasyonu:
Bu, PIC16F877A'daki Zamanlayıcıları öğrenmenize ve kullanmanıza yardımcı olacak PIC Eğitim Serimizdeki beşinci öğretici olacak. Önceki eğitimlerimizde, PIC ve MPLABX IDE'ye Giriş ile başladık, ardından PIC kullanarak LED'i yakmak için ilk PIC programımızı yazdık ve ardından PIC Mikrodenetleyicide gecikme işlevini kullanarak bir LED Yanıp Sönme Sırası yaptık. Şimdi, önceki eğitim donanımında kullandığımız aynı LED Yanıp Sönme sırasını kullanalım ve bununla PIC MCU'muzda Zamanlayıcıları Nasıl Kullanacağımızı Öğreneceğiz. Bu eğitim için LED kartına bir düğme daha ekledik. Daha fazla bilgi edinmek için öğreticiyi gözden geçirin.
Zamanlayıcılar, gömülü bir programcı için önemli iş yüklerinden biridir. Tasarladığımız her uygulama, belirli bir zaman aralığından sonra bir şeyi AÇMAK veya KAPATMAK gibi bir zamanlama uygulaması içerecektir. Tamam, ama zaten aynı şeyi yapan gecikme makrolarımız (__delay_ms ()) varken neden zamanlayıcılara ihtiyacımız var !!
Delay () varken neden Timer?
Gecikme makrosu, "döküm" gecikmesi olarak adlandırılır. Çünkü Gecikme işlevinin yürütülmesi sırasında MCU, yalnızca bir gecikme oluşturarak döküm oturur. Bu işlem sırasında MCU, ADC değerlerini dinleyemez veya Kayıtlarından hiçbir şey okuyamaz. Bu nedenle, Zaman gecikmesinin doğru veya uzun olması gerekmeyen LED yanıp sönme gibi uygulamalar haricinde Gecikme işlevlerinin kullanılması tavsiye edilmez.
Gecikme makrolar da vardır şu kısa geliş,
- Gecikme değeri, gecikme makroları için sabit olmalıdır; program yürütülürken değiştirilemez. Dolayısıyla programcı tanımlı kalır.
- Zamanlayıcıları kullanmaya kıyasla gecikme doğru olmayacaktır.
- Makrolar kullanılarak daha büyük gecikme değerleri oluşturulamaz, örneğin, gecikme makroları ile yarım saatlik bir gecikme oluşturulamaz. Kullanılabilecek maksimum gecikme, kullanılan Kristal osilatöre bağlıdır.
PIC mikrodenetleyici Zamanlayıcıları:
Fiziksel olarak, zamanlayıcı, değeri sürekli olarak 255'e yükselen bir kayıttır ve sonra baştan başlar: 0, 1, 2, 3, 4… 255…. 0, 1, 2, 3……vb.
16F877A PIC MCU üç Zamanlayıcı Modülleri vardır. Timer0, Timer1 ve Timer2 olarak isimlerdir. Zamanlayıcı 0 ve Zamanlayıcı 2, 8 bit Zamanlayıcılardır ve Zamanlayıcı 1, 16 bitlik bir Zamanlayıcıdır. Bu eğitimde, uygulamamız için Timer 0'ı kullanacağız. Zamanlayıcı 0'ı anladığımızda, Zamanlayıcı 1 ve Zamanlayıcı 2'de de çalışmak kolay olacaktır.
Timer0 modülü zamanlayıcı / sayacı aşağıdaki özelliklere sahiptir:
- 8 bit zamanlayıcı / sayaç
- Okunabilir ve yazılabilir
- 8 bit yazılımla programlanabilir ön ölçekleyici
- Dahili veya harici saat seçimi
- FFh'den 00h'ye taşmada kesinti
- Harici saat için kenar seçimi
Bir zamanlayıcı kullanmaya başlamak için, 8-bit / 16-bit zamanlayıcı, Prescaler, Zamanlayıcı kesintileri ve Focs gibi bazı süslü terimleri anlamalıyız . Şimdi her birinin gerçekte ne anlama geldiğini görelim. Daha önce de belirtildiği gibi, PIC MCU'muzda hem 8-bit hem de 16-bit Zamanlayıcılar vardır, aralarındaki temel fark, 16-bit Zamanlayıcının 8-bit Zamanlayıcıdan çok daha iyi Çözünürlüğe sahip olmasıdır.
Ön ölçekleyici, mikrodenetleyicinin osilatör saatini zamanlayıcı durumunu artıran mantığa ulaşmadan önce bölen kısmının adıdır. Ön ölçekleyici kimliğinin aralığı 1 ila 256 arasındadır ve Ön ölçekleyicinin değeri OPTION Register kullanılarak ayarlanabilir (kaldırma dirençleri için kullandığımızla aynı). Her 64 Örneğin, ön ölçekleme değeri daha sonra, 64 ise, inci Timer nabız 1 ile artırılır.
Zamanlayıcı arttıkça ve maksimum değeri olan 255'e ulaştığında, bir kesintiyi tetikleyecek ve kendini tekrar 0'a geri başlatacaktır. Bu kesintiye Zamanlayıcı Kesmesi adı verilir. Bu kesinti, MCU'ya bu belirli zamanın geçtiğini bildirir.
Fosc Osilatörünün Sıklığı açılımı, kullanıldığı Crystal sıklığıdır. Zamanlayıcı kaydı için geçen süre Prescaler değerine ve Fosc değerine bağlıdır.
Programlama ve Çalışma Açıklaması:
Bu eğitimde iki düğmeyi iki giriş ve 8 LED'i 8 çıkış olarak ayarlayacağız. İlk düğme, zaman gecikmesini ayarlamak için kullanılacaktır (her basış için 500ms) ve ikinci düğme, zamanlayıcı dizisinin yanıp sönmesini başlatmak için kullanılacaktır. Örneğin, ilk düğmeye üç kez basılırsa (500 * 3 = 1500 ms) gecikme 1,5 saniye için ayarlanacak ve düğmeye iki basıldığında her bir LED önceden tanımlanmış gecikme süresi ile YANIP KAPANACAKTIR. Kontrol gösterisi video Bu Eğitimin sonunda.
Şimdi, bu temel bilgileri aklımızda tutarak Kod bölümünün sonunda verilen programımıza bakalım.
Programı almadıysanız sorun değil, ama aldıysanız !! Kendinize bir çerez verin ve çıktınızın tadını çıkarmak için programı terk edin. Diğerleri için programı anlamlı bölümlere ayıracağım ve her blokta neler olduğunu size açıklayacağım.
Her zaman olduğu gibi, kodun ilk birkaç satırı Yapılandırma ayarları ve başlık dosyalarıdır, bunu önceki derslerimde zaten yaptığım için bunu açıklamayacağım.
Sonra, tüm satırları atlayalım ve içinde Timer0 için PORT konfigürasyonuna sahip olduğumuz void main fonksiyonuna geçelim.
void main () {/ ***** Zamanlayıcı için Bağlantı Noktası Yapılandırması ****** / OPTION_REG = 0b00000101; // Harici frekansı olan Timer0 ve prescalar olarak 64 // Ayrıca PULL UP'ları Etkinleştirir TMR0 = 100; // 0.0019968s için zaman değerini yükle; delayValue yalnızca 0-256 arasında olabilir TMR0IE = 1; // PIE1 yazmacında zamanlayıcı kesme bitini etkinleştir GIE = 1; // Global Kesmeyi Etkinleştir PEIE = 1; // Çevre Birimi Kesmesini Etkinleştir / *********** ______ *********** /
Bunu anlamak için PIC veri sayfamızdaki OPTION Register'a bakmalıyız.
Önceki eğitimde tartışıldığı gibi bit 7, PORTB için zayıf yukarı çekme Direncini etkinleştirmek için kullanılır. Yukarıdaki şekle bakın, bit 3, MCU'ya ayarlanan aşağıdaki ön ölçekleyicinin WatchDogTimer (WDT) için değil Zamanlayıcı için kullanılması gerektiğini bildirmek için 0 yapılır. Zamanlayıcı modu, bit 5 T0CS'nin silinmesiyle seçilir
(OPTION_REG <5>)
Şimdi, zamanlayıcı için ön ölçekleyici değerini ayarlamak için bit2-0 kullanılır. 64'lük bir ön ölçekleyici değeri ayarlamak için yukarıdaki tabloda gösterildiği gibi, bitler 101 olarak ayarlanmalıdır.
Sonra, Timer0 ile ilişkili Kayıtlara bakalım.
Zamanlayıcı ayarlandıktan sonra artmaya başlar ve 256 değerine ulaştıktan sonra taşmaya başlar, bu noktada Zamanlayıcı kesintisini etkinleştirmek için TMR0IE yazmacının yüksek ayarlanması gerekir. Zamanlayıcı 0'ın kendisi bir çevresel birim olduğundan, PEIE = 1 yaparak Periferik Kesmeyi etkinleştirmeliyiz. Son olarak, Global Interrupt'ı etkinleştirmeliyiz, böylece MCU herhangi bir işlem sırasında Interrupt hakkında bilgilendirilecektir, bu GIE = 1 yapılarak yapılır .
Gecikme = ((256-REG_val) * (Prescal * 4)) / Fosc
Yukarıdaki formül Gecikme değerini hesaplamak için kullanılır.
Nerede
REG_val = 100;
Prescal = 64
Fosc = 20000000
Hesaplamada bu, Gecikme = 0.0019968s
Sonraki satır dizisi, G / Ç Bağlantı Noktalarını ayarlamaktır.
/ ***** G / Ç ****** / TRISB0 = 1 için Bağlantı Noktası Yapılandırması; // MCU'ya PORTB pini 0'ın düğme 1 için giriş olarak kullanıldığını bildir. TRISB1 = 1; // MCU'ya PORTB pini 1'in düğme 1 için giriş olarak kullanıldığını bildir. TRISD = 0x00; // MCU'ya PORT D üzerindeki tüm pinlerin PORTD = 0x00 çıktısı olduğunu söyleyin; // Tüm pinleri 0 / *********** ______ *********** olarak başlat /
Aynı donanımı kullandığımız için bu önceki eğitimimiz ile aynıdır. Giriş olarak başka bir düğme eklememiz dışında. Bu, TRISB1 = 1 satırıyla yapılır .
Sonra, sonsuz while döngüsünün tersine iki kod bloğumuz var. Biri kullanıcıdan zamanlayıcı girdisini almak için, diğeri ise LED'ler üzerinden gecikme sırasını yürütmek için kullanılır. Her satıra karşı yorum yaparak bunları açıkladım.
while (1) {sayım = 0; // Zamanlayıcıyı ana döngüdeyken çalıştırmayın // ******* Kullanıcı **** ////// if (RB0 == 0 && flag == 0) // Ne zaman verilen girdi {get_scnds + = 1; // get_scnds = get_scnds + http: // Değişkeni artırma bayrağı = 1; } if (RB0 == 1) // Sürekli artışı önlemek için bayrak = 0; / *********** ______ *********** /
Kullanıcı düğmeye 1 her bastığında, get_scnds adı verilen bir değişken artırılır. Kullanıcı parmağını düğmeden kaldırana kadar artırma işlemini tutmak için bir bayrak (yazılım tanımlı) değişken kullanılır.
// ******* Gecikmeli dizi yürütme **** ////// (RB1 == 0) {PORTD = 0b00000001 <
Düğmeye iki basılırsa bir sonraki blok devreye girer. Kullanıcı, birinci düğmeyi kullanarak gerekli zaman gecikmesini zaten tanımladığından ve get_scnds değişkenine kaydedildiğinden. Hscnd adlı bir değişken kullanıyoruz, bu değişken ISR (Interrupt service rutini) tarafından kontrol ediliyor.
Kesme hizmet yordamı Timer0 taşmaları her zaman çağrılacak olacağı bir Kesme olduğunu. Bir sonraki blokta ISR tarafından nasıl kontrol edildiğini görelim, her butona basıldığında zaman gecikmesini yarım saniye (0.5s) arttırmak istediğimiz gibi, sonra her yarım saniye için hscnd değişkenini artırmamız gerekir. Zamanlayıcımızı her 0.0019968s (~ 2ms) için aşırı akışa programladığımız için, yarım saniye sayma değişkenini saymak için 250 olmalıdır, çünkü 250 * 2ms = 0.5 saniye. Sayım 250 aldığında (250 * 2ms = 0.5 saniye), bunun yarım saniye olduğu anlamına gelir, bu yüzden hscnd'yi 1 artırır ve sayımı sıfıra başlatırız.
void interrupt timer_isr () {if (TMR0IF == 1) // Zamanlayıcı aşımı nedeniyle zamanlayıcı bayrağı tetiklendi {TMR0 = 100; // Zamanlayıcı Değerini Yükle TMR0IF = 0; // timer interrupt flag sayımını temizle ++; } eğer (sayı == 250) {hscnd + = 1; // hscnd her yarım saniyede bir artırılacak count = 0; }}
Bu yüzden bu değeri kullanıyoruz ve hscnd ile karşılaştırıyoruz ve LED'imizi kullanıcı tanımlı zamana göre değiştiriyoruz. Aynı zamanda son öğreticiye çok benzer.
İşte programımızı anladık ve çalıştırdık.
Devre Şeması ve Proteus Simülasyonu:
Her zamanki gibi , çıktıyı önce Proteus kullanarak doğrulayalım, burada Proteus'un şematik dosyalarını bağladım.
Önceki LED kartımıza bir düğme ekleyin ve donanımımız kullanıma hazır. Bunun gibi bir şeye benzemeli:
Bağlantı tamamlandıktan sonra, kodu yükleyin ve çıktıyı doğrulayın. Herhangi bir sorununuz varsa lütfen yorumlar bölümünü kullanın. Ayrıca tüm süreci anlamak için aşağıdaki Videoya bakın.