1. Diese Seite verwendet Cookies. Wenn du dich weiterhin auf dieser Seite aufhältst, akzeptierst du unseren Einsatz von Cookies. Weitere Informationen

VM-Bordelektrik mit Arduino

Dieses Thema im Forum "Elektrik, Elektronik" wurde erstellt von RaptoRacer, 29.03.2018.

  1. Heiko

    Heiko

    Beiträge:
    3.103
    Ob Prellen oder nicht, werde ich mir einfach anschauen. Habe da mit dem Arduino zuwenig Erfahrung. Auch auf Interrupt-Programmierung möchte ich verzichten, wenn es geht. Klar ist das nicht so schwer und ich habe das bereits in einem anderen Arduino-Projekt realisiert. Aber wenn wir ohne auskämen, fände ich das besser. Lieber den Code einfach halten. Modifizieren und anpassen kann eh jeder machen wie er/sie möchte.

    Ein kleiner Einschub für heute: Kann man bzgl. des Pegels zwei Nanos an einer seriellen Schnittstelle des Unos betreiben?

    Antwort: Ja, man kann. Ich habe da wenig Bedenken.
    Hier die Auswertung mit dem Oszi:

    Arduino Uno und ein Nano Pegel serielle an Powerbank.jpg
    Zwei Nanos an der seriellen des Unos.
    Der Pegel bricht bei Versorgung der Nanos über eine eigene Powerbank nicht ein. Es sieht also gut aus für das Gesamtsystem "Nano-Uno-Nano". Ich habe auch mal bei einem Nano die Powerbank abgezogen. Dann bricht die Spannung minimalst ein. Offensichtlich wird der Nano dann über die serielle versorgt. Fragt mich jetzt nicht warum und wie?! o_O

    Für diese Auswertung wurde das "delay(5000)" der Zentrale auf "delay(10)" herabgesetzt. Sonst wird das Triggern/Spreizen mit dem Oszi schwierig. Mit dieser Einstellung sendet der Uno 100 Telegramme bzw. Betriebszustands-Bytes pro Sekunde an die Nanos.

    Rätsel dazu:
    Wer erkennt, welche Betriebsarten hier eingeschaltet wurden? :rolleyes::D

    Grüße
    Heiko
     

    Anhänge:

    Zuletzt bearbeitet: 15.04.2018
    TitanWolf, Nobbi und Gear7Lover gefällt das.
  2. Heiko

    Heiko

    Beiträge:
    3.103
    Sooo... letzter Stand für heute ist dann das Schalten bzw. Tasten der Hupe.
    Die Schaltung dafür sieht so aus:
    Schaltung zu Stand C_Steckplatine.png
    Uno (Zentrale):
    Der Uno kümmert sich um den Taster, der mit einem "Pull-Up"-Widerstand den digitalen Eingang (Pin 7) im ungedrückten Zustand auf die 5V "zieht". Drückt man den Taster, dann wird der Eingang auf Masse gezogen.

    Nano (Front):
    Hier hängt an Pin 5 die rote LED mit Vorwiderstand, welche die Hupe repräsentiert.

    Beide Arduinos sind unverändert "seriell" verbunden.

    Code Zentrale:
    Code:
    #include <SoftwareSerial.h>
    
    SoftwareSerial mySerial(11, 12); // RX, TX
    int LED = 13;                    // Status-LED auf dem Board
    byte sendeByte = 0;              // das Byte, welches an die Front und ans Heck gesendet wird
    int tasterHupe = 7;              // Taster für Hupe ist am PIN 7
    int tasterstatusHupe = 0;        // Initial wird der Status auf "nicht gedrueckt" gesetzt
    
    void setup() {
      pinMode(LED, OUTPUT);
      pinMode(tasterHupe, INPUT);  //Der Pin mit dem Taster (Pin 7) ist jetzt ein Eingang.
      mySerial.begin(9600);
    }
    
    
    // Alle Betriebsarten werden parallel in einem Byte
    // uebertragen:
    // Bit 0 (Wert 1) = Licht
    // Bit 1 (wert 2) = Tagfahrlicht
    // Bit 2 (Wert 4) = Bremslicht
    // Bit 3 (Wert 8) = Blinker links
    // Bit 4 (Wert 16) = Blinker rechts
    // Bit 5 (Wert 32) = Hupe
    // Bit 6 (Wert 64) = Innenraumbeleuchtung
    // Bit 7 (Wert 128) = --Reserve--
    
    void loop()  {
     
      sendeByte = 0;  // das zu sendende Byte zu Beginn loeschen
     
      // Lichtschalter abfragen
      if (zustandLichtschalter())
      {
        sendeByte = 1;
      }
     
      // Tagfahrlichtschalter abfragen
      if (zustandTagfahrlicht())
      {
        sendeByte += 2;
      }
     
      // Bremslichttaster abfragen
      if (zustandBremslicht())
      {
        sendeByte += 4;
      }
     
      // Blinkerschalter links abfragen
      if (zustandBlinkerLi())
      {
        sendeByte += 8;
      }
     
      // Blinkerschalter rechts abfragen
      if (zustandBlinkerRe())
      {
        sendeByte += 16;
      }
    
      // Hupenschalter abfragen
      if (zustandHupe())
      {
        sendeByte += 32;
      }
    
      // Innenraumbeleuchtungsschalter abfragen
      if (zustandInnenraumbel())
      {
        sendeByte += 64;
      }
     
      // Byte senden
      mySerial.write(sendeByte);
      delay(10);
    }
    
    bool zustandLichtschalter()
    {
      return false;
    }
    
    bool zustandTagfahrlicht()
    {
      return false;
    }
    
    bool zustandBremslicht()
    {
      return false;
    }
    
    bool zustandBlinkerLi()
    {
      return false;
    }
    
    bool zustandBlinkerRe()
    {
      return false;
    }
    
    bool zustandHupe()
    {
      tasterstatusHupe = digitalRead(tasterHupe);
      if ( tasterstatusHupe == LOW )  // durch Pull-Up-Widerstand zieht der Taster beim Druecken den Eingang auf Masse
      {
        digitalWrite(LED, HIGH);      // LED auf dem Board einschalten
        return true;                  // Bit fuer Hupe setzen
      }
      else
      {
        digitalWrite(LED, LOW);       // LED auf dem Board ausschalten 
        return false;                 // Bit fuer Hupe auf null setzen
      }
    }
    
    bool zustandInnenraumbel()
    {
      return false;
    }
    Hier hat sich gar nicht viel getan. Das delay() habe ich bei 10msec gelassen. Also senden wir 100 Telegramme/Bytes pro Sekunde. Den Pin 7 deklarieren wir als digitalen Eingang und gönnen uns eine Integer-Variable, die sich den Zustand des Tasters merken soll.
    Unsere Funktion zum Abfragen des Tasters ist simpel. Es wird der digitale Eingang (Pin 7) abgefragt und true bzw false zurückgegeben. Als kleine Kontrolle habe ich die LED 13, die sich auf dem Uno-Board befindet, parallel zum Tasterdrücken eingeschaltet.

    Code Front:

    Code:
    #include <SoftwareSerial.h>
    
    int LED=13;  // Status-LED
    SoftwareSerial mySerial(2, 3); // Rx, Tx
    char a;
    
    // digitale Eingaenge
    int ausgangHupe = 5;
    
    void setup() {
      pinMode(LED, OUTPUT);
      mySerial.begin(9600); // initialize serial
    
      // digitale Ausgaenge
      pinMode(ausgangHupe, OUTPUT);
    }
    
    // Alle Betriebsarten werden parallel in einem Byte
    // uebertragen:
    // Bit 0 = Licht
    // Bit 1 = Tagfahrlicht
    // Bit 2 = Bremslicht
    // Bit 3 = Blinker links
    // Bit 4 = Blinker rechts
    // Bit 5 = Hupe
    // Bit 6 = Innenraumbeleuchtung
    // Bit 7 = --Reserve--
    
    void loop() {
      if (mySerial.available()) {
        a = mySerial.read();
    
        if (a & 1) {
          // licht(true);
        } else {
          // licht(false)
        }
        if (a & 2) {
          // tagfahrlicht(true);
        } else {
          // tagfahrlicht(false);
        }
        if (a & 4) {
          // bremslicht(true);
        } else {
          // bremslicht(false);
        }
        if (a & 8) {
          // blinkerLinks(true);
        } else {
          // blinkerLinks(false);
        }
        if (a & 16) {
          // blinkerRechts(true);
        } else {
          // blinkerRechts(false);
        }
        if (a & 32) {
          schalteDigitalOut(ausgangHupe, true);
        } else {
          schalteDigitalOut(ausgangHupe, false);
        }
        if (a & 64) {
          // innenraumbeleuchtung(true);
        } else {
          // innenraumbeleuchtung(false);
        }
      }
    }
    
    void schalteDigitalOut(int pin, bool zustand)
    {
      if (zustand)
      {
        digitalWrite(pin, HIGH);  // Pin einschalten
      }
      else
      {
        digitalWrite(pin, LOW);  // Pin ausschalten
      }
    }
    
    Die LED (Hupe) hängt hier an Pin 5. Ist das Bit 5 in unserem empfangenen Byte gesetzt, dann rufen wir eine Funktion auf, die gleich etwas generischer/allgemeiner geschrieben habe. Diese braucht eine Pin-Nummer, welche geschaltet werden soll, und de Sollzustand. So ergibt sich dafür für Hupe=EIN -> Pin 5, true.
    In der Funktion wird der gewünschte Pin mit dem gewünschten Zustand angesteuert.

    Bei mir tut's, bei wem noch? :whistle::)

    Grüße
    Heiko
     
    RaptoRacer und TitanWolf gefällt das.
  3. Fanfan

    Fanfan

    Beiträge:
    5.056
    Ort:
    81249 München
    Liegerad:
    Optima Cheetah
    Trike:
    HP Gekko
    Wenn Schalter benutzt werden, hat @Gear7Lover bezüglich Entprellung Recht - ist schließlich egal, ob das Licht beim Schalten einzelne Millisekunden lang flackert. Bei synchron abgefragten Tastern wird es von der Abfragehäufigkeit abhängen. 100ms halte ich für die Grenze, ab der man die Verzögerung merkt (nicht an Controllern ausprobiert, sondern vor 25 Jahren am Atari - da hat er angefangen, Klicks aus besonders flinken Doppelklicks zu übersehen).
    Kannst ja mal auswerten, ob Du in zwei aufeinanderfolgenden Durchläufen zwei Zustandswechsel feststellst, und im Falle des Falles eine Sekunde lang eine LED anmachen. Ist die Abfragefrequenz zu niedrig, kommt das bei kurzen Tastendrücken vor, ist sie zu hoch, kommt es beim Prellen vor. (Aber eine exakte Wissenschaft ist das sowieso nicht.)

    Gegen Interruptprogrammierung spricht hier wohl die Portabilität zwischen verschiedenen Arduino-Boards. Und bisher sehe ich nichts, was danach verlangt...

    Licht, Bremslicht und Innenraum, das Startbit hat das Oszi wohl weggeschnitten. :) Aber warum steht da "MTB" und "Auto" im Display und nicht "Liegerad"? :confused::D
     
    Heiko gefällt das.
  4. Heiko

    Heiko

    Beiträge:
    3.103
    schalteDigitalOut()... die Funktion kann ich mir auch sparen. War wohl schon nicht mehr so bei der Sache gestern .
    Die macht momentan das Gleiche wie die vorhandene digitalWrite().
    Zumindest bei einfachen Schaltfunktionen kann man sich eine extra Funktion sicher sparen.
     
  5. Fanfan

    Fanfan

    Beiträge:
    5.056
    Ort:
    81249 München
    Liegerad:
    Optima Cheetah
    Trike:
    HP Gekko
    Kennt der Compiler der Arduino-IDE inline-Funktionen? Als solche könnte man das implenentieren. Eine einfache Fallunterscheidung sollte man der Sache noch gönnen, um aus true/false HIGH/LOW zu machen.

    Bei dem internen UART der Atmels kannst Du sicher noch mehr als zwei RX-Pins an einen TX-Pin hängen, mit SoftwareSerial sowieso. Mit der Aktivierung des UART wird ja nur Digitallogik hinter dem Pin zugeschaltet, die Aus- und Eingangsstufen mit ihren Pegelerkennungen und Treibern sind dieselben wie auf normalen Digitalpins. Wenn Du die internen Pullup-Widerstände nicht brauchst, schalte sie an extern beschalteten Pins am besten aus (INPUT statt INPUT_PULLUP als Pin-Mode einstellen oder nach der Konfiguration als Eingang nochmal digitalWrite (pin, LOW) aufrufen). An unbenutzten Pins würde ich sie aktivieren und einschalten, um definierte Pegel zu bekommen.

    Über eine der Clamp-Dioden am RX-Pin. Es gibt ja (außer bei Reset und Versorgung) an jedem Pin intern je zwei Dioden, eine leitet vom Pin in Richtung Vcc, eine von Gnd in Richtung Pin. Und Vcc ist nicht nur im Controller als Versorgung des ganzen Chips geschaltet, sondern geht auch über den Vcc-Pin raus an andere Teile wie den USB-Baustein. Mindestens diese beiden werkeln dann mit den übrigbleibenden ca. 3,5-4,0V mehr oder weniger gekonnt vor sich hin.
     
    Heiko und Nobbi gefällt das.
  6. Reinhard

    Reinhard Team

    Beiträge:
    19.220
    Alben:
    6
    Ort:
    48599 Gronau-Epe
    Velomobil:
    DF
    Trike:
    ICE Sprint
  7. Gear7Lover

    Gear7Lover

    Beiträge:
    4.663
    Alben:
    2
    Ort:
    CH-4556 Steinhof
    Velomobil:
    Milan SL
    Liegerad:
    HP GrassHopper
    Er verwendet delay. Kann ich nicht empfehlen. Das bremst den Programmablauf aus.
    Besser mit millis die Zeit ermitteln wie lange der Taster schon gedrückt ist und nach 20ms oder so erst übernehmen.
     
  8. Fanfan

    Fanfan

    Beiträge:
    5.056
    Ort:
    81249 München
    Liegerad:
    Optima Cheetah
    Trike:
    HP Gekko
    Ähem... bitte nicht so:
    Code:
    if (buttonread == HIGH) {
        delay(5);
        if (digitalRead(buttonPin)) { //Check button twice
            // jetzt war er wirklich gedrückt.  Aktion auslösen...
        };
    };
    
    Wenn der Loop nachher immer noch ein delay(100) oder was in dieser Größenordnung enthält, könnte man vielleicht dieses delay teilen und es so machen:
    Code:
    ...
    <alle Tasten einmal lesen>
    delay(50)
    <alle Tasten nochmal lesen und Zustände vergleichen>
    <Auswerten...>
    delay(50)
    ...
    
    Das ist zwar etwas asymmetrisch bezüglich des "ersten" und "zweiten" Lesens, aber es erwartet die Tastendrücke nicht in einer bestimmten Reihenfolge und dauert nicht um so länger, je mehr Tasten einzulesen sind.
     
    Zuletzt bearbeitet: 16.04.2018
  9. Reinhard

    Reinhard Team

    Beiträge:
    19.220
    Alben:
    6
    Ort:
    48599 Gronau-Epe
    Velomobil:
    DF
    Trike:
    ICE Sprint
    Das war ein Beispiel ... Ich würde auch das zweite Beispiel von @Fanfan verwenden und alle Tasten auf einmal lesen, warten, auswerten. Ein delay wird dann keine negativen Auswirkungen haben, weil der sonstige Programmablauf schon länger dauert.
     
  10. Gear7Lover

    Gear7Lover

    Beiträge:
    4.663
    Alben:
    2
    Ort:
    CH-4556 Steinhof
    Velomobil:
    Milan SL
    Liegerad:
    HP GrassHopper
    Nä, stimmt so nicht. Ein delay hält den Programmablauf an der Zeile an. Die Zykluszeit verlängert sich also um den Wert des delay.
    Auf der Android-Seite gibt es ein Beispiel, entprellen ohne delay mit der millis Funktion. Habs grad nicht zur Hand. Ist aber kein Hexenwerk.
     
  11. Gear7Lover

    Gear7Lover

    Beiträge:
    4.663
    Alben:
    2
    Ort:
    CH-4556 Steinhof
    Velomobil:
    Milan SL
    Liegerad:
    HP GrassHopper
    RaptoRacer gefällt das.
  12. Reinhard

    Reinhard Team

    Beiträge:
    19.220
    Alben:
    6
    Ort:
    48599 Gronau-Epe
    Velomobil:
    DF
    Trike:
    ICE Sprint
    In der Praxis bereitet das keine Probleme und reicht für den hier angedachten Anwendungszweck ganz sicher aus, aber man kann es gern auch anders mit millis() machen ... Hauptsache, man wird irgendwann mal fertig ... :D.
     
  13. Fanfan

    Fanfan

    Beiträge:
    5.056
    Ort:
    81249 München
    Liegerad:
    Optima Cheetah
    Trike:
    HP Gekko
    Die nächsten Schritte wären glaube ich der Anschluss von Endstufen (KSQs, Mosfets, ...) an den Nanos und die Entscheidung, mit was für Schaltern/Tastern gearbeitet werden soll...
     
  14. Nobbi

    Nobbi

    Beiträge:
    5.444
    Alben:
    1
    Ort:
    bei München
    Velomobil:
    DF XL
    Liegerad:
    Nazca Fiero
    Delay-freies Entprellen gibt's übrigens auch als fertige library -> bounce2. Macht im Prinzip das gleiche wie @Gear7Lover s Beispiel, nur schön sauber gekapselt und simpel in der Verwendung.
     
  15. RaptoRacer

    RaptoRacer

    Beiträge:
    13.799
    Ort:
    Irjendwo im Pott
    Velomobil:
    Milan SL
    Liegerad:
    Raptobike Mid Racer
    (y)
     
  16. Heiko

    Heiko

    Beiträge:
    3.103
    Nicht drängeln :D

    Ja. Das würde mich von denen, die hier mitlesen und das umsetzen wollen, auch interessieren. Was für ein Gehäuse soll der Uno/Nano bekommen? Zu Relais, MosFets, Schaltern, Tastern, ... wollte ich mir jetzt nicht so die Gedanken machen. Hab' aktuell kein VM und somit auch keinen Bedarf.
    Ich bastel nun noch am Code rum, dass wir z.B. die Blinker inkl. Warnblinker ans Laufen bekommen und dann soll es das auch weitestgehend von meiner Seite gewesen sein :p

    Die Integration ins VM mit den zwei unterschiedlichen Spannungen, den Schaltern und Gehäusen ist halt auch noch eine ganz ordentliche Aufgabe!

    Grüße
    Heiko
     
  17. Heiko

    Heiko

    Beiträge:
    3.103
    Weiter geht's!
    Es steht die Aufgabe an, einen Blinker zu setzen.

    Schaltung:
    Schaltung zu Stand D.png
    Auf einen neuen Schalter für das "links Blinken" habe ich verzichtet. Das habe ich Code einfach "hart" gesetzt. Die Implementierung und Schaltung ist analog zum Taster vorzunehmen.

    Code Zentrale:
    Code:
    #include <SoftwareSerial.h>
    
    SoftwareSerial mySerial(11, 12); // RX, TX
    int LED = 13;                    // Status-LED auf dem Board
    byte sendeByte = 0;              // das Byte, welches an die Front und ans Heck gesendet wird
    int tasterHupe = 7;              // Taster für Hupe ist am PIN 7
    int tasterstatusHupe = 0;        // Initial wird der Status auf "nicht gedrueckt" gesetzt
    
    void setup() {
      pinMode(LED, OUTPUT);
      pinMode(tasterHupe, INPUT);  //Der Pin mit dem Taster (Pin 7) ist jetzt ein Eingang.
      mySerial.begin(9600);
    }
    
    
    // Alle Betriebsarten werden parallel in einem Byte
    // uebertragen:
    // Bit 0 (Wert 1) = Licht
    // Bit 1 (wert 2) = Tagfahrlicht
    // Bit 2 (Wert 4) = Bremslicht
    // Bit 3 (Wert 8) = Blinker links
    // Bit 4 (Wert 16) = Blinker rechts
    // Bit 5 (Wert 32) = Hupe
    // Bit 6 (Wert 64) = Innenraumbeleuchtung
    // Bit 7 (Wert 128) = --Reserve--
    
    void loop()  {
     
      sendeByte = 0;  // das zu sendende Byte zu Beginn loeschen
     
      // Lichtschalter abfragen
      if (zustandLichtschalter())
      {
        sendeByte = 1;
      }
     
      // Tagfahrlichtschalter abfragen
      if (zustandTagfahrlicht())
      {
        sendeByte += 2;
      }
     
      // Bremslichttaster abfragen
      if (zustandBremslicht())
      {
        sendeByte += 4;
      }
     
      // Blinkerschalter links abfragen
      if (zustandBlinkerLi())
      {
        sendeByte += 8;
      }
     
      // Blinkerschalter rechts abfragen
      if (zustandBlinkerRe())
      {
        sendeByte += 16;
      }
    
      // Hupenschalter abfragen
      if (zustandHupe())
      {
        sendeByte += 32;
      }
    
      // Innenraumbeleuchtungsschalter abfragen
      if (zustandInnenraumbel())
      {
        sendeByte += 64;
      }
     
      // Byte senden
      mySerial.write(sendeByte);
      delay(10);
    }
    
    bool zustandLichtschalter()
    {
      return false;
    }
    
    bool zustandTagfahrlicht()
    {
      return false;
    }
    
    bool zustandBremslicht()
    {
      return false;
    }
    
    bool zustandBlinkerLi()
    {
      return true;
    }
    
    bool zustandBlinkerRe()
    {
      return false;
    }
    
    bool zustandHupe()
    {
      tasterstatusHupe = digitalRead(tasterHupe);
      if ( tasterstatusHupe == LOW )  // durch Pull-Up-Widerstand zieht der Taster beim Druecken den Eingang auf Masse
      {
        digitalWrite(LED, HIGH);      // LED auf dem Board einschalten
        return true;                  // Bit fuer Hupe setzen
      }
      else
      {
        digitalWrite(LED, LOW);       // LED auf dem Board ausschalten
        return false;                 // Bit fuer Hupe auf null setzen
      }
    }
    
    bool zustandInnenraumbel()
    {
      return false;
    }
    Einzige Änderung in diesem Code: Die Funktion "zustandBlinkerLi()" gibt "true" zurück, womit das Bit für den Zustand "links Blinken" gesetzt und gesendet wird.

    Code Front:
    Code:
    #include <SoftwareSerial.h>
    
    int LED=13;  // Status-LED
    SoftwareSerial mySerial(2, 3); // Rx, Tx
    char a;
    
    // digitale Eingaenge
    int ausgangHupe = 5;
    int ausgangBlinkerLinks = 6;
    unsigned long zeitBlinkerAn = 0;
    unsigned long zeitBlinkerAus = 0;
    
    
    void setup() {
      pinMode(LED, OUTPUT);
      mySerial.begin(9600); // initialize serial
    
      // digitale Ausgaenge
      pinMode(ausgangHupe, OUTPUT);
      pinMode(ausgangBlinkerLinks, OUTPUT);
    }
    
    // Alle Betriebsarten werden parallel in einem Byte
    // uebertragen:
    // Bit 0 = Licht
    // Bit 1 = Tagfahrlicht
    // Bit 2 = Bremslicht
    // Bit 3 = Blinker links
    // Bit 4 = Blinker rechts
    // Bit 5 = Hupe
    // Bit 6 = Innenraumbeleuchtung
    // Bit 7 = --Reserve--
    
    void loop() {
      if (mySerial.available()) {
        a = mySerial.read();
    
        if (a & 1) {
          // licht(true);
        } else {
          // licht(false)
        }
        if (a & 2) {
          // tagfahrlicht(true);
        } else {
          // tagfahrlicht(false);
        }
        if (a & 4) {
          // bremslicht(true);
        } else {
          // bremslicht(false);
        }
        if (a & 8) {
          blinkerLinks(true);
        } else {
          schalteDigitalOut(ausgangBlinkerLinks, false);  // kann hier direkt auf AUS gesetzt werden; u.U. kollidiert dies spaeter mit Warnblinken
        }
        if (a & 16) {
          // blinkerRechts(true);
        } else {
          // blinkerRechts(false);
        }
        if (a & 32) {
          schalteDigitalOut(ausgangHupe, true);
        } else {
          schalteDigitalOut(ausgangHupe, false);
        }
        if (a & 64) {
          // innenraumbeleuchtung(true);
        } else {
          // innenraumbeleuchtung(false);
        }
      }
    }
    
    void schalteDigitalOut(int pin, bool zustand)
    {
      if (zustand)
      {
        digitalWrite(pin, HIGH);  // Pin einschalten
      }
      else
      {
        digitalWrite(pin, LOW);  // Pin einschalten
      }
    }
    
    void blinkerLinks(bool zustand)
    {
      if (zustand)
      {                                       // es soll Blinker links gesetzt werden
        if (zeitBlinkerAn == 0)               // wenn es noch keine Startzeit fuer "AN" gibt, dann holen
        {
          zeitBlinkerAn = millis();           // die aktuelle Zeit seit Programmstart holen
        }
        if (millis()-zeitBlinkerAn < 750)     // Blinker soll fuer 750msec an sein, was 1.5Hz entspricht
        {
          schalteDigitalOut(ausgangBlinkerLinks, true);
        }
        else
        {                                     // der Blinker war fuer 750msec an, nun fuer die gleiche Zeit ausschalten
          if (zeitBlinkerAus == 0)            // wenn keine Startzeit fuer "AUS" existiert, dann holen
          {
            zeitBlinkerAus = millis();        // die aktuelle Zeit seit Programmstart holen
          }
          if (millis()-zeitBlinkerAus < 750)  // Blinker soll fuer 750msec an sein, was 1.5Hz entspricht
          {
            schalteDigitalOut(ausgangBlinkerLinks, false);
          }
          else
          {
            zeitBlinkerAn = 0;                // ein kompletter Blinkvorgang ist abgeschlossen
            zeitBlinkerAus = 0;               // deshalb beide Startzeiten wieder zuruecksetzen
          }
        }
      }
    }
    
    Änderungen für den Nano: Den linken Blinker habe ich an Pin 6 gehängt und diesen Pin analog zum "Hupen-Pin" angemeldet als digitalen Ausgang.
    Für eine Zeitmessung benötigen wir noch zwei Variablen, in denen wir Zeiten speichern können. Diese sind vom Typ "unsigned long", da eben auch die Funktion, welche die Zeit zurückgibt, diesen Typ als Rückgabewert hat.
    In der "loop" rufe ich bei gesetztem Blinker-links-Bit die entsprechende Methode auf. Ist das Bit nicht gesetzt, dann wird der Pin gleich in der if-Bedingung ausgeschaltet.
    Die Methode "blinkerLinks()" schaut nun zunächst, ob der Blinker blinken soll. Dieses "if" könnte man wohl auch weglassen, da diese Entscheidung bereits oben beim Auswerten des Bits erfolgte.
    Der Rest ist im Code kommentiert. Die 750msec habe ich aus dem passenden Wikipedia-Eintrag.

    Was macht das Programm?
    Die Hupe funktioniert weiterhin mittels Taster. Die zweite LED blinkt mit 1.5Hz permanent.


    An dieser Stelle würde ich nun vorerst abbrechen. Es tauchen sicher beim Implementieren aller Funktionen Fragen auf, die wir hier gerne besprechen können. Interessant würde sicher noch die Warnblinkanlage werden. Als Basis sollte aber jetzt alles vorhanden sein:
    • Abfragen von Schaltern und Tastern
    • Zustände von einem Arduino zum anderen per serieller Schnittstelle übertragen
    • Ein- und Ausschalten einer LED -> kann mit Relais/MOSFET für größere Verbraucher genommen werden
    • Blinken einer LED in einem definierten Takt

    Bei Fragen: Fragen!
    Ich bin nicht allwissend und sicher kann man wie immer vieles anders lösen. Aber für diese doch recht kurze Zeit mit dem Arduino ist - wie ich finde - noch überschaubarer und erweiterbarer Code entstanden.

    Grüße
    Heiko
     
    RaptoRacer gefällt das.
  18. cnar

    cnar

    Beiträge:
    76
    Ort:
    Arnheim (Niederlande)
    Velomobil:
    Quest XS Carbon
    Liegerad:
    Challenge Hurricane
    Ich habe jetzt nicht alle post's gelesen, aber wenn das Ganze eine echte Bus-Loesung werden soll, sollten doch eigentlich auch die Schalter/Taster am Tiller in den Bus einbezogen werden. Sonst hat man trotz Bus immer noch mindestens 7 Draehte die vom Tiller zum Computer gefuehrt werden muessen. Und fuer jede neue Funktion wie Fernlicht oder Lichthupe muessen dann doch wieder neue Strippen gezogen werden.

    Christian
     
  19. Fanfan

    Fanfan

    Beiträge:
    5.056
    Ort:
    81249 München
    Liegerad:
    Optima Cheetah
    Trike:
    HP Gekko
    Das läuft auf 3-4 Leitungen und eine Platine am Tiller hinaus. Was würdest Du denn alles auf den Tiller legen wollen? Die Schalter/Taster müssen ja nur eine Leitung auf Masse ziehen, d.h. Du brauchst für n Funktionen n+1 Leitungen. Mit Hupe und Blinker wären das vier Leitungen. Licht, Fernlicht, Innenraumlicht und Warnblinker hätte ich auf dem Radkasten vermutet. Vielleicht auf dem Tiller noch eine Lichthupe (Taster parallel zum Fernlichtschalter), dann sind's fünf Leitungen.

    Unabhängig davon würde ich für die Verwendung von Tastern noch einen Punkt in die Runde werfen: Wenn man Taster zum Ein- und Ausschalten jeweils kurz antippt, erkennt man nicht an ihrer Stellung, ob das zugehörige Licht gerade an ist. Kann man tagsüber als Fahrer sehen, welche Lichter leuchten? Wenn nicht, werden einige Anzeige-LEDs auf der Zentrale interessant, die man auch wieder vom Controller aus ansteuern muss - und die man nachts vielleicht abschalten möchte, aber dazu kann man auch die Vorwiderstände der LEDs über einen Schalter an die Versorgung führen und braucht keinen zusätzlichen Controllerpin.
     
    Zuletzt bearbeitet: 17.04.2018
  20. TitanWolf

    TitanWolf

    Beiträge:
    5.779
    Alben:
    9
    Ort:
    Nahe Gera
    Trike:
    Eigenbau
    Das würde ich grundsätzlich nicht empfehlen, sondern die Status-LEDs über den Spannungsversorgungsausgang zu den jeweiligen Verbrauchern versorgen. Wieso? Weil Du ansonsten einen defekten Transistor, eine verbuggte Ansteuerung o.Ä. nicht erkennst: Die Status-LED wird über den µC weiterhin aktiviert, doch die eigentliche Beleuchtung bleibt finster. Oder andersherum.

    Viele Grüße
    Wolf