• Die Forumsregeln und Nutzungsbedingungen findet ihr in der Navbar unter Impressum !
    Bitte unbedingt beachten!
    Wie überall im Leben gibt es Spielregeln, so auch hier!
    Die Datenschutzerklärung zum DSGVO findet ihr ebenfalls in der Navbar unter Datenschutzerklärung !
    Hinweis nach DSGVO :
    Es ist hier keinerlei Angabe erforderlich. Alle Angaben in diesem Bereich sind öffentlich sichtbar und werden freiwillig gemacht. Mit einem Eintrag in diesem Bereich erkenne ich dieses an, und bestätige die Datenschutzerklärung zur DSGVO für das Forum gelesen zu haben.

    Danke
  • Hallo Gast, beschränke dich hier bitte auf den Bereich der Elektronik. Die Fahrzeuge oder Gebäude, wo diese Elektronik eingebaut wird bitte in dem passenden Fachbereiich behandeln. Auch wenn Teile des Projektes dadurch im Forum doppelt vorhanden sind! Danke.

Arduino Verkehrsleittafel mit Arduino angesteuert

DO1XXY

New member
Registriert
12.04.2013
Beiträge
579
Hallo Gemeinde,

vor einiger Zeit habe ich einen Bruder Warnleitanhänger mit einer Timerschaltung (NE555) umgerüstet. Dadurch fiel die automatische Abschaltung der Blinkanlage weg und ich konnte die Zeitvorgaben für das Aufleuchten der beiden Flasher und der LEDs für die Richtungspfeile selber bestimmen.

Um dem Verkehrsleitschild noch mehr Aufmerksamkeit zu verschaffen habe ich für ein Adurinoboard ein Sketch (Programm) geschrieben. Das Pflichtenheft:
- Doppelblitz der beiden oberen großflächigen Leuchten (Flasher)
- weiches auf- und nachleuchten der LEDs für den Richtungspfeil
- Ansteuerung einer Bakenkette mit x-beliebiger Anzahl von LED (bei mir 5).

So sieht das Ergebniss aus:

Um diese Inhalte anzuzeigen, benötigen wir die Zustimmung zum Setzen von Drittanbieter-Cookies.
Für weitere Informationen siehe die Seite Verwendung von Cookies.

Der Sketch dazu:
Code:
/* Lichtsteuerung für Verkehrsleittafel mit gedimmten Richtungspfeil, Flasher und Bakenlauflicht */

// Zuordnung der LEDs auf die Pins des Portsteckers

int ledPin = 3; // Richtungspfeile analoger Ausgang für Dimmer
int led1 = 2; // Flasher

int led2 = 4; // Bakenlauflicht
int led3 = 5; // Bakenlauflicht
int led4 = 6; // Bakenlauflicht
int led5 = 7; // Bakenlauflicht
int led6 = 8; // Bakenlauflicht


int del1=50; // Impulszeit Flasher
int del2=250; // Übergangszeit zwischen Flasher und Richtungspfeilen
int del3=20; // FadeIn/FadeOut für die Richtunspfeile
int del4=40; // Übergangszeit LED zu LED im Bakenlauflicht
int del5=30; // Leuchtdauer der einelnen LEDs im Bakenlauflicht
int del6=5; // Übergangszeit Fade Out zu Flasher

void setup() { 

pinMode(ledPin, OUTPUT); // Richtungspfeile
pinMode(led1, OUTPUT); // Flasher

pinMode(led2, OUTPUT); // Bakenlauflicht
pinMode(led3, OUTPUT); // Bakenlauflicht
pinMode(led4, OUTPUT); // Bakenlauflicht
pinMode(led5, OUTPUT); // Bakenlauflicht
pinMode(led6, OUTPUT); // Bakenlauflicht

}

// Verkehrsleittafel
void loop() {

{ 
// fade in from min to max in increments of 5 points:
for(int fadeValue = 0 ; fadeValue <= 255; fadeValue +=5) { 
// sets the value (range from 0 to 255):
analogWrite(ledPin, fadeValue); 
// wait for 30 milliseconds to see the dimming effect 
delay(del3); 
} 

digitalWrite(led6, HIGH); // Baken LED 6
delay(del4); // Leuchtdauer LED 6
digitalWrite(led6, LOW); 
delay(del5);

digitalWrite(led5, HIGH); // Baken LED 5
delay(del4); // Leuchtdauer LED 5
digitalWrite(led5, LOW); 
delay(del5);

digitalWrite(led4, HIGH); // Baken LED 4
delay(del4); // Leuchtdauer LED 4
digitalWrite(led4, LOW); 
delay(del5);

digitalWrite(led3, HIGH); // Baken LED 3
delay(del4); // Leuchtdauer LED 3
digitalWrite(led3, LOW); 
delay(del5);

digitalWrite(led2, HIGH); // Baken LED 2
delay(del4); // Leuchtdauer LED 2
digitalWrite(led2, LOW); 
delay(del5);

// fade out 
for(int fadeValue = 255 ; fadeValue >= 0; fadeValue -=5) { // Fadingrange 0-255
analogWrite(ledPin, fadeValue); 
delay(del6); // Wartezeit bis zum Fading 
} 

digitalWrite(led1, HIGH); // Impulszeit für den Flasher
delay(del1); 
digitalWrite(led1, LOW); 
delay(del1); // Übergangsverzögerung vom Flasher zu de Richtungspfeilen

digitalWrite(led1, HIGH); // Impulszeit für den Flasher
delay(del1); 
digitalWrite(led1, LOW); 
delay(del2); // Übergangsverzögerung vom Flasher zu de Richtungspfeilen
}
}

Gruß
Armin de DO1XXY

P.S.: ich helfe gerne beim Programmieren eines Arduino
 
Hallo Armin,

hört sich interessant an. Leider kann man das Video nicht öffnen.
 
Moinsen,

sollte aber gehen. Ich öffne es mit Firefox auf dem Ultrabook und dem Dolphin Browser auf dem Tablet ohne Probleme.

Gruß
Armin de DO1XXY
 
Das Video funktioniert.
Mit Firefox und auch mit Google Chrome.

Schöner Effekt. Gut gelöst.
Die Warnbaken wollte ich bei mir auch immer schon dran machen.
Aber die Zeit fehlt. Ich habe einfach zu viele Projekte in Arbeit.
 
So, heute kann ich es auch sehen. Toll gemacht :ok

Werde mir den Sketch mal abspeichern.
 
Hallo Bert,

kleine Ursache große Wirkun - hauptsache es geht jetzt.

@ Winni: danke für das Kompliment. Was mir nicht gefällt ist das Outfit der Warnbaken. EIne von hinten durchgesteckte gelbe LED im Klarsichtgehäuse ist nicht das was mir auf Dauer zusagt. Ursprünglich wollte ich die Abdeckkappen von Rafi Leuchten auf die Schilder setzen, was aber richtig ins Geld geht. Gestern habe ich bei RC-Bruder passende Warnbaken gesehen. Das mal als Hinweis auf realistisch aussehende Warnbaken - es sei denn Du hast mit Deinen genialen 3D Druckerprojekten schon etwas in petto.

Gruß
Armin de DO1XXY
 
Hallo Armin,

ich habe mir den Source code mal genau angesehen, du arbeitest ja mit vielen "delays". Wenn man dann eine Auswertung von einen Kanal machen möchte kann das stören.
Ich habe mal so ein Lauflicht mit einem Zähler (timer) und sehr kurzem delay aufgebaut.

Code:
int timer=0;
const int LED1=5; // LED 1
const int LED2=6;
const int LED3=7; 
const int LED4=8;
const int LED5=9;
const int LED6=10; 
const int LED7=11;
const int LED8=12;

void setup() 
{ 
pinMode (LED1, OUTPUT); // LED rot
pinMode (LED2, OUTPUT); // LED rot
pinMode (LED3, OUTPUT); // LED rot
pinMode (LED4, OUTPUT); // LED rot
pinMode (LED5, OUTPUT); // LED rot
pinMode (LED6, OUTPUT); // LED rot
pinMode (LED7, OUTPUT); // LED rot
pinMode (LED8, OUTPUT); // LED rot
} 

void loop() 
{ 
timer = timer+1;
delay (10); // kurze Pause - ist die Zeitbasis
switch (timer) {
  case 1:
  digitalWrite (LED1,HIGH);
  //digitalWrite (LED8,LOW);
  break;
  case 21:
  digitalWrite (LED2,HIGH);
  digitalWrite (LED1,LOW);
  break;
  case 41:
  digitalWrite (LED3,HIGH);
  digitalWrite (LED2,LOW);
  break;
  case 61:
  digitalWrite (LED4,HIGH);
  digitalWrite (LED3,LOW);
  break;
  case 81:
  digitalWrite (LED5,HIGH);
  digitalWrite (LED4,LOW);
  break;
  case 101:
  digitalWrite (LED6,HIGH);
  digitalWrite (LED5,LOW);
  break;
  case 121:
  digitalWrite (LED7,HIGH);
  digitalWrite (LED6,LOW);
  break;
  case 141:
  digitalWrite (LED8,HIGH);
  digitalWrite (LED7,LOW);
  break;
  case 161:
  digitalWrite (LED8,LOW); // alle LED aus
  break;
  case 181: //alle LED an
  digitalWrite (LED1,HIGH);
   digitalWrite (LED2,HIGH);
    digitalWrite (LED3,HIGH);
     digitalWrite (LED4,HIGH);
      digitalWrite (LED5,HIGH);
       digitalWrite (LED6,HIGH);
        digitalWrite (LED7,HIGH);
         digitalWrite (LED8,HIGH);
   break;
 case 191: //alle LED aus
  digitalWrite (LED1,LOW);
   digitalWrite (LED2,LOW);
    digitalWrite (LED3,LOW);
     digitalWrite (LED4,LOW);
      digitalWrite (LED5,LOW);
       digitalWrite (LED6,LOW);
        digitalWrite (LED7,LOW);
         digitalWrite (LED8,LOW);   
   break;      
}
if (timer == 211) {
  timer = 0; }
}
 
Hallo Ihr beiden,
ich würde es ganz ohne delay und Zähler machen, mit dem internen Timer über millis.
 
Hier noch der Code am Beispiel Blink ohne Delay Für Blinken der internen LED an Pin 13.

Code:
/* Blinken ohne "delay()"
 *
 * Schaltet eine LED, welche an einem digitalen Pin liegt ein- und aus
 * ohne die "delay()" Funktion zu verwenden. Das heisst anderer Code
 * kann zur gleichen Zeit ausgeführt werden ohne blockiert zu werden.
 */
 
byte ledPin = 13;                           // LED liegt am (digitalen) Pin 13
boolean value = LOW;                   // Startwert der LED
unsigned long previousMillis = 0;  // speichert wie viele Sekunden seit derletzten Änderung vergangen sind
unsigned long interval = 1000;     // Interval zwischen zwei Änderungen
 
void setup()
{
  pinMode(ledPin, OUTPUT);           // Setzt den ledPin (Pin 13) als Ausgang
}
 
void loop()
{
  // Code der immer laufen soll kommt hier hin.
 
 /* es wird kontrolliert, ob die Zeit für das Blink-Intervall schon abgelaufen ist
  * Wenn die Zeitdifferenz zwischen dem Letzten Abspeichern und der aktuellen Zeit größer
  * als das Intervall ist, so wird die nachfolgende Funktion ausgeführt.
  */
  if (millis() - previousMillis > interval) {
    previousMillis = millis();   // aktuelle Zeit abspeichern
 
    // LED Zustand wecheln.
    value = !value;
 
    // Wert auf den Ausgang schreiben
    digitalWrite(ledPin, value);
  }
}
 
Moin, moin...

bei solchen Arbeiten definiere ich mir immer eine Status Variable. Diese definiert die Aktion, die gerade bearbeitet wird.

Diese Stati können z. B. sein
- Blitzer ein
- Blitzer aus
- Blitzer zweites mal ein
- Blitzer aus
- Pfeil faden
- Barke schalten

Dann setze ich den Timer auf einen Standardwert. Dieser ergibt sich aus dem Status.

Wenn der Timer zieht wird der Status kontrolliert und die zum Status gehörende Aktion durchgeführt.

Blitzer ein : LEDs an und Timer auf 100ms, Status setzen auf "Blitzer aus"
Blitzer aus : LEDs an und Timer auf 100ms, Status setzen auf "Zweiter Blitzer ein"
Zweiter Blitzer ein : LEDs an und Timer auf 100ms, Status setzen auf "Zweiter Blitzer aus"
Zweiter Blitzer aus : LEDs an und Timer auf 100ms, Status setzen auf "Pfeil faden", PWM Wert auf 0
Pfeil faden : Wenn PWM Wert < 250 dann PWM Wert um 10 erhöhen, Timer auf 10ms und Status belassen. Wenn PWM Wert = 250 dann Pfeil aus, Status auf "Barke schalten", Barkenzaehler auf 0, Barke 0 ein, Status auf "Barke schalten"
Barke schalten : Aktuelle Barke ausschalten, Barkenzähler erhöhen, wenn < Anzahl Barken, diese Barke einschalten, Timer auf 100ms und Status belassen, andernfalls, wenn Barkenzähler = Anzahl (wir haben ja bei 0 begonnen) den Status auf "Pfeil ein" setzen, Time auf 100ms

Diese Art der Abarbeitung hat folgende Vorteile:
- Es arbeitet wir ein Ablaufprogramm. Durch die Definition neuer Stati und Aktionen ist das Programm sehr flexibel und kann einfach erweitert werden.
- Durch die konsequente Steuerung per Timer ist die loop() Funktion komplett frei zur Bearbeitung anderer Dinge. Dies kann z. B. die Analyse von Servo Signalen sein.

Wenn man es auf die Spitze treiben möchte kann man die Analyse des Servo Signals ebenfalls in einen Interrupt legen, dann langweilt sich die loop() Funktion zu Tode ;)

Bei der Bearbeitung der Timer muss man darauf achten die auszuführenden Programmteile nicht zu groß werden zu lassen. Die Berechnungen von Variablen sollte sich auf '+' und '-' beschränken, '*' und '/' fressen sehr viel Rechenzeit. Weiterhin bitte wo es geht mit Integer Variablen (8- bzw. 16 Bit) arbeiten Fließkommaoperationen sollten in Timern und Interrupts vermieden werden. Ausgänge ein- bzw. ausschalten ist kein Problem, da es intern eh nur ein kleine Bit-Operation ist.

Zu beachten ist dass die Timerroutinen den kompletten Arbeitsprozess unterbrechen und anhalten, auch die loop() Funktion. Daher sollten die darin ausgeführten Arbeiten möglichst "einfach" sein.

Fragen dazu ? Immer her damit :)
 
Moin Winni,

die Delay Funktion hat aber auch einen ganz entscheidenden Vorteil, sie spart Strom.

In Deinem Code wird die loop() Funktion in einem fort ohne jede Pause aufgerufen. Somit läuft der Prozessor kontinuierlich auf 100% Volllast. Das führt zu einem Mehrverbrauch an Strom und produziert Abwärme. Abhilfe schafft z. B. ein delay(interval-10). Denn knapp eine Sekunde lang muss die CPU nichts tun, also warum eine Sekunde lang die loop() Funktion immer und immer wieder aufrufen lassen...

Grundsätzlich sind delay() Aufrufe in der loop() Funktion zu empfehlen, denn sie versetzen die CPU in eine Art "Schlaf" und der Prozessor läuft in dieser Zeit nur in Teillast (Timer, Interrupts).

Es kommt immer darauf an welche Arbeiten in der loop() Funktion ausgeführt werden sollen. Danach kann man den Einsatz von delay() Aufrufen planen.

Beispiel : Ich lese per pulseIn() einen Servowert und schalte eine LED ein bei Vorwärts und aus bei Rückwärts.

Also lese ich per pulseIn(Pin, HIGH) den Wert. Ist er < 1500 schalte die die LED aus, ansonsten ein. Wenn ich pulseIn() sofort wieder aufrufe wartet diese auf das nächste HIGH, der loop() ist blockiert und die pulseIn() Funktion produziert Last.

Ein Servoimpuls dauert 20ms. Der HIGH Bereich des Signals ist je nach Empfänger bis zu 2,5ms lang, der Rest ist LOW. Während diesem LOW muss ich nichts tun. Also könnte die loop() Funktion so aussehen:

Code:
void loop()
{
  uint32_t nServoValue = pulseIn(2, HIGH);
  digitalWrite(13, (nServoValue < 1500) ? LOW : HIGH);
  
  delay(15);
}

Da die restliche Zeit des Servosignals
Code:
für mich nichts spannendes passiert kann ich das Programm und auch die CPU für 15ms schlafen legen. 2,5ms sollten ausreichen um die LED zu schalten.
 
Hallo Peter,

gestern habe ich die Delays entfernt und die Bestimmung über millis() durchgeführt. Selbst wenn der ATMega dadurch mehr Strom verbraucht, das Schaltverhalten hat sich verbessert. Ich bin zwar noch nicht am Ziel, aber einen Schritt weiter.

@ Willi: der Sketch mit der Nutzung des Delays stammt aus einem bekannten Forum. Ich habe ihn mal so übernommen :).

Gruß
Armin de DO1XXY
 

Servonaut
Zurück
Oben Unten