Tanju Taşçılar, 3 Mayıs 2002
doc uC003-030502
Günümüzde yaygın olarak kullanılan ve mikroişlemciler tarafından işlenmesi oldukça
kolay olan seri haberleşme tiplerinin başında gelenlerden biri RS232'dir. RS232 asenkron
tipte bir seri haberleşmedir. Yani bitlerin belirlenmesinde bir referans işareti olan saat
işareti bulunmamaktadır. Bunun yerine bitlerin zamanlaması kullanılmaktadır. Bu da
böyle bir seri haberleşmenin zamanlamasını ön plana çıkarmaktadır.
Standart RS232'de haberleşme bir start biti ile başlar, genellikle 8 data bitinin
ardından bir veya iki stop biti ile sona erer. Data bitlerinin sayısı 5 ile 9
arası seçilebilir. Ayrıca stop biti öncesi parite biti kullanılabilir. Parite biti
iletişimdeki hataları azaltmak için kullanılabilir. Kullanımı seçimliktir. Hiç parite biti
kullanılmayacağı gibi kullanılan parite bitinin anlamına göre even, odd, mark ve space olarak
adlandırılan özelliklerde olabilir. Bu durumda birçok kombinasyon olabilmesine karşın
genellikle 8N1 şeklinde belirtilen, paritesiz 8 data biti ve bir stop biti şeklindeki kombinasyon
kullanılmaktadır. Ayrıca RS232 yalnızca protokol standardı değil aynı zamanda elektriksel
özelliklerin de belirtildiği bir standarttır. Ancak burada elektriksel standartları ile
ilgilenmeyeceğiz. Ayrıca eğer kendi sistemimizin içinde bu tür bir iletişim şeklini kullanıyorsak
yukarda belirtilenlere de uymak zorunda değiliz. Mesela 16 data biti olan bir protokol de
kullanabiliriz. Aslında burada inceleyeceğimiz örnek NRZ formatında bir seri iletişimi esas olarak
işlemektedir. NRZ formatı seri iletişimde kullanılan formatlardan biridir. Data ve
işaret için kullanılan lojik seviyeler bu formatta sabittir. Yani genel kullanımıyla burada
0 olan bit lojik 0, 1 olan bit lojik 1 seviyesinde olmaktadır.
Bu incelemede 8N1 formatını kullanacağız. Bu formatın işaret şekli aşağıda görülmektedir.
Bu şekilde de görüldüğü gibi, sinyal olmadığı durumda data hattı lojik 1 seviyesindedir. İletişim
0 olan start biti ile başlar. 8 adet data bitinden sonra 1 olan stop biti gelir.
Asankron olan RS232 iletişiminde zamanlama ile işlem yapılmaktadır. Bu durumda temel olarak alınan
zaman bir bit zamanına karşılık gelen zamandır. RS232'oe standart olarak 120 Baud'dan başlayan ve
115000'e kadar giden bit zamanlamaları kullanılmaktadır. Burada en çok kullanılan 9600 Baud değerini
kullanacağız. 9600 Baud'da bir bit zamanı 1/9600 saniye yani yaklaşık
104 mikrosaniyedir. Pic kullanılan
sistemlerde çok büyük bir çoğunlukla 4 MHz'lik bir kristal ve dolayısı ile 1 mikrosaniyelik komut zamanı
kullanılmaktadır. Biz de bunu temel alacağız. Değişik parametreler için isteyen kendi değişikliklerini
yapabilir.
Zamanlamanın önemli olduğu bu sistemde gerekli doğruluğu tutturabilmek için işlemcinin iletişim
boyunca başka işlerle rahatsız edilmemesi gerekmektedir. Bu konuda işleyeceğimiz biçiminde herhangi bir
interrupt kullanılmayacağı için işlemci iletişim boyunca yalnızca bu işle ilgilenecektir. Aslında böyle
bir durumda gerçek zamanlı bir işletim sisteminden söz edemeyeceğiz. Dolayısı ile yazacağımız program
bu şekilde olacaktır. Eğer gerçek zamanlı görevler yapacaksak bu tür bir programlamayı kullanmamız
uygun değildir. Bu durumda ya interrupt kullanmak veya zaman dilimlemesi sistemini kullanarak çok
katı program yazmamız gerekmektedir.
Zamanlama olayını bir de dışardan gelecek olan bilginin de asenkron olacağını düşünerek gözönünde
bulundurmamız gerekmektedir. Yani işlemcimiz başka bir iş yaparken dışardan bilgi gelmeye başlarsa
ve biz yeterince hızlı olarak bunu değerlendiremezsek gelen bilgiyi kaçırırız. Bu ilave durum da
program şeklimizi etkileyecektir. Genellikle bu bizi dışardan bir bilgi bekleyen ve bu bilgiye karşılık
bir işlem yapan ve sonunda da bir cevap veren sistemlerle sınırlı bırakacaktır.
Teknik olarak gönderme rutinini inceleyelim. Böyle bir rutinde bir bit zamanı olan 104 mikrosaniye
süresince 0 olan start biti ile başlarız. Bu bitin bitiminde ilk bit olan Bit0 için gerekli lojik seviyede
yine bit zamanı kadar bekler ardından diğer data bitleri için aynı işlemi yaptıktan sonra stop biti için
1 değerini bir bit zamanı kadar tutar ve rutinimizi sona erdiririz. Bu rutinde her değişiklik bitlerin
başlangıç anına denk gelmektedir.
;***SCI_Write
MOVWF S_Reg
MOVLW .8
MOVWF S_Counter
BCF Tx ;Start bit
GOTO $+1
GOTO $+1
GOTO $+1
GOTO $+1
CALL S_Delay
Wr_Loop ;Send data bits
BTFSS S_Reg,LSB
BCF Tx
BTFSC S_Reg,LSB
BSF Tx
RRF S_Reg,F
NOP
CALL S_Delay
DECFSZ S_Counter,F
GOTO Wr_Loop
BSF Tx ;Stop bit
CALL S_Delay
;---SCI_Write
Programda mümkün olduğu kadar basit bir şekil kullanabilmek için tek bir gecikme rutini kullanılıyor.
Bu durumda da bazı yerlerde uyum sağlamak için zaman dolguları kullanılmakta. Öncelikle göndereceğimiz data
S_Reg adlı seri işlem registerine yüklenmekte. Bitlerin sayısı olan 8 de S_Counter adlı sayaca yüklenmekte.
Zaman dolguları ile birlikte S_Delay rutini ile bir bit zamanı geçirilmekte. Bu aynı zamanda start bitini
bitirmekte. Sıra 8 adet data bitine gelmekte. S_Reg'deki 0'ncı bit dikkate alınarak gönderme çıkışı olan Tx'in
değeri belirlenmekte. S_Reg sağa kaydırılarak yeni bit yerine gelmekte ve bu işlem 8 defa tekrarlanmakta. Her
seferinde bir bit zamanı sonunda işlem bitmekte. 8 data biti tamamlanınca değeri 1 olan stop biti Tx'e
yerleştirilmekte ve yine bir bit zamanı beklenmektedir. Bunun sonunda işlem tamamlanmaktadır.
;***SCI_Read
MOVLW .8
MOVWF S_Counter
Rx_Start
CLRWDT
BTFSC Rx
GOTO Rx_Start
MOVLW .10
GOTO $+1
CALL S_Delay_Half
BTFSC Rx ;? True start bit
GOTO Rx_Start ;No, false start bit
Rx_Loop
CALL S_Delay
GOTO $+1
CLRC
RRF S_Reg,F
BTFSC Rx
BSF S_Reg,MSB
DECFSZ S_Counter,F
GOTO Rx_Loop
MOVLW .23
CALL S_Delay_Half ;For stop bit
BTFSS Rx
GOTO Main_Loop ;Receive error
;---SCI_Read
Gönderme rutini ise alma rutininden biraz değişiklik içermekte. Gönderirken gerekli işareti oluşturmakta
iken bu sefer bu işaretten bilgiyi oluşturacağız. Hazırlık için S_Counter'e alınacak olan bit sayısı 8'i
yükleriz. Bu durumda öncelikle işaret başlangıcını algılamamız gerekmektedir. Data yokken sinyal hattında
lojik 1 bulunmaktadır. Biz lojik 0'ın gelmesini bekleyeceğiz. Start bitinin başlaması ile lojik 0
algılanır. Bu durumda sinyalden gerekli bilgiyi oluşturmak için en kolay yöntem belli zaman aralıkları
ile örnekleme yapmak olacaktır. Bunun için de gönderilen bitlerin ortalarına rastlayan zamanlar
örnekleme noktaları olarak kullanılır. Ancak burada öncelikle yarım bit zamanı bekleyerek start bitinin
doğruluğunu denememiz gerekir. Zaman dolguları ile S_Delay_Half rutini sonrası yarım bit zamanı sonrasına
gelmiş oluruz. Burada hatta hala 0 olup olmadığına bakarız. Eğer 0 ise işlemin normal olduğunu düşünerek
diğer bitleri almaya devam ederiz. Yok değil ise yine başa döner yeni bir başlangız bekleriz.
Bu noktada tam start bitinin ortasında bulunmaktayız ve ilk data bitinin ortasına kadar gitmek için
bir bit zamanı bekleriz. Daha sonra S_Reg registerini sağa kaydırarak yeni bit için yer açarız. Bu durumda
yeni bit MSB yani 7. bit olacaktır. Rx'in değerine göre bu biti değiştiririz. Bu işleme 8 data biti de bitene
dek devam ederiz. 8 data biti bittikten sonra bilgimiz gelen sinyalden yeniden oluşturulmuştur. Bu durumda
bir bit zamanı daha bekler ve stop bitinin 1 olup olmadığını kontrol ederiz. Eğer herşey normal ise işlem
tamamlanmıştır.
Aşağıda 12c508 için yazılmış olan programın tamamı yer almaktadır. Son derece basit olan bu programda
bir bayt bilgi alınmakta ve alınan bilgi geri yollanmaktadır. Bu çok basit işlemci ile çok basit bir
programdır.
Title "Mikrosis Elektronik Tutorial - SW_RS232"
Subtitle "Revision 1.0 - Jan 2002"
;**********************************************************
; By Tanju TASCILAR
; (c)Mikrosis Elektronik
;**********************************************************
Processor 12C509
Include "P12C509.INC"
Errorlevel 1,-207
__CONFIG _XT_OSC&_WDT_ON&_CP_OFF&_MCLRE_OFF ; Set up config bits
__IDLOCS 0F000 ; Set up ID locations 0F000
; I/O pin naming
#Define Tx GPIO,4 ;SCI Tx
#Define Rx GPIO,3 ;SCI Rx
;RAM Area *************************************************
;Bank 0
CBlock 0C
S_Reg ;Serial work register
S_Counter
c_1 ;Counter
EndC
#Define Out_Bit S_Reg,MSB
; DDR values **********************************************
GPIO_DDR EQU B'00101000'
; Port reset values ***************************************
GPIO_RST EQU B'00010001' ;GPIO reset value
; Control words *******************************************
Option_RST EQU B'01000000' ;OPTION reset value
MSB EQU .7
LSB EQU .0
;**********************************************************
; Main
;**********************************************************
MOVWF OSCCAL ;Optional
CALL Init_All
GOTO Main_Loop
;**********************************************************
; Serial work delay
;**********************************************************
S_Delay
CLRWDT
MOVLW .22
S_Delay_Half
MOVWF c_1
NOP
S_D_Loop
NOP
DECFSZ c_1,F
GOTO S_D_Loop
RETURN
;**********************************************************
; Init All
;**********************************************************
Init_All
MOVLW GPIO_RST
MOVWF GPIO
MOVLW GPIO_DDR
TRIS GPIO
MOVLW Option_RST
OPTION
RETURN
;**********************************************************
; Main Loop
;**********************************************************
Main_Loop
;***SCI_Read
MOVLW .8
MOVWF S_Counter
Rx_Start
CLRWDT
BTFSC Rx
GOTO Rx_Start
MOVLW .10
GOTO $+1
CALL S_Delay_Half
BTFSC Rx ;? True start bit
GOTO Rx_Start ;No, false start bit
Rx_Loop
CALL S_Delay
GOTO $+1
CLRC
RRF S_Reg,F
BTFSC Rx
BSF S_Reg,MSB
DECFSZ S_Counter,F
GOTO Rx_Loop
MOVLW .23
CALL S_Delay_Half ;For stop bit
BTFSS Rx
GOTO Main_Loop ;Receive error
;---SCI_Read
;***SCI_Write
MOVWF S_Reg
MOVLW .8
MOVWF S_Counter
BCF Tx ;Start bit
GOTO $+1
GOTO $+1
GOTO $+1
GOTO $+1
CALL S_Delay
Wr_Loop ;Send data bits
BTFSS S_Reg,LSB
BCF Tx
BTFSC S_Reg,LSB
BSF Tx
RRF S_Reg,F
NOP
CALL S_Delay
DECFSZ S_Counter,F
GOTO Wr_Loop
BSF Tx ;Stop bit
CALL S_Delay
;---SCI_Write
GOTO Main_Loop
END
sw_rs232.asm kaynak kodu.