Ich möchte ZWEI Timer, den ich Starte. dann läuft eine Zeit. Nach Ablauf der Zeit soll etwas ausgeführt werden. Es soll aber möglich sein, den Timer neuzustarten bevor er abgelaufen ist, sodass die Zeit wieder von neu läuft ohne das sonst etwas ausgeführt wird.
Und das ganz per Interrupt.
Hier habe ich mich schon mal versucht:
#include "TimerOne.h"
int alle_x_sekunden = 3;
int i = 0;
void setup() {
Serial.begin(9600);
delay(2000);
Serial.println("Starte...");
int alle_x_sekunden = 5;
Timer1.initialize(alle_x_sekunden * 1000000);
Timer1.attachInterrupt(blinken);
//Timer1.setPeriod(3000000);//3 sek
//Timer1.stop();
}
void blinken() {
Serial.println("Ausgeführt");
if (i >= 1) { //Nur wenn Interrupt das 2te mal aufgerufen wurde, weil er beim Start direkt einmal schon durchfläuft
//Mache etwas
Serial.println("Stop");
Timer1.stop();
//Timer1.detachInterrupt();
}
i++;
}
void loop() {
Timer1.restart();
Timer1.start();
Serial.println("starte");
delay(800);
}
Das Problem ist, das bei jedem Start der Interrupt schon 1x durch läuft.
Und wie ich noch einen zweiten Timer, der davon unabhänig ist mache weiß ich gar nicht.
Hallo,
Nach einer ordentliche Dokumentation über Interrupts suche ich noch, will mich bald damit auseinandersetzen.
Ich kann dir nur diese 3 teilige Doku (über Multitasking) von Adafruit anbieten. (Teil 2 = Interrupt)
Ja, gut...
Aber das ist doch kein Grund für Interrupts...
(glaube ich)
Ich könnte dir einen Timer zur Verfügung stellen, welcher keinen zusätzlichen Interrupt nutzt.
Aber wovon man mehrere Instanzen gleichzeitig einsetzen kann und welcher Restart fähig ist.
BlinkWithSimpleTimer:
// Wieder eine Variation des BlinkWithoutDelay
#include "SimpleTimer.h"
SimpleTimer timer; // timer Instanz anlegen
void setup()
{
pinMode(LED_BUILTIN,OUTPUT);
}
void loop()
{
if(timer(1000)) // wenn abgelaufen
{
digitalWrite(LED_BUILTIN,!digitalRead(LED_BUILTIN));
timer.start();
}
}
wenn es unbedingt mit Hardware-Timer sein soll, dann vielleicht so. Man schreibt sich die benötigten Funktionen und ruft sie an geeigneter Stelle auf. Wenn die "Zeit gestoppt" werden soll nachdem die Zeitspanne um ist, dann füge ohne Atomic {} die disable Comp Zeile in die zugehörige ISR ein. Ansonsten kannst du jederzeit die nächste Zeitspanne mit der enable Comp Funktion setzen. Wenn das ISR stoppen und neue Zeitspanne setzen getrennt erfolgen soll, dann zerteile die letzten beiden Funktionen. Aktuell werde beide seriellen Ausgaben jeweils für sich betrachtet immer im gleichen zeitlichen Abstand ausgegeben.
Wenn kein Interrupt benötigt wird, könntest Du per millis() dutzende Timer nutzen - zwar Alle dann nur in ms Auflösung und Alle mit gleichem Takt, aber so zu starten/pausieren/stoppen/rücksetzen wie Du Das willst/programmierst.
Meine CAN-Module haben einen INT-Pin, womit Diese dem Arduino signalisieren, daß 'was da ist'.
Was passiert bei Dir bzw. was für Daten bekommst Du?
(meine Module sind 8MHz, im Auto werden wohl 16MHz benötigt ... gefährliches Halbwissen )
Wenn kein Interrupt benötigt wird, könntest Du per millis() dutzende Timer nutzen - zwar Alle dann nur in ms Auflösung und Alle mit gleichem Takt, aber so zu starten/pausieren/stoppen/rücksetzen wie Du Das willst/programmierst.
Meine CAN-Module haben einen INT-Pin, womit Diese dem Arduino signalisieren, daß 'was da ist'.
Was passiert bei Dir bzw. was für Daten bekommst Du?
(meine Module sind 8MHz, im Auto werden wohl 16MHz benötigt ... gefährliches Halbwissen )
MfG
Ich habe auch nur ein Modul mit 8 Mhz. Ich lese nur Tasten zB. Lenkradtasten und Zündung bzw den Schlüssel Status.
Mein Problem ist, das ich einen Button habe und nur ein Signal bekomme, wenn er gedrückt wurde.
Jetzt möchte ich unterscheiden zwischen einem normalen, langen und doppelten Druck.
Nun bekomme ich wenn es ein normaler ist ja nur 1 mal das Signal und weiß nicht ob noch ein Doppelter kommt und muss darauf 110 ms warten.
Hier erstmal als Version mit Button damit ich nicht immer ins Auto rennen muss
const int buttonPin = 8; // the number of the pushbutton pin
const int ledPin = 10; // the number of the LED pin
int buttonState = 0;
unsigned long DifferenzStempMillis = 0;
unsigned long PreviousStempMillis = 0;
unsigned long CurrentStempMillis = 0;
//unsigned long CurrentStemp2Millis = 0;
//unsigned long CurrentStemp3Millis = 0;
unsigned long anCurrentMillis = 0;
unsigned long anPreviousMillis = 0;
unsigned long anZeitDifferenz = 0;
unsigned int EinfacherDruck = 0;
unsigned int DoppelterDruck = 0;
unsigned int LangerDruck = 0;
unsigned int ZeitNeuerDruck = 300; // Ab hier beginnt ein ganz neuer Druck
//unsigned int ZeitDelayHalten = 20; // Zeit die beim Halten zwischen jedem Ausführen gewartet werden soll.
//unsigned int ZeitEinfacherDruck = 500;
unsigned int ZeitLangerDruck = 110; //Bis hier ist ein Druck lang je kleiner desto eher ist er lang
unsigned int ErsterDruck = 0;
void DauerAuswerten(int Typ) //NUR BEI BUTTON HIGH
{
//Akutelle Zeit von diesem Druck
anCurrentMillis = millis();
anZeitDifferenz = anCurrentMillis - anPreviousMillis;
anPreviousMillis = anCurrentMillis;
//Serial.print("Druck Differenz: ");
//Serial.println(anZeitDifferenz);
ErsterDruck = 0;
/////////NEUER DRUCK/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
if (
anZeitDifferenz >= ZeitNeuerDruck //Ist es einer neuer Druck? //ZeitNeuerDruck=500 wenn letzter druck 300ms her dann setzte alles zurück und beginne mit Einfacher druck
|| DoppelterDruck == 1 && anZeitDifferenz >= 120 //Wenn DoppelterDruck erkannt wurde soll es schnell gehen bis man wieder neu drücken kann
|| LangerDruck == 1 && anZeitDifferenz >= 120 //Wenn Langer erkannt wurde soll es schnell gehen bis man wieder neu drücken kann
)
{
Serial.println("NEUER DRUCK");
ErsterDruck = 1;
LangerDruck = 0;
EinfacherDruck = 1;
DoppelterDruck = 0;
//Zeit vom Letzen Druck
CurrentStempMillis = millis();
DifferenzStempMillis = CurrentStempMillis - PreviousStempMillis;
PreviousStempMillis = CurrentStempMillis;
}
///////////NICHT SCHALTEN///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
else if (
anCurrentMillis - CurrentStempMillis >= ZeitLangerDruck //(ZeitNeuerDruck - 200) // Wenn bis hier nicht losgelassen wurde, dann gilt es nicht mehr als EinfacherDruck
&&
EinfacherDruck == 1
)// && anZeitDifferenz <= 110)//Ist es ein langer Druck? //erst 350ms jetzt 400 // Verhindert das bei einem langen druck geschaltet wird
{
EinfacherDruck = 0;
Serial.println("NICHT SCHALTEN");
}
/////////DOPPELT/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
if ( //Ist es ein Doppelter Druck?
//anCurrentMillis - CurrentStempMillis >= 80 //100 Vllt Sinnlos?
//Fällt weg mit ErsterDruck && anCurrentMillis - CurrentStempMillis <= ZeitNeuerDruck //500 Obere Grenze sonst würe DoppelterDruck zu lange möglich
//&&
anZeitDifferenz >= ZeitLangerDruck //200 unterscheidet zwischen langem und doppelten drücken
//&& DoppelterDruck == 0
&& ErsterDruck == 0
&& LangerDruck == 0
|| DoppelterDruck == 1
)
{
Serial.println("DoppelterDruck Erkannt...");
//CurrentStemp2Millis = millis();
DoppelterDruck = 1;
EinfacherDruck = 0;
}
/////////LANG/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
else if (
anCurrentMillis - CurrentStempMillis >= (ZeitNeuerDruck - 100)
&& anZeitDifferenz <= ZeitLangerDruck //200 unterscheidet zwischen langem und doppelten drücken
//&& LangerDruck == 0
&& DoppelterDruck == 0
) // 400
{
LangerDruck = 1;
Serial.println("LangerDruck Erkannt...");
//CurrentStemp3Millis = millis();
}
else if (EinfacherDruck == 1)
{
Serial.println("Einfacher Druck");
}
//Serial.println("-----------");
delay(100);
}
void setup() {
Serial.begin(9600);
pinMode(ledPin, OUTPUT);
pinMode(buttonPin, INPUT);
}
void loop() {
buttonState = digitalRead(buttonPin);
if (buttonState == HIGH) {
//Serial.println("gedrückt");
digitalWrite(ledPin, HIGH);
DauerAuswerten(1);
} else {
//erial.println("nicht gedrückt");
digitalWrite(ledPin, LOW);
}
}
Starte...
INTERRUPT 1
INTERRUPT 2
FERTIG!
A 2000
B 2000
INTERRUPT 1
A 4560
INTERRUPT 2
B 5200
INTERRUPT 1
A 8755
INTERRUPT 2
B 9395
INTERRUPT 1
A 12949
INTERRUPT 2
B 13589
Zwischen Starte und Fertig soll nichts ausgeführt werden!
was denkst du warum die serielle Ausgabe in der loop mit Flag Auswertung stattfindet?
Zudem, welche funktionale Änderung hast du wenn die serielle in der ISR steht?
Kannste zwar nicht wissen, okay, sollte aber angesprochen werden.
Ist nicht böse gemeint.
Wenn es jedoch nur um banale Dinge wie Taster etc. und solchen Kleinkram geht, dann sind die Hardwaretimer eh überflüssig. Wäre gut gewesen wenn das vorher bekannt gewesen wäre. Denn der Aufwand lohnt nicht. Man kann sich zwar damit auch befassen, aber nicht dafür.
Vielleicht rückt combie seine Lib raus oder verlinkt sie, da greife ich jetzt nicht vor. Da sind viele Funktionen zusammengefasst enthalten. Ich selbst hätte nur eine eigene Funktion um einen kurzen von einem langen Tastendruck zu unterscheiden. Mit Doppelklick habe ich noch nichts probiert. Läuft alles mit der Nutzung von millis() hinaus. Egal was du machst oder nutzt.
wegen den Interrupt. Du müsstest stop_Timer1 ganz am Anfang von setup schreiben, danach alles andere, dann sollte das klappen Scheinbar läuft der Timer1 im Hintergrund schon los obwohl er nicht genutzt wird. Das Versteckspiel des IDE Komfort's.
wegen kurzer und langer Tastendruckerkennung zeige ich mal meinen Code dazu. Vielleicht kann man den vereinfachen vielleicht auch nicht. Wichtig ist das er erstmal funktioniert. Vielleicht kann es jemand gebrauchen, keine Ahnung. Ich habe damit den einen Taster vom Alpsencoder zu "zweien" gemacht für eine klitze kleine Menüsteuerung.
Beim langen Tastendruck wird auch gewartet bis man wieder loslässt. Eigentlich könnte reagiert werden wenn die max. Wartezeit erreicht ist, habe dazu aber noch keinen wirklichen Ansatz gefunden ohne die komplette Funktion umzubauen. Erweiterbar wäre es noch auf 3 Wartezeiten, wobei das dann vom Benutzer eine gewisse Übung verlangen würde. Vielleicht nicht so sinnvoll.
/*
Doc_Arduino - german Arduino Forum
IDE v1.8.5
08.12.2017
Arduino Mega2560
kurzen und langen Tastendruck erkennen
*/
const byte _Taster = 2;
const byte _LED1 = 30;
const byte _LED2 = 31;
void setup() {
Serial.begin(500000);
pinMode(_Taster, INPUT_PULLUP); // mit INPUT_PULLUP invertierte Logik
pinMode(_LED1, OUTPUT);
pinMode(_LED2, OUTPUT);
}
void loop() {
update_Taster();
}
void Taster ()
{
static bool state_Taster = false;
static unsigned long last_push = 0;
unsigned long diff = 0;
static bool toggle_long = false;
static bool toggle_short = false;
unsigned long ms = millis();
bool read_Taster = digitalRead(_Taster); // Tasterstatus einlesen
if (read_Taster != state_Taster) { // wenn Tasterstatus verschieden zu vorher
state_Taster = read_Taster;
if (read_Taster == LOW) {
last_push = ms; // letztes Kontakt prellen merken
}
else {
diff = ms - last_push; // wenn Taster losgelassen Differenz berechnen
}
}
if (diff > 450) {
toggle_long = !toggle_long;
digitalWrite(_LED1, toggle_long);
Serial.println(diff);
}
if (diff > 50 && diff < 250) {
toggle_short = !toggle_short;
digitalWrite(_LED2, toggle_short);
Serial.println(diff);
}
}
void update_Taster ()
{
static unsigned long last_millis = 0;
const byte Entprellzeit = 20; // Taster Entprellzeit [ms]
if (millis()-last_millis > Entprellzeit) {
last_millis = millis();
Taster();
}
}