ImpulsGeber mit millis()

Hallo,
diese millis() können einen ja in den Wahnsinn treiben.
Ich versuche gerade mir einen Impulsgeber zu programmieren- mit millis().
Die High/Flanke soll eine Länge von 30ms oder 50ms haben.
Die Länge der Low/Flanke soll veränderbar über ein Poti sein. "intervall"
So sieht es aus und funktioniert, gefällt mir aber noch nicht so richtig:

intervall = map(val,0,1023,0,3600); // LowFlanke von 0 bis 3600 einstellbar

if (millis() - zStempel > intervall)  
 {   
  zStempel = millis();
digitalWrite(LED, HIGH);
delay(30);               // die Länge der High/Flanke
digitalWrite(LED, LOW);
}

Was mir hier nicht gefällt ist das "delay()" Hält das nun den Arduino auf,
oder läuft es im "Hintergrund" weil in einer "millis()Schleife"?

Ich bekomme keine zweite millis()Schleife in die erste.
Ist es überhaupt möglich millis() ineinander zu verschachtel?
Gruß und Dank
Andreas

SkobyMobil:
Ich versuche gerade mir einen Impulsgeber zu programmieren- mit millis().
Die High/Flanke soll eine Länge von 30ms oder 50ms haben.
Die Länge der Low/Flanke soll veränderbar über ein Poti sein. "intervall"
So sieht es aus und funktioniert, gefällt mir aber noch nicht so richtig:

Vor allem wird es mit "delay" niemals richtig funktionieren, wenn Du mehr als einen Impuls auf diese Weise programmieren möchtest.

Schon bei zwei Impulsen mit verschiedener Taktrate bkommst Du bei Blockierung mit "delay" überhaupt keine "überlappenden Impulse" hin, also dass z.B. ein 50ms Impuls startet während ein 30ms Impuls aktiv ist oder umgekehrt.

Das muss komplett ohne delay programmiert werden.
Und auch ohne jegliche andere Form von "busy waiting" in einer while-Schleife.

Hallo,
ich möchte keine überlappenden Impulse. Entweder eine HighFlanke von 30ms ODER
eine HighFlanke von 50ms.
Die LowFlanke soll "frei" veränderbar sein.
Wenn ich Dich richtig verstanden habe, dann blokiert "dalay()" also auch hier?

Wenn ich das, was ich hier programmiert habe- richtig verstehe, dann passiert
doch folgendes.
Intervall mit Poti auf 3000, delay(30)
Ich habe eine LowFlanke von 3000ms, dann eine HighFlanke von 30ms- u.s.w.
Das funktioniert so lange richtig, bis ich mit Intervall unter 30ms komme?
LaufzeitFehler/Zeiten lassen wir mal aussen vor.
Gruß und Dank
Andreas

Ich verstehe dich nicht!
Was sind High Flanken und Low Flanken...
Und dann diese Zeiten?
Sägezahn?
Dreieck?

Du meinst doch Puls Zeiten und Pause Zeiten, oder?
Und die Flanken sollen doch sicherlich "rechteckig sein" ....

Was du da (vermutlich) meinst, heißt bei mir z.B. PWM !
Eine besondere PWM, aber eine PWM. (zumindest so ähnlich)

static uint32_t zStempel, zStempel2;
static uint8_t led_state;
static uint8_t last_led_state;

if (millis() - zStempel > intervall)
{
	zStempel = millis();
	zStempel2 = zStempel;
	
	led_state = 1;
}

if(led_state == 1 && millis() - zStempel2 >= 30) led_state = 0;

if(last_led_state != led_state)
{
	last_led_state = led_state;
	digitalWrite(LED, led_state);
}

sowas?

SkobyMobil:
ich möchte keine überlappenden Impulse. Entweder eine HighFlanke von 30ms ODER
eine HighFlanke von 50ms.
Die LowFlanke soll "frei" veränderbar sein.

OK, wenn Dich ein delay(30) oder delay(50) im Programmablauf nicht weiter stört und nur ein Vorgang zu timen ist, kannst Du es auch mit delay machen. In dem Fall sogar mit fast derselben Art der Taktgenerierrung, zu der ich heute bereits einmal ein Beispiel gepostet hatte.

Hier dann angepaßt auf Deinen Anwendungsfall:

// Funktionen im Takt abarbeiten, Demo by 'jurs' for German Arduino-Forum
void setup() {
  Serial.begin(9600);  
}

boolean takt(unsigned int taktDauer)
// liefert true falls seit dem letzten Aufruf ein neuer Takt begonnen hat
{
  static unsigned long prevMillis;
  boolean result=false;
  while( millis() - prevMillis >= taktDauer){
    prevMillis += taktDauer;	
    result=true;
  }
  return result;
}

boolean shortImpulse=true;
unsigned int dauer=3000;
void loop() 
{
  dauer=analogRead(A0)*60; // Dauer mit Poti setzen zwischen 0 und 60*1023=61380 ms
  if (takt(dauer))
  {
    shortImpulse=!shortImpulse; // Impulse wechseln ab
    if (shortImpulse)
    {
      Serial.println("30");
      delay(30);
    }
    else
    {
      Serial.println("50");
      delay(50);
    }
  }  
}

Der Beispielcode gibt nur etwas auf Serial aus.
Wenn Du Pins vor dem delay auf einen Wert und nach dem delay auf einen anderen Wert setzen möchtest, kannst Du das vor/nach dem delay leicht einfügen.

Beim "ODER" wußte ich nicht, wonach Du entscheiden möchtest, ob ein 30 oder 50 ms delay kommen soll, ich habe es daher mal auf "immer abwechselnd" eingestellt.

SkobyMobil:
Wenn ich Dich richtig verstanden habe, dann blokiert "dalay()" also auch hier?

Ja natürlich: delay blockiert den Programmablauf immer, wenn es ausgeführt wird.
Und jede Art "busy waiting" mit while-Schleifen blockiert den Programmablauf ebenfalls.

Hallo,
was bei Dir "PWM" heißt, das meine ich nicht.
Ich will auch kein Sägezahn oder Dreieck.

Ich möchte einfach einen digitalen Ausgang für 30ms auf High setzen.
Das möchte ich alle 3000ms, oder 2450ms oder einer anderen Zeitspanne.
Aber immer nur 30ms auf High.
Einfach, aber nicht zu gebrauchen;

void loop()
{
digitalWrite(LED, HIGH); //High/Flanke
delay(30);               // Länge der HighFlanke
digitalWrite(LED, LOW);  // LowFlanke
delay(3000);             // Länge der LowFlanke
}

Wenn Du das auf einem Oszi anschaust, dann sind das "Rechtecke" von
verschiedener Länge.
Hat aber nichts mit Deinem "RechteckSignal" zu tun, weil die Höhe der Flanke
immer gleich ist.
Gruß und Spaß
Andreas

Hallo,

mit Deinem "Flanken" bringst Du Dich und uns alle durcheinander. Flanke ist Flanke. Die kannste nicht verändern. Du meinst immer die Dauer des anstehenden High oder Low Pegels. Mehr nicht.

Du schreibst 2 Funktionen mit millis für jeweils die High und Low Signaldauer. In jeweils der Funktionen gibt es eine Statusvariable, die besagt, ob die ms dieser Funktion schon abgelaufen sind oder nicht. Damit sperrst Du den Funktionseintritt der anderen Funktion und umgekehrt. Ist etwas Aufwand, funktioniert aber.

Hallo,
ich habe keine Lust hier alles 5mal zu erklären… Entweder habe ich eine
Wolldecke im Hals, oder ihr könnt mich nicht verstehen.

"Was mir hier nicht gefällt ist das "delay()"
Wenn ich "delay()" wollte, dann könnte ich es auch bei meiner ersten Version
lassen.

Die beiden "millis()" beeinflussen sich gegenseitig. Das sollte ich mit
"Wahrheit" erschlagen können. Das bekomme ich hin.
Schönen Dank für eure Mühe.
Gruß und Spaß
Andreas

Hallo,
so- jetzt habe ich mich wohl wieder beruhigt.

Ha, ha, ha,
"Das sollte ich mit "Wahrheit" erschlagen können."

Das habe ICH mir so gedacht! Die Sache erweist sich als schwieriger wie gedacht.
So einfach ist es nicht, "zwei" millis() etwas machen zu lassen, das sie
zusammen machen sollen.
So wie ich mir das gedacht habe, so habe ich es aber nicht hinbekommen.

Dann habe ich mir einmal die Sketche angeschaut die Ihr mir zum basteln
vorgeschlagen habt.
jurs hat leider im ersten Post überlesen, das ich kein delay() im Sketch
haben möchte. Sein Sketch funktioniert etwas widerwillig, aber es geht-
eben nur mit delay().

Dann hat sschultewolter auch noch einen Sketch mit geheimnisvollen
(static uint32_t) Bezeichnungen zur Verfügung gestellt.
Der funktioniert soweit einwandfrei. Was mir noch nicht gefällt ist dieses
"static uint32_t" Das muß ich einmal nachschlagen.
Wie auch immer…
Als ich den in meinen EnergieManagament eingefügt hatte wurde die Sache
viel zu umständlich. Hier soll eine LED blinken, da soll ein Pin High sein,
dort soll gezählt werden und ein Poti soll auch noch ausgewertet werden.
Das war mir dann zum auszuprobieren zu umständlich.

Was machen? Ich habe den Sketch von sschultewolter so geändert, das er mit
einem Poti bedient werden kann- und dann einfach auf meinen 328P geladen.
Da kann er rumwuseln ohne mich zu stören und ich bekomme einen "echten"
Impuls an meinen Mega geliefert. Genial!
Also, schönen Dank für eure Mühe- und Sorry
Gruß und Spaß
Andreas

"uint32_t" ist nichts anderes als "unsigned long" auf einen 8-Bit Prozessor

SkobyMobil:
so- jetzt habe ich mich wohl wieder beruhigt.

Na bravo!

SkobyMobil:
jurs hat leider im ersten Post überlesen, das ich kein delay() im Sketch
haben möchte. Sein Sketch funktioniert etwas widerwillig, aber es geht-
eben nur mit delay().

Ach was, hier und da eine kleine Änderung und das delay ist weg.

// Blinker mit einstellbarer Periodendauer by 'jurs' for German Arduino-Forum

#define LED 13

void setup() {
  Serial.begin(9600);  
  pinMode(LED,OUTPUT);
}

boolean takt(unsigned int taktDauer)
// liefert true falls seit dem letzten Aufruf ein neuer Takt begonnen hat
// Parameter taktDauer muss größer als 0 sein!
{
  static unsigned long prevMillis;
  if (taktDauer==0) // Sonderfall taktDauer==0 behandeln
  {
    prevMillis=millis();
    return true;
  }
  boolean result=false;
  while( millis() - prevMillis >= taktDauer){
    prevMillis += taktDauer;	
    result=true;
  }
  return result;
}

unsigned int dauer;
unsigned long taktBeginn;
void loop() 
{
  dauer=analogRead(A0)*4; // Dauer mit Poti setzen zwischen 0 und 4*1023= 4092 ms
  if (takt(dauer)) taktBeginn=millis(); // ein neuer Takt beginnt
  if ((millis()-taktBeginn)<30) // in den ersten 30 ms des neuen Taktes
    digitalWrite(LED,HIGH);
  else 
    digitalWrite(LED,LOW);
}

sschultewolter:
"uint32_t" ist nichts anderes als "unsigned long" auf einen 8-Bit Prozessor

Jetzt müsste man nur noch wissen was unsigned(unsigniert) bedeutet

Hallo,
das könnte man nachschlagen...
Manchmal braucht man negative Zahlen- ein anderes Mal nicht.
Dünnes Eis:
Es gibt zwei numerische Variablen- signet (mit Vorzeichen) und unsigned- eben ohne Vorzeichen.
Ist die Variable unsigned, ist sie immer Positiv. Stellst Du das Schlüsselwort "unsigned" der Variablen
nicht voran, dann kann sie negativ, wie auch positiv sein. Stellt man der Variablen "unsigned" voran
kannst DU- als Programmierer, sicher- sofort erkennen, das diese Variable nur einen positiven Wert haben kann.
Gruß und Spaß
Andreas

??

Ist das eine ernsthafte Frage? Wenn ja, wundert es mich, dass du die Frage stellst, skorpi!

Falls sie dennoch ernsthaft gemeint ist, wobei ich hier gerne auf die Basics verweise:

Es gibt unsigned und signed Werte.

Im Regelfall sind Integer Werte signed. Soll heißen vorzeichenbehaftet.
Somit kann eine Variable sowohl einen positiven als auch negativen Wert annehmen. (Wertebereich /2 ).

Bei unsigned, also ohne Vorzeichen ist der komplette Wertebereich positv. Beispiel an einem (u)int8_t. welcher auch als byte/char bekannt ist.
Ein signed Wert(char) geht von -128 bis 127. Ein Wert unsigned Wert hingehen von 0 - 255-

Vorzeichenbehaftete int-Typen
Typname	Bit-Breite	Wertebereich	C-Entsprechung (avr-gcc)
int8_t	8	?128 ? 127	?27 ? 27?1	signed char
int16_t	16	?32768 ? 32767	?215 ? 215?1	signed short, signed int
int32_t	32	?2147483648 ? 2147483647	?231 ? 231?1	signed long
int64_t	64	?9223372036854775808 ? 9223372036854775807	?263 ? 263?1	signed long long
Vorzeichenlose int-Typen
Typname	Bit-Breite	Wertebereich	C-Entsprechung (avr-gcc)
uint8_t	8	0 ? 255	0 ? 28?1	unsigned char
uint16_t	16	0 ? 65535	0 ? 216?1	unsigned short, unsigned int
uint32_t	32	0 ? 4294967295	0 ? 232?1	unsigned long
uint64_t	64	0 ? 18446744073709551615	0 ? 264?1	unsigned long long

http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Ganzzahlige_Datentypen_.28Integer.29

Hallo,

und weil die C Entsprechnung manchmal von Compiler zu Compiler unterschiedlich ist, kann man das auf seinen µC sich ausgeben lassen was er wirklich für eine Datentypgröße hat.

void setup()  {
  
 Serial.begin(57600);  
 
 Serial.println("\n Angaben sind in Bit");
 Serial.print("CHAR .......... "); Serial.println(sizeof(char)*8);
 Serial.print("SHORT ......... "); Serial.println(sizeof(short)*8);
 Serial.print("INT ........... "); Serial.println(sizeof(int)*8);
 Serial.print("WORD .......... "); Serial.println(sizeof(word)*8);
 Serial.print("LONG .......... "); Serial.println(sizeof(long)*8);
 Serial.print("LONG LONG ..... "); Serial.println(sizeof(long long)*8);
 Serial.print("FLOAT ......... "); Serial.println(sizeof(float)*8);
 Serial.print("DOUBLE ........ "); Serial.println(sizeof(double)*8);
 Serial.print("LONG DOUBLE ... "); Serial.println(sizeof(long double)*8);
 
 Serial.println("\n Angaben sind in Byte");
 Serial.print("CHAR .......... "); Serial.println(sizeof(char));
 Serial.print("SHORT ......... "); Serial.println(sizeof(short));
 Serial.print("INT ........... "); Serial.println(sizeof(int));
 Serial.print("WORD .......... "); Serial.println(sizeof(word));
 Serial.print("LONG .......... "); Serial.println(sizeof(long));
 Serial.print("LONG LONG ..... "); Serial.println(sizeof(long long));
 Serial.print("FLOAT ......... "); Serial.println(sizeof(float));
 Serial.print("DOUBLE ........ "); Serial.println(sizeof(double));
 Serial.print("LONG DOUBLE ... "); Serial.println(sizeof(long double));
 Serial.println("\n*** ENDE  ***\n");
  
}   // Ende setup


void loop(void) {
 

}   // Ende loop

Edit:

Ich habe das bis jetzt immer so verstanden das die Datentyp Angaben wie "int8_t" oder "int16_t" Compiler unabhängig sind. Dagegen sind die Datentypangaben wie "int" oder long" immer von Compiler abhängig. Manche sind hier 16Bit und woanders 32Bit groß.