PWM works

This commit is contained in:
2025-12-08 16:03:17 +01:00
parent 46077bcf1c
commit b16d941e62
3 changed files with 37 additions and 35 deletions

BIN
EE-Editor-Project.eeproj Normal file

Binary file not shown.

View File

@@ -1,12 +1,13 @@
#include "MotorController.h" #include "MotorController.h"
static constexpr uint16_t PWM_TOP = 0xFFFF; // PWM-Top für Timer1 (Fast PWM, ICR1)
static constexpr uint16_t PWM_TOP = 4095; // 12-bit Auflösung, ~488 Hz bei Prescaler 8
// Default-Konfiguration // Default-Konfiguration
const MotorConfig_t defaultConfig = { const MotorConfig_t defaultConfig = {
.minPWM = 0, .minPWM = 0,
.maxPWM = PWM_TOP, .maxPWM = PWM_TOP,
.inverted = false, .inverted = true,
.responseSpeedAccel = 50, // ca. 50% pro Sekunde Beschleunigung .responseSpeedAccel = 50, // ca. 50% pro Sekunde Beschleunigung
.responseSpeedDecel = 200, // schnelleres Abbremsen .responseSpeedDecel = 200, // schnelleres Abbremsen
// Stark progressiv: viel Feingefühl unten, steiler Verlauf oben // Stark progressiv: viel Feingefühl unten, steiler Verlauf oben
@@ -35,6 +36,10 @@ void MotorController::loadDefaults()
{ {
config = defaultConfig; config = defaultConfig;
if (config.minPWM > PWM_TOP)
config.minPWM = PWM_TOP;
if (config.maxPWM > PWM_TOP)
config.maxPWM = PWM_TOP;
// Response-Werte absichern // Response-Werte absichern
if (config.responseSpeedAccel <= 0) if (config.responseSpeedAccel <= 0)
config.responseSpeedAccel = 50; config.responseSpeedAccel = 50;
@@ -59,6 +64,10 @@ void MotorController::setConfig(const MotorConfig_t &newConfig)
{ {
config = newConfig; config = newConfig;
if (config.minPWM > PWM_TOP)
config.minPWM = PWM_TOP;
if (config.maxPWM > PWM_TOP)
config.maxPWM = PWM_TOP;
// min/max sanity // min/max sanity
if (config.maxPWM < config.minPWM) if (config.maxPWM < config.minPWM)
{ {
@@ -173,15 +182,14 @@ int16_t MotorController::applyDynamicResponse(int16_t targetPercent)
} }
targetPercent = constrain(targetPercent, 0, 100); targetPercent = constrain(targetPercent, 0, 100);
int16_t targetPromille = targetPercent * 10; int32_t targetPromille = (int32_t)targetPercent * 10;
int32_t delta = targetPromille - smoothedPromille;
int16_t delta = targetPromille - smoothedPromille;
// responseSpeed = Prozent pro Sekunde → Promille pro Sekunde // responseSpeed = Prozent pro Sekunde → Promille pro Sekunde
int16_t maxChangePerSec = (delta >= 0 ? config.responseSpeedAccel : config.responseSpeedDecel) * 10; int32_t maxChangePerSec = (delta >= 0 ? config.responseSpeedAccel : config.responseSpeedDecel) * 10L;
// maximaler Delta in diesem Zeitintervall // maximaler Delta in diesem Zeitintervall (mit Rundung)
int16_t maxDelta = (int16_t)((maxChangePerSec * (int32_t)elapsedTime) / 1000L); int32_t maxDelta = (maxChangePerSec * (int32_t)elapsedTime + 999) / 1000L;
if (maxDelta < 1) if (maxDelta < 1)
maxDelta = 1; // minimale Änderung erlauben maxDelta = 1; // minimale Änderung erlauben
@@ -190,7 +198,7 @@ int16_t MotorController::applyDynamicResponse(int16_t targetPercent)
else if (delta < -maxDelta) else if (delta < -maxDelta)
delta = -maxDelta; delta = -maxDelta;
smoothedPromille += delta; smoothedPromille += (int16_t)delta;
lastUpdateTime = currentTime; lastUpdateTime = currentTime;
return (smoothedPromille + 5) / 10; // runden return (smoothedPromille + 5) / 10; // runden
@@ -198,38 +206,30 @@ int16_t MotorController::applyDynamicResponse(int16_t targetPercent)
uint16_t MotorController::computePwm(uint16_t pwmLogical) uint16_t MotorController::computePwm(uint16_t pwmLogical)
{ {
// explizit 0 erlauben, auch wenn minPWM > 0 gesetzt ist // bei nicht invertierter Logik darf 0 auch unter minPWM fallen
if (pwmLogical == 0) if (!config.inverted && pwmLogical == 0)
return 0; return 0;
uint16_t pwmOut = pwmLogical; uint32_t base = pwmLogical;
if (pwmOut < config.minPWM) if (base < config.minPWM)
pwmOut = config.minPWM; base = config.minPWM;
if (pwmOut > config.maxPWM) if (base > config.maxPWM)
pwmOut = config.maxPWM; base = config.maxPWM;
uint32_t pwmOut = base;
if (config.inverted) if (config.inverted)
{ {
// Logischer Wert im Bereich [min,max] wird gespiegelt // Logischer Wert im Bereich [min,max] wird gespiegelt
uint32_t span = (uint32_t)config.maxPWM - (uint32_t)config.minPWM; uint32_t span = (uint32_t)config.maxPWM - (uint32_t)config.minPWM;
uint32_t offset = (uint32_t)pwmLogical - (uint32_t)config.minPWM; uint32_t offset = base - (uint32_t)config.minPWM;
uint32_t invOffset = span - offset; uint32_t inv = (uint32_t)config.minPWM + (span - offset);
uint32_t inv = (uint32_t)config.minPWM + invOffset; pwmOut = inv;
if (inv > PWM_TOP)
inv = PWM_TOP;
pwmOut = (uint16_t)inv;
} }
if (pwmOut < config.minPWM)
pwmOut = config.minPWM;
if (pwmOut > config.maxPWM)
pwmOut = config.maxPWM;
// Clamp auf 16-bit Top (ICR1)
if (pwmOut > PWM_TOP) if (pwmOut > PWM_TOP)
pwmOut = PWM_TOP; pwmOut = PWM_TOP;
return pwmOut; return (uint16_t)pwmOut;
} }
void MotorController::printStatus() void MotorController::printStatus()
@@ -255,6 +255,8 @@ void MotorController::printStatus()
Serial.print(config.maxPWM); Serial.print(config.maxPWM);
Serial.print(" span="); Serial.print(" span=");
Serial.print((uint32_t)config.maxPWM - (uint32_t)config.minPWM); Serial.print((uint32_t)config.maxPWM - (uint32_t)config.minPWM);
Serial.print(" top=");
Serial.print(PWM_TOP);
Serial.print(" respA="); Serial.print(" respA=");
Serial.print(config.responseSpeedAccel); Serial.print(config.responseSpeedAccel);
Serial.print(" respD="); Serial.print(" respD=");

View File

@@ -206,8 +206,8 @@ void loop()
motor.maintain(); motor.maintain();
// PWM auf Timer1 ausgeben (OC1A / D9), MotorController liefert bereits invertiert/geklemmt // PWM auf Timer1 ausgeben (OC1A / D9), MotorController liefert bereits invertiert/geklemmt
uint16_t pwmOut = gCurrentPwm; uint16_t pwmOut = gCurrentPwm;
if (pwmOut > 0xFFFF) if (pwmOut > 0x0FFF)
pwmOut = 0xFFFF; pwmOut = 0x0FFF;
OCR1A = pwmOut; OCR1A = pwmOut;
#ifdef DISPLAY_ENABLE #ifdef DISPLAY_ENABLE
@@ -273,7 +273,7 @@ void updateDisplay()
void configurePWMFrequency() void configurePWMFrequency()
{ {
// Timer1 16-bit Fast PWM on OC1A (Pin D9) // Timer1 Fast PWM on OC1A (Pin D9)
// Mode 14: Fast PWM, TOP = ICR1 // Mode 14: Fast PWM, TOP = ICR1
pinMode(motorPwmPin, OUTPUT); pinMode(motorPwmPin, OUTPUT);
@@ -287,10 +287,10 @@ void configurePWMFrequency()
TCCR1A |= (1 << WGM11); TCCR1A |= (1 << WGM11);
TCCR1B |= (1 << WGM12) | (1 << WGM13); TCCR1B |= (1 << WGM12) | (1 << WGM13);
// 16-bit Auflösung, voller Bereich // 12-bit Auflösung, niedrigere PWM-Frequenz (~488 Hz bei Prescaler 8)
ICR1 = 0xFFFF; ICR1 = 0x0FFF;
OCR1A = 0; OCR1A = 0;
// Prescaler 8 für ~2 kHz (16 MHz / 8 / 65536) // Prescaler 8
TCCR1B |= (1 << CS11); TCCR1B |= (1 << CS11);
} }