PIC12f508 i bilirmisiniz?
PIC ailesinin en küçüklerinden ve en eskilerinden biridir. 8 bacaklı, tarih öncesi bir yaratık olan 12f508, ailenin en yeteneksizlerinden biridir ayrıca. Interrupt yoktur mesela. Analog / Dijital çevirici falanda yoktur. Donanımsal iletişim araçları yoktur. Hafızası sadece 512/25 byte tır. Üstelik bu hafızanın 256 byte ının üzerine çağrı veya atlama yapamazsınız!

      Yeni akranları çok daha yetenekli ve güçlüdürler ama bu eski dostu akranlarıyla hatta ünlülerle yarıştırmak nedense çok çekici, malum boş işler işte.

      Bu projede PIC12F508 ile HT16K33 LED kontrol chip ini I2C protokolü ile 2 kablo üzerinden kumanda edeceğiz. Videoda 12F508 i Süper Star ARDUINO ile aynı işi yaparken görmektesiniz!.

      PIC12F508 HT16K33 chipini, HT16K33 chipide Adafruit ten klonlanan bir devre üzerinde 8x8 LED matrisine kumanda ediyor. Aslında bu chip 8x16 lık matrisi kontrol edebilir. Bununlada kalmayıp aynı anda 8x16 lık bir tuş takımınıda kontrol edebiliyor ama bu projede o kısma bulaşmıyoruz, çünkü gerek yok.

      Bu chip genellikle 2 renkli led matris panellere kumanda için kullanılıyor ama nedense Adafruit bu devrede chip in yarısını boş bırakmış, buda yetmemiş, chip adres ayarını 2 bit ile sınırlamış. Oysa Keyestudio bu devreyi klonlarken chip in tüm adres seçeneklerini desteklemiş ve plakete adres için 3. bitide eklemiş. Böylece 0-7 adres aralığında toplam 8 modülü sadece iki kablo üzerinden kontrol etmek mümkün. Peki iyi güzelde bize ne? Bilmem. Boş işler peşindeyiz malum. 8 bacaklı eski dost PIC12F508 ile 16 modüllük (8x64 LED!) akan yazı devresi yapabilmek yeterince boş iş gibi geldi bana. Malesef şu an için elimde o kadar modül yok dolayısıyla bu projede tek panel ile yetineceğiz.

      Programın içinde gerekli açıklamalar var ama genede nasıl çalışıyor anlatmaya çalışayım.

      İlk olarak çözülmesi gereken konu I2C protoklü. Internette zilyon tane I2C yazısı var ama anlamak başka, 1mHz (4mHz/4) hızında, sadece 1 adet 8 bit lik saati olan ama interrupt ı olmayan bu PIC ile gerçekleştirmek başka iş.
      Bu projede I2C açısından bizi ilgilendiren dört konu var:

  1. İletişimi başlat sinyali.
  2. Veri gönderme (bit+saat darbesi) bölümü.
  3. ACK (anladım) sinyalini okuma.
  4. İletişimi bitir sinyali.

İletişimi Başlat: Kolay. Öncelikle eklemem lazım, iki hat (SCK: Saat darbesi, SDA: Veri hattı) kullanılmadığı zaman daima HIGH olmak zorunda. Bu yüzden PIC in SDA için seçtiğimiz bacağı ile +V arasında 10k lık bir direnç var (PullUp). 4. bacak (GP3) hariç herhangi bir bacağı SDA olarak seçebilirsiniz. Ben 2. (GP5) bacağı seçtim. Aynı şekilde 4. bacak dışında herhangi bir bacağıda SCK yapabilirsiniz, benim seçimim 3. (GP4) bacak. Çünkü GP4 ve GP5 dışındaki tüm bacaklar PIC i programlamak için kullanılıyor, yazılım üzerinde çalışırken pek çok kez deneme yapmak gerekiyor ve PIC i breadboard dan sök, programlayıcıya tak, gerisingeri sök, yerine tak uzun iş. Program bacaklarını boşta bırakıp programlayıcıyı breadboard a takmak daha kolay.
Nerede kalmıştım? Hah, kullanılmadığı zaman iki hat ta HIGH olmak zorunda. Böylece hatta bağlı cihazlar komut beklemeleri gerektiğini anlıyorlar.
İkinci bir kural, Veri hattı (SDA) sadece saat darbesi (SCK) LOW iken değişebilir. Saat darbesi (SCK) HIGH iken veri hattındaki (SDA) değişiklik Efendi (Master) yani yönetici arkadaş tarafından yapılırsa, yönetici iletişim başlatıyor veya bitiriyor anlamına gelir.
Dolayısı ile iletişimi başlatmak çok kolay. Beklerken zaten iki hat ta HIGH. İletişimi başlatmak istediğimizde veri (SDA) hattını LOW a çekmekle hatta bağlı tüm cihazlara "Aloooo bişey söyleyeceğim!" demiş oluyoruz. Bitti.

Veri Gönderme (Yazma): Bu bölümde fazla zor değil aslında. Kurallar şöyle; Yazma işlemi bitene kadar veri hattı (SDA), saat darbesi (SCK) HIGH iken asla değişemez. Saat darbesi (SCK) LOW dan HIGH a geçtiğinde, hatta bağlı cihazlar veri hattını (SDA) okuyarak saat darbesinin (sck sda yazmaktan yoruldum, herhalde öğrendiniz artık sinyal isimlerini) LOW a düşmesini beklerler. Saat HIGH iken veri hattı HIGH ise yollanan Bit=1 dir, LOW ise Bit=0 dır. Bu işlem 8 kez tekrarlandığında veri gönderme (yazma) işi bitmiştir.

Anladım (ACK) sinyali: İşin bu kısmı mantıken biraz zor. Çünkü çıkış olarak ayarladığımız veri hattından, hatta bağlı kölelerin (Slave) "Söylediğini anladık patron" dediğini duyabilmek için bu hattı okuyabilmemiz yani veri bacağını giriş yapmamız gerekiyor. En azından internette konuyu anlatan herkes böyle yapıyor ama bizim ihtiyar 12F508 de böyle yapmak problem. Çünkü sinyallerin zamanlaması önemli ve bir bağın giş/çıkış ayarı bu işemcide iki komut gerektiriyor ve bana göre saniyenin milyonda ikisi kadar süren bu komut çoook uzun zaman alıyor.
Peki ne yapabiliriz? PIC imizin başka durumlarda problem çıkarabilen bir özelliği var! Çıkışa işlenen sinyal ile ilgli bacağın mantık durumu farklı yerlerde tutuluyor. Yani bir bacağı HIGH yaptığınızda bacak başka bir devre tarafından LOW a çekilmişse, bacak çıkış olduğu halde okuma yaparsanız verdiğiniz komutu değil, bacağın fiziksel olarak gerçek durumunu okuyorsunuz. Özetle bacağı giriş yapmaya gerek yok. Bu durum bize hız kazandırıyor. Çünkü 8. bit i yolladığımızda köle, saatin LOW a düşmesini bekliyor, eğer 8 bit i de düzgün almışsa saat LOW olur olmaz veri hattını LOW a çekiyor. Bizim hızlıca yapmamış gereken iş saati LOW a çekmek, kısa bir süre beklemek, saati HIGH a çekmek ve kısa bir ara verip veri hattını okumak. Bu kısa aralar sadece saniyedenin milyonda 1 i kadar çünkü işlemcimiz saniyede bir milyon işlem yapabiliyor ancak I2C standartlarına göre bu aralar 0.8uS yani saniyenin milyonda 0.8 i. İşte bu yüzden bacak işlevini değiştirmenin 2 uS sürmesi bana göre çooook uzun. Sonuçta 1uS lik aralarla işlemi yapabiliyoruz ve veri hattını okuyoruz. Eğer veri hattı LOW a çekilmişse kölemiz komutumuzu anladı. Düşmediyse anlamadı...

İletişimi Bitir Sinyali: Eh bu sinyalde başlatın tersi olduğu için çok kolay. Hat boştayken zaten iki sinyalde HIGH idi. Hatırlayın saat HIGH iken veri değişemez. Saat HIGH iken veri nin LOW a çekilmesi başla anlamına gelir. Bu yüzden kurallara uygun şekilde davranıyoruz ve önce saati LOW a, sonra veriyi LOW a çekiyoruz. Kısa bir aradan sonra veri hattını HIGH a çekiyoruz ve bitti. Köleler patronun gittiğini anlıyor ve her iki hatta HIGH olduğu için otomatikman herkes bekleme durumuna geçiyor.

      Bunların dışında birde "Yeniden Başla" durumu var ancak bizi ilgilendirmediği için atlıyorum.
Başla ve dur sinyallerini I2C_Start ve I2C_Stop isimli iki alt rutine yazıyoruz. Üçüncü alt rutinimiz I2C_Write. Anladım (ACK) sinyalini okumakta zamanlama zorluğu yüzünden bu rutinin işi.

      Gerekli işlemleri komut (Alt rutin) haline getirdiğimize göre şimdi I2C üzerinden cihazları nasıl kontrol edeceğimize bakalım:
I2C hattına bağlı her cihazın (Köle) kendine özel bir adresi vardır. Bu adresler üreticiler tarafından belilenir ve HK16T33 ün adresi 1110000 tür. Bu ikili sayı onluk sistemde 122, onaltılıkta 70 olarak yazılır. Şimdi niye ikili onlu onaltılı sayı konusuna girdim? Çünkü burada dikkat edilmesi gereken bir durum var. I2C protokolü veriyi 8bit olarak iletir. Oysa cihaz adresleri 7 bittir! Adresi I2C ile kölelere gönderebilmek için 1 bit eklemek gerekir. Bu bit Oku/Yaz anlamına gelir. Yani ilgilendiğimiz cihaza veri yollayacaksak eklenen bit sıfır, cihazdan veri alacaksak (okuyacaksak) eklenen bit bir olur. Bu durumda adres değişir! Bağlı cihaza doğru adresi yollamazsak cihaz cevap vermez ve bir işlem yaptıramayız. İşte bu yüzden bu konu önemli. Örneğin cihaz adresini bulmak için ARDUINO örneklerini incelediniz diyelim, ARDUINO için HK16T33 ün adresi (7bit) 1110000 = 0x70 tir. Oysa kullanacağımız adres (8bit) 11100000 = 0xE0 dır. Arduino amatörleri hedeflediği için kütüphaneleri gerekli düzeltmeleri yapar dolayısı ile farklı sayılarla karşılaşırsınız, işin kötüsü üreticiler I2C araçlarının dökümlerinde bazen 7 bazen 8 bitlik adresi verirler ve kaç bit olduğunu belirtmezler....

      Peki bu adres olayı nereden çıktı, şöyle, yönetici ilk önce iletişimi başlatır. "Alooooo!", ardından yöneteceği cihazın adresini gönderir, "Ahmeeet", o adrese sahip cihaz I2C hattına bağlı ise ve söyleneni anladıysa "Anladım!" (ACK) der. Bu andan itibaren bitti sinyali gelene kadar hattaki cihazlardan Ahmet dışındaki kimse yollananlarla ilgilenmez. Böylece iki kablo üzerinden yüzlerce cihaza kumanda edilebilir.
Peki bu HK16T33 ün adresi 0xE0 ise birden fazla olduğunda birbirlerinden nasıl ayrılacaklar? Devre plaketi üzerinde 3 adet jumper boş bırakılmıştır. Bu jumperlerı kısa devre ederek cihazın adresine 0-8 ekleyebiliriz. Çağırırkende bu adreslere göre çağırırız. Yani;

1. Cihaz: Jumper 000 = Adres 0xE0 (1110000)
2. Cihaz: Jumper 001 = Adres 0XE1 (1110001) 
3. Cihaz: Jumper 010 = Adres 0XE2 (1110010) 
4. Cihaz: Jumper 011 = Adres 0XE3 (1110011) 
5. Cihaz: Jumper 100 = Adres 0XE4 (1110100) 
6. Cihaz: Jumper 101 = Adres 0XE5 (1110101) 
7. Cihaz: Jumper 110 = Adres 0XE6 (1110110) 
8. Cihaz: Jumper 111 = Adres 0XE7 (1110111)

Mantığı anladınız umarım.
Tabii bu adresleri kullanırken sonlarına 8. bit ide eklememiz gerekiyor. Bu işlemi yazılımla yapıp vakit kaybetmek yerine basitçe adresi ikili sistemde yazmak daha kolay. Örn 1110000b yazdığınızda 8 hane yazdığınızdan emin olduğunuz sürece bir yanlışlık olmaz. Alışık olduğumuz onlu sistemde veya geleneksel programcı alışkanlığıyla onaltılı sistemde yazarsak yanlışlık yapmak çok kolay. Çünkü bu sistemlerde 7 ve 8 bit arasında ciddi fark oluşur.

Gelelim ekrana neyin nasıl yazılacağına. HK13T66 aldığı verileri kendi hafızasına yazar. Hafızası 8x16 bittir. İlk 8 bit birinci LED modülüne, ikinci 8bit ikinci LED modulüne bağlıdır. Basitçe özetlemek gerekirse hafızaya yazdığınız sayıları LED modülde binary (ikili) olarak görürsünüz.

Örn. A harfi yazalım;
 1- İletişimi Başlat
 2- Adresi göder
 3- ACK geldiyse,
 4- İlk komutu gönder: 0000 0000 = Adres sıfıra sayı yazacağım
    (Cihaz adresi ile karıştırmayın, cihazın hafıza adresinden bahsediyoruz)
 5-  1. Byte ı gönder:  0011 1000 = Bu sayı adres 0 a yazılır.
 6-  2. Byte ı gönder:  0000 0000 = Sıfır gönderiyoruz çünkü ikinci LED modülümüz yok.
 7-  3. Byte ı gönder:  0100 0100 = Bu sayı adres 2 ye yazılır
 8-  4. Byte ı gönder:  0000 0000 = Sıfır gönderiyoruz çünkü ... vs. vs.
 9-  5. Byte ı gönder:  0100 0100 = Bu sayı adres 4 e yazılır
10-  6. Byte ı gönder:  0000 0000 = Sıfır gönderiyoruz çünkü ... vs. vs.
11-  7. Byte ı gönder:  0111 1100 = Bu sayı adres 6 e yazılır
12-  8. Byte ı gönder:  0000 0000 = Sıfır gönderiyoruz çünkü ... vs. vs.
13-  9. Byte ı gönder:  0100 0100 = Bu sayı adres 8 e yazılır
14- 10. Byte ı gönder:  0000 0000 = Sıfır gönderiyoruz çünkü ... vs. vs.
15- 11. Byte ı gönder:  0100 0100 = Bu sayı adres 10 e yazılır
16- 12. Byte ı gönder:  0000 0000 = Sıfır gönderiyoruz çünkü ... vs. vs.
17- 13. Byte ı gönder:  0100 0100 = Bu sayı adres 12 e yazılır
18- 14. Byte ı gönder:  0000 0000 = Sıfır gönderiyoruz çünkü ... vs. vs.
19- 15. Byte ı gönder:  0000 0000 = Bu sayı adres 14 e yazılır
20- 16. Byte ı gönder:  0000 0000 = Sıfır gönderiyoruz çünkü ... vs. vs.
21- İletişimi bitir.

Bu komut dizisinden sonra LED matris şöyle görünecektir;

               ..OOO...      ........
               .O...O..      ........
               .O...O..      ........
               .OOOOO..      ........
               .O...O..      ........
               .O...O..      ........
               .O...O..      ........
               ........      ........

      Yazı yazabilmemiz için bütün alfabeyi bir şekilde yukarıdaki şekilde PIC in hafızasına yüklememiz, sonra biraz hesap kitap işiyle cümle içindeki harflerin hafızadaki başlangıç adreslerini bulup modüle yazmamız ayrıca kayma işlemi içinde RAM içinde tampon bir alan oluşturup daha fazla işler yapmamız lazım.

      Ama burada hafıza büyük bir problem. Afabede 29 harf var. Sadece büyük harfleri eklesek, işaretlerle uğraşmasak, karakterleri 8 değil 5 bit yapsak (Hafızadan tasrruf numaralarımın hepsi bu kadar..) 29x5 = 145 byte eder. mikro işlemcilerde veri saklamanın iki yolu vardır RAM a yazmak veya program bölgesi ROM a yazmak. Karakter çözümleme/hesaplama işleri olmadan bile yazılım 127byte yer kaplıyor. RAM sadece 25byte ve bir kısmını yazılım için kullanıyoruz yani RAM ı unutalım. Tablo (veri) depolayacabileceğimiz ve bu tabloya erişebileceğimiz hafıza boyu sadece 256byte! 127+145 = 272 byte! kısaca hem alfabe hemde alfabeye göre hesap kitap yapacak bir yazılımı bu chip e sığdırmamız mümkün değil!

      O halde nasıl yapacağız?

Basit. Hile yapacağız. Programımız 127byte olduğuna göre elimizde 256-127 = 129 byte lık depo alanı var. Bunun anlamı; hafızaya 8x129 bit lik resim yükleyebiliriz. Yazmak istediğimiz şeyi blok halinde hazırlarsak kaydırma işide kolay, Tablonun ilk adresinden göstermeye başlayıp belli aralıklarla (Örn. saniyede 25 kere - Pal TV standardı) adresi bir arttırdığımızda amacımıza ulaşırız.

Mesela;

Tablo1
    retlw   00000000b       ; 0000           
    retlw   00000000b       ; 0001           
    retlw   00000000b       ; 0002           
    retlw   11111110b       ; 0003   1111111 
    retlw   00010000b       ; 0004      1    
    retlw   00010000b       ; 0005      1    
    retlw   00010000b       ; 0006      1    
    retlw   11111110b       ; 0007   1111111 
    retlw   00000000b       ; 0008           
    retlw   01111100b       ; 0009    11111  
    retlw   11000110b       ; 0010   11   11 
    retlw   10000010b       ; 0011   1     1 
    retlw   11000110b       ; 0012   11   11 
    retlw   01111100b       ; 0013    11111  
    retlw   00000000b       ; 0014           
    retlw   01100100b       ; 0015    11  1  
    retlw   10010010b       ; 0016   1  1  1 
    retlw   10010111b       ; 0017   1  1 111
    retlw   10010010b       ; 0018   1  1  1 
    retlw   01001100b       ; 0019    1  11  
    retlw   00000000b       ; 0020           
    retlw   01111100b       ; 0021    11111  
    retlw   10000010b       ; 0022   1     1 
    retlw   10010010b       ; 0023   1  1  1 
    retlw   01011100b       ; 0024    1 111  

      "HOŞGELDİN" in ilk dört harfi. Farkettiyseniz ilk örnekteki gibi soldan sağa değil, 90 derece sağa dönmüş üstelik harfler ters!
Bu düzenleme sayesinde harfleri 8 değil 5 kolonda temsil ederek hafızadan kazanıyoruz, harfler ters çünkü LED modülümüzü pinleri aşağıya gelecek şekilde yerleştirdiğinizde gönderdiğiniz veri ters görüntüleniyor, bu tasarımdan dolayı döndürme işlemini yazılımla yapmaya hafızada yer olmadığı için veriyi ters hazırlıyoruz. Üstelik modülde bilinmeyen bir sebepten dolayı ilk kolon son kolondan sonra geliyor, yani herşey 1 pixel yukarı kayıyor, bunun önüne geçmek için yazılımda veriyi göndermeden 1bit yukarı kaydırıyoruz, sadece 3 komut aldığı için yazılımda yapmak sorun değil görsel olarak yapmaya çalışmak çok daha kafa karıştırır.

Sonuç :
En eski, en beceriksiz, en düşük kapasiteli ama en iyi bilinen 8 bacaklı bir PIC mikro ile videoda izlediğiniz yazı/resim karışık uzun kayan yazı yapmanın mümkün olduğunu gördük. Üstelik bu işi I2C protokolü ile iki bacak üzerinden yaptık. Bu kadar kısa ve kolay değiştirilemeyecek akan yazı ne işe yarar? Öncelikle egomuzu tatmin etmeye yarar. Sonraki adım I2C üzerinden 64K lık hafıza çipine erişerek 65.536 karakterlik yazılar yazabilmek olduğunu düşünürsek önü çok açık bir proje olduğu inkar edilemez. Düşünün, 2 entegre, bir direnç, bir LED modülü ile 65.536 karakterlik akan yazı, iki entegrenin yaklaşık 10 TL ye, direncin ise hurda kutusundan geldiğini düşünürsek fena değil değilmi?.


Kaynak kodunu ve HEX dosyasını sağdaki linklerden indirebilirsiniz.

; ***********************   Proje Tanımı   ***********************
; ***    HT16K33 I2C LED Sürücü ile 8x8 LED Display kontrolü   ***
; ***********************   © 26.11.2017   ***********************
; ***                     _______  _______                     ***
; ***                    |       \/       |                    ***
; ***          (+5V) -> [| 1 Vdd    Vss 8 |] <- (GND)          ***
; ***                    |                |                    ***
; ***            SDA <> [| 2 GP5    GP0 7 |] <- ICP/Dat        ***
; ***                    |                |                    ***
; ***            SCL <- [| 3 GP4    GP1 6 |] <- ICP/Clk        ***
; ***                    |                |                    ***
; ***        ICP/Vpp -> [| 4 GP3    GP2 5 |] -> Track          ***
; ***                    |   (PIC12f508)  |                    ***
; ***                     ----------------                     ***
; ***                                                          ***
; ***                   HK16K33 Hafıza yapısı                  ***
; ***                                                          ***
; ***       Adres (Tek sayılı adresler 2. Matrise bağlı)       ***
; ***  bit  0 2 4 6 8 A C   bit  1 3 5 7 9 B D                 ***
; ***  +-+ +-+-+-+-+-+-+-+  +-+ +-+-+-+-+-+-+-+                ***
; ***  |7| | | |1|1| | | |  |7| |1|1|1|1|1| | |                ***
; ***  |6| | |1| | |1| | |  |6| |1| | | | |1| |                ***
; ***  |5| |1| | | | |1| |  |5| |1| | | | |1| |                ***
; ***  |4| |1| | | | |1| |  |4| |1|1|1|1|1| | |                ***
; ***  |3| |1|1|1|1|1|1| |  |3| |1| | | | |1| |                ***
; ***  |2| |1| | | | |1| |  |2| |1| | | | |1| |                ***
; ***  |1| |1| | | | |1| |  |1| |1|1|1|1|1| | |                ***
; ***  |0| | | | | | | | |  |0| | | | | | | | |                ***
; ***  +-+ +-+-+-+-+-+-+-+  +-+ +-+-+-+-+-+-+-+                ***
; ***         1. Matris            2. Matris                   ***
; *** Örn: 2 rekli led matrisinde Kırmızılar 1., Yeşiller 2.   ***
; ***      matrise bağlı. Veya Tek renkli 2 adet 8x8 LED in    ***
; ***      birincisi 1. ikincisi 2. matrise bağlı.             ***
; ***                                                          ***
; ***      8 adet HT16K33 aynı veri hattına bağlanabilir.      ***
; ***      Böylece 8 hane iki renkli veya 16 hane tek renkli   ***
; ***      LED dizisi yapılabilir.                             ***
; ****************************************************************
; **************************   Başlık   **************************
    title "HT16K33 I2C V1.0"    ; Proje Başlığı                   
    list    p=12f508            ; İşlemci tanımı                  
    #include <p12f508.inc>      ; İşlemci tanımlamalar dosyası    
    errorlevel  -302, -207      ; Gereksiz hata mesajlarını kaldır
    radix   dec                 ; Yazılım Desimal (On) tabanlı    
 
   __CONFIG _CP_OFF & _MCLRE_OFF & _WDT_OFF & _IntRC_OSC
 
; **************************  Sabitler  **************************
Led1    EQU 0   ; GP0
Led2    EQU 1   ; GP1
Led3    EQU 2   ; GP2
SW1     EQU 3   ; GP3
SCL     EQU 4   ; GP4
SDA     EQU 5   ; GP5
 
; *******************  Tanımlar / Kısayollar  *******************
#define Track   GPIO,2          ; Osiloskop Takip Sinyali        
#define DatLO   bcf GPIO,SDA    ; SDA = LOW                      
#define DatHI   bsf GPIO,SDA    ; SDA = HIGH                     
#define ClkLO   bcf GPIO,SCL    ; SCL = LOW                      
#define ClkHI   bsf GPIO,SCL    ; SCL = HIGH                     
 
; Kullandığım HT16K33 devresi ADAFRUIT HT16K33 devresinin klonu. 
; Adafruit in devresinde nedense matrix bire bir bağlanmamış.    
; Row7 (Bit7) Kolon7 ye bağlı, Row0-6 (Bit0-6) Kolon6-0 a bağlı  
; bu durumda yazılan datada;                                     
;          8 bit sırayla 76543210 iken,                          
;             Led sırası 07654321 oluyor.                        
; bu yüzden data yı göndermeden 1 bit sola kaydırıyoruz.  
; Tabii bu durumda komutlar bozuluyor. Bu bozulmanın
; önüne geçmek için komutları baştan ters yönde bozuyoruz.
; Örn;
; HT16K33 Adresi+1bit Write (0) = 11100000
;                                 +-------+
;                                 |       |
;                                 |       v 
;                                 _11000001       
#define HT_Adres        11000001b ; 1110000+0                     
#define HT_Osc          01000010b ; 00100001                     
#define HT_BlinkOff     00000011b ; 10000001                     
#define HT_Brightness   11011111b ; 11101111                     
 
; *******************  Değişkenler (25 Byte)  *******************
    cblock  0x07    ; Değişkenler başlangıç adresi               
;   isim      Addr No Açıklama                                   
    d1      ; 0x07 01 Döngü değişkenleri                         
    d2      ; 0x08 02 Döngü değişkenleri           
    d3      ; 0x09 03 Döngü değişkenleri           
    d4      ; 0x0a 04 Döngü değişkenleri          
    veri    ; 0x0b 05 okunan/yazılan veri                
    flag    ; 0x0c 06 işaretçi                    
    Ledler  ; 0x0d 07 Led Sıra 1                    
            ; 0x0e 08 Led Sıra 2                    
            ; 0x0f 09 Led Sıra 3                    
            ; 0x10 10 Led Sıra 4                    
            ; 0x11 11 Led Sıra 5                    
            ; 0x12 12 Led Sıra 6         
            ; 0x13 13 Led Sıra 7 (Ledler+6)
    sayac   ; 0x14 14 Döngü değişkenleri            
    patt    ; 0x16 15 Diyagonal Demo pattern i
    demo    ; 0x16 16 Döngü değişkenleri            
    OnSaniye; 0x17 17 Döngü değişkenleri
    TabloC  ; 0x18 18 Tablo Sayac
    TabloI  ; 0x19 19 Tablo Index
    Bos20   ; 0x1a 20                               
    Bos21   ; 0x1b 21                               
    Bos22   ; 0x1c 22                               
    Bos23   ; 0x1d 23                               
    Bos24   ; 0x1e 24                               
    Bos25   ; 0x1f 25                               
    endc
 
; ****************************************************************
; ***                      Kod Başlangıcı                      ***
; **********************  Donanım Ayarları  **********************
    ORG     0x0000          ; PIC Program hafızası başlangıç adresi
    movwf   OSCCAL          ; Fabrika OSCCAL ayar değeri       ***
Atla                        ;                                  ***
    clrf    GPIO            ; Bütün çıkışlar Low               ***
    movlw   00001000b       ; I/O                              ***
    TRIS    GPIO            ;                                  ***
    ;       +---------------- WakeUp on Pin Change iptal       ***
    ;       |+--------------- Weak Pull Ups (GP0,GP1,GP3) iptal***
    ;       ||+-------------- TMR0 kaynağı Fosc/4              ***
    ;       |||+------------- TMR0 Edge = Low2Hi               ***
    ;       ||||+------------ Prescaler WTD a                  ***
    ;       |||||+++--------- Prescaler = 1:1                  ***
    movlw   11001000b       ;                                  ***
    option                  ;                                  ***
AnaDongu                    ; Program ana döngüsü              ***
    ClkLO                   ; I2C Hattını idle yap             ***
    DatHI                   ; I2C Hattını idle yap             ***
    ClkHI                   ; I2C Hattını idle yap             ***
    ; XXXXXXXXXXX HT16K33 Ayarlar XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    call    I2C_Start       ; İletişimi başlat                 ***
    movlw   HT_Adres        ; Komut 0x7 Device Adres = 0x0     ***
    call    I2C_Write       ; Device ı çağır                   ***
    movlw   HT_Osc          ; Komut 0x21 : turn on oscillator  ***
    call    I2C_Write       ;                                  ***
    call    I2C_Stop        ; İletişimi bitir                  ***
 
    call    I2C_Start       ; İletişimi başlat                 ***
    movlw   HT_Adres        ; Komut 0x7 Device Adres = 0x0     ***
    call    I2C_Write       ; Device ı çağır                   ***
    movlw   HT_BlinkOff     ; Komut 0x81 : BlinkOFF            ***
    call    I2C_Write       ;                                  ***
    call    I2C_Stop        ; İletişimi bitir                  ***
                            ;                                  ***
    call    I2C_Start       ; İletişimi başlat                 ***
    movlw   HT_Adres        ; Komut 0x7 Device Adres = 0x0     ***
    call    I2C_Write       ; Device ı çağır                   ***
    movlw   HT_Brightness   ; Komut 0xEF : Max Parlaklık       ***
    call    I2C_Write       ;                                  ***
    call    I2C_Stop        ; İletişimi bitir                  ***
; *************  Ayarlar tamam şimdi bir şey göster  *************
Loop1                       ;                                  ***
Demo                        ; Diagonel akan çizgiler           ***
    movlw   11110000b       ;                                  ***
    movwf   patt            ; Demo Pattern                     ***
DemoL                       ;                                  ***
    movlw   250             ; Bu demo 10sn sürecek...          ***
    movwf   OnSaniye        ; 10sn sayacı                      ***
DemoLoop1                   ;                                  ***
    movlw   8               ; 8 Kolon = 8 tur                  ***
    movwf   demo            ; Demo döngü sayacı                ***
                            ;                                  ***
    call    I2C_Start       ; İletişim başlasın                ***
    movlw   HT_Adres        ; Device Adres = 0                 ***
    call    I2C_Write       ; Device ı çağır                   ***
                            ;                                  ***
    movlw   0               ; Hafıza adresi sıfır (İlk Kolon)  ***
    call    I2C_Write       ;                                  ***
                            ;                                  ***
DemoLoop                    ;                                  ***
    movfw   patt            ; Grafik                           ***
    call    I2C_Write       ; 1. Bloğa yaz (Çift sayılı adresler)*
    movlw   0               ; sonraki Byte ı boş bırakıyoruz   ***
    call    I2C_Write       ; (Tek sayılı adresler)            ***
    bcf     STATUS,C        ; CARRY i sıfırla                  ***
    rlf     patt,f          ; Grafiği 1 bit sola kaydır        ***
    btfsc   STATUS,C        ; Taşma varsa                      ***
    bsf     patt,0          ; Byte ın başına ekle              ***
                            ;                                  ***
    decfsz  demo,f          ; Tur sayacını eksilt              ***
    goto    DemoLoop        ; Sıfır değilse sonraki tura atla  ***
                            ;                                  ***
    call    I2C_Stop        ; 8 kolonda yüklendi. İletişimi kes***
                            ;                                  ***
    bcf     STATUS,C        ; Grafik 8 bitlikti, 8 turda ilk haline döndü
    rlf     patt,f          ; oysa kaymaya devam etsin istiyoruz, kaydırdık
    btfsc   STATUS,C        ; Taşma varsa                      ***
    bsf     patt,0          ; Byte ın başına ekle              ***
                            ;                                  ***
    call    Delay25fps      ; Görüntüyü saniyede 25 kez yenilemek için bekle
    decfsz  OnSaniye,f      ; OnSaniye Sayacı                  ***
    goto    DemoLoop1       ; sıfır olmadıysa Demo ya devam    ***
                            ;                                  ***
Demo2
; ****************************************************************
; *******************  Grafik Pattern demo  **********************
    movlw   TabloSonu-Tablo1 - 8 ; Grafik satır sayısı (Tablo boyu)
    movwf   TabloC          ; Tablo sayacına yükle
Tekrarla
    clrf    TabloI          ; Tablo Index i sıfır
DemoLoop2
    call    I2C_Start       ; İletişim başlasın
    movlw   HT_Adres        ; Device Adres = 0
    call    I2C_Write       ; Device ı çağır
 
    movlw   0               ; Sayfa adresi sıfır
    call    I2C_Write
 
    movlw   8
    movwf   demo            ; Demo döngü sayacı
DemoLoopb
    movfw   TabloI          ; Tablo index i
    call    Tablo1          ; index teki veri
    call    I2C_Write
    movlw   10000001b       ; 2. Byte ı boş bırakıyoruz
    call    I2C_Write
    incf    TabloI,f        ; index i bir ilerlet
    decfsz  demo,f
    goto    DemoLoopb       ; 8 byte lık iç döngü
 
    call    I2C_Stop        ; İletişimi bitir
 
    call    Delay25fps      ; Saniyede 12.5 kare olsun
    call    Delay25fps      ;
 
    movlw   7
    subwf   TabloI,f        ; index i 7 byte geri sar
    bsf     flag,7          ; Demo2 başladı göstergesi
 
    decfsz  TabloC,f        ; Tablo sayacını eksilt
    goto    DemoLoop2       ; Sıfır olmadıysa bu döngüye devam
 
    goto    DemoL           ; Baştan al
 
 
; ****************************************************************
I2C_Start
    ClkHI                   ; SCK High 
    DatHI                   ; SDA High 
    DatLO                   ; SDA Low  
    ClkLO                   ; SCK Low
    retlw   0
 
I2C_Stop
    DatLO
    ClkHI
    DatHI
    retlw   0
 
I2C_Write
    movwf   d4          ; Yedekle
    movwf   veri
    movlw   8
    movwf   d1
    clrc                ; CARRY i sıfırla
    rrf     veri,f      ; Veri yi 1 bit sağa at ??
    btfsc   STATUS,C    ; Taşma varmı?
    bsf     veri,7      ; Varsa verinin 7. bitini Set et.
i2cLoop ; XXXXXXX Bit Yaz XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    ClkLO               ; SCK LOW - Clock bitti                    
    btfsc   veri,7      ; Bit = 1 mi?
    goto    Bit1
    DatLO               ; SDA LOW - Data ancak SCK LOW iken değişir
    goto    Bitt
Bit1
    btfsc   veri,7      ; Bit = 1 mi?
    DatHI               ; 1 se SDA HI
 
Bitt
    ClkHI               ; SCK HI - Clock Başla   
    rlf     veri,f      ; Sonraki bit i sona getir
    decfsz  d1,f        ; bit sayacını 1 eksilt
    goto    i2cLoop     ; sıfır olmadıysa sonraki bit i yolla 
    ClkLO               ; SCK LOW - Clock bitti
    ; XXXXXXX Bit Yaz Bitti XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    DatHI         ; 2uS Delay
    ClkHI               ; SCK LOW - Clock başla  
    btfss   GPIO,SDA    ; ACK (LOW) Varmı?
    goto    ACK_Var
    ; ACK yok, tekrar dene
    bsf     Track       ; Hata var, haberci LED i aç
    movfw   d4          ; Veriyi yedekten al
    goto    I2C_Write   ; Tekrar yolla
ACK_Var
    ClkLO               ; SCK LOW - Clock bitti
    DatHI               ; SDA HI  - 
    bcf     flag,0      ; ACK flag ını temizle
    bcf     Track       ; Haberci LED i kapat
 
    retlw   0
 
Delay25fps; XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
; XX  İşlemci saniyede 1.000.000 işlem yapar.                          XX
; XX  HT16K33 ü güncellemek 2.058 işlem sürüyor.                       XX
; XX  Saniyede 25 kez (PAL TV standardı) güncelleme yapacaksak         XX
; XX  güncelleme arasının 1.000.000 / 25 = 40.000 işlem sürmesi gerek. XX
; XX  40.000 - 2.058 = 37.942 işlem eder.                              XX
; XX  Burada 37942 sürecek bir döngü ile gerekli zamanı harcıyoruz.    XX
; XX  Bu tip dömgüleri hesaplamak kolay değil. Dolayısı ile küçük bir  XX
; XX  yardım almak isterseniz; http://www.piclist.com/cgi-bin/delay.exe
; XX  adresini ziyaret edebilirsiniz.                                  XX
; XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Delay25fps ;37938 cycles
    movlw   0xA3
    movwf   d1
    movlw   0x1E
    movwf   d2
Delay25fps_0
    decfsz  d1, f
    goto    $+2
    decfsz  d2, f
    goto    Delay25fps_0
    retlw   0    ;4 cycles (including call)
; XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
; 
Tablo1
    addwf   PCL,f
    retlw   00000000b       ; 0000           
    retlw   00000000b       ; 0001           
    retlw   00000000b       ; 0002           
    retlw   11111110b       ; 0003   1111111 
    retlw   00010000b       ; 0004      1    
    retlw   00010000b       ; 0005      1    
    retlw   00010000b       ; 0006      1    
    retlw   11111110b       ; 0007   1111111 
    retlw   00000000b       ; 0008           
    retlw   01111100b       ; 0009    11111  
    retlw   11000110b       ; 0010   11   11 
    retlw   10000010b       ; 0011   1     1 
    retlw   11000110b       ; 0012   11   11 
    retlw   01111100b       ; 0013    11111  
    retlw   00000000b       ; 0014           
    retlw   01100100b       ; 0015    11  1  
    retlw   10010010b       ; 0016   1  1  1 
    retlw   10010111b       ; 0017   1  1 111
    retlw   10010010b       ; 0018   1  1  1 
    retlw   01001100b       ; 0019    1  11  
    retlw   00000000b       ; 0020           
    retlw   01111100b       ; 0021    11111  
    retlw   10000010b       ; 0022   1     1 
    retlw   10010010b       ; 0023   1  1  1 
    retlw   01011100b       ; 0024    1 111  
    retlw   00000000b       ; 0025           
    retlw   11111110b       ; 0026   1111111 
    retlw   10010010b       ; 0027   1  1  1 
    retlw   10010010b       ; 0028   1  1  1 
    retlw   10000010b       ; 0029   1     1 
    retlw   00000000b       ; 0030           
    retlw   11111110b       ; 0031   1111111 
    retlw   00000010b       ; 0032         1 
    retlw   00000010b       ; 0033         1 
    retlw   00000010b       ; 0034         1 
    retlw   00000000b       ; 0035           
    retlw   11111110b       ; 0036   1111111 
    retlw   10000010b       ; 0037   1     1 
    retlw   10000010b       ; 0038   1     1 
    retlw   01000100b       ; 0039    1   1  
    retlw   00111000b       ; 0040     111   
    retlw   00000000b       ; 0041           
    retlw   10111110b       ; 0042   1 11111 
    retlw   00000000b       ; 0043           
    retlw   11111110b       ; 0044   1111111 
    retlw   01110000b       ; 0045    111    
    retlw   00011000b       ; 0046      11   
    retlw   00001100b       ; 0047       11  
    retlw   11111110b       ; 0048   1111111 
    retlw   00000000b       ; 0049           
    retlw   00000000b       ; 0050           
    retlw   00000000b       ; 0051           
    retlw   00000000b       ; 0052           
    retlw   01000010b       ; 0053    1    1 
    retlw   10000110b       ; 0054   1    11 
    retlw   10001010b       ; 0055   1   1 1 
    retlw   10010010b       ; 0056   1  1  1 
    retlw   01100010b       ; 0057    11   1 
    retlw   00000000b       ; 0058           
    retlw   01111100b       ; 0059    11111  
    retlw   10000010b       ; 0060   1     1 
    retlw   10000010b       ; 0061   1     1 
    retlw   10000010b       ; 0062   1     1 
    retlw   01111100b       ; 0063    11111  
    retlw   00000000b       ; 0064           
    retlw   01000010b       ; 0065    1    1 
    retlw   11111110b       ; 0066   1111111 
    retlw   00000010b       ; 0067         1 
    retlw   00000000b       ; 0068           
    retlw   01101100b       ; 0069    11 11  
    retlw   10010010b       ; 0070   1  1  1 
    retlw   10010010b       ; 0071   1  1  1 
    retlw   10010010b       ; 0072   1  1  1 
    retlw   01101100b       ; 0073    11 11  
    retlw   00000000b       ; 0074           
    retlw   00000000b       ; 0075           
    retlw   00000000b       ; 0076           
    retlw   00110000b       ; 0077     11    
    retlw   01001000b       ; 0078    1  1   
    retlw   11011100b       ; 0079   11 111  
    retlw   01111110b       ; 0080    111111 
    retlw   11111100b       ; 0081   111111  
    retlw   01111000b       ; 0082    1111   
    retlw   00110000b       ; 0083     11    
    retlw   00000000b       ; 0084           
    retlw   00000010b       ; 0085         1 
    retlw   00000111b       ; 0086        111
    retlw   00000111b       ; 0087        111
    retlw   00000110b       ; 0088        11 
    retlw   11111100b       ; 0089   111111  
    retlw   10000000b       ; 0090   1       
    retlw   01000000b       ; 0091    1      
    retlw   00000000b       ; 0092           
    retlw   00111100b       ; 0093     1111  
    retlw   01000010b       ; 0094    1    1 
    retlw   10101001b       ; 0095   1 1 1  1
    retlw   10000101b       ; 0096   1    1 1
    retlw   10000101b       ; 0097   1    1 1
    retlw   10101001b       ; 0098   1 1 1  1
    retlw   01000010b       ; 0099    1    1 
    retlw   00111100b       ; 0100     1111  
    retlw   00000000b       ; 0101           
    retlw   00000000b       ; 0102           
    retlw   00000100b       ; 0103        1  
    retlw   00011100b       ; 0104      111  
    retlw   00011110b       ; 0105      1111 
    retlw   00011111b       ; 0106      11111
    retlw   00011111b       ; 0107      11111
    retlw   00111110b       ; 0108     11111 
    retlw   01011100b       ; 0109    1 111  
    retlw   01011100b       ; 0110    1 111  
    retlw   01111100b       ; 0111    11111  
    retlw   01011100b       ; 0112    1 111  
    retlw   01011110b       ; 0113    1 1111 
    retlw   01111111b       ; 0114    1111111
    retlw   00111111b       ; 0115     111111
    retlw   00011110b       ; 0116      1111 
    retlw   00011100b       ; 0117      111  
    retlw   00000000b       ; 0118           
TabloSonu
    retlw   0x0             ; Ölçüm/Test için 
    retlw   0x0             ; boş bırakılmış  
    retlw   0x0             ; hafıza....      
    retlw   0x0             ;
    retlw   0x0             ;
    retlw   0x0             ;
    retlw   0x0             ;
    retlw   0x0             ; 0126
 
 
 
    org     0x01f0
    retlw   0               ; 12f508 in yazılım
    retlw   0               ; ile ilgili bilgi 
    retlw   0               ; saklayacak yeri  
    retlw   0               ; yok.             
    retlw   3               ; Sürüm Numarası.  
 
 
    END
 
Projemiz:

PIC12F508 ve HT16K33 ile 8x8 LED sürümü

Devrenin BreadBoard'a kurulması


Malzeme Listesi
  1. Keyestudio HT16K33 8x8 LED Modülü
  2. PIC12F508 (dorukanstore.com | direnc.net)
  3. 10k direnç ( Hurda kutusunda )
  4. Breadboard, koblo vs. (Size kalmış)

PIC Programcı: Expkits PK3
NOT: Proje MPLAB IDE v9.82 ile derlenmiştir.
İlgili Dosyalar:
Asm Dosyası : İndir  ( 0 indirme )
Hex Dosyası : İndir  ( 0 indirme )

Neden olmasın?


En Alt??