📊 hal::pwm
Pulse Width Modulation - PWM Sinyal Üretimi
~320 lines
~12 function
STM32/GD32/ESP32
📖 Overview
PWM modülü, timer donanımını kullanarak let genişlikli dijital sinyaller üretir. Motor hız kontrolü, LED parlaklık ayarı, servo kontrol ve analog çıkış simülasyonu for kullanılır.
🔑 Key Features
- Konfigüre edilebilir frekans (1 Hz - 1 MHz+)
- 0-100% duty cycle kontrolü
- Çoklu kanal desteği (4 kanala kadar)
- Complementary output (dead-time ile)
- Hardware sync ve trigger
- DMA destekli dalga formu üretimi
- One-pulse mode
- Encoder interface mode
🚀 Quick Start
import hal::pwm, hal::gpio
// PWM pin setup (TIM3 CH1 -> PA6)
gpio.pin_init(gpio.PORT_A, 6, do
mode: gpio.MODE_AF,
af: gpio.AF2_TIM3
end)
// PWM initialization (1 kHz, 50% duty)
let pwm_handle = pwm.init(pwm.TIM3, pwm.CHANNEL_1, do
frequency: 1000, // 1 kHz
duty_cycle: 50, // 50%
polarity: pwm.ACTIVE_HIGH,
mode: pwm.MODE_PWM1
end)
// Start PWM
pwm.start(pwm_handle)
// Update duty cycle
pwm.set_duty_cycle(pwm_handle, 75) // 75%
📦 Tipler ve Enum'lar
// Timer Seçimi
enum Timer {
TIM1, TIM2, TIM3, TIM4, TIM5,
TIM8, TIM9, TIM10, TIM11, TIM12
}
// PWM Kanalları
enum Channel {
CHANNEL_1, CHANNEL_2, CHANNEL_3, CHANNEL_4
}
// PWM Modları
enum Mode {
PWM1, // Active when CNT < CCR
PWM2 // Active when CNT > CCR
}
// Polarity
enum Polarity {
ACTIVE_HIGH, // High is active
ACTIVE_LOW // Low is active
}
// Alignment Mode
enum Alignment {
EDGE, // Edge-aligned
CENTER1, // Center-aligned mode 1
CENTER2, // Center-aligned mode 2
CENTER3 // Center-aligned mode 3
}
struct PWMConfig do
frequency: int, // Hz (1-1000000)
duty_cycle: float, // 0.0-100.0
polarity: Polarity,
mode: Mode,
alignment: Alignment
end
💡 Example 1: LED Dimming (Parlaklık Kontrolü)
LED parlaklığını PWM ile kontrol etme
import hal::pwm, hal::core
function led_dimmer() do
// PWM setup (10 kHz)
let led_pwm = pwm.init(pwm.TIM2, pwm.CHANNEL_1, do
frequency: 10000,
duty_cycle: 0,
polarity: pwm.ACTIVE_HIGH,
mode: pwm.MODE_PWM1
end)
pwm.start(led_pwm)
// Fade in/out loop
loop do
// Fade in (0% -> 100%)
for brightness in 0..100 for do
pwm.set_duty_cycle(led_pwm, brightness.float())
core.delay_ms(10)
end
core.delay_ms(500)
// Fade out (100% -> 0%)
for brightness in (0..100).reverse() for do
pwm.set_duty_cycle(led_pwm, brightness.float())
core.delay_ms(10)
end
core.delay_ms(500)
end
end
💡 Example 2: DC Motor Hız Kontrolü
L298N sürücüsü ile motor kontrolü
import hal::pwm, hal::gpio
struct Motor do
pwm: PWMHandle,
dir_pin1: GPIOPin,
dir_pin2: GPIOPin
end
function motor_init() -> Motor do
// Direction pins
let in1 = gpio.pin_init(gpio.PORT_B, 0, gpio.MODE_OUTPUT)
let in2 = gpio.pin_init(gpio.PORT_B, 1, gpio.MODE_OUTPUT)
// PWM for speed (20 kHz)
let motor_pwm = pwm.init(pwm.TIM1, pwm.CHANNEL_1, do
frequency: 20000,
duty_cycle: 0,
polarity: pwm.ACTIVE_HIGH,
mode: pwm.MODE_PWM1
end)
pwm.start(motor_pwm)
return Motor do
pwm: motor_pwm,
dir_pin1: in1,
dir_pin2: in2
end
end
function motor_set_speed(motor: Motor, speed: float) do
// speed: -100 to +100 (negative = reverse)
if speed > 0 do
// Forward
gpio.pin_write(motor.dir_pin1, gpio.HIGH)
gpio.pin_write(motor.dir_pin2, gpio.LOW)
pwm.set_duty_cycle(motor.pwm, speed)
else if speed < 0 do
// Reverse
gpio.pin_write(motor.dir_pin1, gpio.LOW)
gpio.pin_write(motor.dir_pin2, gpio.HIGH)
pwm.set_duty_cycle(motor.pwm, -speed)
else do
// Stop
gpio.pin_write(motor.dir_pin1, gpio.LOW)
gpio.pin_write(motor.dir_pin2, gpio.LOW)
pwm.set_duty_cycle(motor.pwm, 0.0)
end
end
function ana() do
let motor = motor_init()
// Acceleration test
for speed in 0..100 for do
motor_set_speed(motor, speed.float())
core.delay_ms(50)
end
core.delay_ms(2000)
// Deceleration
for speed in (0..100).reverse() for do
motor_set_speed(motor, speed.float())
core.delay_ms(50)
end
motor_set_speed(motor, 0.0) // Stop
end
💡 Example 3: Servo Motor Kontrolü (SG90)
50Hz PWM ile servo açı kontrolü
import hal::pwm
struct Servo do
pwm: PWMHandle,
min_pulse: float, // ms
max_pulse: float // ms
end
function servo_init(timer: Timer, channel: Channel) -> Servo do
// Servo: 50Hz, 1-2ms pulse width
let servo_pwm = pwm.init(timer, channel, do
frequency: 50, // 50 Hz (20ms period)
duty_cycle: 7.5, // 1.5ms pulse (90°)
polarity: pwm.ACTIVE_HIGH,
mode: pwm.MODE_PWM1
end)
pwm.start(servo_pwm)
return Servo do
pwm: servo_pwm,
min_pulse: 1.0, // 1ms = 0°
max_pulse: 2.0 // 2ms = 180°
end
end
function servo_set_angle(servo: Servo, angle: float) do
// angle: 0-180 degrees
let clamped = angle.clamp(0.0, 180.0)
// Map angle to pulse width (1-2ms)
let pulse_ms = servo.min_pulse +
(clamped / 180.0) * (servo.max_pulse - servo.min_pulse)
// Convert to duty cycle (20ms period)
let duty = (pulse_ms / 20.0) * 100.0
pwm.set_duty_cycle(servo.pwm, duty)
end
function ana() do
let servo = servo_init(pwm.TIM2, pwm.CHANNEL_1)
// Sweep 0° to 180°
loop do
for angle in 0..180 for do
servo_set_angle(servo, angle.float())
core.delay_ms(15)
end
for angle in (0..180).reverse() for do
servo_set_angle(servo, angle.float())
core.delay_ms(15)
end
end
end
💡 Example 4: Buzzer Melodi Çalma
PWM frekans değiştirerek nota üretme
import hal::pwm, hal::core
// Note frequencies (Hz)
const DO = 262
const RE = 294
const MI = 330
const FA = 349
const SOL = 392
const LA = 440
const SI = 494
const DO_HIGH = 523
function buzzer_init() -> PWMHandle do
let buzzer = pwm.init(pwm.TIM3, pwm.CHANNEL_2, do
frequency: 440, // Default: LA (440 Hz)
duty_cycle: 50,
polarity: pwm.ACTIVE_HIGH,
mode: pwm.MODE_PWM1
end)
return buzzer
end
function play_tone(buzzer: PWMHandle, freq: int, duration_ms: int) do
pwm.set_frequency(buzzer, freq)
pwm.start(buzzer)
core.delay_ms(duration_ms)
pwm.stop(buzzer)
end
function play_melody(buzzer: PWMHandle) do
// "Twinkle Twinkle Little Star"
let melody = [
(DO, 500), (DO, 500), (SOL, 500), (SOL, 500),
(LA, 500), (LA, 500), (SOL, 1000),
(FA, 500), (FA, 500), (MI, 500), (MI, 500),
(RE, 500), (RE, 500), (DO, 1000)
]
her (note, duration) in melody for do
play_tone(buzzer, note, duration)
core.delay_ms(50) // Short pause between notes
end
end
function ana() do
let buzzer = buzzer_init()
loop do
play_melody(buzzer)
core.delay_ms(2000)
end
end
📊 API Referansı
Initialization
function init(timer: Timer, channel: Channel, config: PWMConfig) -> PWMHandle
function deinit(handle: PWMHandle)
function start(handle: PWMHandle)
function stop(handle: PWMHandle)
Configuration
function set_duty_cycle(handle: PWMHandle, duty: float) // 0.0-100.0
function get_duty_cycle(handle: PWMHandle) -> float
function set_frequency(handle: PWMHandle, freq: int) // Hz
function get_frequency(handle: PWMHandle) -> int
function set_polarity(handle: PWMHandle, pol: Polarity)
Advanced
function set_pulse_width(handle: PWMHandle, width_us: int) // Microseconds
function enable_complementary(handle: PWMHandle, deadtime_ns: int)
function set_phase_shift(handle: PWMHandle, phase_degrees: float)
function configure_dma(handle: PWMHandle, buffer: Dizi[int])
⚙️ Platform Desteği
| Platform | Timers | Max Freq | Resolution |
|---|---|---|---|
| STM32F4 | TIM1-14 | 84 MHz | 16-bit |
| STM32F1 | TIM1-4 | 72 MHz | 16-bit |
| ESP32 | LEDC 0-7 | 40 MHz | 20-bit |
| GD32VF103 | TIM0-6 | 108 MHz | 16-bit |
💡 Best Practices
- Frekans seçimi: Motor kontrolü for 20-25 kHz (insan işitme aralığı dışı)
- Servo kontrol: 50 Hz const frekans, 1-2ms pulse genişliği
- LED dimming: 100+ Hz (göz yanıp sönmeyi algılamaz)
- Timer çakışması: Aynı timer'ın farklı kanallarını kullanın
- Dead-time: H-bridge kontrolünde shoot-through önlemek for gerekli
🔗 Related Modules
- hal::timer - Hardware timer (PWM'in temeli)
- hal::gpio - GPIO AF configuration
- hal::dma - DMA-based waveform generation