Problem mit PWM Frequenz und Chrono

Ich grüsse das Schwarmwissen!

Ich hätte ein kleines Problem, dem ich nicht auf die Schliche komme...:

Für eine Test- Anwendung in der Firma habe ich mich anerboten die Programmierung zu übernehmen.
Es geht darum, eine Last (Widerstand) und einen Lüfter, der einen PWM Eingang mit 79 Hz (±10%) zu testen. So als simple Wareneinangsprüfung..
Der Widerstand wird ebenfalls an einem PWM Ausgang, über einen MosFET angesteuert. Der Lüfter PWM hängt direkt am Arduino.
Dabei sollen beide Ausgänge unabhängig in der Reihenfolge "aus ; 1/3 ; 2/3 ; 3/3 ; aus" geschaltet werden. Dies über je einen Taster, der eine RGB Led hat, die visuelle Rückmeldung der eingestellten Stufe geben.

Der Code funzt soweit, was PWM Ausgänge Heizung, Lüfter und RGB Rückmeldung betrifft. Habe zum testen die Ausgänge mit LED versehen, diese leuchten den Stufen entsprechend mehr oder weniger hell.
Farbliches Feintuning der RGB LED folgt dann noch..

Nun zum eigentlichen:

Ich kriege den einen Ausgang (Pin 11,) nicht dazu, die 79 Hz zu liefern. Ich habe versucht das mit der PWM-Lib zu lösen, tut aber nicht.. die anderen Ausgänge können mit der Standard- Frequenz laufen.

Dann wäre noch ein Sicherheitstimer, der nach einer einstellbaren Zeit (aktuell 1 min) den Ausgang abschalten soll, falls er auf einer Stufe aktiv ist. Dazu wollte ich die Chrono- Lib nehmen.

Welchen denk oder Syntaxfehler mache ich da..?
Vielleicht kann mir da jemand einen wertfollen Tip oder Denkanstoss geben..

Code und verwendete Libs im Anhang.

Danke Euch im voraus!

Tom

Heat_Vent.ino (4.75 KB)

ArduinoPWMFrequencyLibrary_v1-5.zip (13.7 KB)

Chrono-master.zip (227 KB)

Hallo,

79Hz sind machbar, aber nicht ohne Nebenwirkungen. analogWrite wird intern von verschiedenen Timern bedient je nach Pin den man verwendet. Das heißt wenn man einen Timer "verstellt" takten auch die anderen Pins die da dranhängen mit diesen Takt.

Welchen Arduino verwendest du?

Derzeit sehe ich im unübersichtlichen Sketch das du PWM auf den Pins 2,4,5,6,7,8,9,11 benutzen möchtest?

Hallo,

bei genauer Betrachtung kannst du nur einen Mega2560 haben, dann haste Glück. Zufall oder?

Pin - Timerbelegung
-------------------
2 ... OC3B
4 ... OC0B
5 ... OC3A
6 ... OC4A
7 ... OC4B
8 ... OC4C
9 ... OC2B
11 .. OC1A

Timer 1 wird von dir nur von Pin 11 benutzt und damit komplett frei eigene Zwecke.

Damit kannste folgenden Code verwenden.

/*
 Doc_Arduino - german Arduino Forum
 IDE 1.8.8
 Arduino Mega2560

 01.03.2019
 
 Timer 1:   Mode 8
 TOP:       ICR1 (Frequenz bestimmend)
 Pulsweite: OCR1A 
 Schaltpin: 11   
*/

const unsigned int TOP = 99;  // konstant
unsigned int DutyCycle = 25;  // 25% Pulsweite, OCR1A <= ICR1 !!!
const byte pin_PWM   = 11;  


void setup()  { 
  pinMode(pin_PWM, OUTPUT);   
      
  set_Timer1(); 

  OCR1A = DutyCycle;    // 0 ... 99
}

  
void loop() {           

                               
}   


// ****** Funktionen ******* //
    
void set_Timer1()   
{
  cli();         // Interrupts ausschalten
  TCCR1B = 0;    // Reset, unter anderem Timer stoppen
  TCCR1A = 0;    // Reset 
  TCNT1  = 0;    // Reset
  TIMSK1 = 0;    // Reset  
  ICR1 = TOP;
  OCR1A = 0;     // Pulsweite, OCR1A <= ICR1  
  TCCR1A = (1<<COM1A1); 
  TCCR1B = (1<<WGM13) | (1<<CS12) | (1<<CS10);    // Prescaler 1024 
  sei();         // Interrupts einschalten
}

Das Register OCR1A kannste jederzeit in dem Mode ändern solange du die erwähnten Bedingungen einhälst.

Hi

Ok, einen PWM kann der AVR selber in Hardware - aber bei 79Hz (+/-10) muß der Arduino verdammt viel schlafen, wenn Er Nichts Anderes zu tun bekommt.
Sowohl den PWM-Takt wie die Abschaltung via millis() erschlagen.
Mit einem Mega hätte man definitiv genügend Pins frei, ein Uno/Nano sollte damit aber auch nicht überfordert sein:
2x PWM
2x Umschalt-Taster
6x LED
Wären '10 aktive Pins' - 2,3,4,5,6,7,8,9,10,11 - da wären 12,13,A0,A1,A2,A3,A4,A5,(A6),(A7) noch frei.
An A4/A5 (Uno/Nano) könnte man ein I²C-Display hängen, A6/A7 (nur beim Nano) könnte man für die Taster missbrauchen (sind reine analog-In !!).
An der 13 könnte man einen Heart-Beat (Herzschlag) ausgeben lassen - irgendwie muß der Arduino die ganze Wartezeit, bis endlich wieder was umzuschalten ist, überbrückt bekommen :wink:

Rein Interesse halber: Woher kommen die 79Hz?

MfG

Guten Morgen!
Danke schon mal für die Antworten!

Ja, ich benutze einen Mega 2560, diese Info hätte von Anfang an reingehört...
Nano oder Uno fallen flach, weil zuwenig PWM Ausgänge, brauche 8:

Die Pins 0 und 1 sind die Eingänge der Taster
Pins 4, 5, 6 Ausgänge (auch PWM) für die erste Status RGB LED
Pins 7, 8, 9 dito, für die zweite RGB LED

Pin 2 PWM Ausgang für den MosFET

Pin 11 PWM Ausgang für den Lüfter

Genau dieser soll die 79 Hz generieren
Diese Frequenz ist gemäss Lüfter- Hersteller nötig um die Drehzahl mittels PWM einzustellen, ungewöhnlicher Wert, aber die Hardware will es halt so...

@Doc_Arduino: also meinen Code so weiter verwenden, und Deinen Code am Anfang und Ende einfügen, richtig?
Ich bin nicht so tief im Thema, sowas hab ivch auch noch nie gemacht, bis jetzt reichten die Standard Frequenzen um etwas zu dimmen oder Ausgänge zu schalten..
Zu Deiner angesprochenen Unübersichtlichkeit: da bin ich für Anregungen oder Tipps offen, wie sollte ich es besser machen?

@postmaster_ino: ja, da könnte noch viel dran, ist aber vom Arbeitgeber so nicht gewollt, habe den Vorschlag schon gleich als ich das übernommen habe eingebracht, auch mit Drehzahl und Temperaturrückmeldung und so..

Frage noch zum Sicherheitstimer, wie krieg ich das hin, dass der mir nach Ablauf der jeweiligen Zeit den Ausgang abstellt, das hab ich nicht gepeilt...

Schönen Tag allen!

Tom

Hi

Eine Zwit lässt sich unter Zuhilfenahme von millis() einfach abfragen.
millis() liefert als Wert die vergangene Zeit in Millisekunden zurück.
Bei jedem EIN-Schaltbefehl merkst Du Dir, wann Dieser begonnen hat.
In loop() schaust Du bei JEDEM Durchlauf, ob die Zeit bereits um ist.
Das macht man so:

if (millis()-startzeit>=wartezeit) {
  //Zeit abgelaufen, tue irgendwas
}else{
  //Zeit noch nicht abgelaufen, der Else-Zweig ist optional
}

Wenn Du oben in die Abfrage noch mit rein bringst, ob die Aktion überhaupt gerade läuft, wäre Das auch 'überlauf-sicher' - sofern Dein Mega 'immer' laufen soll, wird millis() nach 49,batsch Tagen auf Null überlaufen - der Abfrage ist's egal, Die 'regelt Das heraus', aber wenn diese 49,batsch Tage nicht erneut gestartet wurde, greift hier für die Wartezeit wieder der Else-Zweig, wenn Du Den verwendest.

Wenn der Mess-Apparillo aber nur Morgens für die heutigen Messungen angeschaltet wird (oder vll. auch Mal über's Wochenende das Ausschalten vergessen wird, passiert Das nicht, da millis() jedes Mal bei 0 mit Zählen anfängt).

Wenn Das Alles in Hardware passiert (also per chipeigenen PWM-Pins), musst Du Diese je nach Aktion nur an/aus schalten, die Taktung erfolgt dann rein in Hardware.
Achte darauf, daß Du Dir den millis()-Timer nicht verbiegst - sonnst ist die millis()-Millisekunde langsamer, oder gar nicht mehr vorhanden, da der OVL-Interrupt dieses Timer nicht mehr greift, Der millis() umstellt.

MfG
Edit Code-Tag repariert ... Vorschau rules :confused:

Hallo,

deine PWM Lib hauste raus und übernimmst meine Funktionen. Habe noch eine neue Funktion erstellt für ständige Änderungen am Tastverhältnis mit kleiner Sicherheitsabfrage. Da sich der nutzbare Wertebereich zwischen 0 und 99 bewegt, kannste mit 1er Sprüngen in 1% Schritten arbeiten. Zufällig ganz praktisch. Falls du es feiner benötigst kann das geändert werden. Der nächste nutzbare Bereich wäre 0 bis 396 mit Prescaler 256 statt 1024. Ich denke das brauchst du nicht.

Sicherheitstimer. Um das wirklich zu verstehen musste da erstmal selbst durch. Die Nutzung von millis/micros ist wie im Alltag mit deiner Uhr. Hier zwei Links mit guten Erklärungen. Das musste verstehen lernen, dann kannste damit alles erschlagen.

Theseus erklärt millis()
http://forum.arduino.cc/index.php?topic=400102.msg2752141#msg2752141

GuntherB - BlinkwithoutDelay - Die Nachtwächtererklärung
http://forum.arduino.cc/index.php?topic=423688.0

@ postmaster:
Die 79Hz Erzeugung rein in der loop in das eine. Das andere ist das Tastverhältnis in der loop. Beides in der loop konstant zuhalten ist nahezu unmöglich. Der Lüfter jault irgendwann.

const unsigned int TOP = 99;  // 
unsigned int DutyCycle = 25;  // 25% Pulsweite, OCR1A <= ICR1 !!!
const byte pin_PWM   = 11;  


void setup()  { 
  pinMode(pin_PWM, OUTPUT);   
      
  set_Timer1(); 

  set_pwm_DutyCycle (DutyCycle);
}

  
void loop() {           
                               
}   


// ****** Funktionen ******* //

void set_pwm_DutyCycle (unsigned int duty)
{
  if (duty <= TOP) {    // einfache Plausibilitätsabfrage
    OCR1A = duty;   
  }
}


void set_Timer1()   
{
  cli();         // Interrupts ausschalten
  TCCR1B = 0;    // Reset, unter anderem Timer stoppen
  TCCR1A = 0;    // Reset 
  TCNT1  = 0;    // Reset
  TIMSK1 = 0;    // Reset  
  ICR1 = TOP;
  OCR1A = DutyCycle;   // Pulsweite, OCR1A <= ICR1  
  TCCR1A = (1<<COM1A1); 
  TCCR1B = (1<<WGM13) | (1<<CS12) | (1<<CS10);    // Prescaler 1024 
  sei();         // Interrupts einschalten
}

Hallo!

Nach ferienbedingter Abwesenheit habe ich Eure Tipps ausprobiert, der Code von Doc funktioniert perfekt, vielen Dank!

Nur mit dem timer hab ich immer noch ein kleines Problem..
Er springt mir nicht aus der Schleife zurück, aber warum, ich komm nicht drauf...

Welchen Denkfehler hab ich da eingebaut?

Hier der Code:

//variables:

#define x 50                // 1/3 Wert H/L  85
#define y 150               // 2/3 Wert H/L  170       
#define z 255               // 3/3 Wert H/L  255
int Sicherheitszeit = 1;           // Sicherheitstimer in Minuten

//--------------------------------------------------------------

//constants, do not change

#define taster1 0           // Lüftung
#define taster2 1           // Heizung
#define pwmh 2              // pwm pin Heizung
#define pwmv 11             // pwm pin Lüftung
#define hred 4              // rote Taster LED Heizung
#define hgreen 5            // grüne Taster LED Heizung
#define hblue 6             // blaue Taster LED Heizung
#define vred 7              // rote Taster LED Lüftung
#define vgreen 8            // grüne Taster LED Lüftung
#define vblue 9             // blaue Taster LED Lüftung
#define debounce_delay 20   // Prellzeit


//--------------------------------------------------------------

//program variables

bool taster1_wert;
bool taster1_wert_alt;
bool taster2_wert;
bool taster2_wert_alt;
uint8_t taster1_count;
uint8_t taster2_count;
unsigned long timeh1;
unsigned long timeh2;
unsigned long timeh3;
unsigned long timev4;
unsigned long timev5;
unsigned long timev6;
const unsigned int TOP = 99;  //
unsigned int DutyCycle = 0;  // 0% Pulsweite, OCR1A <= ICR1 !!!
const byte pin_PWM   = 11;
unsigned long secura = (Sicherheitszeit * 1000);
int timerh1;
int timerh2;
int timerh3;
int timerv4;
int timerv5;
int timerv6;

//--------------------------------------------------------------


//program

void setup() {
pinMode (taster1, INPUT_PULLUP);
pinMode (taster2, INPUT_PULLUP);
pinMode (hblue, OUTPUT);                              // setzt den Pin 4 als Ausgang
pinMode (hgreen, OUTPUT);                             // setzt den Pin 5 als Ausgang
pinMode (hred, OUTPUT);                               // setzt den Pin 6 als Ausgang
pinMode (vblue, OUTPUT);                              // setzt den Pin 7 als Ausgang
pinMode (vgreen, OUTPUT);                             // setzt den Pin 8 als Ausgang
pinMode (vred, OUTPUT);                               // setzt den Pin 9 als Ausgang
pinMode(pin_PWM, OUTPUT);
int randomSeed(analogRead(0));
set_Timer1();
set_pwm_DutyCycle (DutyCycle);
timerh1 = LOW;
timerh2 = LOW;
timerh3 = LOW;
timerv4 = LOW;
timerv5 = LOW;
timerv6 = LOW;


}



void loop()
{
static uint32_t debounce_time;
if (millis() - debounce_time > debounce_delay)
{ taster1_wert = digitalRead(taster1);
  if (taster1_wert != taster1_wert_alt)
  { debounce_time = millis();
    taster1_wert_alt = taster1_wert;
    if (!taster1_wert)
    { taster1_count++;
      if (taster1_count > 3) taster1_count = 0;
    }
  }
}
if (taster1_count == 0) funktion0();
if (taster1_count == 1) funktion1();
if (taster1_count == 2) funktion2();
if (taster1_count == 3) funktion3();


if (millis() - debounce_time > debounce_delay)
{ taster2_wert = digitalRead(taster2);
  if (taster2_wert != taster2_wert_alt)
  { debounce_time = millis();
    taster2_wert_alt = taster2_wert;
    if (!taster2_wert)
    { taster2_count++;
      if (taster2_count > 3) taster2_count = 0;
    }
  }
}

if (taster2_count == 0) funktion4();
if (taster2_count == 1) funktion5();
if (taster2_count == 2) funktion6();
if (taster2_count == 3) funktion7();


}



void funktion0() //alles aus Heizung
{
analogWrite(pwmh, 0);
analogWrite(hred, 0);
analogWrite(hgreen, 0);
analogWrite(hblue, 0);
timerh1 = LOW;
timerh2 = LOW;
timerh3 = LOW;
}

void funktion1() // 1/3 Heizung, Farbe gelb
{
if (timerh1 == LOW) {
  timerh1 = HIGH;
  timeh1 = millis();
  analogWrite(pwmh, x);
  analogWrite(hred, 255);
  analogWrite(hgreen, 255);
  analogWrite(hblue, 0);
}
else {
  (timerh1 == HIGH); {
    if (millis() - timeh1 > secura) {
      taster2_count = 0;
      timerh1 = LOW;
      funktion0();
    }
  }
}
}
void funktion2() // 2/3 Heizung, Farbe orange
{
if (timerh2 == LOW) {
  timerh2 = HIGH;
  timeh2 = millis();
  analogWrite(pwmh, y);
  analogWrite(hred, 255);
  analogWrite(hgreen, 127);
  analogWrite(hblue, 0);
}
else {
  (timerh2 == HIGH); {
    if (millis() - timeh2 > secura) {
      taster2_count = 0;
      timerh1 = LOW;
      funktion0();
    }
  }
}
}

void funktion3() // 3/3 Heizung, Farbe rot
{
if (timerh3 == LOW) {
  timerh3 = HIGH;
  timeh3 = millis();
  analogWrite(pwmh, z);
  analogWrite(hred, 255);
  analogWrite(hgreen, 0);
  analogWrite(hblue, 0);
}
else {
  (timerh3 == HIGH); {
    if (millis() - timeh3 > secura) {
      taster2_count = 0;
      timerh2 = LOW;
      funktion0();
    }
  }
}
}


void funktion4() //alles aus Lüftung
{
set_pwm_DutyCycle (DutyCycle = 0);
analogWrite(vred, 0);
analogWrite(vgreen, 0);
analogWrite(vblue, 0);
timerv4 = LOW;
timerv5 = LOW;
timerv6 = LOW;
}

void funktion5() // 1/3 Lüftung, Farbe aqua
{
set_pwm_DutyCycle (DutyCycle = x);
analogWrite(vred, 0);
analogWrite(vgreen, 255);
analogWrite(vblue, 255);
if (timerv4 == HIGH) {
  if (millis() - timev4 > secura) {
    taster2_count = 0;
    funktion4();
    timev4 = millis();
    if (timerv4 == LOW) {
      timerv4 = HIGH;
      timev4 = millis();
    }
  }
}
}

void funktion6() // 2/3 Lüftung, Farbe blau
{
set_pwm_DutyCycle (DutyCycle = y);
analogWrite(vred, 0);
analogWrite(vgreen, 0);
analogWrite(vblue, 255);
if (timerv5 == HIGH) {
  if (millis() - timev5 > secura) {
    taster2_count = 0;
    funktion4();
    if (timerv5 == LOW) {
      timerv5 = HIGH;
      timerv4 = LOW;
      timev5 = millis();
    }
  }
}
}

void funktion7() // 3/3 Lüftung, Farbe grün
{
set_pwm_DutyCycle (DutyCycle = z);
analogWrite(vred, 0);
analogWrite(vgreen, 255);
analogWrite(vblue, 0);
if (timerv6 == HIGH) {
  if (millis() - timev5 > secura) {
    taster2_count = 0;
    funktion6();
    if (timerv6 == LOW) {
      timerv6 = HIGH;
      timerv5 = LOW;
      timev6 = millis();
    }
  }
}
}

void set_pwm_DutyCycle (unsigned int duty)
{
if (duty <= TOP) {    // einfache Plausibilitätsabfrage
  OCR1A = duty;
}
}
void set_Timer1()
{
cli();         // Interrupts ausschalten
TCCR1B = 0;    // Reset, unter anderem Timer stoppen
TCCR1A = 0;    // Reset
TCNT1  = 0;    // Reset
TIMSK1 = 0;    // Reset
ICR1 = TOP;
OCR1A = DutyCycle;   // Pulsweite, OCR1A <= ICR1
TCCR1A = (1 << COM1A1);
TCCR1B = (1 << WGM13) | (1 << CS12) | (1 << CS10); // Prescaler 1024
sei();         // Interrupts einschalten
}

Ich grüsse das Schwarmwissen!

Und ich dich, der die Code Tags noch nicht kennt.

Hi

Wo ist Da eine Schleife?

Vll. wäre Es sinnvoll, wenn Du - für Die, Die Deinen Sketch nicht (mehr) vor Augen haben, zu Erläutern, was Der eigentlich machen soll.
Grob drüber geschaut sollte Der zwei Mal jeweils mit Einem Taster eine von vier Funktionen 'durch-tasten'.

MfG

Hallo

@combie: da bin ich jetzt überfragt, was damit gemeint ist, bitte entschuldige..

zur Erläuterung, auf postmaster's Anstupser: (Board Mega2560)

Zwei Taster sollen jeweils unabhängig zwei PWM Ausgänge 4stufig (3 Stufen, aus) ansteuern.
Eine visuelle Rückmeldung erfolgt mit ebenfalls 2 RGB led, die je nach Stufe andere Mischfarben ausgeben.

Der PWM Ausgang an Pin11 taktet mit 79Hz, funktioniert dank Doc_Arduino's Funktion tiptopp (80Hz)
Der zweite PWM hat die Standardfrequenz des Arduinos. Auch dies funzt so wie erwartet.

Mein Problem ist jetzt, dass ich pro Ausgang eine Art Timer laufen lassen will, der mir nach einer festgelegten Zeit (zum jetzigen Zeitpunkt 10s, im vorigen Post 1 Sekunde) die Funktionen stillegt (alles aus). Idealerweise wenn von Funktion zu Funktion gewechselt wird, soll er neu starten, damit die max. Zeit wieder beginnt.

Irgendwie hab ich da einen Knoten im Kopf, ich komme nicht darauf, wieso nach ablauf der Zeit in den Funktionen 1-7 nichts passiert... :confused: "Kopfkratz".. Ich hab versucht die Nachtwächtererklärung umzusetzen aber wohl nicht richtig...
Vielleicht hab ich's (noch) nicht begriffen, ein kleiner Hinweis, wo ich den Denkfehler mache würde mich freuen, ich will ja was lernen.

Und, bitte nicht mit Steinen werfen, ich bin neu auf dem Gebiet, bisherige Basteleien mit Arduino waren von einfacher Natur..
:-[

Danke Euch!

Tom

Hallo,

zu viele Klammern, zu viele Vergleiche. Else macht genau das Gegenteil wenn der if Vergleich nicht gültig ist.

Du solltest Deine Tasterabfragen bündeln und in eine eigene Funktion auslagern.
Darin kannste die auch gleich mit entprellen. Dann wäre die loop um Welten übersichtlicher.
Am Ende kannste die Tastennummern und Funktionsaufrufe in ein switch case packen.
Zusammen mit enum kannste den Tastennummern sprechende Namen geben.
Was du mit den Funktionsnamen auch tun solltest.
Für deine High/Low Variablen konsequent bool verwenden.
Für Pins konsequent const byte verwenden.
Ich würde auch keinen Mischmasch verschiedener Datentyp Schreibweisen empfehlen.
Entweder alles Standard C++ oder alles Arduino like.
Ich würde die Variablenname für deine timer... auch lesbar unterscheidbarer benennen.
Ich garantiere dir nach 3 Monaten blickst du nicht mehr durch beim debuggen.
Das so als paar Hinweise.

Stellvertretend geändert, wenns funktioniert alle anderen ebenfalls abändern.

void funktion1() // 1/3 Heizung, Farbe gelb
{
  if (timerh1 == LOW) {
    timerh1 = HIGH;
    timeh1 = millis();
    analogWrite(pwmh, x);
    analogWrite(hred, 255);
    analogWrite(hgreen, 255);
    analogWrite(hblue, 0);
  }
  else {
    if (millis() - timeh1 > secura) {
      taster2_count = 0;
      timerh1 = LOW;
      funktion0();
    }
  }
}

Hallo,

hab was übersehen u.a. wegen den ähnlichen Namen. :wink:
Du setzt deine timerhx 2x auf Low, in der Funktion und in Funktion0.
Damit beginnen natürlich alle Funktionen die gerade gültig sind erneut von vorn.

Du musst eine Timerfunktion für alle bauen. Diese liefert true oder false zurück. Die aktuelle Zeit wird einmalig übergeben bzw. bei Funktionswechel aktualisiert. Danach wird entschieden ob es weitergeht oder alles abgeschalten wird. Ideales Terrain für switch-case und damit einen ordentlichen Ablaufplan. :slight_smile: