Sıfırdan STM32F0 Dersleri – USART
Bu yazında en sevdiğim çevre birimi olan USART dan bahsedeceğim.USART : Universal Synchronous/Asynchronous Receiver/Transmitter olarak açılır.Açılımındanda anlaşılacağı üzere senkron ve asenkron olarak çalışabilir.
Temelde 2 pin kullanılır. TX ve RX.
TX Transmitter(Verici) RX Receiver(Alıcı) Anlamına gelir.Herhangi bir cihaz ile bağlantı yapılırken çapraz bağlantı yapılır.
USART’ın ilk yapılması gereken ayarı Baud Rate dir. Baud rate iletişim hızını belirler. Bir diğer nokta ise her seferinde kaç bit gideceğidir.Bizim uygulamada 8 bit kullandık. Parity biti kullanmadık yani N(none) Stop iti ise 1 olarak ayarlayacağız. Son olarak CTS, ve RTS pinleri kapalı.
Bunu 8N1 olarak da görebilirsiniz. USART çok derin bir konu olduğundan fazla giremeyeceğim.
Bu uygulamada bilgisayarın seri portu ile iletişim kuracağız. Masaüstü bilgisayarlarda seri port mevcut.Fakat bu port’un volt değerleri biraz farklı .Bunu Normal lojik seviyeye indirmek için ayrı bir devre yapılır. MAX232 devresini inceleyebilirsiniz.
Bu çok zahmetli olabilir veya bilgisayarda seri port olmayabilir.
Bunun için USB/Seri çevirici kullanacağım. Hem küçük hemde bilgisayarda seri port olmasına gerek kalmadan sanal bir port oluşturup kullanılabiliyor.
Dikkat edilmesi gereken nokta çeviricinin TX-RX pinleri 3.3V seviyesinde olmalı. Yoksa Discovery kit zarar görür. Bilgisayar ile STM iletişimi için bir çok hazır terminal programı var.
Fakat ben biraz C# ile kendime bir terminal programı hazırladım. Siz hazır bir program kullanabilirsiniz. COM porta dikkat ediniz seri çevirici taktığınızda oluşan sanal portu seçip öyle port açmalısınız. USART’ı STM de nasıl kullanacağımızı öğrenmeye başlayalım. Standart olarak LED kontrolü yapıp bu LED durumunu bilgisayara gönderelim.
Bağlantı Şu şekilde yapılmalıdır.
TX –> RX
RX –> TX
GND –> GND
Tabi besleme pinini unutmayın. İsterseniz harici bir kaynaktan besleme yapabilirsiniz ama unutmayın GND ler ortak olmalı.
Yazılımda öncelikle yapılarımızı tanımlıyoruz.
GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStrutcure; NVIC_InitTypeDef NVIC_InitStructure;
Daha sonra clock işlemlerini yapıyoruz.Bu uygulamada kullanılan USART1 APB2 olarak clock veriliyor.
USART1 Pinleri şu şekilde;
A9 -> TX
A10 -> RX
LED hazırlama işlemi
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOC, &GPIO_InitStructure);
Şimdi USART1 için AF modda gereken ayarları yapalım.Öncelikle A9 ve A10 pinlerini AF(Alternative Function – Alternatif fonksiyon) moduna alıyoruz.Push-pull, pin numaraları, pull-up, ve 50mhz’e göre ayarladıktan sonra init ediyoruz.
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure);
Dikkat edilmesi gereken bir noktaherhangi bir pini AF modda kullanacaksak o pini Afconfig fonksiyonu ile ayarlamamız gerekiyor.Bu fonskiyon 3 parametre alıyor.Port, source, af.USART1 A portunda.Pinsource ise 9 ve 10 yani pinleri belirtiyoruz.Hangi AF seçeneğinde kullanıldığı parametrenin kaynağına giderek inceleyebilirsiniz. USART1 için AF1 denmiş.Bu bilgiler datasheet de mevcut. Dökümanlar sürekli açık bulunsun ara ara incelemek de fayda var.
GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_1); GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_1);
Şimdi USART ayarlarını yapabiliriz. Baud olarak 9600 veya 115200 kulanabiliriz. Yeter ki 2 tarafta da aynı baud seçili olsun. WordLength ile kaç bit göndereceğimiz belirliyoruz. 8b seçtik.Parity biti None(yok) stop biti 1 ve USART_HardwareFlowControl_None ile CTS,RTS kapalı.Son olarak hem data gönderip hem alacağımız için hem TX hemde RX modunu seçiyoruz.Ayarları yüklüyoruz.Bir diğer özellik ise USART bir veri alırsa kesme oluşturabilsin diye RXNE kesmesini aktif ediyoruz.Bir çok kesme mevcut.Bunları inceleyebilirsiniz. USART_CMD ile çalıştırıp hazır hale getiriyoruz.
USART_InitStrutcure.USART_BaudRate = 115200; USART_InitStrutcure.USART_WordLength = USART_WordLength_8b; USART_InitStrutcure.USART_Parity = USART_Parity_No; USART_InitStrutcure.USART_StopBits = USART_StopBits_1; USART_InitStrutcure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStrutcure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; USART_Init(USART1, &USART_InitStrutcure); USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); USART_Cmd(USART1, ENABLE);
Kesme olur da NVIC olmaz mı !
USART ın kesme ismi bu şekilde verilmiş.Aman ezberden yapmıyoruz.Mesela USART1_IRQn’e sağ tıklayıp “Find declaration of “USART1_IRQn”” dersek bizi stm23f0xx.h dosyasında bir kısıma götürecek bu kısımda kesme başlıklarını öğrenebilirsiniz. Mesela timer6 kullansaydık. TIM6_IRQn değil TIM6_DAC_IRQn kullanacaktık.Bu arada o dosyadaki makrolara dikkat edin 32f051 için olan kısım biraz yukarıda.
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_InitStructure.NVIC_IRQChannelPriority = 0; NVIC_Init(&NVIC_InitStructure);
Sonunda USART çalıştı. USB/Seri çevirici ile (TX-RX, RX-TX, çapraz bağlantı)yaptık.Peki şimdi ne yapabiliriz.Bilgisayardan 1 ve 0 yollayalım. STM ile 1 ve 0 ı kontrol edip LED durumunu değiştirelim ve bilgisayara LED açık LED kapalı gibi bir metin gönderelim.Şimdi kesme fonksiyonunu belirtelim.
static unsigned int LEDState = 0; void USART1_IRQHandler(void) { if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) { if((char)USART_ReceiveData(USART1) == '1') LEDState = 2; if((char)USART_ReceiveData(USART1) == '0') LEDState = 1; } USART_ClearITPendingBit(USART1, USART_IT_RXNE); }
USART kesmesinde RXNE yi kontrol edelim.TRUE ise USART dan 1 gelmiş iseLEDState’i 2 0 gelmiş ise 1 yapalım.Başlangıç durumu 0 olsun.Okuma işlemi oldukça basit.USART_ReceiveData(USART1) fonksiyonuna tek parametre veriyoruz.USART numarası. ve bize 8 bitlik bir değer döndürüyor bunu hex yerine char olarak alıp 1 ve 0 ile kontrolünü yaptık.İşimiz bittiğinde ise bayrağı temizledik.Şimdi ana programda bunu kontrol ettirelim.
while(1) { if(LEDState == 2) { GPIO_SetBits(GPIOC, GPIO_Pin_8); USART_SendString(USART1, "LED On\r\n"); LEDState = 0; } if(LEDState == 1) { GPIO_ResetBits(GPIOC, GPIO_Pin_8); USART_SendString(USART1, "LED Off\r\n"); LEDState = 0; } }
Burada duruma göre işlemler yapıp LEDState’i sıfır yapıyoruz.
USART_SendString diye bir fonskiyon oluşturdum.Bu fonksiyon USART dan string göndermemizi sağlıyor.Normalde C de string yoktur ama bir kaç trick ile benzer bir işlem yapabiliriz.
static void USART_SendString(USART_TypeDef* USARTx, char* s) { while(*s) { while(!USART_GetFlagStatus(USARTx, USART_FLAG_TC)); USART_SendData(USARTx, *s); s++; } }
Şimdi elimden geldiğince her şeyi açıklamaya çalışıyorum.Biraz C çalışmakta fayda var ben burada biraz zorlanmıştım.Fonksiyon ilk parametresi USART numarası.Diğeri ise char s’in pointer adresi.Burada yaptığımız olay string in sırayla karakterlerini gönderip(TC flag’ı RESET ise yani Transmission Complete ise) s++ ile bir sonraki karaktere geçip s* ‘\0′(string sonu) olana kadar bu işlemi yapıyoruz.Sondaki”\r\n” ise
“\r = CR (Carriage Return) // Used as a new line character
\n = LF (Line Feed) // Used as a new line character
\r\n = CR + LF // Used as a new line character in Windows”
Yani gönderme bitti enter yap yeni bir şey gönderebilirim anlamında.
En üstte prototipini tanımlayarak işlemi bitirebiliriz.
static void USART_SendString(USART_TypeDef* USARTx, char* _string);
#include "stm32f0xx_conf.h" static unsigned int LEDState = 0; static void USART_SendString(USART_TypeDef* USARTx, char* s); void USART1_IRQHandler(void) { if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) { if((char)USART_ReceiveData(USART1) == '1') LEDState = 2; if((char)USART_ReceiveData(USART1) == '0') LEDState = 1; } USART_ClearITPendingBit(USART1, USART_IT_RXNE); } int main(void) { GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStrutcure; NVIC_InitTypeDef NVIC_InitStructure; RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA | RCC_AHBPeriph_GPIOC, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOC, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_1); GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_1); USART_InitStrutcure.USART_BaudRate = 115200; USART_InitStrutcure.USART_WordLength = USART_WordLength_8b; USART_InitStrutcure.USART_Parity = USART_Parity_No; USART_InitStrutcure.USART_StopBits = USART_StopBits_1; USART_InitStrutcure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStrutcure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; USART_Init(USART1, &USART_InitStrutcure); USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); USART_Cmd(USART1, ENABLE); NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_InitStructure.NVIC_IRQChannelPriority = 0; NVIC_Init(&NVIC_InitStructure); while(1) { if(LEDState == 2) { GPIO_SetBits(GPIOC, GPIO_Pin_8); USART_SendString(USART1, "LED On\r\n"); LEDState = 0; } if(LEDState == 1) { GPIO_ResetBits(GPIOC, GPIO_Pin_8); USART_SendString(USART1, "LED Off\r\n"); LEDState = 0; } } } static void USART_SendString(USART_TypeDef* USARTx, char* s) { while(*s) { while(!USART_GetFlagStatus(USARTx, USART_FLAG_TC)); USART_SendData(USARTx, *s); s++; } }
Son olarak çalışma videosu sizlerle.
https://www.youtube.com/watch?feature=player_embedded&v=0yjwHbt9974
Baran Bey, İyi çalışma olmuş eyvallah, fakat
yazdığınız kodları web sayfasından kopyalayabilseydik daha iyi olurdu.
ne firefox’da nede chrome da kodlar kopyalanamıyor.
Bence kodlar proje dosyası halinde download edilebilmeli.