Küçük bir bilgisayar olan mikro kontrolcünün birçok çevre birimi vardır. Bu birimler genelde tüm işlemler için işlemciyi kullanır. Eski AVR ürünlerde olmayan Event (olay) sistemi bunu değiştiriyor.
Event System
Event ile bir çevre birimi birden fazla çevre birimiyle işlemci harici bağlantı kurabiliyor. Bir olay oluştuğunda diğer çevre birimlerine işlem yapma şansı tanıyor. Bir buton ile zamanlayıcıyı çalıştırmak veya bir çıkışa bağlı ledi yakmak gibi hiç bir işlemci gücü harcamadan kod yazmadan işlem yapılabiliyor. Bu bağlantılar kanal olarak adlandırılmış ve her olay başlatıcı bir kanala bağlanırken bu olaya göre işlem yapan kullanıcı (user) çevre birimleri bir den fazla olabiliyor. Bir buton olay oluşturucu (generator) tek bir kanala bağlanabiliyor. Bu butonun durumuna göre işlem yapmak için bir pin çıkışı, zamanlayıcı, ADC veya başka bir çevre birimi aynı anda kullanıcı olarak bağlanabiliyor.
Bu kanallar sistem saatine göre senkron veya asenkron olarak ayrılır. Sistem çevresel saati kullanır ama yapılandırmaya bağlı olarak uyku durumunda da çalışır. Sisteme bağlı olarak üç adat çıkış pini (EVOUTx) bulunur. Bu seride bu şekilde bir sınırlama vardır. Event out pinlerini kullanmak için PORTMUX.CTRLA registerindeki ilgili bite "1" yazmak gerekir. PORTMUX.CTRLA|=PORTMUX_EVOUT0_bm;
Donanım olarak çevre birimlerinden gelen olaylar dışında yazılımla da olay oluşturulabilir. Uyku modunda bu işlem geçersiz olur. Yazılımla olay oluşturmak için ASYNCSTROBE veya SYNCSTROBE registerine "1" yazmak yeterlidir.
Asenkron Olay Kanalları
Tabloda belirtildiği gibi asenkron olaylar için dört adet kanal bulunur. Bu kanallara yalnızca bazı çevre birimlerinin bağlanacağı gibi hepsine bağlanabilenlerde vardır. Örneğin PORTB de yer alan PIN7 sadece ASYNCCH1 e bağlanabilir. RTC taşma olayı ASYNCCH0-3 şeklinde hepsine bağlanabilir. EVSYS.ASYNCCH1=EVSYS_ASYNCCH1_PORTB_PIN7_gc;//ASYNCCH1_PORTB_PIN7_gc=0x11 olarak tanımlıSenkron Olay Kanalları
Asenkronda olduğu gibi senkron olaylar içinde bazı kanallar özeldir ve sadece o kanala bağlanabilir.Senkron Olay Kullanıcı Kanalları
PORTMUX
Uygulama
/*
* attiny1614_event_tcb.c
*
* Created: 18.03.2024 17:17:24
* Author : haluk
*/
#define F_CPU 333333// sigorta ayarlarıyla 16MHz/48
#include <avr/io.h>
#include <util/delay.h>
int main(void){
CPU_CCP=CCP_IOREG_gc;
CLKCTRL_MCLKCTRLB=CLKCTRL_PDIV_48X_gc|CLKCTRL_PEN_bm;//ana saat/48
PORTB.DIRCLR|=PIN7_bm;//pb7 giriş
PORTB.PIN7CTRL|=PORT_PULLUPEN_bm;// pull up açık
EVSYS.ASYNCCH1=EVSYS_ASYNCCH1_PORTB_PIN7_gc;//PB7 asenkron kanal 1 de olay oluşturucu
EVSYS.ASYNCUSER11=EVSYS_ASYNCUSER11_ASYNCCH1_gc;//TCB1 asenkron kullanıcı olarak asenkron kanal 1 e bağlı
EVSYS.ASYNCUSER9=EVSYS_ASYNCUSER9_ASYNCCH1_gc;//EVOUT1 asenkron kullanıcı olarak asenkron kanal 1 e bağlı
PORTMUX.CTRLA|=PORTMUX_EVOUT1_bm;//EVOUT 1 çıkış açık
TCB1.CNT=0x00;//sayaç sıfırlandı
TCB1.CCMP=0xffff;//top değer
TCB1.CTRLB|=TCB_CCMPEN_bm|TCB_CNTMODE_SINGLE_gc;// eşleşme çıkış açık, tek çekim modu
TCB1.EVCTRL|=TCB_FILTER_bm|/*TCB_EDGE_bm|*/TCB_CAPTEI_bm;//filtre açık, tek çekim düşen kenar,event açık
TCB1.CTRLA|=TCB_CLKSEL_CLKDIV2_gc|TCB_ENABLE_bm;//ana saat/2,enable
//main clock 333333Hz/2 TCB saati 166666Hz olur. Saniyedeki darbe sayısı 1666666 ise 16 bit CCMP en fazla
//65535 olur 65535/166666=0,39 sn çıkış verir.
while (1)
{
}
}
Giriş Yakalama Frekans ve PWM Ölçüm
Bu uygulamada yaklaşık 1 KHz PWM ölçümü yaptım. 2MHz e kadar ölçüm yapabildim. Logic analizörle arada ufak bir fark var. Bu fark iç osilatörün yetersizliği sanırım. 1 KHz frekansında CNT sayacı yeterli gelecektir. Bundan daha düşük bir frekans ile örneğin 50 Hz frekansta CNT taşacaktır. TCB1 saat kaynağı olarak yeterli prescalere sahip değil. Bu nedenle TCA kullanılmalıdır. Gerekli açıklamaları aşağıda yaptım.
/*
* attiny1614_Event_PWM_Freq.c
*
* Created: 20.03.2024 20:51:33
* Author : haluk
*/
#include <avr/io.h>
#include <stdio.h>
#include <util/atomic.h>
#include "tiny1_uart.h"
volatile uint16_t period=0;
volatile uint16_t high=0;
volatile uint16_t flag=0;
volatile double hsure=0;
volatile double sure=0;
volatile double oran=0;
char sonuc[256];
ISR(TCB1_INT_vect){
if (flag<=100){//100 örnekten birini alıyoruz
flag++;
TCB1.INTFLAGS=TCB_CAPT_bm;// kesme bayrağı temizlendi
}
}
int main(void){
CPU_CCP=CCP_IOREG_gc;
CLKCTRL_MCLKCTRLB=CLKCTRL_PDIV_6X_gc|(0<<CLKCTRL_PEN_bp);//20MHz
PORTB.DIRCLR=PIN1_bm;//PORTB1 giriş yapıldı
EVSYS.ASYNCCH1=EVSYS_ASYNCCH1_PORTB_PIN1_gc;//pb1 asenkron olay oluşturucu kanal 1 e bağlandı
EVSYS.ASYNCUSER11=EVSYS_ASYNCUSER11_ASYNCCH1_gc;//tcb1 asenkron kullanıcı olarak kanal 1 e bağlandı
TCA0.SINGLE.CTRLA|=TCA_SINGLE_ENABLE_bm|TCA_SINGLE_CLKSEL_DIV8_gc;// tca başlatıldı
TCB1.CTRLB|=TCB_CNTMODE_FRQPW_gc|TCB_ASYNC_bm;//frekans pwm ölçüm modu, asenkron giriş açık
TCB1.EVCTRL|=TCB_CAPTEI_bm|TCB_FILTER_bm;// event giriş açık, filtre açık
TCB1.INTCTRL=TCB_CAPT_bm;// kesme açık
TCB1.CTRLA|=TCB_ENABLE_bm|TCB_CLKSEL_CLKDIV1_gc;// tcb saat kaynağı iç osilatör
//TCB1.CTRLA|=TCB_ENABLE_bm|TCB_CLKSEL_CLKTCA_gc;// saat kaynağı olarak tca seçildi
//düşük frekanslarda tca seçilmeli
uart_basla(Bd115200);
while (1) {
if (flag>100){
ATOMIC_BLOCK(ATOMIC_RESTORESTATE){// işlem sırasında kesme oluşmaması gerekiyor
flag=0;
period=TCB1.CNT;
high=TCB1.CCMP;
hsure=(double)high/20;//f_cpu 20000000 high/fcpu= sn*1000000=us cinsinden
sure=(double)period/20;//f_cpu 20000000 period/fcpu= sn*1000000=us cinsinden
//Fcpu değişirse formül değişir
oran=(double)high/period;
sprintf(sonuc,"per=%u high=%u\n",period,high);//ham cnt ve ccmp değerleri
uart_dizi(sonuc);
sprintf(sonuc,"persure=%.2fus, high sure=%.2fus, oran=%.2f\n",sure,hsure,oran);
uart_dizi(sonuc);
}
}
}
}
Hiç yorum yok:
Yorum Gönder