DRV8874Driver (AI coded)
- from machine import Pin, PWM, Timer
- import time
- # ==============================================================================
- # 1. HILFSFUNKTION: BERECHNUNG DES IPROPI-WIDERSTANDS
- # ==============================================================================
- def calculate_ipropi_resistor(vref: float, itrip_max: float) -> float:
- """Berechnet den benötigten Widerstandswert (R_IPROPI) für den DRV8874."""
- A_IPROPI = 450e-6
- if itrip_max <= 0 or vref <= 0:
- raise ValueError("VREF und maximaler Strom müssen größer als 0 sein.")
- return vref / (itrip_max * A_IPROPI)
- # ==============================================================================
- # 2. TREIBER-KLASSE MIT OPTIONALER TIMER-ÜBERGABE
- # ==============================================================================
- class DRV8874Driver:
- def __init__(self, pwm_in1, pwm_in2, pin_nfault, pin_nsleep, use_interrupt=False, use_softstart=False, timer=None):
- """
- Initialisiert den DRV8874 Motortreiber im nicht-blockierenden Modus.
- :param pwm_in1: machine.PWM Objekt für IN1
- :param pwm_in2: machine.PWM Objekt für IN2
- :param pin_nfault: machine.Pin Objekt (Eingang mit PULL_UP)
- :param pin_nsleep: machine.Pin Objekt (Ausgang)
- :param use_interrupt: Wenn True, wird ein Hardware-Interrupt auf nFAULT gesetzt
- :param use_softstart: Wenn True, rampt der Motor sanft auf die Zielgeschwindigkeit
- :param timer: Optionales machine.Timer Objekt. Wenn None, wird ein interner Timer erstellt.
- """
- self.in1_pwm = pwm_in1
- self.in2_pwm = pwm_in2
- self.nfault = pin_nfault
- self.nsleep = pin_nsleep
- self.interrupt_active = use_interrupt
- self.softstart_active = use_softstart
- self.has_fault = False
- self.current_duty = 0
- self.target_duty = 0
- self.duty_step = 0
- self.current_direction = None
- # Timer zuweisen oder automatisch erstellen
- if timer is not None:
- self.ramp_timer = timer
- print("--> Externer Timer für Soft-Start zugewiesen.")
- else:
- # Fallback auf Standard-Timer, falls kein externer übergeben wurde
- self.ramp_timer = Timer(-1) if hasattr(Timer, "KEYBOARD_INTERRUPT") else Timer(0)
- print("--> Interner Timer für Soft-Start automatisch erstellt.")
- # Chip aufwachen lassen & stoppen
- self.nsleep.value(1)
- self.stop(mode='brake')
- if self.interrupt_active:
- self.nfault.irq(trigger=Pin.IRQ_FALLING, handler=self._fault_isr)
- print("--> Hardware-Interrupt für nFAULT aktiviert.")
- if self.softstart_active:
- print("--> Nicht-blockierender Soft-Start aktiviert.")
- def _fault_isr(self, pin):
- """Interne ISR bei Überstrom. Schaltet sofort aus und stoppt den Timer."""
- self.in1_pwm.duty_u16(0)
- self.in2_pwm.duty_u16(0)
- self.ramp_timer.deinit()
- self.has_fault = True
- def _timer_ramp_callback(self, t):
- """Wird im Hintergrund periodisch aufgerufen, um die PWM zu erhöhen."""
- if self.check_fault():
- self.stop(mode='coast')
- return
- if abs(self.target_duty - self.current_duty) <= abs(self.duty_step):
- self.current_duty = self.target_duty
- self.ramp_timer.deinit()
- else:
- self.current_duty += self.duty_step
- self._apply_pwm(self.current_direction, self.current_duty)
- def check_fault(self) -> bool:
- """Prüft auf Fehler."""
- if self.interrupt_active:
- return self.has_fault
- else:
- return self.nfault.value() == 0
- def reset_fault(self):
- """Fehler zurücksetzen."""
- print("Setze DRV8874 via nSLEEP zurück...")
- self.stop(mode='brake')
- self.has_fault = False
- self.nsleep.value(0)
- time.sleep_ms(5)
- self.nsleep.value(1)
- time.sleep_ms(5)
- def stop(self, mode='brake'):
- """Stoppt den Motor SOFORT und bricht jede aktive Beschleunigungsrampe ab."""
- self.ramp_timer.deinit()
- if mode == 'brake':
- self.in1_pwm.duty_u16(0)
- self.in2_pwm.duty_u16(0)
- elif mode == 'coast':
- self.in1_pwm.duty_u16(0)
- self.in2_pwm.duty_u16(0)
- self.nsleep.value(0)
- self.current_duty = 0
- self.target_duty = 0
- self.current_direction = None
- def drive_motor(self, direction: str, speed_percent: float, duration_ms=500):
- """Startet den Motor oder ändert die Geschwindigkeit verzögerungsfrei."""
- self.nsleep.value(1)
- self.ramp_timer.deinit()
- if self.check_fault():
- print("WARNUNG: Motor kann nicht starten. nFAULT ist aktiv!")
- return
- if speed_percent > 100.0: speed_percent = 100.0
- if speed_percent < 0.0: speed_percent = 0.0
- self.target_duty = int((speed_percent / 100.0) * 65535)
- self.current_direction = direction.lower()
- if self.softstart_active and self.target_duty > self.current_duty:
- step_interval_ms = 20
- total_steps = duration_ms // step_interval_ms
- if total_steps < 1: total_steps = 1
- self.duty_step = (self.target_duty - self.current_duty) // total_steps
- if self.duty_step == 0: self.duty_step = 1
- self.ramp_timer.init(period=step_interval_ms, mode=Timer.PERIODIC, callback=self._timer_ramp_callback)
- else:
- self.current_duty = self.target_duty
- self._apply_pwm(self.current_direction, self.current_duty)
- def _apply_pwm(self, direction, duty):
- if direction == 'forward':
- self.in2_pwm.duty_u16(0)
- self.in1_pwm.duty_u16(duty)
- elif direction == 'backward':
- self.in1_pwm.duty_u16(0)
- self.in2_pwm.duty_u16(duty)
- # ==============================================================================
- # 3. HAUPTPROGRAMM (ANWENDUNGSBEISPIEL MIT EXTERNEM TIMER)
- # ==============================================================================
- # Hardware-Pins konfigurieren (Beispiel für Raspberry Pi Pico)
- pwm1 = PWM(Pin(16)); pwm2 = PWM(Pin(17))
- pwm1.freq(20000); pwm2.freq(20000)
- fault_pin = Pin(18, Pin.IN, Pin.PULL_UP)
- sleep_pin = Pin(19, Pin.OUT)
- # --- Schritt A: Timer-Objekt AUSSERHALB erstellen ---
- # Wir deklarieren hier einen dedizierten Hardware-Timer (z.B. Timer ID 1)
- mein_externer_timer = Timer(1)
- # --- Schritt B: Objekt initialisieren und den externen Timer übergeben ---
- motor = DRV8874Driver(
- pwm_in1=pwm1,
- pwm_in2=pwm2,
- pin_nfault=fault_pin,
- pin_nsleep=sleep_pin,
- use_interrupt=True,
- use_softstart=True,
- timer=mein_externer_timer # <-- Hier wird das externe Objekt übergeben
- )
- # Motor testen
- print("Starte Motor...")
- motor.drive_motor('forward', 100.0, duration_ms=1000)
Pasted 2026-10-13 23:42:10
Short link:
Short link: