07- UART Seri İletişim Örnekleri

07- UART Seri İletişim Örnekleri

Merhaba sevgili okuyucu.

Bir önceki yazıda UART iletişim için kütüphane oluşturmuştuk. Bu yazıda oluşturduğumuz bu kütüphaneyi kullanara 3 örnek yapacağız. Tüm örnekleri PIC ve bilgisayar arasında yapacağız. Bilgisayar ile arasındaki bağlantıyı seri porttan direkt olarak yapabileceğimiz gibi herhangi bir seri-usb dönüştürücü kullanarak da yapabilirsiniz. Ben bu testleri elimdeki PL2303 entegreli bir dönüştürücü ile yaptım.

Donanım

Seri portta 9 pin bulunmaktadır. Bunlardan sadece üçünü kullanarak iletişimi gerçekleştireceğiz. Biri veriyi almak için bir tanesi veriyi göndermek için diğeri ise toprak (-) ucudur. İki farklı elektronik sistemi birbirine bağlamak için ortak bir uç mutlaka olması zorunludur. Genelde bu ortak uç eksi (-) uçtur. Aksi olduğu durumlar da mevcuttur tabi ki.

IMG_20160409_193339.1

IMG_20160409_193540.1

Unutulmaması gereken nokta şu ki bu seri port pinleri direkt olarak PIC e bağlanmamalıdır. İki cihazın TTL voltajları birbirine eşit değildir. RS232 portu +13 ve -13 volt arasını kullanırken bizim PIC imiz 5 ve 0 volt arasında konuşur. Bu durumu en basit yolla çözecek entegremiz ise adeta bir hayat kurtarıcı olan MAX232 entegresidir. 16 pine sahip ve iki giriş iki çıkış iletişim kapasitesi vardır. Yani aynı anda 2 PIC i 2 RS232 portuyla konuşturabilir. Ve bunu sadece 4 kapasitörle yapabilmektedir. Gayet basit bir devre olduğu için direkt olarak devreyi veriyorum. Kapasitöreler 1 ile 20 uF arasında olabilirler.

Bilgisayardan herhangi bir seri terminal yazılımı ile bu okumayı yapabilirsiniz. Ben linux makinemde GtkTerm aldı programı kullandım.

04-USART04-USART_şema04-USART_bbYazılım

Öncelikle bir proje açıyoruz ve bir main dosyası oluşturuyoruz. Açtığımız projenin klasörüne önceki yazıda oluşturduğumu kütüphane dosyasını ekliyoruz. MPLABX de projeye sağ tıklayıp “Add Existing item…” yani “Var olan bir dosya ekle” diyerek açılan sayfadan uart.h dosyamızı seçiyoruz. MPLABX bu proje için artık kütüphane dosyamızı tanıyor. #include “uart.h” komutu ile main fonksiyonumuza da tanıtıyoruz. Artık uart.h içindeki fonksiyonları çağırabilir olacağız.

Onun yanına pic16f877a.h kütüphane dosyamızı eklemek de yararımıza olacaktır. Gerekli konfigürasyon ayarlarını yapıp saat hızımızı da belirledikten sonra çekirdek kodumuz artık hazır. Tekrar söylüyorum. Yazının buraya kadarki kısımında kavrayamadığınız bir şey var ise önceki bölümlere bakınız. Elbet bahsetmiş olmalıyım.

Şimdi sıra geldi uart_init() fonksiyonunu çalıştırıp iletişim ayarlarını yapmaya. 9600 bit/s lik hızı seçiyoruz. Fakat yavaş mod mu hızlı mod mu seçeceğimize datasheet e bakarak karar veriyoruz.

uart4BRGH = 0 için 9.6Kbit hızı seçersek gerçek hız değeri 9.766K olacak. Bu durumda hata yüzdemiz %1.73 olduğunu görebiliriz.

BRGH = 1 için 9.6Kbit hızı seçersek gerçek hız değeri 9.615 olacak. Bu durumda hata yüzdemiz %0.16 olacak.

Bu tabloya bakarsak 9600 bitlik bir hız için ideal mod “hızlı” mod olacaktır. BRGH değerinin 1 olduğu. Bu yüzden uart_init(9600,1); komutunu kullanıyoruz. BRGH değerini 0 almak isterseniz. uart_init(9600,0); şeklinde kullanabilirsiniz.

Örnek 1

İlk projede 0-255 arası tüm değerleri arada belli bir süre boşluk bırakarak bilgisayara göndereceğiz. Bilgisayar tarafında hem karakter değerini hem de ASCII karşılığını göreceğiz.

Bunun için bir değişkene ihtiyacımız var. Bu değişkeni 255 e kadar birer birer arttıracağız ve her iki gönderim arasında 100 milisaniye bekleme yapacağız. Kodlar basit ve açıklamaları yanında olduğu için direkt olarak veriyorum.

Sonuç

Terminal programınızı açıp 9600,8,N ayarlarını yaparak PIC e güç verdiğiniz taktirde bu şekilde verileri almaya başlayacaksınız. Görünüm ayalarından HEX olarak göstermeyi seçerseniz her karakterin 8 bitlik değerini görebilirsiniz. Aksi halde çektiğim videodaki sağ taraf gibi  olabilir.

 

Örnek 2

İlk örnekte tek karakter göndermeyi denemiştik. Şimdi ise öncelikle birçok karakterden oluşan bir metin göndereceğiz. Ardından bir reel bir tam sayı göndereceğiz. Her zaman açıklayıcı bir şeyler yazmayacağımızı hatta çoğu zaman veri olarak hesaplanmış sayıların gideceğini düşünürsek bu bölüm hayli önemli.

Bu kod ile bir reel bir tam sayı bir de karakter kümesi oluşturduk. Değişkenler ile ilgili bölüm bir sonraki bölüm olacak.

Tekrar iletişim ayarlarımızı yaptık.

Daha önce kütüphanemizde oluşturduğumuz fonksiyonu çağırarak göndermek istediğimiz metini giriyoruz. Burada önemli iki nokta var. İlki Türkçe karakter kullanmamak. Bunların kullanımı bilgisayarda karşılıksız kalacaktır. İkinci nokta ise \r\n kullanımı. Burada \r ve \n birer karekteri temsil ederler. Ve bu kullanım terminale aşağı satıra geçmesini ve satır başı yapmasını söyler. Bunu kullanmamızın nedeni sonraki yazacaklarımızın bir sonraki satırda olmasını istememizdir.

Bu kod çok önemli. Fakat bunu yazmadan önce sprintf fonksiyonunu kullanabilmek için öncelikle stdio.h kütüphanesini main fonksiyonuna eklemek gerekiyor.

Koda geri dönecek olursak şunu görüyoruz. Öncelikle girdiğimiz değerler virgül ile ayrıldı. Bu ayrılan değerleri tek tek inceleyelim.

 

Bunun anlamı şudur. s değişkenine tırnak içindeki “Reel sayi = %4.2f\r\nTam sayi = %d\r\n” değerini aktar. Fakat bunu yaparken %4.2f yerine virgülden sonra girdiğim ilk değer olan f değerini %d yerine ise virgülden sonra girdiğim ikinci değer olan i değerini koy. Bu şekilde “Reel sayi = 1.41\r\nTam sayi = 56\r\n” yazısını elde etmiş olduk. \r\n kısmının “alt satıra geç ve satır başı yap” demek olduğunu söylemiştik. Yani çıkış değerimiz şu şekilde olacak.

s karakterini oluşturduk. Sıra geldi yazmaya.

Çoklu karakterden oluşan değerlerimizi gönderdiğimiz fonksiyona bu değişkeni vermek yeterli olmaktadır.

Ve 5 saniyelik beklemeyi vererek okunur halde çıktımızı elde edebiliriz.

Sonuç

Örnek 3

Gerek karakter gerek sayı gönderim örneklerini gördük. Sıra geldi daha heyecanlı kısma. Bilgisayardan girilen komutu okuma ve ona göre işlem yapabilme.

Bu uygulamada bilgisayardan bir değer girilmesini isteyeceğiz. Girilen değer “a” karakteri ile başlıyorsa C5 portuna bağladığımız LED yanacak. Eğer “kapat” yazılırsa LED sönecek. Bu şekilde hem tek karakter hem çoklu karakter okuma örneklerini yapmış olacağız. Burada aslında ileride bahsedeceğim bir konuya değinmiş olacağız. Kesmeler. Kesme dediğimiz yapı belirli bir şey gerçekleştiğinde o an PIC ne yapıyorsa yapsın işlem yarıda duraklatılarak bizim o öncelikli işin yapılmasını sağlamak. Yani burada kullanacağımız örnek şu şekilde olacak. Biz while ile sonsuz döngü içinde herhangi bir şey yaparken bilgisayardan gelen verinin araya kaynamamasını istiyoruz. Örneğin tasarım gereği belirli bir yere 1 saniyelik bekleme verdik. Eğer bu bekleme sırasında veri gelirse kesinlikle okuma gerçekleştirilemez. Bunu mümkün kılmak kesmelerle olasıdır. Kesme “interrupt” olarak geçer. 16F877A mikrodenetleyicide 15 kesme bulunmaktadır. Bu yazıda konusu geçecek olan kesme USART iletişim kullanırken bir veri geldiğinde oluşacak RCIE kesmesidir. PIE1 register ına bakarsak görebiliriz. Kesme ayarlarını ise INTCON register ında görebiliriz.

uart5uart6Öncelikle minimum kodumuzu oluşturalım.

Konfigürasyon ayarlarını yaptık. Kütüphaneleri ekledik. RC5 i pin bağlayacağımız için çıkış olarak ayarladık. İletişim ayarlarını yaptık ve ekranda görünmesini istediğimiz yazıyı gönderdik.

Ardından bu kodu yazıyoruz while döngüsüne henüz gelmeden main fonksiyonu altında. Burada yaptığımız şudur. RCIE kesmesini aktif et. Çevresel kesmelere izin ver. Ve izin verilmiş tüm sekmeleri çalıştır. Bunu yaparak çevresel bir kesme olan RCIE kesmesini aktif etmiş ve çalıştırmış oluyoruz. Yani veri gelince bu kesme oluşacak.

Bu kesme oluşunca oluşacak olayı yazmaya geldi sıra. Bir fonksiyon yaratıyoruz main fonksiyonu dışında.

Kodların anlamı şunu ifade ediyor. RCIE kesmesini başta devre dışı bırak. Çünkü biz işlem yaparken oluşabilecek başka bir kesme bu işleminde  kesilmesine neden olabilir. Yani biz gelen veriyi incelerken RCIE kesmesinin gelip gelmediğine bakma. En sonda da zaten fonksiyondan çıkarken bunu tekrar atktif ediyoruz.

Asıl önemli kısım şu. PIR1 register ı altındaki RCIF biti.

uart7Bu RCIE kesmesinin flag ıdır. Yani bayrağıdır. Bunu şu şekilde düşünün. Bilgisayarda bir iş yapıyorsunuz. Ama mail geldiğinde hemen o maile bakma ihtiyacınız var. Mail gelmesi bir kesmedir. Maile bakıp işinize devam edeceksiniz. İşte CRIF biti o mailin geldiğini haber veren bildirimdir. Biz bu değeri 1 olarak okursak verinin tam olarak geldiğini anlamış oluruz. Mail gelidiği an bayrağı kaldırarak bize bilgiyi veriyor. Kodda da görüleceği gibi bu değerin 1 olduğu durumda gerekli işlemleri yapacak olmamız. İşlemi yaptıktan sonra da bu değeri 0 yaparak bayrağı indiriyoruz.

Biz veriyi karakter karaker alacağımız için öncelikle bir i değişkeni oluşturup bu her karakterde bu değeri bir arttırmak kolaylık sağlayacaktır. Ayrıca karakterleri hafızaya alacağımız bir karakter dizisine ihtiyacımız var. Burada maksimum 10 karakter alabilen bir dizi işimizi görecektir. Bu değişkenleri global olarak tüm fonksiyonlardan dışarıda bir yere yazıyoruz.

Karakter geldiğinde öncelikle karakteri geçici olarak bir yere yazmamız gerekecek. temp isimli bir karakter oluşturuyoruz ve seri yoldan gelen veriyi okuyoruz. Biz ne olduğunda işlem yapmak istiyoruz ? Bir kelime veya karakter girip “Enter” tuşuna bastığımızda. O yüzden gelen değerin “Enter” tuşu olup olmadığını kontrol etmek işimizi kolaylaştıracaktır. Eğer “Enter” tuşu gelmediyse i sıradaki dizi değişkenine karakterimizi aktarıp i değerini 1 arttırıyoruz. Bu sayede gelen kelimeyi tek tek toplayabiliriz. Eğer “Enter” tuşuna basılmışsa bizim gelen veriyi kontrol edip bir karar vermemiz gerekmektedir. Öncelikle kontrol amaçlı bu veriyi bilgisayara geri yolluyoruz.

Gönderdiğimiz veriyi okuyorsak eğer yanlış yapmamışız anlamına gelecektir bu. Ardından dizinin ilk karakterinin “a” olup olmadığına bakıyoruz. Buradaki önemli nokta dizinin ilk karakterinin 1. değil 0. karakter olması. Eğer ilk karakter “a” ise LED i yakabiliriz.

Sıra geldi “kapat” karakter dizisini okumaya. Bunu “a” karakterini okuyarak yaptığımız gibi yapamıyoruz. Tek tek “ilk harf k mi ? ikinci harf a mı ?” şeklinde de yapabiliriz fakat bu zorluğu ortadan kaldırmak için stdio.h ve string.h kütüphanelerini dosyamıza ekleyerek strcmp() fonksiyonunu kullanıyoruz. Bu fonksiyon ile dizimizin “kapat” karakterlerinden oluşup oluşmadığını sorgulayabiliriz. Fonksiyondan gelen değer 0 ise gelen verinin “kapat” olduğunu anlayabiliriz. Bu durum gerçekleşirse LED imizi kapatıyoruz. Ve ardından dizi değişkenimizi ve i değişkenimizi sıfırlayıp bir sonraki veriye hazırlıyoruz. Son durumda tüm kodumuz bu şekilde oluyor.

Kısaca özetlersek, USART kesmesi oluştu ve gelen veriyi inceleyip LED i yakıp söndürdük. Farkettiyseniz while döngüsü boş kaldı. Buraya istediğimiz kodu yazabiliriz. Tamamen while döngüsü dışında yaptığımız bu seri iletişim örneği en sağlıklı yöntemdir veri kaybına karşı.

SONUÇ

Videoda görüldüğü gibi PIC i öncelikle resetliyorum. Bu sayede başlangıç yazısını de görmüş oluyoruz. Çünkü o yazı sadece PIC e güç verildiğinde yazacak şekilde kodlandı. Verdiğim Proteus dosyasında hex dosyasınızı simüle edip aynı sonucu alabilirsiniz.

Bir sonraki yazıda görüşmek üzere.

Proje ile ilgili MPLAB, Fritzing ve Proteus dökümanlarına aşağıdaki linkten ulaşabilirsiniz.