Okullar için Robotik ve Mühendislik · anaokulundan liseye

3. ünite / 11 · yaklaşık 5 saat

GPIO: yazmaçlarla ve HAL ile

Saat açma, MODER/OTYPER/PUPDR ile yapılandırma, ODR/IDR ile yazma-okuma, BSRR'nin atomikliği ve HAL karşılıkları.

Bu ünitenin sonunda

  • Bir GPIO portunu kullanmadan önce RCC'den saatini açmak
  • MODER, OTYPER ve PUPDR bitleriyle pini giriş, çıkış, alternatif işlev ya da analog yapmak
  • ODR, IDR ve BSRR ile pin yazmak ve okumak; oku-değiştir-yaz yarışını açıklamak
  • Aynı işi HAL ile yazıp kayıt düzeyiyle karşılaştırmak

Ders notları

STM32'de her GPIO portu (GPIOA, GPIOB…) 16 pinlik bir yazmaç kümesidir. Kullanmadan önce saatini açmak gerekir: RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN. Saat kapalıyken yazmaçlara yazılan her şey yok sayılır; bu, yeni başlayanın ilk hatasıdır.

Yapılandırma yazmaçları

  • MODER: pin başına 2 bit. 00 giriş, 01 çıkış, 10 alternatif işlev (UART, PWM), 11 analog (ADC).
  • OTYPER: pin başına 1 bit. 0 push-pull (1'i de 0'ı da sürer), 1 open-drain (yalnız 0'a çeker; I²C gibi).
  • PUPDR: pin başına 2 bit. 00 yok, 01 pull-up, 10 pull-down.

Veri yazmaçları

IDR pinlerin o anki seviyesini okur. ODR çıkış değerini tutar. GPIOA->ODR |= 1 << 5 bir oku-değiştir-yaz işlemidir: okuma ile yazma arasında bir kesme aynı portun başka bir bitini değiştirirse o değişiklik silinir. BSRR bu sorunu çözer: alt 16 bite yazılan 1 o pini set eder, üst 16 bite yazılan 1 reset eder; tek yazmadır, araya bir şey giremez.

PA5 çıkış: MODER[11:10] = 01   PA5 = 1: BSRR = 1 << 5   PA5 = 0: BSRR = 1 << 21

HAL

HAL (Hardware Abstraction Layer) aynı işi HAL_GPIO_Init, HAL_GPIO_WritePin, HAL_GPIO_ReadPin ile yapar: okunaklı ve ailelerarası taşınabilir, biraz daha yavaş ve büyük. Gerçek projelerde çoğunlukla HAL kullanılır; yazmaçları bilmek ise hata ayıklarken ve zamanlamanın kritik olduğu yerde işe yarar.

Simülasyonlar

GPIO yazmaç görüntüleyici: MODER, OTYPER, PUPDR, ODR, IDR

Bitlere tıklayarak PA5'i (Nucleo LED'i) ve PC13'ü (kullanıcı butonu) yapılandır. Sanal pin seviyesi, IDR okuması ve aynı işi yapan kayıt düzeyi ile HAL C kodu birlikte değişir. BSRR yazmasını ve kısa devreyi dene.

Nucleo-F401RELD2 · PA5 = floatB1PC13 IDR = 0 (clk off)
MODER
0x0000_0000
OTYPER
0x0000_0000
PUPDR
0x0000_0000
ODR
0x0000_0000
IDR
0x0000_0000

GPIOA5: input · push-pull · pull none · 00 in

/* kayıt düzeyi */
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
GPIOA->MODER = (GPIOA->MODER & ~(3U << (5 * 2))) | (0U << (5 * 2));
GPIOA->PUPDR = (GPIOA->PUPDR & ~(3U << (5 * 2))) | (0U << (5 * 2));
uint32_t level = (GPIOA->IDR >> 5) & 1U;
/* HAL */
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitTypeDef g = {0};
g.Pin = GPIO_PIN_5; g.Mode = GPIO_MODE_INPUT; g.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &g);
GPIO_PinState level = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5);

Saat kapalı yazmaçlara yazılanlar yok sayılır.

3B STM32 geliştirme kartı

Nucleo benzeri kart 3B masada: GPIOA saatini aç, PA5'i MODER ile çıkış yap ve BSRR yaz; başlık pinleri ve LD2 anında değişir. TIM3 PWM'i açınca motor görev oranına göre döner, kartın üstünde zamanlayıcı dalgası görünür. Sürükleyerek döndür, iki parmakla yakınlaştır. Durum testli saf mantıktan gelir.

GPIOA MODER 0x0000_0000 · ODR 0x0000_0000 (saat kapalı) PA5 = float → LD2 sönük TIM3 CH1: 20,000 kHz · görev 0,0% → 0,00 V → 0 rpm
RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
GPIOA->MODER = (GPIOA->MODER & ~(3U << (5 * 2))) | (0U << (5 * 2));
GPIOA->PUPDR = (GPIOA->PUPDR & ~(3U << (5 * 2))) | (0U << (5 * 2));
uint32_t level = (GPIOA->IDR >> 5) & 1U;

Kendin dene

Yazmaç görüntüleyicide PA5'i çıkış yap (MODER bitleri 01) ve ODR'nin 5. bitine tıkla: LED yanıyor mu? Saat kapalıyken aynı şeyi dene. PC13'ü pull-up'sız giriş yap ve butonu bırak: IDR neden titriyor? Pull-up aç. Son olarak PA5'i push-pull 1 sürerken "dışarıdan GND'ye çek" seçeneğini aç ve kısa devre uyarısını oku; open-drain'e geçince ne değişiyor?

Wokwi'de

  • Wokwi'de yeni bir proje aç ve kart olarak Nucleo-C031C6'yı seç (STM32C0 de MODER/ODR/IDR düzenini kullanır; taban adresleri farklıdır).
  • LED'i ve butonu bağla; önce HAL_GPIO_WritePin ile, sonra BSRR yazmacıyla yak.
  • Blue Pill (STM32F103) seçersen GPIO'nun CRL/CRH yazmaçlarıyla ayarlandığını gör: aileler arasındaki farkın canlı örneği.
Wokwi'yi aç (yeni sekme)

Kod

LED (PA5): kayıt düzeyinde, CMSIS başlıklarıyla
#include "stm32f4xx.h"

int main(void) {
  RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;            /* 1) GPIOA saatini aç */
  GPIOA->MODER &= ~(3U << (5 * 2));                /* 2) PA5 kip bitlerini temizle */
  GPIOA->MODER |=  (1U << (5 * 2));                /*    01 = genel amaçlı çıkış */
  RCC->AHB1ENR |= RCC_AHB1ENR_GPIOCEN;
  GPIOC->PUPDR &= ~(3U << (13 * 2));               /* PC13 giriş (sıfırlamada zaten 00) */
  while (1) {
    if ((GPIOC->IDR & (1U << 13)) == 0)            /* Nucleo butonu basılıyken 0 */
      GPIOA->BSRR = 1U << 5;                       /* set: tek yazma, atomik */
    else
      GPIOA->BSRR = 1U << (5 + 16);                /* reset: üst 16 bit */
  }
}
Aynı iş HAL ile
#include "stm32f4xx_hal.h"

int main(void) {
  HAL_Init();                                      /* SysTick 1 ms, NVIC grubu */
  __HAL_RCC_GPIOA_CLK_ENABLE();
  __HAL_RCC_GPIOC_CLK_ENABLE();
  GPIO_InitTypeDef g = {0};
  g.Pin = GPIO_PIN_5; g.Mode = GPIO_MODE_OUTPUT_PP; g.Pull = GPIO_NOPULL; g.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOA, &g);
  g.Pin = GPIO_PIN_13; g.Mode = GPIO_MODE_INPUT;
  HAL_GPIO_Init(GPIOC, &g);
  while (1) {
    GPIO_PinState b = HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_13);
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, b == GPIO_PIN_RESET ? GPIO_PIN_SET : GPIO_PIN_RESET);
    HAL_Delay(5);                                  /* basit sıçrama önleme */
  }
}

Sık yapılan hatalar

  • GPIO saatini açmayı unutmak: yazmaçlar hiç değişmez, kod "çalışmıyor" gibi görünür.
  • MODER'i |= ile ayarlamak: önceki 2 bit temizlenmezse 01 | 10 = 11 (analog) olur. Önce maskele, sonra yaz.
  • ODR'ye kesme ve ana döngüden birlikte |= ile yazmak: yarış durumu. BSRR kullan.
  • Nucleo butonunun basılıyken 0 okunduğunu unutmak (dış pull-up'lı, GND'ye çeker).

Yazılım mühendisliği bağlantısı

Bit işlemlerini adlandırılmış küçük fonksiyonlara sar: gpio_set_mode(GPIOA, 5, MODE_OUTPUT).

  • Bu fonksiyonlar bir yazmaç yapısı üzerinde çalışırsa (gerçek adres yerine sahte struct), bilgisayarda birim testi yapılabilir: bu simülasyondaki gibi.
  • HAL mı yazmaç mı kararını kod incelemesinde gerekçesiyle yaz.

Kendini sına

  1. PA5'i genel amaçlı çıkış yapmak için MODER'in hangi bitlerine ne yazılır?

  2. BSRR = 1 << 21 ne yapar?

  3. ODR |= ... yerine BSRR neden tercih edilir?

  4. Open-drain çıkışa 1 yazılınca pin ne olur (pull-up yoksa)?

Gerçek parçalar (Hyvex, 3B modelli)

ESOF 323, 2. hafta

Esc
  • PanelAna sayfaSayfa
  • ModüllerTüm modüllerSayfa
  • ParçalarParça ansiklopedisiSayfa
  • Mühendislik yoluBüyükler için robotik: 128 parça, 7 seviyeSayfa
  • Robotik dersi (ESOF 323)Üniversite robotik dersi, 14 haftaSayfa
  • Drone dersiBüyükler için: parça, simülasyon, yazılım; 10 üniteSayfa
  • Blok atölyesiSerbest blok programlamaAraç
  • Devre laboratuvarıSanal Arduino ve devreAraç
  • Robot arenasıSanal robot sürüşüAraç
  • OyunlarBloklarla 8 öğretici oyunAraç
  • Mikro Kart atölyesiSanal LED kartı bloklarla programlaAraç
  • Robot atölyesiMikro Kart'ı robota tak, bloklarla görev yapAraç