Hupe, Blinker, Fernlicht steuern für Cafe Racer

Hallo zusammen,

ich habe mir letzte Woche einen Thinary Nano Every gekauft und habe ein kleines Programm für nen Kumpel geschrieben.

Er möchte über vier Taster die Funktionen Hupe, Blinker links/rechts und Fernlicht steuern.

Dabei soll der Taster für die Hupe 1:1 im Programm durchgeschliffen werden.
Über den zweiten und dritten Taster sollen die Blinker bei einmaliger Betätigung mit 1,5 Hz blinken und bei erneuter Betätigung wieder ausgehen.
Der vierte Taster soll bei einmaliger Betätigung das Fernlicht anschalten und bei erneuter Betätigung wieder ausmachen.


//EINGÄNGE
#define IN_Hupe 2
#define IN_Blink_L 3
#define IN_Blink_R 4
#define IN_Fernlicht 5

//AUSGÄNGE
#define OUT_Fern_Kontroll 7          //Kontrolleuchte für Fernlicht
#define OUT_Hupe 8
#define OUT_Blink_L 9 
#define OUT_Blink_R 10
#define OUT_Fernlicht 11
#define OUT_Blink_Kontroll 12       //Kontrolleuchte für Blinker links+rechts


//lokale Variablen
bool Fernlicht_Status = false;
bool Blinker_links_Status = false;
bool Blinker_rechts_Status = false;

//ISR Variablen
volatile bool interrupt_links;
volatile bool interrupt_rechts;
volatile bool interrupt_fernlicht;
volatile bool interrupt_hupe;


void setup()
{
  attachInterrupt(IN_Blink_L, interruptBlinkerLinks, RISING);
  attachInterrupt(IN_Blink_R, interruptBlinkerRechts, RISING); 
  attachInterrupt(IN_Fernlicht, interruptFernlicht, RISING);  
  attachInterrupt(IN_Hupe, interruptHupe, CHANGE); 
  

//Pins als Ausgänge definieren
  pinMode(OUT_Hupe, OUTPUT); // HUPE OUT
  pinMode(OUT_Blink_L, OUTPUT); // BLINKER LINKS OUT 1,5HZ
  pinMode(OUT_Blink_R, OUTPUT); // ,,      RECHTS OUT 1,5HZ
  pinMode(OUT_Fernlicht, OUTPUT); // FERNLICHT OUT 
  pinMode(OUT_Blink_Kontroll, OUTPUT); // BLINKER KONTROLLEUCHTE
  pinMode(OUT_Fern_Kontroll, OUTPUT); // Fernlicht Kontrolleuchte
}

//Interrupt Hupe
void interruptHupe()
{
  if(interrupt_hupe)
  {
    interrupt_hupe = false;
    digitalWrite(OUT_Hupe, LOW);    
  }
  else
  {
    interrupt_hupe = true;
    digitalWrite(OUT_Hupe, HIGH);
  }
}


//Interrupt Fernlicht
void interruptFernlicht()
{
  if(interrupt_fernlicht)
  {
    interrupt_fernlicht = false;
    digitalWrite(OUT_Fernlicht, LOW); 
    digitalWrite(OUT_Fern_Kontroll, LOW); 
      
  }
  else
  {
    interrupt_fernlicht = true;
    digitalWrite(OUT_Fernlicht, HIGH);
    digitalWrite(OUT_Fern_Kontroll, HIGH);    
  }
}



//Interrupt Blinker links
void interruptBlinkerLinks()
{
	if(interrupt_links)
	{
		interrupt_links = false;		
	}
	else
	{
		interrupt_rechts = false;
		interrupt_links = true;
	}
}

//Interrupt Blinker rechts
void interruptBlinkerRechts()
{
	if(interrupt_rechts)
	{
		interrupt_rechts = false;
	}
	else
	{
		interrupt_links = false;
		interrupt_rechts = true;
	}
}

void loop()
{
//Blinker links mit 1,5 Hz blinken lassen
if(interrupt_links)
{
  digitalWrite(OUT_Blink_L, HIGH);
  digitalWrite(OUT_Blink_Kontroll, HIGH);
  delay(666);
  digitalWrite(OUT_Blink_L, LOW);
  digitalWrite(OUT_Blink_Kontroll, LOW);
  delay(666);
}
else
{
  digitalWrite(OUT_Blink_L, LOW);
  digitalWrite(OUT_Blink_Kontroll, LOW);
}


//Blinker rechts mit 1,5 Hz blinken lassen
if(interrupt_rechts)
{
  digitalWrite(OUT_Blink_R, HIGH);
  digitalWrite(OUT_Blink_Kontroll, HIGH);
  delay(666);
  digitalWrite(OUT_Blink_R, LOW);
  digitalWrite(OUT_Blink_Kontroll, LOW);
  delay(666);
}
else
{
  digitalWrite(OUT_Blink_R, LOW);
  digitalWrite(OUT_Blink_Kontroll, LOW);
}


}

Das Programm funktioniert soweit ganz gut, allerdings glaube ich, dass das Programm noch Verbesserung vertragen kann. (z.B. das Blinken nicht über delay realisieren, softwareseitige Entprellung, Interrupts entfallen lassen?)

Ein anderer Lösungsansatz von mir (vor den Interrupts) war das ständige Abfragen der Eingänge, aber wenn das Programm einmal mit "blinken" beschäftigt war, dann hatte ich das Gefühl nie den richtigen Zeitpunkt abpassen zu können um die Blinker wieder auszuschalten.

aktuelle Probleme:
Manchmal kommt es vor, dass beim Betätigen des Fernlicht-Tasters das Fernlicht an und wieder direkt ausgeht. Ich vermute mal, dass der Taster prellt und der Interrupt öfters aufgerufen wird.
(generell für jeden Taster)

Es kann vorkommen, dass wenn ich den Taster der Hupe ganz schnell hintereinander betätige, dass der Ausgang der Hupe an bleibt.

Warum müssen die Eingänge mit Pulldown Widerständen versehen werden? Wenn ich die nämlich weglasse, dann bleibt der Eingang bei einmaligen Betätigen auf HIGH :face_with_raised_eyebrow:

schau dir mal das Beispiel "Blink Without Delay" an.
Bau es nach.
lerne es.
So blinkt man ohne Delay und dann braucht man auch keine Interrupts zum Button auslesen.

1 Like

Hallo
In der Beschreibung fehlt noch der Warnblinker.

1 Like

Da offene Eingänge als Empfänger arbeiten und die angeschlossenen Kabel sind die Antenne. Damit Empfänger die alle möglichen Störsignale und werten diese als Nutzsignal.

1 Like

Der Eingang ist sehr hochohmig.
Ehe die Ladung aufgebraucht ist, vergeht einiges an Zeit.
Und dann gibt es zwischendurch noch Zustände, die weder HIGH noch LOW sind.
Da passieren dann ganz spannende Sachen :wink:

1 Like

Da stimme ich Dir zu!

Man kann das alles mit "Bordmitteln" lösen, oder man holt sich die Unterstützung einer Bibliothek wie den MobaTools, die sich über die Arduino-IDE installieren läßt.

  • to implement time functions without use of delay().
  • to debounce and evaluate up to 32 buttons/switches (per instance)

Eine Beschreibung gibt es auch auf Deutsch.

1 Like

Danke euch für die Antworten, werde mich mal ein wenig in die MobaTools einlesen :slight_smile:

Muss nicht..
Ist nur notwendig, wenn das Fahrzeug auch vorher schon damit ausgerüstet war.

Aber davon ab....
So wie ich sehe, ist die Erfahrung gering und die Beleuchtung Sicherheitsrelevant
Eigentlich keine gute Kombination.

2 problematische Aspekte:

  1. Das Bordnetz von Verbrennungsmotorbetriebenen Fortbewegungsmittel ist elektrisch sehr verschmutzt. Störungen von der Zündanlage, Spannungserhöhungen und Unterspannungen durch Einschalten von großen Verbrauchern (Fernlicht) und langsame Spannungsnachregelung. Das muß bei der Projektierung des Projekt berücksichtigt werden.
  2. Zulassung des Fahrzeugs. Durch Modifikationen sicherheitsrilevanter Teile erlöscht die Betriebsbewilligung.

Grüeß Uwe

1 Like

Stimmt, dass ist ja auch für ne Mofa.
Da ist es nicht notwendig.

Habe eben versucht die MobaTools zu installieren. Leider wird der Nano Every nicht unterstützt. Aber auf jeden Fall interessante Bibliothek! :slight_smile:

Der Nano Every ist so neu und anders, der wird von fast keiner Lib unterstützt.

Gruß Tommy

Außerdem hast Du keinen orginal Arduino Nano Every sondern einen Nachbau mit einem abgespeckten Controller (4808 statt des 4809)

Grüße Uwe

Meine Multitasking Libs und DatenflussDinger sollten darauf laufen.
Nur die Combie Pin läuft dann in einer Emulation.
Wobei, wenn ich mich richtig erinnere, @Doc_Arduino eine angepasste Version gebaut hat.

Ich besitze das Original, trotzdem ist der noch immer, nach mehr als einem Jahr Besitz, sehr lausig unterstützt, obwohl da original Arduino draufstehen darf. :thinking:

Hier wäre der Link zur angepassten Pin Lib
Damit würden die häßlichen defines wegfallen und man arbeitet mit Objekten.
Ich kann nicht einschätzen ob das dem TO hilft bzw. ob er damit klarkommt.
Das wäre wieder so ein Sprung von 0 auf 100. Müßte man langsam angehen.
Auf der anderen Seiten sind Bsp. dabei die, soweit meine Hoffnung, selbsterklärend sein sollten.

Was man sich auch anschauen / nutzen kann ist MegaCoreX. Hätte man zum Bsp. mehrere Serielle im Hand umdrehen usw. zur Verfügung. Das schnelle Pin schalten wird intern mit defines gemacht. Die Funktionsnamen sind eher Arduino "kompatibel" bzw. ähnlich gehalten.

speziell @ TO:
Wenn ich mir das Eingangsprogramm so anschaue, würde ich auch sagen, auch wenn es schon gesagt wurde, dass man die delays durch millis Anwendung ersetzen sollte. In dem Zuge werden dann keine Interrupts benötigt, weil nichts mehr blockiert und damit Polling ausreichend ist. Je nach Lernfortschritte könnte man zusammengehörende Dinge in struct's verpacken, was mehr Übersicht bringt und damit mehr Sicherheit. Das wäre schon ein ganz großer Schritt denke ich. Ob du bei digitalRead, digitalWrite bleibts oder eine andere Pin Lib verwendest, hat mit all dem erstmal wenig zu tun. Das ist dann die übernächste Optimierungsstufe, wenn das andere verstanden wurde. Dabei gehts dann mehr um Schnelligkeit und Objektprogrammierung.

Das mußt du trennen. Alle Libs von Arduino funktionieren mit dem Every. Also Original funktioniert immer. Solange die Drittanbieter immer Standardfunktionen verwenden, solange funktionieren diese auch mit dem Every. Essig wird es wenn Drittanbieter anfangen direkt auf die Hardware zu zugreifen. Dann funktioniert dann logischerweise nicht mehr. Sie müßten die Register vom ATmega4809 ergänzen.

Abgesehen von den Standardfunktionen gibts eben unter der Haube große Unterschiede, weil es eben ein anderer neuer µC ist. Wenn zum Bsp. die Möglichkeiten der Timer bekannter wäre, dann wären die Lösungen zu manchen Fragen hier wie Frequenz oder Pulsweite messen ganz easy, weil das der Timer Typ TCB zum Bsp. alles kann. Ich habe es zu mindestens im Link versucht zu erklären wie das funktioniert. Mittels Eventsystem kann man nicht herausgeführte Pins durch andere ersetzen. Man muss sich da nur einmal reindenken. Das ist im Grunde ähnlich zum bekannteren ATmega328P wenn man abseits der Standardfunktion etwas direkt mit der Hardware machen möchte. Da muss man auch das Manual aufschlagen, lesen, probieren und verstehen. Ganz normaler Vorgang.

Hallo Doc,
und herzlichen Dank für die Bereitstellung der Informationen zum Thema NANO vs NANO Every.

Mir war der Begriff Cafe Racer bislang unbekannt. Bitte beachte unbedingt die gesetzlichen Bestimmungen und besonders die Haftung, der Du Dich nicht entziehen kannst! Obdachlosenbiografien können mit sowas anfangen.

Entschuldigung, das wußte ich nicht. Leider hast Du einen Exoten ausgesucht. Ein Nano mit ATmega328 wäre vermutlich die bessere Wahl gewesen.

Dann eben mit der eigenen Hand getippt exemplarisch für die Blinker. Getestet mit UNO:

const byte L = {0};                       // Richtung Links
const byte R = {1};                       // Richtung Rechts

//EINGÄNGE
const byte IN_Hupe = 2;
const byte IN_Blink[2] = {3, 4};          // Links, Rechts
const byte IN_Fernlicht = 5;

//AUSGÄNGE
const byte OUT_Fern_Kontroll = 7;         //Kontrolleuchte für Fernlicht
const byte OUT_Hupe = 8;
const byte OUT_Blink[2] = {9, 10};        // Links, Rechts
const byte OUT_Fernlicht = 11;
const byte OUT_Blink_Kontroll = 12;       //Kontrolleuchte für Blinker links+rechts


//Variablen
uint32_t jetzt = millis();

void setup()
{
  //Pins als Eingänge mit PullUp-Widerstand definieren, aktiv = LOW
  pinMode(IN_Hupe, INPUT_PULLUP);
  pinMode(IN_Blink[L], INPUT_PULLUP);
  pinMode(IN_Blink[R], INPUT_PULLUP);
  pinMode(IN_Fernlicht, INPUT_PULLUP);

  //Pins als Ausgänge definieren
  pinMode(OUT_Hupe, OUTPUT); 			      // HUPE OUT
  pinMode(OUT_Blink[L], OUTPUT); 		    // BLINKER LINKS OUT 1,5 Hz
  pinMode(OUT_Blink[R], OUTPUT);     		// BLINKER RECHTS OUT 1,5 Hz
  pinMode(OUT_Fernlicht, OUTPUT);    		// FERNLICHT OUT
  pinMode(OUT_Blink_Kontroll, OUTPUT); 	// BLINKER KONTROLLEUCHTE
  pinMode(OUT_Fern_Kontroll, OUTPUT); 	// Fernlicht Kontrolleuchte
}

void blink_LR(byte richtung)
{
  static uint32_t entprell_vorhin[2] = {0, 0};
  const uint32_t entprell_intervall = {100};
  static uint32_t blink_vorhin[2] = {0, 0};
  const uint32_t blink_intervall = {666};
  bool aktTaster = !digitalRead(IN_Blink[richtung]);
  static bool altTaster[2] = {0, 0};
  static bool MERKER_Blink[2] = {0, 0};

  if (jetzt - entprell_vorhin[richtung] >= entprell_intervall)
  {
    if (aktTaster != altTaster[richtung])
    {
      altTaster[richtung] = aktTaster;
      entprell_vorhin[richtung] = jetzt;
      if (aktTaster)
      {
        MERKER_Blink[richtung] = !MERKER_Blink[richtung];
      }
    }
  }
  if (MERKER_Blink[richtung])
  {
    if (jetzt - blink_vorhin[richtung] >= blink_intervall)
    {
      blink_vorhin[richtung] = jetzt;
      digitalWrite(OUT_Blink[richtung], !digitalRead(OUT_Blink[richtung]));
    }
  } else {
    digitalWrite(OUT_Blink[richtung], LOW);
  }
}

void blink_Kontroll()
{
  digitalWrite(OUT_Blink_Kontroll, digitalRead(OUT_Blink[L]) || digitalRead(OUT_Blink[R]));
}

void loop()
{
  jetzt = millis();
  blink_LR(L);
  blink_LR(R);
  blink_Kontroll();
}

Die Blinker blinken völlig unabhängig voneinander, es gibt noch keine gegenseitige Verriegelung. Daher weiß die Kontrollleuchte auch nicht so richtig, wie sie blinken soll.

1 Like

Super, vielen Dank dass du dir die Zeit genommen hast!
Im Nachhinein wäre es mit einem Nano einfacher gewesen, allerdings war ich sehr auf die Anzahl an Interrupts fixiert und der Nano hatte leider nur 2.

Ich werde später mal dein Programm einspielen und schauen wie es sich verhält.