28 Şubat 2018 Çarşamba

Independent watchdog (IWDG)

STM32L051 işlemcisinde bulunan Independent watchdog özelliğini inceleyeceğiz.

         Bu yazımızda bir problemin oluşması durumunda veya zaman aşımı uygulamaları için kullanılan bu özelliği inceleyeceğiz.

Yazılım hatasından kaynaklanan arızaları çözmek için kullanılır.
  •  Zaman aşımı oluştuğunda sistem reset’i oluşturur.
  •  Ana clock sinyali bir hatadan dolayı dursa bile her zaman aktiftir.
  •  Bir kez aktif edilmiş ise kapatılamaz sadece tekrar yenilenmek zorundadır. Yani timeout sayacını sıfırlamak gerekir.

Uygulama avantajları:
  •           Ana uygulama dışında tamamen bağımsız bir işlemdir.
  •           Donanım veya yazılım ile başlatılabilir.
  •           Standby modunda veya stop modunda low-power olarak dondurabilir.

       Yazılım hatasından kaynaklanan sorunları tespit etmek için ve çözmek için kullanılır. Sayıcı zaman aşımı değerine ulaştığında bir reset sırasını tetikler. Saat bağımsız bir 37 kHz düşük hızlı dahili RC osilatöre (LSI RC) sahip olduğundan, ana clock başarısız olsa bile watchdog aktif kalır. Bir kez aktif edildiğinde sadece bir reset ile pasif edilebilir.

       Uygulamalar için en önemli yararlarından birisi, ana clock’dan bağımsız çalışabilme yeteneğidir. Ayrıca, IWDG, isteğe bağlı baytları kullanarak donanım veya yazılım aracılığıyla yapılandırılabilir. Stop mod veya Standby süresince IWDG sayacı dondurulabilir.

IWDG ana özellikleri:
  •           12-bit bağımsız çalışan downcounter
  •           Bağımsız RC osilatörden Saat sinyali (LSI)
  •           Koşullu Reset ( watchdog aktif ise)
    • Downcounter değeri 0x000’a geldiğinde
    • Downcounter sayacı window dışında tekrar yüklendiğinde ( window opsiyonu seçili ise)
       IWDG 12-bit bağımsız çalışan bir downcounter sayacına sahiptir. 37-kHz olan dahili bir low-speed osilatörden saat sinyalini alır. 

       IWDG ne zaman aktif edilir ise, downcounter sayacı sıfır gittiğinde veya downcounter window dışında tekrar yüklendiğinde (bu opsiyon aktif ise) reset sinyali oluşturulur.


        IWDG register’ları CORE voltajının bulunduğu alana yerleştirilmiştir. Bu mimari kullanılarak IWDG özelliği Stop ve Standby modlarında kullanılabilmektedir. LSI osilatör frekansı 8-bit prescaler ile bölünerek kullanılmaktadır.

        IWDG başlatıldığında 12-bit sayaç reset değeri olan 0xFFF’den aşağı doğru saymaya başlar. IWDG sayacını yenilemek için Anahtar değer olarak 0xAAAA Key register içerisine yazılarak sayacın terkrar geri yüklenmesi gerekmektedir. Yani bu anahtar girilmeden sayaç temizlenemez. Yazılım içerisinde yanlışlıkla bu sayacın temizlenmesi imkânsızdır.

         Downcounter sayaç değeri(0x000) olduğunda bir sistem reset sinyali üretilir.

        Window opsiyonu aktif edilmiş ise, sayaç window içerisinde yenilenmek zorundadır. Window dışında yenilenir ise bir sistem reset sinyali oluşturulur ve sistem resetlenir.
IWDG donanımı cihazın opsiyon byte’ları ile aktif edilir. Aktif edildi ise, watchdog power on durumunda otomatik olarak başlatılır.

        Herhangi bir reset’lenmeyi önlemek için Key register sayaç 0 değerine ulaşmadan önce veya window’da (bu opsiyon aktif ise) düzenli aralıklarla yenilenmelidir. IWDG yazılımda başlatılması birkaç adımda yapılandırılır.
  •           İlk adım watchdog’un başlatılması için Key register’a 0x0000 CCCC yazılır.
  •           Daha sonra IWDG register koruması 0x0000 5555 yazılarak kaldırılır.
  •           IWDG prescaler IWDG_PR register üzerinden ayarlanır.
  •           Watchdog sayacı IWDG_RLR reload register üzerinden başlangıç değeri ayarlanır.

       Önceki kayıtlara eriştikten sonra kayıtların güncellendiğini onaylamak için IWDG_SR bitinin sıfırlanmasını beklemek gereklidir.
  •          İki seçim mevcuttur. IWDG window opsiyonu aktif etmek veya pasif etmek.
    •        IWDG_WINR register içerisine window değeri yazılarak window opsiyon aktif edilir.
    •         Diğeri, Key register içerisine 0x0000 AAAA yazılarak window opsiyonu pasif edilir.

       IWDG zaman tabanı LSI saatinden 37kHz'de beslenir. IWDG_PR prescaler register LSI saat frekansını 4’den 256’ye kadar bölebilir. Watchdog sayacı tekrar yükleme değeri 12-bit olarak IWDG_RLR register içerisine yazılabilir.

        IWDG zaman aşımını belirlemek için bir formül kullanılabilir. IWDG zamanı seçilen watchdog sayıcısının geri yükleme değerinin yanı sıra LSI periyoduna ve prescaler değerine bağlıdır. Parametre limitleri göz önüne alındığında, IWDG zaman aşımı değeri :

37kHz / 4(prescaler) = 9,25ms * 4095(reload value) = 37,8 saniye
37kHz / 256(prescaler) = 144,5us * 1(reload value)  = 144,5 us

arasında olabilir.

       IWDG çevrebirimi tarafından bir reset sinyali oluşturulduktan sonra, RCC_CSR register içerisinde yer alan IWDGRSTF bayrağı işlemcinin hangi sebepten reset’lendiğini anlamak için set edilir.

       Mikro kontrolör Debug moda girdiğinde, IWDG sayacı DBG modülündeki DBG_IWDG_STOP bit’inin değerine bağlı olarak normal çalışmaya devam eder veya durur.

       IWDG, beslemenin kapalı olduğu durum olan Shutdown modu hariç tüm çalıştırma ve düşük güç modlarında etkin olabilir. Bununla birlikte, Stop0, Stop1, Stop2 ve Bekleme modlarında, watchdog sayacı FLASH_OPTR register’ın ilgili bitleri programlanarak dondurulabilir.

       Şimdi bunu STM32CubeMx ve Atollic IDE kullanarak uygulayalım ve sonuçlara bakalım.
Öncelikle CubeMx’de projemizi adım adım oluşturalım.


      Resimde görüldüğü gibi “New Project” kısmına basalım.


      Çıkan listeden kullanacağımız işlemciyi seçelim. Ben STM32L051K8T6 kullanacağım için yukarıdaki resimde de görüldüğü üzere bu işlemciyi seçip “OK” butonuna basıyoruz.


       Projemiz için ana ekran yukarıdaki şekilde geldi.


       Öncelikle Atollic programında debug yapabilmek için yukarıda görüldüğüü gibi “Peripherals” sekmesinin altında yer alan “SYS” sekmesinin altındaki “Debug Serial Wire” seçeneğini seçiyoruz. Bu seçimi yapmadan proje oluşturduğumuzda Atollic programı debug yapmamıza izin vermeyecektir.

























       Daha sonra “Peripherals” sekmesinin altında bulunan “IWDG” sekmesinden  “Activated” kısmını işaretleyerek Independent Watchdog özelliğini aktif hale getiriyoruz.


       Daha sonra “Clock Configuration” kısmına gelip HCLK değerini 32MHz olarak değiştirip Enter tuşuna basıyoruz. Böylece sistem clock frekansımızı 32MHz olarak ayarlamış oluyoruz.
         Resimde de görüleceği üzere IWDG clock kaynağı 37kHz’dir. İncelemelerim sonucunda her işlemci ailesinde bu değer farklılıklar göstermektedir.

       Şimdi de LED’lerimizin bağlı olduğu pinleri ayarlayalım.


       Kırmızı LED’imizi PB7 pinine , yeşil LED’imizi de PB6 pinine bağlayalım. Pin üzerine gelerek sağ tuş ile açılan menüden “Enter User Label” seçeneğini seçerek LED’lerin isimlerini tek tek girelim.
      Daha sonra 

      Yukarıdaki resimde işaretlenmiş olan “Configuration” sekmesinde bulunan “IWDG” butonuna tıklayarak IWDG menüsünü açınız.


       Burada 3(üç) adet parametre bulunuyor. Bunlar;
  • IWDG counter clock prescaler
  • IWDG window value
  • IWDG down-counter reload value

      Yukarıdaki anlatılan formülü hatırlayalım:

İstenilen Zaman = (LSI RC Osilatör Frekansı / Prescaler)* down-counter reload değeri

      Biz presclaer değerini 32, ve down-counter reload değerini 865 verirsek,

      İstenilen Zaman = (37 kHz / 32)*865 = 1000,15ms olarak hesaplanır. Yani biz sistemin resetlenmemesi için yaklaşık 1 saniye içerisinde down-counter reload değerini yeniden yüklememiz gerekecek.

      Bu değerleri parametrelere girdikten sonra “OK” butonuna basarak menüden çıkalım.
Şimdi proje ayarlarını yapacağız.



                “Project” menüsünden yukarda görüldüğü gibi “ Setting…” kısmına basarak proje ayarlarını yapacağımız menüyü açalım.


      Ben proje ismi olarak IWDG_DENEME ismini verdim. “Project Location” kısmına programın nereye oluşturulmasını istiyor iseniz oranın yolunu yazın. “Toolchain /IDE” kısmından Atollic IDE ile çalışacağımızdan dolayı “TrueSTUDIO” seçeneğini seçiyoruz. “OK” butonuna basarak menüyü kapatıyoruz. 


       “Project” kısmından “Generate Code” kısmını seçerek programın oluşturulmasını sağlıyoruz.


      Karşımıza yukarıda resmi gösterilen onay menüsü gelecektir. Eğer çalışma ortamınız Linux ise “Open Folder” butonuna basın. Çünkü Linux sistemlerinde Atollic otomatik açılmıyor. Windows ise “Open Project” butonuna basıyoruz. Atollic programı otomatik olarak oluşturulan programı açacaktır.



      Atollic projeyi açtıktan sonra “Src” klasörü altında bulunan “main.c” dosyasına çift tıklayarak açıyoruz.


      Daha sonra programımızı derlemek için;



      Yukarıdaki resimde gösterilen çekiç sembolüne basarak derleme işlemini başlatıyoruz.


      Resimde de gösterildiği gibi “MX_IWDG_Init();” fonksiyonu üzerine Ctrl tuşuna basarak tıklıyoruz. Fonksiyonun bulunduğu konum gelecektir.


      Aslında HAL kütüphaneleri register seviyesinde bizim yapmamız gereken işleri kendi halletmiş durumda. Biz sadece bahsi geçen parametreleri giriyoruz. Kısaca konu başında anlatılan Key register vb. register’ların içeriği kütüphane içinde halledilmiş oluyor. Merak edenler için HAL_IWDG_Init fonksiyonunu incelemelerini öneririm. Yukarıdaki resimde de görüldüğü gibi formüle yerleştirdiğimiz değerler parametrelere set edilmiş durumdalar.

      Öncelikle IWDG counter’ı yenilemeden sistemin reset'lendiğini görmek için main fonksiyonu içerisini aşağıdaki gibi değiştirelim.


      Öncelikle MX_IWDG_Init() fonksiyonundan sonra 2000ms’lik bir gecikme fonksiyonu ekledik. Daha sonra while döngüsü içerisine Hal_Delay(50) fonksiyonu ile 50ms’lik bir gecikme ve Kırmızı LED’imizi her seferinde yakıp söndürecek HAL_GPIO_TogglePin fonksiyonunu ekledik. Programı derleyip çalıştırdığımızda kırmızı LED’in üzerindeki sinyal aşağıdaki gibi olacaktır.


      Osilaskop görüntüsünde de görüldüğü gibi LED periyodik olarak yanıp sönüyor ve reset sinyalinden sonra tekrar periyodik yanıp sönüyor. Şimdi IWDG counter’ı yenileyerek aynı kodu çalıştıralım.


      Yukarıdaki kod parçasında görüldüğü gibi while döngüsünün içerisine IWDG counter’ı yenileyen fonksiyon olan HAL_IWDG_Refresh eklendi. Yani yaklaşık 50ms’de bir watchdog sayacı yenilenecek ve böylece reset sinyali oluşmayacak. Kodu çalıştırdığımızda ki osilaskop görüntüsü aşağıdaki gibidir.


      Kırmızı LED periyodik hiç ara vermeksizin 50ms’de bir yanıp sönüyor. Bu durumda iken işlemcinin ana clock sinyali fail eder ise reset sinyali üretilecek ve program tekrar çalışmaya başlayacaktır.


İyi çalışmalar arkadaşlar.....

29 Aralık 2016 Perşembe

RTOS 
Real Time Operating System

    Mikrodenetleyiciler küçük ve kaynakları sınırlı işlemcilerdir. işlemciler programlarını ROM veya FLASH'ta tutarlar. Programları buradan yürütürler. Programın çalışması için RAM'e ihtiyaç duyarlar. Tipik bir program direkt olarak ROM'dan çalışır.

    Mikro denetleyiciler en alt gömülü uygulamalar kullanarak özelleştirilmiş işlemleri yaparlar. FreeRTOS, Real Time Scheduling, Görevler arası iletişim(inter-task communication) , zamanlama(timing) ve senkronizasyon ilkelerini içerir. 

    İşletim sistemi tasarımlarında önemli bir konu olan işlemci zamanlama algoritmalarına bir göz atalım. (CPU scheduling algorithms). Bu algoritmaların çalışma prensibi şöyledir; sırası gelen işlem biz bunlara genelde fonksiyon diyoruz. Bekleme sırasına alınarak görevlendirici (dispatcher) olarak adlandırılan bir işlem tarafından CPU'ya gönderilir. RTOS işlemci zamanlama algoritmasının izin verdiği kadar, fonksiyonu bitene kadar veya belirli bir zaman geçene kadar çalıştırır ve hafızadan kaldırır. Böylece birden çok fonksiyon tek bir işlemci tarafından çalıştırılır. Burada kullanılan algoritmaları iki kısımda inceleyebiliriz;
  • Kesintili algoritmalar (preemptive algorithms)
  • Kesintisiz algoritmalar (nonpreemptive algorithms)
    Kesintili algoritmalarda bir Task( bundan sonra işlemlere Task  diyeceğiz) RTOS tarafından belirlenmiş bir süre kadar çalıştırılır ve diğer bir Task'ın çalıştırılmasına geçer. Böylece birden fazla Task zaman paylaşımlı olarak çalıştırılmış olur.

    Kesintisiz algoritmalarda  çalıştırılan Task bitene kadar diğer Task çalıştırılmaz. Task'lar birbirlerini beklerler. Kesintisiz algoritmalara örnek;
  
En Kısa Task İlk (Shortest job first)
İlk Gelen İlk Çıkar (First in first out)
İlk Gelen Son Çıkar (First in last out)

Birbirini Dışlama (Mutually Exclusive)


    İki Task'ın birbiri ile ilişkisizliğini belirtmek için kullanılan terimdir. Bazı dokümanlarda Mutex olarak kısaltılarak da kullanılır.

    İki Task paralel olarak çalıştırıldığında (aslında zaman paylaşımlı kısım kısım çalıştırıldığında) aynı kaynağı veya global tanımlanmış aynı değişkeni kullanabilirler. Bu kullanım yazılımda hatalara sebep olabilir. Bu problemin çözümü için Task'ların senkronize edilmesi gerekmektedir. Temel işletim sistemlerinde 4(dört) yöntem kullanılır.
  • Koşullu Değişkenler (Conditional Variable)
  • Semaforlar (Semaphores)
  • Kilitler (Locks)
  • Monitörler (Monitors)
    Biz bunlardan Semaforları inceleyelim.

Semafor (Semaphors)


    İşletim sistemlerinde eş zamanlı programlamada sıkça kullanılan bir yöntemdir. Birden fazla Task'ın aynı anda çalışması durumunda birbirleri için risk teşkil ettikleri zamanlarda Task'ların birbirlerini beklemesini sağlayan bir mekanizmadır.

    Semafor kullanımında bölünmezlik (atomicity) baş roldedir. Yani tanımlanmış bir semafor'un içerisinde çalışan birden fazla fonksiyon işletim sistemi tarafından tek bir Task olarak kabul edilir ve araya herhangi bir Task girerek çalıştırılmaz. Semafor'lar iki tipte kullanılırlar;
  • İkili Semafor'lar (Binary Semaphores)
  • Tam sayı Semafor'lar ( Integer Semaphores)
    İkili semafor'lar sadece iki Task arasında eşleme sağlarlar. Üçüncü bir Task'a eşleme sağlamazlar. Tam sayı semafor'lar istenilen sayıda Task arasında eşleme sağlarlar.

Kaynak: ST UM1722.pdf , Yrd.Doç.Dr.Şadi Evren ŞEKER


19 Kasım 2016 Cumartesi

CLANG C Derleyici İncelemeleri

Ubuntu 14.04 LTS işletim sisteminde Uçbirimi açalım. Uçbirime aşağıdaki komutu yazalım.

hakki@hakki-Lenovo-ideapad-300-17ISK:~/Clang_prg$ gedit

ile gedit editörünü açın. Burada aşağıdaki kodu yazın.

#include <stdio.h>
#include <stdlib.h>

// this program count from 1 to 10 in a for loop.

int main()
{
         int z=10;

         char text[]="value of i = ";
         int i;

         printf("\nStart of the program!\n\n");
         for(i=0; i<10;i++)
         {
                  /* code */
                  printf("%s = %d\n", text, i+1);
         }

         printf("\nEnd os the program!\n");
         
         return 0;
}
Yazdığımız c kodunu sample.c olarak bulunduğunuz dizin içerisine kayıt edin. gedit editörünü kapatın. Komut satırına tekrar gelin.

hakki@hakki-Lenovo-ideapad-300-17ISK:~/Clang_prg$ ls

komutunu işletin ve dizin içerisindeki dosyalara bakın.

sample.c

görüldüğü gibi oluşturmuş olduğumuz c dosya burada. Şimdi bu dosyayı clang compiler ile derleyelim.

komut satırına bunu yazın.

hakki@hakki-Lenovo-ideapad-300-17ISK:~/Clang_prg$ clang sample.c

derleme sonrasında dizin içerisine tekrar bakalım;

hakki@hakki-Lenovo-ideapad-300-17ISK:~/Clang_prg$ ls
a.out sample.c

Derleme sonrasında dizin içerisinde a.out isimli bir doysa oluştu. Şimdi bu dosyayı çalıştıralım.
Komut satırına ./ ile beraber oluşan a.out dosyasının ismini uzantısı ile beraber yazalım.

hakki@hakki-Lenovo-ideapad-300-17ISK:~/Clang_prg$ ./a.out

Program çalıştığında aşağıdaki çıktıyı verir.

Start of the program!

value of i = = 1
value of i = = 2
value of i = = 3
value of i = = 4
value of i = = 5
value of i = = 6
value of i = = 7
value of i = = 8
value of i = = 9
value of i = = 10

End os the program!

Şimdi de çalıştırılabilir dosya derleyelim;
Komut satırına aşağıdaki komutları yazalım.

hakki@hakki-Lenovo-ideapad-300-17ISK:~/Clang_prg$ clang sample.c -o result

Derleme sonrasında tekrar dizin içerisine bakalım.

hakki@hakki-Lenovo-ideapad-300-17ISK:~/Clang_prg$ ls

a.out result sample.c

Görüldüğü gibi result isminde bir çalıştırılabilir dosya oluştu. Şimdi tekrar bu dosyayı çalıştıralım.

hakki@hakki-Lenovo-ideapad-300-17ISK:~/Clang_prg$ ./result

Program aşağıdaki gibi çıktı verecektir.

Start of the program!

value of i = = 1
value of i = = 2
value of i = = 3
value of i = = 4
value of i = = 5
value of i = = 6
value of i = = 7
value of i = = 8
value of i = = 9
value of i = = 10

End os the program!

Şimdi yazdığımız kodu derledik ve çalıştırdık. Lakin kodumuz ile ilgili uyarıları hiç görmedik. Uyarıları görebilmek için aşağıdaki komutları kullanarak kodumuzu derleyelim.

hakki@hakki-Lenovo-ideapad-300-17ISK:~/Clang_prg$ clang -Wall sample.c -o

resultsample.c:8:6: warning: unused variable 'z' [-Wunused-variable]
int z=10;
^
1 warning generated.

Çıktıdan görüldüğü üzere 1 adet uyarımız var. Kod içinde "int" tipte "z" değişkeni oluşturmuşuz lakin bu değişkeni hiç kullanmamışız. Derleyici bizi uyarıyor. Kodumuzu gedit ile tekrar açalım.

hakki@hakki-Lenovo-ideapad-300-17ISK:~/Clang_prg$ gedit sample.c

#include <stdio.h>
#include <stdlib.h>

// this program count from 1 to 10 in a for loop.

int main()
{
         //int z=10;

         char text[]="value of i = ";
         int i;

         printf("\nStart of the program!\n\n");
         for(i=0; i<10;i++)
         {
                  /* code */
                  printf("%s = %d\n", text, i+1);
         }

         printf("\nEnd os the program!\n");
         
         return 0;
}

Burada ilgili tanımlamayı comment içine alalım ve kodumuzu tekrar derleyelim.

hakki@hakki-Lenovo-ideapad-300-17ISK:~/Clang_prg$ clang -Wall sample.c -o result

Derleme sonrası uyarı mesajı almadık. Şimdi kodumuzu çalıştıralım.

hakki@hakki-Lenovo-ideapad-300-17ISK:~/Clang_prg$ ./result

Start of the program!

value of i = = 1
value of i = = 2
value of i = = 3
value of i = = 4
value of i = = 5
value of i = = 6
value of i = = 7
value of i = = 8
value of i = = 9
value of i = = 10

End os the program!

hakki@hakki-Lenovo-ideapad-300-17ISK:~/Clang_prg$ 

Böylece ilk "c" kodumuzu yazdık , derledik ve çalıştırdık.

Saygılarımla...

5 Eylül 2016 Pazartesi

Merhaba,

RF ile ilgili öğrenci projeleri, mikro işlemcili kart tasarımları yapılır. irtibat için m.hakki.kaplan@gmail.com adresinden ulaşabilirsiniz.


28 Haziran 2016 Salı

SPARK GAPS TEKNİĞİ



      Spark Gap metodu elektronik kartlarda bulunan konnektör girişlerinden gelebilecek yüksek voltajlı ESD’yi önleyen bir PCB tekniğidir. Yüksek ESD voltajı oluşturulan boşluklardan Ground’a sıçrayarak devrede bulunan girişler korunmuş olur.


Formulasyon


V= (3000.p.d)+1350

Burada p atmosfer basıncı, d ise iki gap arasındaki uzaklıktır(milimetre)
Bazı uygulanmış PCB örnekleri;







1 Aralık 2015 Salı


STM32F407’de PID Denetleyicisi Uygulaması


                PID (Proportional Integral Differential – Oransal İntegral Diferansiyel) denetleyicisi düzenlemede temel yapı taşıdır. Bu birçok farklı şekilde uygulanabilir. Bu örnekte mikrodenetleyicide nasıl kod yazılır ve yeteneklerin basit bir gösterimi yapılmıştır.
               

İyi karıştırılırmış bir su kabı düşünün (sistem) ki bu sistemin çevre sıcaklığının üstünde bir sıcaklıkta kalması gerekmektedir (referans değer “R” olsun). Bizim yapmamız gereken su içerisine bir termometre (sensor) koymak ve bununla sıcaklığı okumaktır ( anlık değer “X” olsun). Su çok soğuk ise kabın altına yerleştirilmiş olan ısıtıcı (aktuator) çalıştırılsın. Termometre okunarak termometre değeri istenilen değere geldiğinde ısıtıcı kapatılsın. Suyun sıcaklığı hala biraz zaman (aşmayı) için yükselir ve daha sonra azalmaya başlar. Suyun sıcaklığı istenilen değerin altına düştüğünde, biz ısıtıcıyı tekrar açalım. Isıtıcı ısınır ve suyu ısıtmaya başlar ama suyun sıcaklığı yine istenilen değere ulaştığında işlem tekrarlanır. Biz bir düzenleme sistemine sahibiz, burada denetleyicimiz; gerçek değeri gözlemler referans değer ile karşılaştırırız ve karşılaştırmanın sonucunda sistemi etkileriz. Bu durum basit bir şekilde figür 1’de gösterilmiştir.

Figür 1. Düzenlemenin ham ve basitleştirilmiş hali

                Yukarıdaki örnekte su sıcaklığı hiçbir zaman istenen değerde kalmaz, ancak bunun yerine çevresinde salınımlar oluşur. Salınımlar sistemin “F”, algılayıcı ve ısıtıcı özelliklerine bağlıdır. Sıcaklık davranışını iyileştirmek ve salınımı azaltmak için denetleyicide daha karmaşık kararlar tanımlayarak düzenleme sürecini geliştirebiliriz. Örneğin aşma miktarını biliyorsak sıcaklığı istenilen değere gelmeden önce durdurabiliriz.  Biz gerçek sıcaklığı istenilen sıcaklığa yakın olduğunda suyu ısıtan sıcaklık miktarını azaltarak da bu bahsi geçen aşmayı azaltabiliriz. Başka olasılıklarda vardır. Ama bunlar kontrol ünitesinde ki tanımlamalar ile hayata geçirilebilirler. Bu duruma PID düzenleme adı verilir.

                Yukarıdaki örnek açısından düzenleme teorisinin bileşenleri ikinci dereceden diferansiyel eşitlikle açıklanabilir ve düzenlenmiş sistem ikinci dereceden olarak isimlendirilir. Bunlar PID denetleyici tarafından en iyi şekilde evcilleştirilmiştir.


Figür 2. PID denetleyici ile kontrol edilen sistem

                PID denetleyicisinde ilk istenilen değer ve anlık gerçek diğer karşılaştırılarak aralarındaki fark hesaplanır. Hesaplanan hata sinyali oransal (Proportional),integral (Integral) ve farksal bölüme (Differential) ayrılır. Bu üç bileşen ilgili faktörler (Kp, Kd, Ki) ile toplanarak final değer elde edilir. Bu final değer (Reg) ısıtıcı tarafından kullanılan değerdir.

                Böyle bir PID denetleyicisi mikrodenetleyicide periyodik olarak uygulanmalıdır. Yukarıdaki eylemlerin yapılma zamanı düzenlenmiş sistemin cevap zamanını karşılamalıdır. Yani eylem zamanı yeteri kadar kısa olmalıdır. Periyodik örnekleme, hesaplama ve değerin üretilmesi için bu tekrar çağırılmalıdır. Aynı programlama çatısı daha önceki yazılarımızda FIR ve IIR filtrelemede kullanılmıştır. Mikrodenetleyici kurulumu aynıdır. Tüm denetleyici hesaplama fonksiyonları kesme fonksiyonu içerisindedir. Programın listesi figür 3’de verilmiştir.

                Program değişkenlerin tanımlamaları ile başlar. İki integer tipte dairesel tampon istenen ve gerçek değer için kullanılmıştır.  Ek olarak iki floating tipte işaretçi dairesel tampon (floating point circular buffers) hata ve bir önceki çıkış değeri için kullanılmıştır. Bileşenler için üç değişken ve ilgili ağırlık faktörleri için üç floating point sayı ve kurulum tanımlanmıştır. Sonuç olarak değişim oranı hesaplaması için gerekli bir değişken tanımlanmış ve kurulumu yapılmıştır.

                Ana program içerisinde ADC ve DAC kurulumları, örnekleme frekansı 10kHz olan her 100us ADC çevrimini başlatan timer programlanmıştır. NVIC kesme denetleyici ADC kesme isteğini aktif hale getirmiştir. Daha sonra mikrodenetleyici sonsuz döngüye girer. PID düzenleyicisi program yürütülürken oransal (Proportional), integral (integral) ve diferansiyel (Differential) bileşenler için ağırlıkların değişimine izin verilir. Durum butonu periyodik olarak kontrol edilir, zaman gecikmesi sonsuz döngü başında döngü tarafından tanımlanmaktadır. Sonraki 3 (üç) program satırı oransal bileşen (Proportional component) ağırlık değerini değiştirmek için kullanılır.  Buton S370( port E’ bit 0’a bağlı olan buton) buton S375 (port E bit 5’e bağlı olan buton)  ile birlikte basıldığında, o zaman ağırlık bir artırılır. Buton S370 buton S374 birlikte basıldığında ise (port E, bit 4, 0x10) daha sonra ağırlık bir azaltılır. Üçüncü satır 0 ile 1000 arasında değerler (dâhil) ile orantılı ağırlık değerini sınırlar. Sonraki üç satır diferansiyel bileşen için ağırlıklarla aynı işi yapar ve sonraki üç satır integral bileşen için aynı işi yapar. Sonuç olarak bu üç ağırlık LCD ekrana yazdırılır.

#include "stm32f4xx.h"
#include "LCD2x16.c"

int Ref[64], x[64], Ptr; // dairesel tamponların tanımlanması
int Error[64], Reg[64]; // hata ve önceki çıkış vektörlerinin tanımlanması
float Prop, Dif, Int = 0; // üç bileşenin tanımlamaları
float Kp = 1.0, Ki = 0.0, Kd = 0.0; // kurulum parametrelerinin tanımlamaları
float Ts = 0.0001; // TIM2’nin 8400 sabit değeri için 10kHz’e ayarlanması

int main ()
{
GPIO_setup(); // GPIO kurulumu
DAC_setup(); // DAC kurulumu
ADC_setup(); // ADC kurulumu
Timer2_setup(); // Timer 2 kurulumu
NVIC_EnableIRQ(ADC_IRQn); // NVIC ADC kesme isteğinin aktif edilmesi
LCD_init();
LCD_string("Kp:", 0x00); LCD_string("Kd:", 0x09); LCD_string("Ki:", 0x49);


// genlik ve zaman gecikmesinin ayarlanması – belirsiz döngü
while (1)
{
for (int i = 0; i < 2000000; i++) {}; // zaman gecikmesi
if ((GPIOE->IDR & 0x003f) == (0x01 + 0x20)) Kp++; // Kp’nin manuel ayarlanması
if ((GPIOE->IDR & 0x003f) == (0x01 + 0x10)) Kp--;
if (Kp<0) Kp = 0; if (Kp > 1000) Kp = 1000;
if ((GPIOE->IDR & 0x003f) == (0x02 + 0x20)) Kd += 0.001; // Kd’nin manuel ayarlanması
if ((GPIOE->IDR & 0x003f) == (0x02 + 0x10)) Kd -= 0.001;
if (Kd < 0) Kd = 0; if (Kd > 1) Kd = 1;
if ((GPIOE->IDR & 0x003f) == (0x04 + 0x20)) Ki += 0.0001; // Ki’nin manuel ayarlanması
if ((GPIOE->IDR & 0x003f) == (0x04 + 0x10)) Ki -= 0.0001;
if (Ki < 0) Ki = 0; if (Ki > 1) Ki = 1;
LCD_sInt3DG((int)Kp,0x03,1); // Kp’yi LCD ekrana yaz
LCD_sInt3DG((int)(Kd*1000),0x0c,1); // Kd’yi LCD ekrana yaz
LCD_sInt3DG((int)(Ki*10000),0x4c,1); // Ki’yi LCD ekrana yaz
};
}


// kesme fonksiyonu
void ADC_IRQHandler(void) // yaklaşık 6us sürer
{
GPIOE->ODR |= 0x0100; // PE08 high yap
Ref[Ptr] = ADC1->DR; // ADC -> dairesel tampon x1
x[Ptr] = ADC2->DR; // ADC -> dairesel tampon x2
// PID hesaplamayı başlat
Error[Ptr] = Ref[Ptr] - x[Ptr]; // hatayı hesapla
Prop = Kp * (float)Error[Ptr]; // oransal kısım (Proportional)
Dif = Kd * (float)(Error[Ptr] - Error[(Ptr-1) & 63]) / Ts; // diferansiyel kısım
Int += Ki * (float)Error[Ptr]; // integral kısmı
Reg[Ptr] = (int)(Prop + Dif + Int); // üçünü topla
// PID hesaplamasını durdur
if (Reg[Ptr] > 4095) DAC->DHR12R1 = 4095; // DAC çıkış limiti
else if (Reg[Ptr] < 0) DAC->DHR12R1 = 0;
else DAC->DHR12R1 = (int)Reg[Ptr]; // düzenleyici çıkışı-> DAC
DAC->DHR12R2 = Error[Ptr] + 2048; // hata -> DAC
Ptr = (Ptr + 1) & 63; // dairesel tampon işaretçisini artır
GPIOE->ODR &= ~0x0100; // PE08 low yap
}
Figür 3. PID denetleyici uygulaması program listesi


                Tüm hesaplamalar kesme fonksiyonu içerisinde gerçekleşir. İki ADC’nin çevrim sonuçları önce dairesel tampona saklanır. Bu iki değerin arasındaki fark hesaplanır. Sonra acilen üçüncü dairesel tampona hata olarak saklanır. Sonraki üç satırda üç bileşen ve ağırlık hesaplanır. Dördüncü satırda diğer bileşenler eklenir ve dördüncü dairesel tampon olan “Reg” içerisine toplanarak saklanır. Bu değer düzenleyici çıkışı olacaktır ve DAC’a gönderilecektir. Fakat DAC 0 ile 4095 arasındaki değerleri kabul edebilir, bu durumda diğer sayılarda bu aralık içerisine katılır; örneğin 4097 ile DAC’da 1 sayısı aynıdır ve bu düzenleyicide önemli hataya neden olur. Sayılar kabul edilebilir değerler için en iyi şekilde sınırlandırılır ve bu sonraki üç kod satırında yapılır. İkinci DAC hata sinyalinin analog sürümünü üretmek için kullanılır ve değer hata değerine 2048 ekleyerek DAC aralığının yarısı için kaydırılır. Sonunda dairesel tampon işaretçisi güncellenir.

Figür 4. Uygulama için bağlantı

                Kesme fonksiyonu içerisinde başlangıçta ve bitişte port e bit-0 high ve low yapılarak fonksiyon içerisindeki harcanan zaman ölçülür. Bu yaklaşık olarak 6us’dir.

                Program DAC çıkışı (Reg, DAC1) ve ADC girişi (gerçek değer, ADC2-> DR, ADC3 giriş) arasında basit ikinci derece sistemini ekleyerek test edilebilir. Diğer ADC (ADC->DR, ADC2 girişi) istenilen değerin okunması için kullanılır. İki seri bağlanmış RC devreleri ikinci dereceden sistem için bir yedek olarak kullanılabilir; Bu gösterimi kolaylaştırır. Ek olarak istenilen değer olan “Ref” ve parazit sinyali olan “Intf” bir fonksiyon jeneratörü kullanılarak üretilebilir. Komple örnek devrenin bağlantıları figür 4’de verilmiştir.

                Figür 5’den 8’e figür 4’deki devre için gerçek değerler (X, kırmızı), fark değerleri Kp, Kd ve Ki için verilmiştir. Parazit sinyali “Intf” sıfır olarak tutulur ve istenilen değer (Ref mavi) 10Hz frekansında kare dalgadır. “Ref” sinyalinin ofseti ADC göstergesinin ortasına yakın ayarlanır. Yatay gösterge çizelgesi saniyeleri, dikey gösterge çizelgesi volt değerini verir.

Figür 5. Kp=1, Kd=0,Ki=0; oransal kazanç çok düşük ve gerçek değer(kırmızı) istenilen değere ulaşmıyor.


Figür 6. Kp=50, Kd=0,Ki=0; oransal kazanç yüksek, gerçek değer(kırmızı) istenilen değere(mavi) yakın, fakat salınımlar görünür halde


Figür 7. Kp=50, Kd=40, Ki=0; diferansiyel kazanç salınımları düzeltir fakat gerçek değer(kırmızı) hala istenilen değer(mavi) ile aynı değil.

Figür 8. Kp=50, Kd=40, Ki=40; integral kazancı istenilen değerin ortalamasını gerçek değerin ortalamasına doğru iter

                Sonraki diyagramlar figür 9’dan figür 12’ye kadar olan diyagramlarda düzenlenmiş sistem cevapları (kırmızı) parazit sinyali (mavi) olarak verilmiştir. Referans sinyali (gösterilmemiştir) 1.21V değerinde sabit tutulmuştur. Bu düzenleyici işini düzgün yaparsa yanıtın sabit olduğu tahmin edilmiştir.

Figür 9. Kp=1, Kd=0, Ki=0; oransal kazanç çok düşük ve girişim yapan sinyalin etkisi önemli

Figür 10. Kp=50, Kd=0, Ki=0; oransal kazanç yüksek, gerçek değer (kırmızı) 1.21V’ta yakın lakin girişim sinyalinin neden olduğu salınımlar görünür halde

Figür 11. Kp=50, Kd=40, Ki=0; diferansiyel kazanç salınımı düzeltmiş lakin gerçek değer(kırmızı) istenilen değer (1.21V) ile aynı değil

Figür 12. Kp=50, Kd=40, Ki=40; integral kazanç istenilen değer (1.21V) ile aynı olması için gerçek değerin ortalamasını alır.

Şimdilik bu kadar arkadaşlar Gülen
Sorularınız ve önerileriniz için m.hakki.kaplan@gmail.com adresinden her zaman bana ulaşabilirsiniz.
Hakkı KAPLAN