STM32 HAL Kütüphanesi ile UART Protokolünü Kullanma

Önceki yazımızda CubeMX ile ön ayarları oluşturmuştuk ve projemizi hazırlamıştık. Bu projede örnek bir kod olarak 0x01 değerini UART protokolü ile lojik analizöre gönderdim ve bunun grafiğini elde ettim. Bu grafiği açıklayarak yazımıza başlayalım.

Burada programda sürekli olarak gönderdiğim verinin bir kesitini görmekteyiz. 1 ile işaretlediğim kısım START biti olup iletişimi başlatır. 2 numaradan itibaren devam eden kısım veri kısmı olup 8 bitlik veriyi sol hizalı şekilde göndermektedir. Benim gönderdiğim veri 0x01 olduğu için 10000000 şeklinde yollamıştır. Bunu grafikten görebilirsiniz. 3 numaralı bit ise STOP biti olup verinin tamamlandığını haber verir. START -> Veri -> STOP şeklinde devam eden bu veri aktarımı en yapılabilecek en basit asenkron seri veri aktarımıdır. Eğer istenirse eşlik biti gibi çeşitli özellikler burada eklenebilir. Bu kutucuk aynı zamanda frame yani çerçeve adıyla da adlandırılmaktadır. Bunun zamanlamasını ise önceden belirlediğimiz baud değeri olan 9600 ile belirliyorduk. Yani bir saniye 9600’e bölünür ve elde edilen değer aralığında ölçüm yapılır. Burada bunu anladığımıza göre şimdi bu sinyali nasıl ürettiğimize bir bakalım.

Önceki makalede ürettiğimiz projenin başlık dosyalarına baktığımızda stm32f3xx_hal_conf.h dosyasında şöyle bir değişiklik olduğunu görüyoruz.

Bunu daha önceden size anlatmıştık. Kullanmak istediğimiz HAL sürücüsünü buradan açıklama işaretlerini kaldırarak etkin hale getiriyoruz.  Bu tanımlama ile dosyanın aşağısındaki koşullu tanım yapısı işletilmektedir.

Kısacası burada yaptığımız iş stm32f3xx_hal_uart.h dosyasını projemize dahil etmektir. HAL kütüphanesinde her sürücünün ayrı bir dosyası olduğunu size söylemiştik. Başlık dosyalarında daha fazla bir farklılık görmediğimiz için şimdi inceleyeceğimiz ikinci dosya olan “src” klasöründeki stm32f3xx_hal_msp.c dosyasına bakalım.

Burada HAL kütüphanesinde yaptığımız UART ayarları ile ilgili ön ayarlar yer almaktadır. Bunların USART sürücüsünün veri tipleri ile alakalı olmadığını görmüş olmanız lazımdır. Öncelikle huart adındaki yapının Instance yani eşleştirildiği birimin adının USART1 olup olmadığına dair bir denetleme kodu görülmektedir. Bunu şuradan görebiliriz.

Şimdilik bunun hakkında bir fikrimiz yok çünkü main.c içerisindeki yapıyı incelemedik. Fakat ADC biriminde gördüğümüz gibi bu yapı kütüphane ile alakalı olup eğer bu ayarı yaptıysak aşağıdaki diğer gerekli komutları çalıştırmak üzere buraya koyulmuştur.

Burada USART1 biriminin saatini etkinleştirdiğimiz gibi GPIOC biriminin saatini de etkinleştiriyoruz. Çünkü TX ve RX ayakları GPIOC birimine bağlanmıştır. Sonrasında ise yapacağımız GPIO sürücüsünü kullanarak bu ayak ayarlarını yapmak.

Görüldüğü gibi GPIO_InitStruct.Mode kısmında GPIO_MODE_AF_PP olarak ayak için alternatif fonksiyon seçeneğini seçtik. Bu alternatif fonksiyonun ne olacağını ise aşağıdaki GPIO_InitStruct.Alternate yapısına eklenen değer ile görmekteyiz. GPIO_AF7_USART1 değeri alternatif fonksiyon olarak USART1 birimini kullanın demektir. Her ayak başına düşen alternatif fonksiyonların ne olacağını ise datasheetten öğrenebiliriz. Buna benzer kodları önceden ayrıntısıyla açıkladığımız için çok üzerinde durmuyoruz. Şimdi ise main.c dosyasına bakalım ve buradaki komutları inceleyelim.

Size kütüphane kılavuzunu incelerken öncelikle UART_HandleTypeDef adında bir yapı tipinin tanımlanması gerektiği ve bunlara gerekli verilerin yazılmasından bahsetmiştik. Öncelikle böyle bir yapı tipinde değişken tanımlıyoruz ve bunu program huart1 olarak adlandırıyor. Biz programdan bağımsız olduğumuzda istediğimiz bir adı koyabiliriz. Kodun devamında bizim USART1 birimi için ayrı bir saat ayarlaması yapıldığını görmekteyiz.

Burada PeriphClkInit atlı RCCEx sürücüsüne ait yapıya saat ayarı değeri yüklenip ayarlanmaktadır. Kısacası öncelikle ayarlayacağımız saat RCC_PERIPTHCLK_USART1 yani USART1 biriminin saati olarak seçilmiştir. Sonrasında ise bu hangi saat kaynağından besleneceği RCC_USART1CLKSOURCE_PCLK2 değeri ile belirlenmiştir. USART1 bu durumda PCLK2 saatinden beslenmektedir. Şimdi ise asıl incelememiz gereken yere geliyoruz. MX_USART1_UART_Init fonksiyonu içerisinde huart1 adında tanımladığımız sürücü yapı tipine ayar verilerini yüklüyoruz. Bunun için şöyle bir kod bloku kullanılmıştır.

Burada programda yaptığımız ayarların aynısını görmemiz mümkündür. Öncelikle Instance değerine birimin adı atanmıştır. USART1 demek ile USART1 birimindeki yazmaçlara erişim sağlamış oluruz. Bu atadığımız değerler de USART1 yapısı içerisindeki yazmaçlara yüklenmektedir. USART1’in yazmaçlarına erişmek için ok operatörünü (->) kullandığımızı unutmayalım. Kısacası USART1 burada karşımıza içinde yazmaçları bulunduran bir yapı olarak çıkmaktadır. Bu UART1 yapısı donanım olarak UART1 birimini temsil etmektedir. Bu yapının içerisinde hangi yazmaçların olduğunu da kaynak kodunu inceleyerek görebiliriz.

Bu yazmaçların ve donanımı temsil eden yapıların HAL kütüphanesinden bağımsız halde olduklarını söyleyelim. İstenirse HAL hiç kullanılmadan program yazılabilir. Bu tanımlamalar stm32f303xc.h dosyasında mevcuttur. Biz yazmaç tabanlı program yazarken de bu sayfayı referans olarak kullanabiliriz.

Kodun devamına baktığımızda huart1.Init.xxxx diye devam ettiğini görüyoruz. Burada huart1 yapısının içerisinde Init adlı bir yapının değişkenlerine erişim olduğunu görebiliriz. Init yapısı UART_InitTypeDef tipinde olup çeşitli ayar verilerini içerisinde bulundurur. Şimdi veri göndermek için kullandığımız fonksiyonu inceleyelim.

Bu fonksiyon başta anlaması zor gibidir fakat aldığı parametreler oldukça basittir. Fonksiyonun prototipini inceleyerek daha iyi açıklamaya çalışalım.

Görüldüğü gibi önce tanımladığımız UART yapısı, sonra veri, sonra verinin boyutu ve en sonunda da zaman aşımı süresi belirtilmektedir. Bizim ch verisi burada işaretçi olarak alınmaktadır. Aynı şekilde UART_HandleTypeDef verimiz de işaretçi olarak alınır. O yüzden adresleme operatörü ile (&) bu verilerin değerini aktarmamız gereklidir. Öncelikle ch adında ve 0x01 değerinde bir karakter verisi oluşturuyoruz ve bunu adresleyerek işaretçiye çevirip argüman olarak aktarıyoruz. Sonrasında ise verinin uzunluğu ve zaman aşımı süresini yazdıktan sonra fonksiyonumuz tamamlanmış oluyor.

Bilmemiz gereken önemli bir nokta ise mikrodenetleyici 3.3V ile çalışmakta ve 5V seri iletişim ekipmanları ile uyumda sıkıntı yaşayabilmektedir. Ayrıca bilgisayara doğrudan seri iletişimle bağlayacağımız bir USB portu bulunmamaktadır. Ben fazla uğraşmak istemeyip lojik analizörle bir analiz yaptım. Daha sonra UART konusunu daha ayrıntılı ele almak üzere burada bırakıyoruz.

Bizi Facebook grubumuzda takip etmeyi unutmayın. Bilgili ve öğrenmeye hevesli bir topluluk oluşturmak istiyoruz.

https://www.facebook.com/groups/1233336523490761/

UYARI!!

 

 

 

 

Gökhan Dökmetaş

"Arduino Eğitim Kitabı" ve "Arduino ve Raspberry PI ile Nesnelerin İnterneti" kitaplarının yazarı. Başkent Teknoloji ve Dedektör Merkezi'nde Ar-ge Sorumlusu. Araştırmacı-Yazar.

You may also like...

1 Response

  1. Nurettin Şenyer dedi ki:

    Merhaba,

    Öncelikle ayrıntılı açıklamanız için teşekkürler.

    UART için MspInit işlevini çalışma zamanında çağırmak mümkün müdür? Amacım çalışma zamanında UART1 (ör) için atanmış default (ör. PD1) ve alternate (PA1) pinlerden veri akışını (ör. sadece Rx) yönetmek.

    Daha açık haliyle UART1 önce default pin (PD1) üzerinden veri alacak. Çalışma zamanında duruma göre alternate pin (PA1) den veri almaya başlayacak.

    HAL_UART_MspInit ve HAL_UART_MspDeInit işlevlerinde ki içeriği özelleştirerek çağırdım. Veri almayı başaramadım.

    Mümkün müdür? Herhangi bir öneriniz olur mu?

    Değerli vaktiniz için teşekkürler

Bir cevap yazın

E-posta hesabınız yayımlanmayacak.