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"
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
const MotorConfig_t defaultConfig = {
.minPWM = 0,
.maxPWM = PWM_TOP,
.inverted = false,
.inverted = true,
.responseSpeedAccel = 50, // ca. 50% pro Sekunde Beschleunigung
.responseSpeedDecel = 200, // schnelleres Abbremsen
// Stark progressiv: viel Feingefühl unten, steiler Verlauf oben
@@ -35,6 +36,10 @@ void MotorController::loadDefaults()
{
config = defaultConfig;
if (config.minPWM > PWM_TOP)
config.minPWM = PWM_TOP;
if (config.maxPWM > PWM_TOP)
config.maxPWM = PWM_TOP;
// Response-Werte absichern
if (config.responseSpeedAccel <= 0)
config.responseSpeedAccel = 50;
@@ -59,6 +64,10 @@ void MotorController::setConfig(const MotorConfig_t &newConfig)
{
config = newConfig;
if (config.minPWM > PWM_TOP)
config.minPWM = PWM_TOP;
if (config.maxPWM > PWM_TOP)
config.maxPWM = PWM_TOP;
// min/max sanity
if (config.maxPWM < config.minPWM)
{
@@ -173,15 +182,14 @@ int16_t MotorController::applyDynamicResponse(int16_t targetPercent)
}
targetPercent = constrain(targetPercent, 0, 100);
int16_t targetPromille = targetPercent * 10;
int16_t delta = targetPromille - smoothedPromille;
int32_t targetPromille = (int32_t)targetPercent * 10;
int32_t delta = targetPromille - smoothedPromille;
// 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
int16_t maxDelta = (int16_t)((maxChangePerSec * (int32_t)elapsedTime) / 1000L);
// maximaler Delta in diesem Zeitintervall (mit Rundung)
int32_t maxDelta = (maxChangePerSec * (int32_t)elapsedTime + 999) / 1000L;
if (maxDelta < 1)
maxDelta = 1; // minimale Änderung erlauben
@@ -190,7 +198,7 @@ int16_t MotorController::applyDynamicResponse(int16_t targetPercent)
else if (delta < -maxDelta)
delta = -maxDelta;
smoothedPromille += delta;
smoothedPromille += (int16_t)delta;
lastUpdateTime = currentTime;
return (smoothedPromille + 5) / 10; // runden
@@ -198,38 +206,30 @@ int16_t MotorController::applyDynamicResponse(int16_t targetPercent)
uint16_t MotorController::computePwm(uint16_t pwmLogical)
{
// explizit 0 erlauben, auch wenn minPWM > 0 gesetzt ist
if (pwmLogical == 0)
// bei nicht invertierter Logik darf 0 auch unter minPWM fallen
if (!config.inverted && pwmLogical == 0)
return 0;
uint16_t pwmOut = pwmLogical;
if (pwmOut < config.minPWM)
pwmOut = config.minPWM;
if (pwmOut > config.maxPWM)
pwmOut = config.maxPWM;
uint32_t base = pwmLogical;
if (base < config.minPWM)
base = config.minPWM;
if (base > config.maxPWM)
base = config.maxPWM;
uint32_t pwmOut = base;
if (config.inverted)
{
// Logischer Wert im Bereich [min,max] wird gespiegelt
uint32_t span = (uint32_t)config.maxPWM - (uint32_t)config.minPWM;
uint32_t offset = (uint32_t)pwmLogical - (uint32_t)config.minPWM;
uint32_t invOffset = span - offset;
uint32_t inv = (uint32_t)config.minPWM + invOffset;
if (inv > PWM_TOP)
inv = PWM_TOP;
pwmOut = (uint16_t)inv;
uint32_t offset = base - (uint32_t)config.minPWM;
uint32_t inv = (uint32_t)config.minPWM + (span - offset);
pwmOut = 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)
pwmOut = PWM_TOP;
return pwmOut;
return (uint16_t)pwmOut;
}
void MotorController::printStatus()
@@ -255,6 +255,8 @@ void MotorController::printStatus()
Serial.print(config.maxPWM);
Serial.print(" span=");
Serial.print((uint32_t)config.maxPWM - (uint32_t)config.minPWM);
Serial.print(" top=");
Serial.print(PWM_TOP);
Serial.print(" respA=");
Serial.print(config.responseSpeedAccel);
Serial.print(" respD=");

View File

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