Ufak tefek ipuçları

Başlatan alisumer, 04 Ocak 2024, 14:39:30

alisumer

nekadar işinize yarar bilmiyorum ama programlama yaparken kullanırken işinize yarayacak denediğim ve işime yarayan bazı algoritmalar oluyor .bunlar genellikle deveye hendek atlatmak yerine köprüden geçirmeyi sağlayan kestirme yollar,
Bir örnek verecek olursam ortalama alma yöntemini kullanmayan yoktur genellikle okuduğumuz bir analog verinin nispeten daha stabil olmasını sağlar tabi işlemci için zaman harcayan bir işlem ard arda yaptığımız okumaları toplamak sonrasında okuduğumuz sayı adedine bölmek. kestirme olacak bir yöntem ise eğer kesin bir kuralı yoksa okuma adedinizin örneğin illede 10 okuma yapıp ortalamasını almanız gerekmiyorsa işlemci için en fazla süreyi harcayan bölme işleminden(32bit işlemlerde ASM de 8mhz osc için ortalama  500us) kurtulabilirsiniz. bu okuma sayısını 2 lik tabanda katlar şeklinde verirseniz sadece sağa kaydırarak birkaç çevrim ile iş hallolabilir örneğin 2 ye bölmek için değeri bir sağa kaydırmanız 4 e bölmek için iki 8 e bölmek için 3, 16 ya bölmek için 4 sağa kaydırmanız yeterli ve bu işlemde 4 sağa kaydırma  sadece 8mhz osc için 2us sürer.32 ye bölmek ise 2,5us .ve bu böylece katlayarak devam etse bile harcayacağınız süre sadece bir komut süresi kadar olur.işe yarar 
Hep meraktan

elektro77

Alıntı yapılan: alisumer - 04 Ocak 2024, 14:39:30nekadar işinize yarar bilmiyorum ama programlama yaparken kullanırken işinize yarayacak denediğim ve işime yarayan bazı algoritmalar oluyor .bunlar genellikle deveye hendek atlatmak yerine köprüden geçirmeyi sağlayan kestirme yollar,
Bir örnek verecek olursam ortalama alma yöntemini kullanmayan yoktur genellikle okuduğumuz bir analog verinin nispeten daha stabil olmasını sağlar tabi işlemci için zaman harcayan bir işlem ard arda yaptığımız okumaları toplamak sonrasında okuduğumuz sayı adedine bölmek. kestirme olacak bir yöntem ise eğer kesin bir kuralı yoksa okuma adedinizin örneğin illede 10 okuma yapıp ortalamasını almanız gerekmiyorsa işlemci için en fazla süreyi harcayan bölme işleminden(32bit işlemlerde ASM de 8mhz osc için ortalama  500us) kurtulabilirsiniz. bu okuma sayısını 2 lik tabanda katlar şeklinde verirseniz sadece sağa kaydırarak birkaç çevrim ile iş hallolabilir örneğin 2 ye bölmek için değeri bir sağa kaydırmanız 4 e bölmek için iki 8 e bölmek için 3, 16 ya bölmek için 4 sağa kaydırmanız yeterli ve bu işlemde 4 sağa kaydırma  sadece 8mhz osc için 2us sürer.32 ye bölmek ise 2,5us .ve bu böylece katlayarak devam etse bile harcayacağınız süre sadece bir komut süresi kadar olur.işe yarar 
Biliyorum siz asm cisiniz ama pbp de bir örnek vermeniz mümkün mü?
"Eğer bir konuyu öğrenmek istiyorsan o konunun öğretmeni ol; daha iyi öğrenmek istiyorsan o konuda bir kitap yaz; daha da iyi öğrenmek istiyorsan yazdığın kitabi oku"

alisumer

hatırladığım kadarıyla pbp de de kaydırma işlemi makro kısmında asm kodu olarak gene kaydırma işlemi yapıyor bir farkı olmaz pbp de de kullanılabilir ama kod kısmını basic ustalarına bırakiyim unuttum galiba komut hangisiydi :) :D
Hep meraktan

alisumer

sanırım "değer=değer>>4" gibi birşey olması gerekiyor 16 ya bölmeyi yapar
Hep meraktan

alisumer

sıkça kullandığım diğer bir yöntem koşullu dallanmalarda sık kullanılan eşit değilse yada eşitse koşulu için çıkarma yapmak yerine iki değerin eşit olması halinde  "xor" işleminin 0 değerini vermesi sonucu  STATUS registerin "Z" bayrağının "1"olmasıdır.
a=21
b=21
movf a ,w
xorwf b,w
btfss status ,z
goto  esitdegil
goto esit 
Hep meraktan

alisumer

#5
bana kolaylık sağlayan başka bir yöntem ise dizi değişken tanımladığımda örneğin "a" değişkeni 32 bitlik bir değişken ise ve değişken tanımlama kısmında da bu uzunluk belirtilmişse sabit vereceğim değerlerin "FSR"ve "INDF" registerleri kullanılarak  verilmesi olabilir hatta bunun kolaylık olsun diye bir makrosunu da yazmıştım her adrese ayrı ayrı değerleri bulup yazmak yerine tek seferde kafa karıştırmadan yazmamızı sağlayacaktır.
cblok 0x20
A  : 4
endc
;kullanımı "PAKET32 6789551,A " Hex karşılığı"0x6799AF"   şeklindedir   
                              ;normalde ilk A nın ilk byte na 0xaf ikincisine 0x99 üçüncüsüne 0x67 yi tek tek yazmak daha zoru bu sayıları bulmak.              
PAKET32 MACRO Var, Address ;
    BANKSEL Address 
    movlw        Address ;
    movwf        FSR                    ;fsr ye A nın adresini yükler yani 0x20 adresini
    movlw        Var & H'FF'            ;;en değersiz byte filtrelenip yazılır
    movwf        INDF                  ;fsr nin işaretlediği adrese değeri yazar
    movlw        Var >>8 & H'FF'        ;;değer 8 bit sağa kaydırılır filtrelenip fsr 1 arttırılır(bir 
    incf        FSR,F                  ;bir sonraki ram bölgesi için fsr bir artar
    movwf        INDF                  ;indf ile 8 sağa kaydırdığımız değer 2.byte olarak yazılır
    movlw        Var >>16 & H'FF'      ;gerisi aynı devam ediyor 
    incf        FSR,F
    movwf        INDF 
    movlw        Var >>24 & H'FF'
    incf        FSR,F 
    movwf        INDF 
    ENDM  
konu aslında makro konusu değil ama fsr ve indf  kullanımı ardışık değer verme işlemlerinde sıraya dizme işlerinde çok fazla hız katar bilmem iyi bir örnekmi ama kullanımı hakkında en çarpıcı örneklerden biri
Hep meraktan

alisumer

ASM yazanların çilesi bank geçişleridir sakladığınız veri ilk banka sığmadığında işlemin sürekli bank değiştirme ile devam etmek zorunda kalır böyle durumlarda tüm banklardan ortak erişilebilen 0x70 ile 0x7f arasındaki ram adreslerini hatırlatıcı ve bayrak verilerini depolamada bolca kullanın.işi oldukça hızlandırıyorlar 
Hep meraktan

alisumer

#7
mplab ide de kullandığım kendi simulasyonu (MPLAB SIM) "SPI" işlemi haricinde çok iyi çalışıyor onda nedense bayrağı sıfırlayamıyor. sorunsuz tüm verileri görebilmek için ise değişken tanımlamalarının "udata" a res .. şeklinde global değişken tanımlanması halinde simulasyonda değişken adları ile değerleri takip edebiliyor , cblock yada equ tanımlamaları malesef simulasyonda sadece register adresi olarak takip ediliyor.Sağladığı yararlara örnek olarak çevrim süresini çok ayrıntılı bir şekilde hatasız veriyor. disassembly listing bölümünde tıklayarak simulasyonu yürüttüğünüzde makro ve alt programların içerisindeki işlemleri de adım adım görebiliyor verilerini takip edebiliyorsunuz view bölümünden görmek istediğiniz verileri seçebilir debug bölümünden ayarlamalar ve kesmeler koyabilirsiniz.en önemlisi harici bir simulasyon programına ihtiyaç duymadan işinizi görmesi ve bedava olması :)



Hep meraktan

designer.21

verdiğiniz bilgiler için çok teşekkür ederiz hocam. kaynak bakımından sıkıntı çektiğimiz ASM ile ilgili yaptığınız paylaşımlar bize fayda vereceği gibi farklı amaçlar için farklı kombinasyonları da kullanabilme becerisi kazandıracaktır.
emeğinize kaleminize sağlık, takipteyiz hocam

alisumer

yavaş yavaş bende öğreniyorum böylelikle motive ediyor beni paylaşmak ben teşekkür ediyorum umarım işe yarar
Hep meraktan

alisumer

#10
biraz basitinden olacak ama en çok unutulan konudur (kendimden biliyorum)RLF yada RRF komutları kullanılıyorken status C bitinin kaydırdığımız registere aynı yönden giriş yapacağını unutmayınız çoğu durumda göz ardı edilir C nin durumu hatalara neden olur bu yüzden de  örneğin bir 8 bitlik kayan ışık projesi için şu kod yanlış çalışabilir art arda iki ledi birlikte yakabilir
call gecikme
rlf portb ,f
çünkü gecikme alt rutininden çıkışta C bayrağının durumu öngörülemeyebilir yada daha öncesinde C yi tetikleyen başka bir kod vardır. Aslında C bitinin kararsızlığı yani çıkarma toplama işlemlerinde taşma olduğunda farklı kaydırma işlemlerinde farklı çalışmasından bu durum kaynaklanır ve unutulur.bunu engellemenin en tembel işi yolu
call gecikme
bcf status ,c
rlf portb ,f 
dir böylece bir komut süresi kaybederek olası sıkıntıdan kurtulabiliriz
Hep meraktan

alisumer

#11
Timer kesmesi kullanılan biraz komplike programlarda ufak bir ipucu : bir senaryoda adxl345 ile eğime göre bir servoyu kontrol etmek istiyorsunuz, fakat servonuzun adxl nin parazitlerinden etkilenmemesi için median alıyorsunuz ve tabiki map fonksiyonu kullanıyorsunuz bu işlem süresini de simulasyonda yaklaşık olarak 17 ms ye sabitlediniz kesmeye girmek için geriye kalan 3 ms süresince beklemek zorundasınız çünkü tekrar okuma yaparsanız zaman yetişmeyecek bir kısmında verileriniz bozulacak öyle kesmeye girecektir.böyle durumlardan kendi oluşturduğunuz bayrakları kullanıp kolayca kurtulabilirsiniz şöyleki.program başında bir bayrak değişkeni tanımlar ve ana döngünün en başında bu değişkenin örneğin 0. bitini low yaparsınız.tüm işlemler bitince bekle diye bir adrese dallandırır ve burada
udata 20
bayrak res 1
ayarlar:
...
...
bcf bayrak ,0

loop:
call adxl_oku
call map
call diz
call sirala
call median_al

....
....
....
bekle:
btfss bayrak ,0
goto bekle
bcf bayrak ,0
goto loop
geri kalan bu süreyi bekle içinde geçirir ve kesmeye girersiniz buradaki bekleme bir zamana bağlı bekleme değil de bayrağa bağımlı bir bekleme olduğundan geçen süre sizi ilgilendirmez buna kesme zamanı önemlidir kesme sonunda ise ayrılırken de
kesme:
.....
.....
.....
AYRIL:  
        BSF    bayrak    ,0              
        MOVLW    .100
        MOVWF    TMR0
        BCF        INTCON    ,T0IF        
        RETFIE

dediğinizde işlemi hiç pause fonksiyonu kullanmadan ve zaman kayması yaşamadan halledersiniz. işin özeti sonrasında programa hatırlatmak istediğiniz her şey için donanım bayrakları dışında da bol bol bayrak kullanın  kolay gelsin.
Hep meraktan

alisumer



mplab ide tools menüsü içerisinde DMCI modülü simülasyonda istediğiniz değişkenlerin değerini slider kullanarak değiştirmenize olanak tanır.ayarlamak için ise açılan ekranda sliderin üzerine sağ tıklayıp değişken adresi değişken boyutu vs bilgileri girmeniz yeterli bu değerlerle simülasyon çalışırken oynamak sisteminizin çalışması hakkında çok yararlı bilgiler verir size
Hep meraktan

alisumer

#13
watchdog timer hakkında biraz konuşmak isterim kendisinin fiziksel bir registeri yok (en azından benim kullandığım serilerde) 31 khz lik dahili osilatör ile çalışıyor bu osilatör uyku modunda bile susmadığından uykudan uyandırma işi için de watchdog timer kullanılabiliyor. en çok kafa karıştıran kısmı ise zaman ayarlaması kendisi 31 khz sinyal ile saydığından bölme oranı olmadan yaklaşık 32 us de bir adım atıyor.diğer timerlerin aksine tek bitlik bir timer aslında yani adımını attığı an reset veya uyandırmaya gidiyor.bu yüzden de kendisi iki adet bölücü ile kullanılabilir durumda biri option registerde 1/1 ile 1/128 arasında diğeri de 16 bit derinliğinde wdtcon(modele göre adı değişebilir) registerinde 1/32 den 1/65536 ya  kadar peki hesaplama nasıl yapılıyor bir bakalım "option"daki bölme oranını 1/1 e ayarladık wdtcon daki bölme oranını da 1/32 ye ayarladığımızda zaman gecikmesi 32us * 32 =1024 us oluyor yani 1 ms minimum reset süresi peki maksimum nekadar süre verebiliriz.OPTION dan 1/128 ve wdtreg den 1/65536
o zaman da 32us*128*65536= 268.435.456us yani yaklaşık 268 saniye sanırım bölme oranları nasıl işliyor anlaşılmıştır.
peki watchdog timer ne işe yarıyor.Örneğin
        
      BTFSS  PIR1 ,SSPIF
      GOTO    $-1  
      RETURN    
böyle bir kod kullanımı spi haberleşmesi için kendi bilgi sayfasında da mevcuttur.riski ise bayrağın bir parazit nedeni ile kalkmama olasılığı olmasıdır.bir senaryo şöyle olabilir pic işlemciler 4 seviye boru hattı ile çalışır bu bir komutun arka planda 4 saat darbesinde çalışmasını doğurur bu esnada önceki komutun ve sonraki komutun boru hattında işlemde olmasını sağlar iyi birşeydir ama parazit geldiğinde clock frekansımızı işlemcinin donanımsal olarak limiti olan frekansın arasına bir darbe de kendi koyar boru hattındaki işlem bitmeden bir adım fazladan atmasına neden olur.o beklediğimiz bayrak master de bizim işlemcimiz olduğundan hiç bir zaman kalkmaz işlemci aynı satırlarda donar.
watchdog timer aslında bizim bitme süresini az çok kestirdiğimiz (özellikle ASM için böyle) önemli işlemlerde o sürenin biraz daha fazlasını vererek eğer makul sürede o komuttan çıkamaz ise işlemcimize reset atmamızı sağlar.
daha basit bir senaryo ise bir 30 ms gecikme sağlayan pause komutunda
              movlw      .235
            movwf      _TMP0
            movlw      .78
            movwf      _TMP1
            decfsz      _TMP0,F
            goto        $-1
            decfsz      _TMP1,F
            goto        $-3
gibi bir asm kodu derlenir status z bayrağı kontrol edilerek işlem yapıldığından gene üstteki senaryo gereği bayrak kalkmadığında örneğin _TMP1 tekrar 255 ten başlar geri saymaya gecikme süremiz bir anda olur sana atıyorum 1 saniye halbüki pause içerisinde wdt yi 1/1024 bölme oranı ile
            BANKSEL    WDTCON
        MOVLW    0X05
        MOVWF    WDTCON
banksel _TMP0
            movlw      .231    ; önceki koddan 4  eksik  yukarıda kullandığımız komutları bir nebze telafi için
            movwf      _TMP0
            movlw      .78
            movwf      _TMP1
            decfsz      _TMP0,F
            goto        $-1
            decfsz      _TMP1,F
            goto        $-3
clrwdt ;yada clrf wdtcon ile timeri tamamen kapatabiliriz
32 ms ye kurabiliriz ve 2 ms gecikme ile de olsa işlemcimizi yeniden başlatabiliriz.kısacası hayati projelerde kullanın bence başarılar

 
Hep meraktan

alisumer

#14
sürekli üstüne koyanların bir gün başına gelecek sorun : kod büyüklüğünün mikro işlemciye ucu ucunu sığdırmaya çalışırken üç beş bir yerlerden kırpma ,kodu kısaltmaya çalışmak olduğunu ter dökerek öğrenmektir.
böyle durumlarda kodda bir çok yerde ayrı ayrı kullandığın aynı yada benzer kodları bir tek yere koymak ve CALL komutu ve bir algoritma ile çağırmak size bayağı bir yer kazandırabilir.bunun en bariz örneği bekleme komutlarıdır.örneğin kodun bir yerinde 50ms bekleme ve başka bir yerinde 100ms bekleme olduğunu varsayalım iki ayrı bekleme komutu yazmak yerine ard arda iki kere 50ms komutunu çağırmak size tek algoritma ile iki işi yapmanızı sağlayabilir böylece kodun uzunluğu 6-7 satır kısalır.yada bir çok bekleme komutu kullanıyorsanız örneğin 1ms, 5ms , 100ms beklemeler olsun bir değişken tanımlar ve tekrar sayısını 1ms için pic_delay programından çıkan koda eklersek;
code:
        ....
        ....
        MOVLW .100
        CALL paus1
        ......
        .......

        MOVLW  .5
        CALL paus1

paus1:
            MOVWF        BKLME    
TEKRAR:
            movlw      .151        ;BU HALİ ORİJİNAL 8MHZ KRİSTAL İÇİN 1 MS BEKLEME SÜRESİDİR
            movwf      _TMP0
            movlw      .3
            movwf      _TMP1
            decfsz      _TMP0,F
            goto        $-1
            decfsz      _TMP1,F
            goto        $-3
            DECFSZ      BKLME            ;BKLME SAYISINI EKLEYEREK ORİJİNAL KODU 
            GOTO        TEKRAR            ;KAÇ TEKRAR YAPACAĞIMIZ BİZE KALIR
            RETURN
            
kod kısaltmanın iyi bir yöntemidir şimdiden alıştırın kendinizi ben neredeyse tamamı bitmiş projeyi programda ufak bir revizyon yapınca işlemciye sığmadığında tüm kartları ve işlemcilerii değiştirme aşamasına geldiğimde aklım başıma geldi har vurup harman savurmuştum program hafızasını.bu yöntem diğer diller için de geçerlidir her bir pause yada delay komutu ayrı kod derler onlarda da kullanabilirsiniz.israf haramdır :)
 
Hep meraktan

Powered by EzPortal