AVR Programlama – USART

USART Nedir?

USART (Universal Synchronous Asynchronous Reciever Transmitter) 5 ile 9 bit arasında data formatına sahip olan senkron ve asenkron çalışabilen en temel seri haberleşme protokollerinden birisidir. Bu yazımızda asenkron haberleşme üzerine duracağımız için daha çok UART’dan bahsedeceğiz. UART full-dublex özelliğe sahiptir. Böylece aynı anda veri okuma ve veri gönderme işlemi yapılabilir. UART haberleşmenin en büyük avantajı sadece 3 pin kullanılarak kolay bir şekilde veri transferi yapılabilmesidir. UART da herhangi bir senkronizasyon olmadığı için haberleşme parametreleri (haberleşme hızı gibi) her iki taraf içinde ortak değerlere set edilir. En büyük dezavantajı ise bir haberleşme hattı kullanılarak sadece bir cihazla iletişim kurulabilir.

UART Haberleşme

UART haberleşmede üç adet terminal kullanılır. Bunlar, TX(transmitter), RX(reciever) ve ortak GND dir. Bir cihaz transmitting yaparken diğer cihaz recieving yapacağı için yukarıda da görüldüğü üzere TX ve RX terminalleri ters bağlanır.

UART haberleşme kullanılarak bir çok cihaz arasında iletişim kurulabilir. Örneğin ;

Mikrodenetleyici <———-> Mikrodenetleyici

Mikrodenetleyici <———–> Modül

Mikrodenetleyici <———–>Bilgisayar (USB TLL dönüştürücü, RS232 veya RS485 kullanılarak)

Yukarıda 9 bit veri gönderilen bir veri paketi görmekteyiz. Adım adım veri paketindeki bitleri inceleyelim.

ST : Haberleşmeyi başlatan start bitidir. Normalde veri hattı lojik 1 seviyesindedir ve lojik 0’a çekildiği an start biti verilmiş olur. Kısaca haberleşme veri hattının lojik 0 yapılması ile başlar.

Data bits(0-8) : Gönderilecek verinin olduğu bitlerdir. Örnek olarak 9 bitlik bir veri gösterilmiş fakat biz uygulamalarımızda 8 biti tercih edeceğiz.

P : Parity bit, verinin doğru şekilde transfer edildiğini kontrol etmek için kullanılır. Kısacası, parity bit kullanılarak çok güvenilir olmayan hata denetimleri yapılabilir. Çok güvenilir olmamasının sebebi ise eğer birden fazla bitte bozulma olur ise bunu tespit edememesidir.

IDLE : Haberleşmenin veri hattının lojik 0 yapılmasıyla başladığını belirtmiştik. Idle line, haberleşme olmadığı zamanlarda veri hattının lojik 1 de tutulmasıdır.

ATMEGA328P USART Registerları

RXCn : Recieve Complete bayrağı, bu bayrak data registerında okunmamış veri olduğu zaman aktiftir daha sonra otomatik olarak kalkar.

TXCn : Transmit Complete bayrağı, bu bayrak data registerındaki veri gönderildiği zaman otomatik olarak temizlenir.

UDREn : USART Data Register Empty bayrağı, alınan veya gönderilen veririnin depolandığı UDR registerının durumunu gösterir. UDRE bayrağı 1 ise veri tamponu boş demektir.

RXCIEn : Recieve Complete Interrupt Enable bitini 1 yapmak RXC bayrağında interrupt’ı etkinleştirir. Veri okuma işleminde kesme kullanacaksak bu biti 1 yapmalıyız.

TXCIEn : Transmit Complete Interrupt Enable bitini 1 yapmak TXC bayrağında interrupt’ı etkinleştirir. Veri gönderimi tamamlandığında bir kesme oluşmasını istiyorsak bu biti 1 yapmalıyız.

RXENn :RXEN bitini bir yapmak haberleşmede recievinig işlemini aktif hale getirir.

TXENn : TXENn bitini bir yapmak, haberleşmede transmitting işlemini aktif hale getirir.

UCSZn2 : Bu bit veri formatını seçmek için kullandığımız UCSZ bitlerinin 2.sidir. Diğer iki bit ise UCSRnC registerındadır. Veri formatını seçmek için kullanacağımız değerler tablosunu UCSRnC registerının altına koyacağım.

UMSELn1:0 : Bu bitler kullanılarak USART biriminin çalışma modu seçilir. Aşağıdaki tabloda değerlerini görmekteyiz.

UPMn1:0 : Bu bitler kullanılarak Parity modu belirlenir. Tablo değerlerini aşağıda görmekteyiz.

USBSn : Biti kullanılarak stop bitinin kaç bit olacağı belirlenir. Bu biti bir yaparsak 2 stop biti ayarlamış oluruz. Bu biti 0 yaparsak stop bitini 1 bite ayarlamış oluruz.

UCSZn1:0 : Bu bitler kullanılarak transfer edilecek verinin kaç bit olduğu belirlenir. Değerlerini aşağıdaki tabloda görmekteyiz. Not: UCSZn2 biti UCSRnB registerındadır.

UBRRnH ve UBRRnL kullanılarak haberleşme hızı belirlenir. Ayarlanmak istenen baud rate değerine göre UBRR değeri hesaplanır ve en önemli 4 biti UBRRH registerına yazılır ve düşük öncelikli 8 biti de UBRRL registerına yazılır.

16Mhz kristal kullanılan sistem için UBRR Hesabı

UDR register’ı veri almak ve veri göndermek için kullanılan tampon bellektir. Hem recieving hemde transmitting işlemi için bu register kullanılır.

Bu bölümde sadece basit bir USART uygulamasında kullanacağımız temel bitlerden bahsettim. USART biriminin daha fazla özelliğini kullanmak için datasheet’i incelemek gereklidir.

UART Örnek

define F_CPU 16000000UL
 include <avr/io.h>
 include <util/delay.h>
 include <avr/interrupt.h>

 volatile char data[50] ; // karakter dizimizi kesme içerisinde kullanacağımız için volatile                                                          olarak   tanımladık

 int count_char = 0 ;
 char new;

 void serial_init(int baudrate);
 void serial_sends(char* s);
 void serial_send(unsigned char data);
int main(void){
DDRB = 0xFF;     
PORTB = 0x00;
serial_init(9600); 
cli(); 
sei(); 
  while(1)
   {  
    PORTB = 0xFF; 
    _delay_ms(1000); 
    PORTB = 0x00; 
    _delay_ms(1000);
   }
}

void serial_init(int baudrate)
{
     int UBRR_VALUE=(((F_CPU/(baudrate*16UL)))-1);
     UBRR0L=(uint8_t)(UBRR_VALUE & 0xFF);
     UBRR0H=(uint8_t)(UBRR_VALUE>>8);
     UCSR0B|=(1<<TXEN0); //Transmitting aktif
     UCSR0B|=(1<<RXEN0); //Recieving aktif
     UCSR0B|=(1<<RXCIE0); //RX complete interrupt aktif
     UCSR0C|=(1<<UCSZ01)|(1<<UCSZ01); // no parity, 1 stop bit, 8-bit data
 }

void serial_sends(char* s)
 {
     // 0 karakterine ulaşana kadar adresi bir arttırarak gönder
     while(s > 0) serial_send(s++);
 }

void serial_send(unsigned char data)
{
 UDR0 = data; // Veri gönder
 while(!(UCSR0A&(1<<UDRE0))){}; //Gönderilen verinin tamamlanmasını bekle
}

ISR(USART_RX_vect) // RX complete kesmesi oluştuğunda girilecek olan kesme servis rutini 
{
  new=UDR0; 
  if (new == '\r') 
   {     
    data[count_char]='\0';     // 
    count_char = 0;     
    serial_sends(data); 
  } 
 else
  {     
   data[count_char]=new;     
   count_char++; 
 } 
 }   

Yukarıda bahsettiğimiz registerların tüm bitlerini kullanmadık, çünkü bazılarının default değerleri zaten yapmak istediğimiz değerlerdeydi. Bu uygulamada kesme yöntemi ile uart üzerinden gelen karakter dizisini tekrar uart üzerinden gönderdik.

Bu uygulamada veri alma işlemi için kesme yönetimi kullandık. Arduino’da olduğu gibi serial.available gibi bir fonksiyon tanımlayabilirdik. Fakat bu yöntem sürekli olarak haberleşme hattına veri gelip gelmediğini kontrol ettiği için CPU kaynağımızı kullanmış olur. Bunun yerine kesme kullanarak sadece veri geldiği zaman çalıştırılmasını istediğimiz fonksiyona (ISR) gidiyoruz. Her an ”Veri geldi mi?” diye kontrol etmek yerine başka işlerde yapabileceğine örnek olması için aynı anda da bir blink işlemi yaptırdık.

Her karakter dizisi sonunda \0 ile biter. Bu sayede gönderilen dizinin boyutunu bilmesek bile son byte’ın hangisi olduğunu biliyoruz ve fonksiyonumuzu ona göre yazıyoruz.

Recieving işleminde ise yeni satır karakteri (\r) ile son byte’ı tespit ediyoruz. Burada dikkat etmemiz gereken şey eğer gönderen cihaz, dizi sonuna yeni satır karakteri koymuyor ise gönderilecek dizinin boyutunu bilip ona göre bir fonksiyon yazmamız gereklidir.

Kesme kullandığımız için ”Veri geliyor mu?” diye sürekli kontrol etmek yerine cpu başka iş yapabiliyor. Burada örnek olarak blink yaptık.

One comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s