Macademia'nın robotik ve mühendislik programı · ücretsiz seviye tespiti ve kişisel öğrenme yolu

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

Zamanlayıcılar ve PWM

Ön bölücü (PSC), otomatik yeniden yükleme (ARR), karşılaştırma (CCR); frekans, görev oranı ve çözünürlük; servo ve motor PWM'i.

Bu ünitenin sonunda

  • Zamanlayıcı sayacının PSC ve ARR ile nasıl saydığını ve taştığını açıklamak
  • İstenen PWM frekansı için PSC ve ARR seçmek; çözünürlük ile frekans arasındaki ödünleşimi göstermek
  • CCR ile görev oranını ayarlamak; servo için mikrosaniye çözünürlüklü ayar kurmak
  • PWM'i hem HAL hem yazmaçlarla başlatmak

Ders notları

STM32 zamanlayıcıları (TIM1–TIM14) donanımda sayan sayaçlardır; işlemci uğraşmadan kesin zamanlama üretirler. Bir zamanlayıcının üç temel yazmacı vardır:

  • PSC (ön bölücü): giriş saatini PSC + 1'e böler.
  • ARR (yeniden yükleme): sayaç 0'dan ARR'ye kadar sayar, sonra başa döner (güncelleme olayı).
  • CCR (karşılaştırma): PWM kip 1'de sayaç CCR'den küçükken çıkış 1'dir.
fPWM = fTIM / ((PSC + 1)(ARR + 1))    görev = CCR / (ARR + 1)

Frekans ve çözünürlük

84 MHz zamanlayıcı saatiyle 20 kHz motor PWM'i için PSC = 0, ARR = 4199: görev oranı 4200 adımda ayarlanır (≈ 12 bit). Aynı saatle 1 MHz istersen ARR = 83 olur, yalnız 84 adım kalır. Yüksek frekans, düşük çözünürlük demektir. Motorlar için 20 kHz insan kulağının üstündedir: motor ötmez.

Servo

Servo 50 Hz'te 1–2 ms darbe ister. PSC = 83 (84 MHz → 1 MHz, 1 µs adım) ve ARR = 19999 seçilirse CCR doğrudan mikrosaniyedir: CCR = 1500 orta konum. 16 bitlik sınır (ARR ≤ 65535) yüzünden düşük frekanslarda PSC büyütülmek zorundadır.

Aynı zamanlayıcı giriş yakalama (enkoder ya da darbe ölçümü), tek darbe ve enkoder arayüzü kiplerinde de çalışır; TIM1 ve TIM8 motor sürmek için ölü zamanlı tamamlayıcı çıkışlar sunar.

Simülasyonlar

Zamanlayıcı ve PWM: PSC/ARR/CCR hesaplayıcı

Sayaç (CNT) testere dişi biçiminde sayar, CCR ile karşılaştırılır, çıkış PWM olur. İstenen frekansı yaz, çözücü 16 bit sınırında PSC ve ARR'yi bulsun; görev oranını ve çözünürlüğü izle.

ARRCCR0OC1
f = 84 MHz / (0 + 1) / (4199 + 1) = 20,000 kHz görev = 1050 / 4200 = 25,0% · çözünürlük 12,0 bit sayım adımı = 0,012 µs

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

PWM hesaplayıcıda 84 MHz ile 20 kHz iste: çözücünün bulduğu PSC/ARR'yi ve çözünürlüğü (bit) not et. Aynı şeyi 50 Hz ve 1 MHz için yap. CCR'yi ARR'den büyük yap: görev oranı ne oluyor? Servo düğmesine bas ve 90° için CCR'nin 1500 olduğunu doğrula.

Wokwi'de

  • Wokwi'de STM32 kartına bir servo bağla ve 50 Hz PWM üret: PSC = f_tim(MHz) − 1, ARR = 19999 ile CCR doğrudan mikrosaniye olur.
  • Wokwi'nin mantık analizörü parçasını PWM pinine bağlayıp görev oranını ölç.
Wokwi'yi aç (yeni sekme)

Kod

TIM3 CH1 (PA6) 20 kHz PWM: HAL
TIM_HandleTypeDef htim3;

void pwm_init(void) {
  /* TIM3 APB1'de: 84 MHz. 84e6 / (0+1) / (4199+1) = 20 kHz */
  htim3.Instance = TIM3;
  htim3.Init.Prescaler = 0;
  htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim3.Init.Period = 4199;                        /* ARR */
  htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
  HAL_TIM_PWM_Init(&htim3);                        /* PA6 AF2 ayarı HAL_TIM_MspPostInit içinde */
  TIM_OC_InitTypeDef oc = {0};
  oc.OCMode = TIM_OCMODE_PWM1;                     /* CNT < CCR iken 1 */
  oc.Pulse = 0;                                    /* CCR */
  oc.OCPolarity = TIM_OCPOLARITY_HIGH;
  HAL_TIM_PWM_ConfigChannel(&htim3, &oc, TIM_CHANNEL_1);
  HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);
}

void pwm_set_percent(uint32_t pct) {
  uint32_t arr = __HAL_TIM_GET_AUTORELOAD(&htim3);
  __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, (arr + 1) * pct / 100);   /* bir sonraki güncellemede geçerli */
}
Aynı PWM, yazmaçlarla
void pwm_init_reg(void) {
  RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
  RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
  GPIOA->MODER  = (GPIOA->MODER & ~(3U << 12)) | (2U << 12);      /* PA6 = AF */
  GPIOA->AFR[0] = (GPIOA->AFR[0] & ~(0xFU << 24)) | (2U << 24);   /* AF2 = TIM3_CH1 */
  TIM3->PSC = 0;
  TIM3->ARR = 4199;
  TIM3->CCR1 = 0;
  TIM3->CCMR1 = (6U << TIM_CCMR1_OC1M_Pos) | TIM_CCMR1_OC1PE;       /* PWM kip 1, ön yükleme */
  TIM3->CCER |= TIM_CCER_CC1E;                                      /* kanal çıkışını aç */
  TIM3->CR1 |= TIM_CR1_ARPE | TIM_CR1_CEN;                          /* sayacı başlat */
}

Sık yapılan hatalar

  • PSC ve ARR'ye "bölücü" değerini yazmak: donanım +1 ekler; 1000'e bölmek için 999 yazılır.
  • APB bölücüsü yüzünden zamanlayıcı saatini yanlış almak (4. ünite).
  • Alternatif işlev numarasını (AF2) ayarlamamak: pin PWM vermez.
  • Çalışırken ARR'yi ön yükleme (ARPE) olmadan değiştirmek: o periyotta tuhaf bir darbe çıkar.

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

PSC/ARR hesabını sihirli sayı olarak değil, derleme zamanında hesaplanan sabitlerle yaz: #define ARR (TIM_HZ / PWM_HZ - 1).

  • Bir static_assert(ARR <= 0xFFFF) sınırı derlemede yakalar.
  • PWM ayarı ile görev oranı hesabını saf fonksiyonda tutup bilgisayarda test et.

Kendini sına

  1. f_TIM = 84 MHz, PSC = 83, ARR = 999. PWM frekansı?

  2. ARR = 999 iken %25 görev için CCR?

  3. Aynı zamanlayıcı saatinde PWM frekansını artırmak çözünürlüğe ne yapar?

  4. Servo için PSC = 83 ve ARR = 19999 seçmenin faydası?

Bu üniteden sonra bitirme projesinde

  • PWM katmanı: pwm_set_percent(), frekans ayarı ve yön pinleri; mantık analizörüyle ölçülmüş frekans ve görev oranı tablosu.

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

ESOF 323, 3. 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ç