Glcd' de kesme problemi

Başlatan mytap, 04 Haziran 2008, 01:46:21

mytap

Merhaba,
   Elimde 128X64 glcd var. Bununla 18f452 ile int girişleri okuyup ekrana bişeyler yazmaya çalışıyorum. girişten okunan frekans değerleri 2-3 khz arası değişiyor. Programda hassas bir interrupt var. Frekans yüksek olduğu için sürekli interrupt oluşuyor.
 
    Sorunum işlemcinin ekrana yazmaya çalıştığı anda tekrar interrupt rutinine gittiği için yazıların saçmalaması. Böyle bişey başına gelen varmı ? Çok çeşitli yollar denedim fakat olmadı bezmek üzereyim.

program şöyle bişey;

on_interrupt INT_RUTIN

Basla:
   Print at  1,1, dec3 SAYI
   delayms 10
goto Basla


INT_RUTIN:
;
;
;
Return
-------------------------------------------------------- hayırlı günler, iyi çalışmalar..  --------------------------------------------------------

karbal656

Merhaba;
birde şöyle dene:

on_interrupt INT_RUTIN
Basla:
delayms 10
goto basla

INT_RUTINI:
'kesmeler iptal
print At 1,1, dec3 sayi
delayms 10
' kesmeler aktif
RESUME


interrupt kesmesinde Return yerine Resume komutunu kullanırsan daha iyi olur.
başarılar.

Gurkan-Demirbas

Merhaba;
Hocam net olarak konuyu anlayabildiğimi zannetmiyorum; ama sanırım bir frekansmetre yapmaya çalışıyorsun.
Olasılıklar üzerinden bir-iki naçizane yorum yapmaya çalışmak isterim.

ISR'ye dallandığında register değerlerini dahili ram'e kaydettirip, ISR'den çıkarken tekrar yüklersen düzelebilir. Belki ISR'den döndüğünde kaldığı yerdeki register değerleri değiştiği için sapıtıyor olabilir.

GLCD'ye birşeyler yazdırırken interruptları disable edip, ekrana yazdırman bittikten sonra tekrar enable etmen de düzeltebilir ama bu durum programında istenmeyen durum yaratır mı bilemiyorum.

Eğer frekans metre yaptıysan; senin yerinde olsam, hardware interrupt yerine Capture kullanırdım (CCP). Böyleceikide birde programı yönlendirip timer ile uğraştırmak derdinden kurtulurdum.

Yazdığım ve isis'de simüle ettiğim bir frekansmetrenin kodunu paylaşmak isterim; ama realtime'da devreyi kurup denemedim !.... sadece bilgisayarda çalışmıştım. programa dikkat edersen, interruptlar enable edilmiyor ama ilgili yerlerde ilgili interrupt flag'ler kontrol edilip ona göre yürütülüyor

'****************************************************************
'*  Name    : CCP_Module.BAS                                      *
'*  Author  : [select VIEW...EDITOR OPTIONS]                    *
'*  Notice  : Copyright (c) 2008 [select VIEW...EDITOR OPTIONS] *
'*          : All Rights Reserved                               *
'*  Date    : 30.05.2008                                        *
'*  Version : 1.0                                               *
'*  Notes   :                                                   *
'*          :                                                   *
'****************************************************************
' Bu program PIC16F877A için yazılmıştır
'
' Input signal should be connected to RC2/CCP1

'----------------- Konfigürasyon Sigortaları--------------
@ DEVICE pic16F877A 
@ DEVICE PIC16F877a, HS_OSC
@ DEVICE pic16F877a, WDT_OFF
@ DEVICE pic16F877a, PWRT_OFF
@ DEVICE pic16F877a, BOD_OFF
@ DEVICE pic16F877a, LVP_OFF
@ DEVICE pic16F877a, CPD_OFF        ; Data Memory Code Protect
@ DEVICE pic16F877a, PROTECT_OFF    ; Program Code Protection

'----------------- LCD Konfigürasyonu --------------
Define  LCD_DREG        PORTD
Define  LCD_DBIT        0       
Define  LCD_RSREG       PORTD
Define  LCD_RSBIT       4
Define  LCD_EREG        PORTD
Define  LCD_EBIT        5
DEFINE LCD_BITS         4
DEFINE LCD_LINES        2   
       
DEFINE OSC              20        'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx  
    
capture	VAR PIR1.2			' CCP1 Yakalama bayrağı PIR1'in 2 nolu biti
overflow VAR	PIR1.0		' Timer1'in taşma bayrağı
period	VAR	WORD			
frekans	VAR	WORD			
frekans1	VAR	WORD		
frekans2	VAR	WORD			

    Pause 50       ' LCD'nin start-up'ı için bekle
    Lcdout $fe, $01   ' LCD'yi temizle
   

T1CON = %00000001
CCP1CON = %00000101
loop:
	IF (capture = 0) Then loop	' Yakalam gerçekleşene kadar bekle
	 
    period.lowbyte = CCPR1L		' Yakalanan değeri period değişkenine aktar (LOW)
    period.highbyte = CCPR1H	' Yakalanan değeri period değişkenine aktar (HIGH)
              
    IF overflow = 0 Then		' Eğer Overflow var ise atla
        frekans = (50000/(period+4))
        frekans1 = frekans / 10
        frekans2 = frekans - (frekans1*10)
        lcdout $FE ,$C0, "  ", DEC frekans1 ,",", Dec frekans2, " KHz   " 
	EndIF
     Pause 50
    capture = 0					' CCP1 yakalama bayrağını sıfırla
    
reset:
	IF (capture = 0) Then reset	' Bir sonraki periodun başlaması için bekle
	
    TMR1L = 0					' Timer1 low register'ı sıfırla
	TMR1H = 0					' Timer1 high register'ı sıfırla
	capture = 0					' Yakalama bayrağını sıfırla
	overflow = 0				' Taşma bayrağını sıfırla

	GoTo loop					' Başa dön
END


kolay gelsin

Gürkan

mytap

Merhaba

aslında devir başına 360 puls veren bir enkoderi okuyup onunla ilgili işlemler yapıyorum yani her pulsun büyük önemi var. Kesme rutininin içinde 10ms gibi zama dilimleri kullanmak zaten işi alt üst ediyor işlemciyi capture olarak ayarlasak bu sistemde ne kadar sağlıklı ve hızlı çalışır?
Interrupt mı yoksa Capturemi ?
-------------------------------------------------------- hayırlı günler, iyi çalışmalar..  --------------------------------------------------------

karbal656

Merhaba
10ms çoksa şöyle bir yol izlenebilir.Glcd nin stablize bir şekilde çalışması için.Bir değişken atarsın mesala Durum adında bu değişkeni her kesmede bir artırırsın ve değişkenin ulaştığı sayıya göre Glcd ye yazdırısın .
Örnek:

INT_RUTINI:
kesmeler iptal
Durum = Durum + 1
if Durum >1000 Then
Durum = 0
Print At 1,1, ..................
Endif
kesmeler aktif
Resume

mytap

Sizin kodları söyle bir yorumlarsak,

kesme rutininde zaten kesmeleri iptal ediyorsunuz bu iptal edilen süre zarfında işlemci encoderdeki verileri zaten okuyamıcak. işlemcimiz ana programa geldiğinde kaldığı yerden devam edicek misal 120 derecede olan encoder okumanın iptal edildiği (kesme rutininin içinde ) bir anda tekrar geldiği yerde 120 dereceyi bulacak. Aslında encoderin pozisyonu zaten değişmiş olacak. 1000 devirde saniyede  17 tur dönen bir motorda 1 turda 360 derece olduğuna baz alırsak açının ne kadar hızlı değiştiğini anlayabiliriz. bu hızı yakalayabiliyorum fakat  Glcd de stabil bir şekilde gösteremiyorum. Yazılar karman çorman görünüyor.
-------------------------------------------------------- hayırlı günler, iyi çalışmalar..  --------------------------------------------------------

Gurkan-Demirbas

Alıntı yapılan: "mytap"aslında devir başına 360 puls veren bir enkoderi okuyup onunla ilgili işlemler yapıyorum
Alıntı yapılan: "mytap"Interrupt mı yoksa Capturemi ?

Şimdi daha iyi anladım konuyu.
Hocam, programın isis'de problemsiz çalışıyor mu?
Burada(encoder'da) 2 şeyi ölçersin;
1) Motorun hızı : Enkoderdan gelecek olan pulse'lerin frekansını ölçüp motorun hızını hesaplarsın; bu durumda en etkili, hızlı ve de en iyi yöntem (bence!..) Capture modu'dur.
2) Motorun Pozisyonunu ölçersin : Burada, gelen pulse'lerin sayısı önemli; Bu yüzden interrupt kullanman gerekiyor bence. Ben olsam hardware interrupt pininden ziyade Timer/counter'ın counter modu'nu tercih ederdim. External Pulse sayısı, set edilen değere ulaştığında bir interrupt yaratılır.

Ama sanırım problemin uzağındayız, Interrupt'dan döndüğünde, kaldığı yerden devam etmesi gerekir. Etmiyorsa aklıma tek neden geliyor: ISR'ye dallandığında, registerlerdeki değerler ile ISR'den döndüğünde registerlerdeki değerler farklı oluyor, yani ISR'de register içerikleri değişiyor. ISR'nin başına ve sonuna save ve relod rutin'leri ekleyip deneyebilir misin?

Bu save ve reload ile ilgili daha önce tartışmıştık
https://www.picproje.org/index.php/topic,20269&highlight=

mytap

Program ISIS te ve gerçek anlamda aynı hatayı veriyor.
Ben encoderle açıları buluyorum bu açılara görede bazı işlemler yapıyorum. Tek problem ekranda okuyamam. Problem sadece bu Glcd ye yazarken kesme oluşuyor ve veriler ekranda tam yazamadan tekrar kesme ile karakterler bozuluyor. acaba lcdye bir sinyal göndersek her yazdığında durdursak yada bunun gibi bişey yapılabilirmi? SG12864J modeli bir Glcd

İlgilenenlere Teşekkürler....
-------------------------------------------------------- hayırlı günler, iyi çalışmalar..  --------------------------------------------------------

karbal656

Tekrar merhaba
Anlatımından anladığım kadarıyla 1sn de yaklaşık 6000 puls okuyorsun
buda şu demek glcd saniyede 6000 defa kesime uğruyor veya veri tazeleniyor.haliyle bu durumda dediğin olay gerçekleşiyor.  Kesme alt programında sadece glcd için bir sayaç belirleyip bu sayacı birer birer artırırsanız  mesala 6000'ne ulaşınca glcd ye yazarsa 1sn arayla veriyi tazelemiş olursunuz. buda stabil bir durum yaratır kanımca. Tabi veri ortalamasıda alabilirsiniz.
Başarılar.

ErsinErce

Lcd ye hangi sıklıkta veri gönderiyosunuz? Saniyede 5-6 defa ekranı tazeleyecek bir döngüyle denerseniz açıyı yakalamanız daha kolay olur (bence)

mytap

Timer0 ile 500ms lik bir zamanla veri gönderiyorum yine yazılar karışıyor. Hiç anlamadım derdinin ne olduğunu
-------------------------------------------------------- hayırlı günler, iyi çalışmalar..  --------------------------------------------------------

Gurkan-Demirbas

Hocam Allah rızası için şu programı koysan da bizi de bulmaca çözme derdinden kurtarsan;

Devre şeması yok, program yok, projede ne yapılması amaçlandığı ve sonucunda ne beklendiği konusunda bile net bir bilgi alamadık;
Bu veriler ışığında, bu yazdıklarımızdan daha fazla yardım edilmesini beklemek, haksızlık olur kanısındayım.

Gürkan

mytap

MaiN: 
 ON_INTERRUPT goto Rb01_rutin   
      '-

 Denetim:

if zaman1 > 30 then 
cls 
print at 3,2, "D:", DEC3 sayac
print at 23,2,"R:", dec4 zaman4 
endif
  
if zero_ok = 0 then sayac = 0
if menu_ok = 0 then tus_kontrol  

   goto denetim
   
RB01_RutiN:   

    if int0if = 1 and portb.1 = 0 then   ' yön tayini Enc_A
    sayac = sayac + 1    
    zaman2 = zaman2 + 1
    endif
    
    if int1if = 1 and portb.0 = 0 then  ' yön tayini Enc_B
     sayac = sayac - 1 
        zaman2 = zaman2 + 1
        endif
          
    if tmr1if = 1 then zaman1 = zaman1 + 1  
    if zaman1 > 36 then
zaman1 = 0
zaman4 = zaman2 * 2 / 6
zaman2 = 0 
tmr1if=0
timer1=0
endif         

if zero_ok = 0 then sayac = 0  
 
if sayac > 359 then sayac = 0                                               '-
if sayac < 0 then sayac = 359     
 
int1if = 0
int0if = 0 
TMR1IF = 0
gieh = 1 
if sayac = 10 then call on_aci            
if sayac = 20 then call yirmi_aci
'
'
'
'
return






if zaman1 > 30 then 
cls 
print at 3,2, "D:", DEC3 sayac
print at 23,2,"R:", dec4 zaman4 
endif
 burada lcdye 200-300 ms de bir yazıyorum ama sapıtıyor
-------------------------------------------------------- hayırlı günler, iyi çalışmalar..  --------------------------------------------------------

ErsinErce

Sorun farklı karakterler çıkması ise önceden yaşadığım bir olayı paylaşayım Protonda donanımsal kesme kullanınca yazmaçlardaki değerler değişiyordu sorunun kaynağı W,STATUS,FSR yazmaçlarının kesmeden önceki haline dönmemesiydi. Şimdi vereceğim kodları kesmeye girince ve kesmeden çıkarken kullanın büyük ihtimalle sizin probleminizde bu.

Macro halinde system_save ve system_restore şeklinde yazmanız yeterli

Kesmeye girince ;
SYSTEM_SAVE MACRO-
ASM-
; Context SAVE the essential registers
movff STATUS,_RAM_END ; Save the STATUS register
movff WREG,_RAM_END - 1 ; Save the WREG
movff BSR,_RAM_END - 2 ; Save the bank select register
movff FSR0L,_RAM_END - 3 ; Save low byte of FSR0
movff FSR0H,_RAM_END - 4 ; Save high byte of FSR0
movff FSR1L,_RAM_END - 5 ; Save low byte of FSR1
movff FSR1H,_RAM_END - 6 ; Save high byte of FSR1
movff FSR2L,_RAM_END - 7 ; Save low byte of FSR2
movff FSR2H,_RAM_END - 8 ; Save high byte of FSR2
movff PRODL,_RAM_END - 9 ; Save the multiply registers
movff PRODH,_RAM_END - 10 ; These require saving because the compiler uses them regularly.
movff TBLPTRL,_RAM_END - 11 ; Save the Table Pointer registers
movff TBLPTRH,_RAM_END - 12 ; These require saving because the compiler uses them regularly.
movff TABLAT,_RAM_END - 13 ; Save the code memory access register

; Save the compiler's SYSTEM variables
lfsr 0,_RAM_END - 14 ; Point FSR0 to the next available piece of memory in high RAM
lfsr 1,_SYSTEM_VARIABLE_COUNT - 1 ; Point FSR1 to the end of the SYSTEM variables in Access RAM
movlw _SYSTEM_VARIABLE_COUNT ; Form a loop for the amount of system variables used
movff POSTDEC1,POSTDEC0 ; Move the compiler's SYSTEM variables from Access RAM into high memory
decfsz WREG,F ; Decrement and skip if zero the variable counter
bra $ - 6 ; Keep placing variables until all done
VARIABLE _RAM_POINTER = (_RAM_END - 14) - _SYSTEM_VARIABLE_COUNT ; Point to the finishing point of the variable save
MOVLB 0  ; Reset BANK
ENDASM-
ENDM


Kesmeden çıkmadan hemen önce;
SYSTEM_RESTORE MACRO-
ASM-
; Restore the compiler's SYSTEM variables
lfsr 0,_RAM_END - 14 ; Point FSR0 to the start of the system variables stored in high memory
lfsr 1,_SYSTEM_VARIABLE_COUNT - 1 ; Point FSR1 to the end of the SYSTEM variables in Access RAM
movlw _SYSTEM_VARIABLE_COUNT ; Form a loop for the amount of system variables used
movff POSTDEC0,POSTDEC1 ; Move the compiler's SYSTEM variables from high memory into Access RAM
decfsz WREG,F ; Decrement and skip if zero the variable counter
bra $ - 6 ; Keep placing variables until all done

; Context RESTORE the essential registers and exit the interrupt
movff _RAM_END - 13,TABLAT ; Restore the TABLAT register
movff _RAM_END - 12,TBLPTRH ; Restore high byte of TBLPTR
movff _RAM_END - 11,TBLPTRL ; Restore low byte of TBLPTR
movff _RAM_END - 10,PRODH ; Restore high byte of PROD
movff _RAM_END - 9,PRODL ; Restore low byte of PROD
movff _RAM_END - 8,FSR2H ; Restore high byte of FSR2
movff _RAM_END - 7,FSR2L ; Restore low byte of FSR2
movff _RAM_END - 6,FSR1H ; Restore high byte of FSR1
movff _RAM_END - 5,FSR1L ; Restore low byte of FSR1
movff _RAM_END - 4,FSR0H ; Restore high byte of FSR0
movff _RAM_END - 3,FSR0L ; Restore low byte of FSR0
movff _RAM_END - 2,BSR ; Restore the bank select register
movff _RAM_END - 1,WREG ; Restore the WREG
movff _RAM_END,STATUS ; Restore the STATUS register
MOVLB 0               ; Reset BANK
ENDASM-
ENDM

mytap

Evet problemler aynıymış. Macro eklemeyi pek beceremedim fakat asm ile yazınca oldu. Teşekkürler bir şeyi daha öğrenmiş olduk bence güzel bir kaynak oldu sayenizde....
-------------------------------------------------------- hayırlı günler, iyi çalışmalar..  --------------------------------------------------------