C ile AVR Programlama -22- USART Kullanımı ve Örnek Kod İncelemesi
AVR’nin USART yazmaçlarını önceki yazımızda bitirmiştik. Artık bu yazmaçlar üzerinden nasıl program yazılacağı ve USART biriminin nasıl kullanılacağını anlatalım. Yazmaçların ADC birimine göre biraz daha ayrıntılı olması ve farklı iletişim tiplerinin ortak kullandığı bitler olması biraz kafamızı karıştırabilir. USART prensipte çok basit olduğu için sadece bayt alma ve bayt gönderme olarak kısa fonksiyonlar yazarak bunu gerçekleştirmemiz mümkündür. Aynı ADC biriminde olduğu gibi öncelikle USART birimini hazır hale getirmek için bir fonksiyon yazmak zorundayız. Bu fonksiyonu yazarak işe başlayalım.
USART birimi yüklenmesi için şu adımlar gerçekleştirilmelidir,
- Baud Oranı Ayarlanmalıdır
- Veri Boyutu Ayarlanmalıdır
- TXEN ve RXEN bitleri ile Alıcı ve Verici Etkinleştirilmelidir.
- Eşlik biti ve Stop bitlerinin sayısı ayarlanmalıdır.
Şimdi bunu program kodu üzerinden görelim.
1 2 3 4 5 6 7 8 9 10 11 |
#define BAUD 9600 // Baud Oranını Tanımlıyoruz #define BAUDRATE ((F_CPU)/(BAUD*16UL)-1) // UBRR için baud verisini ayarlıyoruz void uart_init (void) { UBRRH = (BAUDRATE>>8); // Baudrate'in üst bitlerini kaydırıyoruz UBRRL = BAUDRATE; // kalan bitleri yazdırıyoruz UCSRB|= (1<<TXEN)|(1<<RXEN); // Alıcı ve vericiyi etkinleştiriyoruz UCSRC|= (1<<URSEL)|(1<<UCSZ0)|(1<<UCSZ1); // Veri formatını ayarlıyoruz } |
Bu örnek kodda her komutun ne iş gördüğünü açıklamada yazsak da komutlara bakarak anlamak için bunu yazmaçlar üzerinden anlatmak lazımdır. Öncelikle yukarıda tanımladığımız makroların işlevinden bahsedelim. Yukarıda baud 9600 olarak belirlenmiştir. Bunu anlamak kolay olsa da BAUDRATE olarak tanımlanan makrodaki matematik işlemi bize yeni görünecektir. Mikrodenetleyicinin teknik veri sayfasında UBRR yazmacına yazılacak baud oranının hesabına dair bir formül mevcuttur. Bu kod bu formülün kod haline dönüşmüş şeklidir. Merak edenler için aşağıda formülü verelim.
Kısaca açıklarsak F_CPU değerinde bulunan işlemcinin saat hızı ile BAUD değerinin 16’ya çarpımı bölünür ve bundan 1 çıkarılır. Delay fonksiyonlarında olduğu gibi F_CPU tanımını yapmamışsak yapmamız gerekir. Örneğin #define F_CPU 16000000UL komutu işlemci saat hızının 16MHz olduğunu belirtir.
UBRRH = (BAUDRATE>>8);
Bu kod elde edilen BAUDRATE değerinin bitlerini 8 bit sağa kaydırarak ilk bitleri 8 bitlik ölçüde açığa çıkarır. Örneğin elimizde 16 bitlik bir “0000111111111111” değeri olsun. Bunu sekiz bitlik bir yazmaca yüklediğimizde sağdaki sekiz bit yüklenecek fakat soldaki sekiz bit yüklenemeyecektir. Bunu Yüksek ve Düşük yazmaçlarına sığdırmak için öncelikle sağdaki sekiz birlik düşük yazmaç değerini atmamız gerekir. Bu işlemden sonra değerimiz “00000000000001111” olacaktır. Böylelikle bu dört bit yüksek yazmacın ilk dört bitine yazılacaktır. Geri kalan değer ise bir sonraki komutta düşük yazmaca yazılacaktır. Elimizdeki mikrodenetleyici 8-bit olduğu için böyle büyük değerleri sığdırmak zorunda kalıyoruz.
UBRRL = BAUDRATE; Burada düşük yazmaca BAUDRATE’in tamamı yazdırılmış gibi görünse de aslında sağdaki sekiz biti yazdırılmıştır. Geri kalan bitler de yazdırıldığına göre baud oranı değerini yazdırma ve bu oranı ayarlama işlemi bitmiş oluyor.
UCSR0B|= (1<<TXEN)|(1<<RXEN); UCSRB yazmacındaki TXEN ve RXEN bitleri bir (1) yapılır. Bu aynı ADC’de ADEN bitinin bir (1) yapılması gibi alıcı ve vericiyi etkinleştirir.
UCSR0C|= (1<<UCSZ0)|(1<<UCSZ1); Veri formatının nasıl seçildiğini anlamamız için tekrar yazmaçlara bakmamız lazım. Burada UCSZ0 ve UCSZ1 bitleri bir (1) yapılmıştır. Tablodan anlaşıldığı üzere iletişim 8 bitlik bir veri genişliğinde yapılacaktır. Bundan başka iletişim UMSEL bitlerinin 00 olmasıyla asenkron olduğu için değiştirme gereği duymadık.
Şimdi veri gönderme ve veri alma fonksiyonlarını inceleyelim.
1 2 3 4 5 6 |
// veri gönderme fonksiyonu void uart_transmit (unsigned char data) { while (!( UCSRA & (1<<UDRE))); // yazmacın boş olmasını bekle UDR = data; // yazmaca veri yükle } |
Burada UDRE veri yazmacı bayrağı bir (1) olmadığı sürece program döngüde tutulur ve sonrasında UDR yazmacına fonksiyonun argüman olarak aldığı data değeri yazılır. İşlem bu kadardır.
1 2 3 4 5 6 |
// function to receive data unsigned char uart_recieve (void) { while(!(UCSRA) & (1<<RXC)); // tüm verinin gelmesi için bekle return UDR; // 8 bit veriyi döndür } |
Öncelikle UCSRA yazmacındaki RXC bayrak bitinin bir (1) olup olmadığı kontrol edilir. Veri alma tamamlanınca bu bit bir (1) olacağı için döngüden çıkılır. Sonrasında UDR yazmacının içindeki değer fonksiyondan döndürülür.
Temel olarak USART işlemi bu kadardır. Sonraki yazıda diğer kodları inceleyeceğiz ve konumuza devam edeceğiz.
Kaynaklar:
ATmega328P – Microchip Technology , http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-42735-8-bit-AVR-Microcontroller-ATmega328-328P_Datasheet.pdf, Erişim Tarihi: 18.08.2018
Yash Tambi, Mayank Prasad, The USART of the AVR, http://maxembedded.com/2013/09/the-usart-of-the-avr/, Erişim Tarihi 21.08.2018
Kapak Resmi : http://10rem.net/media/82343/Windows-Live-Writer_b3541542a059_B73E_image_21.png
UYARI!!
Bu sitede yayınlanan yazılar orjinal içerik olup faydalanılan kaynaklar belirtilmiştir. Yazarın izni olmaksızın tamamen alıntı yapılamaz, kopyalanamaz. Kaynak göstermek kaydıyla (Yazının adı, yazar adı ve link) kısmen alıntı yapılabilir.
Hocam merhaba while (!( UCSRA & (1<<UDRE))); bu kodu tam olarak anlayamadım.Yukarıdaki açıklamada Burada UDRE veri yazmacı bayrağı bir (1) olmadığı sürece program döngüde tutulur ve sonrasında UDR yazmacına fonksiyonun argüman olarak aldığı data değeri yazılır şeklinde açıklanmış ama (1<<UDRE) kısmı UDR Yİ 1 YAPMIYOR MU ?
Hayır udre bir olmuyor 1 değeri udre bitinin numarası kadar sola kaydırılıp UCSRA ile AND işlemine tabi tutuluyor. Giriş/Çıkış işlemlerini anlattığım derse yeniden bakın.
#define BAUDRATE ((F_CPU)/(BAUD*16UL)-1) hocam buradaki UL nin yazılma amacı nedir?
C dilinde değerlerin türünü belirtmek için ön ekler ve son ekler vardır. UL ise Unsigned Long anlamına gelir.
Hocam F_CPU yerine 16000000 yazınca hata verdi?Sebebi nedir acaba?
UL son eki ile beraber yazmanız gerekli 16000000UL olarak mesela
Hocam İyi günler
UCSRA yazmacında UDRE biti 1 ise UDR bellek boştur yani veri gönderilmiştir demek.
while (!( UCSRA & (1<<UDRE))); bu döngüde
UCSRA yazmacının 3. biti (UDRE) 1 ile AND'de tabi tutuluyor.
UCSRA yazmacındaki UDRE biti 1 iken while (0) şeklinde olmaktadır ve blogun çalışmaması lazım
UCSRA yazmacındaki UDRE biti 0 iken while (1) şeklinde olmaktadır ve blog çalışmaktadır
yanlış mı anlıyorum while bloğunu?
Yardımcı olbilir misiniz?
1 ile UDRE biti VE işlemine tabi tutuluyor. Burada kadar doğru ama soldaki DEĞİL (!) operatörünü de hesaba katmak lazım. Bu durumda bitler terslenmiş oluyor.
UCSRA yazmacında
** UDRE biti 1 için => DEĞİL (!) terslenmiş haliyle while bloğunun (0) olmaktadır
dolayısıyla bloğun çalıştırılmaması ve veri gönderilmemesi gerekmektedir, bellek boş olmasına rağmen
UDRE biti 0 için => DEĞİL (!) terslenmiş haliyle while bloğunun (1) olmaktadır
bu kodda kaçırdığım vey ayanlış anladığım kısım nedir
UBRRH = (BAUDRATE>>8); açıklamasında 12 bit diyerek 16 bitlik örnek verip 16 ya göre anlatmışsınız.
düzeltildi.