örnek usart kesmesi isteği

Başlatan Maxim, 07 Ekim 2008, 19:59:05

Maxim

selamlar ,

proton+ için bir tane örnek usart kesme örneği aramaktayım ,

hardware olarak seri bilgi gönderme ve almayı interrupt kullanarak gerçekleştirmek için .

hrsout veya hrsin ile değil ,
ON_HARDWARE_INTERRUPT goto KESME
gibi

örnek olmasada olur ,
yani sırayla ne yapılması gerekiyor o da olur

teşekkürler

pro73

Include "PROTON_4.INC"

      Symbol Buffer_size = 16            ' Sets the size of the ring buffer
      Dim Buffer[Buffer_size] As Byte      ' Array    variable for holding received characters
      Dim Index_in   As   Byte         ' Pointer - next empty location in buffer
      Dim Index_out   As   Byte         ' Pointer - location of oldest character in buffer
      Dim Bufchar      As   Byte         ' Stores the character retrieved from the buffer
      Dim I         As   Byte         ' loop counter
      Dim Col         As   Byte         ' Stores location on LCD for text wrapping
      Dim Errflag      As   Byte         ' Holds error flags

       Symbol RCIF   = PIR1.5            ' Alias RCIF (USART Receive Interrupt Flag)
      Symbol OERR   = RCSTA.1            ' Alias OERR (USART Overrun Error Flag)
      Symbol CREN   = RCSTA.4            ' Alias CREN (USART Continuous Receive Enable)
      Symbol LED = PORTD.0             ' Alias LED to PORTD.0

'----------------------------------------------------------------------------------------        
' Initialise variables
      DelayMS 200                     ' Wait for the power supply to stabilise
       Errflag = 0
       Index_in = 0
      Index_out = 0
      I = 0
      Col = 1

      Cls                        ' Clear LCD
      INTCON = %11000000            ' Enable interrupts
      On Interrupt GoTo SerialIn      ' Declare software interrupt handler routine
      PIE1.5 = 1                  ' Enable interrupt on USART

' MAIN PROGRAM STARTS HERE - Blink an LED at 1Hz

Loop:   High LED                    ' Turn on LED connected to PORTD.0
       For I = 0 To 250            ' Delay for .5 seconds (250*2mS)
          DelayMS 2               ' Use a short Delayms within a loop
      Next                     ' Instead of one long delay
       Low LED                    ' Turn off LED connected to PORTD.0
       For I = 0 To 250            ' Delay for .5 seconds (250*2mS)
           DelayMS 2               ' Use a short Delayms within a loop
      Next                     ' Instead of one long delay

Display:                        ' Dump the buffer to the LCD
      If Errflag  > 0 Then Error1      ' Handle error if needed
      If Index_in = Index_out Then Loop   ' loop if nothing in buffer

      GoSub Getbuf               ' Get a character from buffer   
      Print Bufchar               ' Send the character to LCD
      
      Inc Col                     ' Increment LCD location
      If Col > 20 Then            ' Check for end of line
         Col = 1                  ' Reset LCD location
         Print At 2,1,Rep " "\20 , $FE,2   ' Clear line-2 of LCD and Tell LCD to return home
      EndIf

      GoTo Display               ' Check for more characters in buffer
       
'----------------------------------------------------------------------------------------
' Subroutines

      Disable                     ' Don't check for interrupts in this section

Getbuf:                           ' Move the next character in buffer to bufchar
      Index_out = (Index_out + 1)         ' Increment index_out pointer (0 to 63)
      If Index_out > (Buffer_size - 1) Then Index_out = 0   ' Reset pointer if outside of buffer
      Bufchar = Buffer[Index_out]         ' Read buffer location
      Return

'----------------------------------------------------------------------------------------
Error1:                              ' Display error message if buffer has overrun
      If Errflag.1  = 1 Then            ' Determine the error
         Print At 2,1,"BUFFER OVERRUN"   ' Display buffer error on line-2
      Else
         Print At 2,1,"USART OVERRUN"   ' Display usart error on line-2
      EndIf   
      Print $FE,2                     ' Send the LCD cursor back to line-1 home
      For I = 2 To Col               ' Loop for each column beyond 1
         Print $FE,$14               ' Move the cursor right to the right column
      Next
   
      Errflag = 0                     ' Reset the error flag
      CREN = 0                     ' Disable continuous receive to clear overrun flag
      CREN = 1                     ' Enable continuous receive
      GoTo Display                  ' Carry on
   
'----------------------------------------------------------------------------------------   
' Interrupt handler
SerialIn:                                 ' Buffer the character received
      If OERR  = 1 Then Usart_Error            ' Check for USART errors
      Index_in = (Index_in + 1)               ' Increment index_in pointer (0 to 63)
      If Index_in > (Buffer_size - 1) Then Index_in = 0   'Reset pointer if outside of buffer
      If Index_in = Index_out Then Buffer_Error   ' Check for buffer overrun
      HRSin Buffer[Index_in]                  ' Read USART and store character to next empty location
      If RCIF = 1 Then SerialIn               ' Check for another character while we're here

      Resume                              ' Return to program

Buffer_Error:
      Errflag.1 = 1                        ' Set the error flag for software
' Move pointer back to avoid corrupting the buffer. MIN insures that it ends up within the buffer.   
      Index_in = (Index_in - 1) Min (Buffer_size - 1)   
      HRSin Buffer[Index_in]                  ' Overwrite the last character stored (resets the interrupt flag)
Usart_Error:
      Errflag.0 = 1                        ' Set the error flag for hardware   

      Resume                              ' Return to program
proton örnegi

teknikelektronikci

https://www.picproje.org/index.php/topic,22232&highlight=

hocam burdada benim yazdigim usart (rfid icin ) kesme var kolay gelsin
Ey Türk istikbalinin evlâdı! İşte, bu ahval ve şerâit içinde dahi, vazifen; Türk İstiklâl ve Cumhuriyetini kurtarmaktır! Muhtaç olduğun kudret, damarlarındaki asil kanda mevcuttur!

Maxim

ama arkadaşlar bu örneklerin ikiside software interrupt ,

yani
"on interrupt goto kesme " dersek bunun ismi basic interrupt diye geçiyor ,
software interrupt sonuçta ,
kesmeye gitmesi için o anda yapılan işin sonuçlanması bekleniyor .
mesela delayms 1000 komutu sırasında kesme geldi ,
1 saniye bekleyeceksinizki kesmeye gitsin .


diğeri benim asıl yapmak istediğim ,
"on_interrupt goto kesme" yani hardware interrupt.
bu şekilde kullanıldığında ,o anda ne yapılıyorsa yapılsın bırakılır ve kesme işlemi başlatılır .
delayms 1000 komutu kesmeyi ilgilendirmiyor ,
bekleme yapılmadan kesmeye dallanıyor .

OG

PROTON'un SİTESİNDE (Forum)  örnek vardır sanırım. Ben PORT kesme örneğini oradan almıştım. Çalışmasıda mükemmel. PBP daki gibi komutun bitmesi falan beklenmiyor. Basic'de kesme olmuyor diyenlerinde dikkatine.
FORUMU İLGİLENDİREN KONULARA ÖM İLE CEVAP VERİLMEZ.

ground

Geçmiş zamanda kullandığım bir kod.. çalışıyor.

pc den gönderilen her 8bitlik veride iş yaptırabilirsin..
gelen veriyide aynen geri gönderiyor.  

Device  16F877A 
    XTAL    = 20
    Config  CP_OFF , BODEN_OFF , PWRTE_ON , WDT_OFF ,HS_OSC , LVP_OFF

Declare HSERIAL_BAUD 9600 
Declare HSERIAL_RCSTA %10010000 
Declare HSERIAL_TXSTA %00100000 
Declare HSERIAL_CLEAR = On 
Dim GELENVERI As word 

INTCON.7=1 
INTCON.6=1 
PIE1.5 = 1 

ALL_DIGITAL = TRUE

TRISA=0
TRISB=0
TRISC=0
TRISD=0
PORTA=0 
PORTC=0
PORTB=0
PORTD=0

On Interrupt GoTo intr 

main: 
 
     GoTo main 


Disable 
intr: 
If PIR1.5 = 1 Then 
GELENVERI = RCREG 
HSerOut[GELENVERI] 

'yapacağın işlemi buraya yaz 

 
EndIf 

PIR1.5=0 
Resume 
Return
⌒╮'╭⌒╮⌒╮.
╱◥██◣                  
| 田︱田田|              
╬╬╬╬╬╬╬╬╬

Picproje - Sözde değil özde paylaşım..

Maxim

minik bir soru :

usart transmit interrupt nasıl oluşuyor ?

*TXREG registerina gelen datalar ,
register dolguğu zaman TXIF bayrağını 0 yapıyor ,
TXIE biti de 1 ise ,interrupt oluşuyor .

buraya kadar bir yanlış varmı ?

*TXREG registeri bufferı nasıl çalışıyor ?
bir buffer varmı ? boyutu nedir ?

*word değeri atabiliyormuyuz ?

*int oluşması için o zaman buraya sürekli bilgi gönderip dolmasını sağlamamız lazım değilmi ?

slm

Maxim

anlayanlar bakabilirmi ?
hatam nerede ?

sadece gönderme ,
9600 baudrate


Device 16F628A
XTAL 4

DelayMS 500

Config INTRC_OSC_NOCLKOUT,WDT_OFF,PWRTE_ON,LVP_OFF,CP_OFF,MCLRE_OFF,BODEN_ON
ALL_DIGITAL = TRUE
CMCON=7

DelayMS 100

TRISA = %11111111
TRISB = %11111011

Dim B1 As Byte
             
Symbol GIE = INTCON.7 ' Global Interrupt Enable
Symbol PEIE = INTCON.6 'peripheral interrupt enable

Symbol TXIE = PIE1.4
Symbol TXIF = PIR1.4

While GIE=1 : GIE=0 : Wend         ' make sure to disable the Global interrupt
PEIE = 1  'pherepheral interruptlar açıldı.
TXIE = 1  'transmit interrupt açıldı
RCSTA=$90
TXSTA=$24
SPBRG=25

'------------------------------------------------------------------------
GIE=1                       'Enable Global interrupt ( 0 disable)
ON_Interrupt GoTo ISR       ' If interrupted go to ISR         
GoTo LOOP

ISR: '-----------------------

TXREG = B1

TXIF = 0
Context Restore


LOOP: '----------------------
B1 = B1 +1

DelayMS 100
GoTo LOOP

Tagli

@maxiboost; proton+ bilmiyorum ama yukarda sormuş olduğun birkaç soruyu cevaplayabilirim:

TXREG, PIC'in dışarı veri yollamak için kullandığı register'dır. Boş olduğu zaman ilgili bayrağı 1 yaparak kesme oluşturur, içine birşey yükleyerek veri aktarımını başlattığın zaman da bayrağı yine kendisi 0 yapar (senin yapmana gerek yok, zaten yapamazsın). Sanırım burdaki amaç TXREG'in yollama işi bittikçe kesmeye girip sıradaki diğer verilerin de yollanmasını sağlamak. Ancak burda bir register daha var o da TSR (Transmit Shift Register) ve buna erişemezsin. Aslında TXREG'e ilk kez veri attığında bu veri doğrudan TSR'a taşınır ve aktarılmaya başlar ve TXREG yine boşalarak kesme bayrağını 1'de tutmaya devam eder. Bu sırada TXREG'e yükleyeceğin ikinci veri bir çeşit buffer gibi olur (ve bayrağı indirir), TSR'ın işi bitince TXREG'den ikinci veriyi alarak orayı boşaltır ve kesme bayrağı yine kalkar. TSR'ın boş olup olmadığını kontrol etmek için de bir bit mevcut, TSR doluyken 0 olur. Yani 3 yöntemin var: TSR'ı kontrol etmek, kesme kullanmadan kesme bayrağını kontol etmek veya işi kesmeye bırakmak. ASM açısından düşünürsek TXREG'e word atamazsın ama proton+ seri yollanacak wordu ikiye bölüp bufferlar mı onu bilemem.

RXREG gelen verinin RSR'dan (Receive Shift Register) aktarıldığı yerdir. RSR kendisi 2'lik buffera sahiptir. Buna RXREG'i de eklersen 3 gibi düşünebilirsin. Başta hepsi boşken bir veri geldiğinde RSR bunu boş olan RXREG'e atacaktır ve bu ilgili kesme bayrağını kaldırır. Bundan sonra RSR gelen 1 byte daha tutabilir ve bu arada 2. bir byte'ı da almaya (shift yapmaya yani) devam edebilir. Ama bu yoldaki 2. byte bitmeden sen RXREG'i okuyup boşaltmazsan overflow hatası olur (bir hata bayrağı kalkar, temizlemek için senin birşeyler falan yapman gerekir). Burda da RXREG boşaldığında ve RSR'dan onu dolduracak yeni bir veri gelmediğinde ilgili kesme bayrağı kendisi iner.

Not: Bu anlattıklarımı 16F877A'nın datasheet'inden elde ettiğim bilgilere dayanarak söylüyorum. Diğer PIC modellerinde durum farklı olabilir.
Gökçe Tağlıoğlu

Maxim

@Tagli ,
yardımın için teşekkürler ,

birşey dikkatimi çekti ,
acaba senmi yanlış yazdın ,
TSR için boşken 1 ,dolu iken 0 yazıyor sheette ,
benmi yanıldım ?

slm

not:hala neden çalışmıyor bulamadım .

Tagli

Evet haklısın, aklımda yanlış kalmış... Kusra bakmayın. Yukardaki mesajımı düzelttim.

Programında ben de bir hata bulamamıştım. Olmaması gereken tek şey TXIF = 0 ama onun da gereksizliği dışında bir zararı yok, çünkü bir etkisi olmayacaktır. Ama dikkatli bakınca bir ayrıntı dikkatimi çekti: TRISB = %11111011 Aslında oldukça mantıklı görünüyor ama datasheet aynı fikirde değil:
Alıntı yapılan: "16F628A Datasheet"Bit SPEN (RCSTA<7>) and bits TRISB<2:1> have to be set in order to configure pins RB2/TX/CK and RB1/RX/DT as the Universal Synchronous Asynchronous Receiver Transmitter.
TRISB = %11111111 olması gerekiyor.
Gökçe Tağlıoğlu

Maxim

eveet ,

registere bilgiyi ascii karakter olarak göndermemiz gerekiyormuş ,
ben desimal olarak yolluyordum ,haliyle tuhaf karakterler görüyordum .

yani 5 sayısını 5 olarak değilde ,
5 + 48 = 53 olarak gönderince oluyor .

birde ,
sayıyı hane hane yollamak lazım ,
123 sayısını 1 kerede yollayamıyoruz ,
önce 1 ,sonra 2 sonrada 3 göndermemiz gerekiyor ,
tabi gene bunları ascii ye çevirerek ,

ascii ye çevirmek kolay ,
sayıları digitlere ayırmakta kolay ,

1- bu ayırdığım sayıları nasıl peş peşe txreg registerina verebilirim ?
table mı oluşturmak lazım ? takıldım burada ...

2-float sayıları nasıl göndericez ?
arada bir noktamı yollayacaz ?


:roll:

Tagli

Ayırdığın sayıları (yani onların ASCII kodlarını, eğer yanlış anlamadıysam) hafızada (General Purpose Register'larda) geçici olarak bir bölgede tut. Bu bölge sıralı olsun, böylece FSR ve INDF kullanarak (yani dolaylı adresleme ile) ordakileri sırayla okuyup TXREG'e yazabilirsin. Yapman gereken tek şey daha önceden bahsetmiş olduğum 3 yöntemden biriyle veri yollamaya hazır olup olmadığını kontrol etmek (ki ben kesme bayrağını kesme kullanmadan yoklamayı tercih etmiştim...) ve hazır oldukça geçici alandan bir bir sonraki değeri okuyup yollatmak.

Aslında olay alıcı tarafına da bağlı. ASCII olarak yollamak zorunda mısın? Böyle bir zorunluluk yoksa float sayıları normal olarak yollayabilirsin - daha önce bunu başka bir başlık altında uzun uzun tartışmıştık - hatta float sayının nasıl ifade edilecebileceğine de sen karar verebilirsin eğer alıcı tarafındaki programla oynama imkanın varsa.
Gökçe Tağlıoğlu

Maxim

bu konuda sorunlar devam ediyor  :(

bir kere aynı anda başka kesme kullanamıyorum ,
sanki sürekli usart transmit kesmesi oluştuştuğundan başka kesmeye bakamıyor gibi ,

Tagli

Adamlar böyle birşey tasarladıklarına göre insan "Vardır bir hikmeti..." diyor ama açıkçası ben hiç transmit kesmesine ihtiyaç duymadım. Bu kesme, gönderme sırasında başka işlemler de yapıyorsan PIC'in "TXREG boşaldı, haberin olsun, bence TXREG'e veri yükle de ben arka plandan veri göndermeye başlayayım." demesi gibi birşey. Ben gönderme sırasında PIC'e başka işlemler yaptırmadığım için TXIF bayrağını kendim kontrol ediyorum kesme kullanmadan, yani 1 olana kadar döngüye sokuyorum.

Transmit kesmesi ilk yüklemede arka arkaya iki defa oluşur. Çünkü ilk yüklediğin veri doğrudan TSR'a aktarılır ve TXREG yine boşa çıkar. Gönderme işlemin bitince bunu bir şekilde algılayıp TXIE'yi kapatmalısın, yoksa yollayacak verin olmadığı halde kesmeye gidersin. Sanırım gönderilecek veri sayısını tutan bir sayaç işini görecektir. Kesme içinde veriyi TXREG'e yükledikçe sayacı azaltırsın ve 0 olduğunda TXIE'yi kapatırsın. Bunu yapmazsan veri göndermediğin her an kendini kesmede bulursun, yani PIC "Bana iş ver!" diye bağırır  ;)
Gökçe Tağlıoğlu