Hallo,
ich versuche gerade ein Software PWM Generator mit variabler Frequenz (1-20Hz) und variablem Tastverhältnis zu programmieren.
Da die gewünschten Frequenzen sehr niedrig sind, wollte ich das ganze einfach als Software PWM aufbauen und einen Digital Pin ein und wieder ausschalten.
Dazu verwende ich micros(), doch irgendwie bekomme ich kein sauberes Ausgangssignal hin.
Zur Veränderung der Grundfrequenz und des Tastverhältnisses verwende ich einen Drehgeber, was soweit auch zu funktionieren scheint, weil die Sollwerte jeweils korrekt in die entsprechenden Variablen abgelegt werden.
Hier mal der entsprechende Code Auszug der SoftPWM Funktion. Die SoftPWM Funktion rufe ich innerhalb einer switch case Struktur innerhalb loop() auf.
Verwendete Variablen:
// Variables for Solenoid Control
int SolenoidFrequency = 2;
int MinFrequency =1;
int MaxFrequency =20;
int SolenoidDutyCycle = 50;
int MinDutyCycle =0;
int MaxDutyCycle =100;
int OldSolenoidFrequency=0;
int OldSolenoidDutyCycle =0;
unsigned long ActualMicros=0; // actual time in µs
unsigned long PeriodTime =500000; // Time of one DC in µs ( 1000000/SolenoidFrequency)
unsigned long OnTime =0; // On time of PWM DC in µs calculated with selected frequency and selected DC
unsigned long OffTime =0; // Off time of PWM DC in µs calculated with selected frequency and selected DC
unsigned long LastDCUpdate=0; // save the time when last DC was started
bool PWMPinState=LOW;
bool ChangeDC=true;
SoftPWM Funktion:
void SoftPWM(){
// Calculated Total DC Time, on and off Time with selected DC and Frequency
if (SolenoidFrequency != OldSolenoidFrequency) {
PeriodTime=1000000/SolenoidFrequency;
OldSolenoidFrequency = SolenoidFrequency;
}
//PeriodTime=1000000/SolenoidFrequency; // calculate TotalDCTime in µS
if (SolenoidDutyCycle != OldSolenoidDutyCycle) {
OnTime=PeriodTime*SolenoidDutyCycle/100; //calculate on time of DC in µS
OldSolenoidDutyCycle = SolenoidDutyCycle;
OffTime=PeriodTime-OnTime;
DEBUG_PRINT("OnTime soll ");
DEBUG_PRINTLN(OnTime);
}
//ActualMicros=get_T2_micros(); // used when Timer2 library is used
ActualMicros=micros();
if (ActualMicros - LastDCUpdate >= PeriodTime && PWMPinState==LOW){
//Its time set output high
DEBUG_PRINT("Periodtime soll ");
DEBUG_PRINTLN(PeriodTime);
DEBUG_PRINT("Periodtime ist ");
DEBUG_PRINTLN(ActualMicros -LastDCUpdate);
PWMPinState = HIGH;
digitalWrite(solenoidPwmPin, PWMPinState );
LastDCUpdate=ActualMicros;
}
if (ActualMicros - LastDCUpdate >= OnTime && PWMPinState ==HIGH) {
// its time to switch off again
PWMPinState = LOW;
digitalWrite(solenoidPwmPin, PWMPinState );
DEBUG_PRINT("OnTime ist : ");
DEBUG_PRINTLN(ActualMicros - LastDCUpdate);
}
}
Auszug aus der case Struktur
case S_OpenLoopControl:
/* Case Description:
* One can control open loop the solenoid voltage
* By dafault one can manipulate the Duty Cycle by turning the knob
* To change the Frequency doubleclick the knob and the change the frequency
* to change again the Duty Cycle doubleklick again the knob
*/
lcd.setCursor(0,0);
lcd.print("Openloop Control");
lcd.setCursor(0,1);
lcd.print("Frequenz in Hz : ");
lcd.print(SolenoidFrequency);
lcd.setCursor(0,2);
lcd.print("Dutycycle in % : ");
lcd.print(SolenoidDutyCycle);
SoftPWM();
break;
Mich wundert die Abweichung in der Frequenz. Hier ein Auszug des Debug Prints:
"
OnTime soll 260000
OnTime ist : 263584
Periodtime soll 500000
Periodtime ist 525976
"
Zudem wird eine Veränderung des Tastverhältnisses (einstellbar zw. 0-100%) nicht immer übernommen.
Über Tipps freue ich mich sehr!
Gruß Alex