Hallo, Ich möchte mit meinem Arduino folgendes erstellen:
2 LEDs sollen getrennt von einander mit unterschiedlichen Schaltzeiten
angesteuert werden. Hab mir die Finger schon wunggegoogelt, vielleicht
hab Ihr ein Paar Tipps.
Die erste LED soll 250ms an sein , dann 750 ms aus sein.
gleichzeitig soll dabei die 2. Led 500 ms aus , dann 250 ms dann wieder
250 ms aus sein.
Aufpassen, das sind Mikrosekunden, keine Millisekunden! Da wird es aus meiner Sicht schon komplexer, das Timing einzuhalten. Natürlich müsste man dazu klären, wie genau das Timing sein muss bzw. den genauen Verwendungszweck kennen.
ziemlich genau wenns geht. Ob milli oder micro ist erstmal egal, mir gehts es in erster Linier um die Grundfuktion, wie das zu realisieren ist?
Beide leds knallen abwechselnt auf ne Fotodiode die an einem Transimpedanzverstärker hängt. Über Filter gelangen die Signale auf nen Analogeingang. die Spannungen müssen bei led rot an bzw. ir an eingelesen werden.
also wenn du ms meinst (und nicht us), sollte das doch einfach sein:
void loop() {
blinkLed1();
blinkLed2();
}
void blinkLed1() {
if (millis()-timer1<250) digitalWrite(LED1, HIGH);
if ((millis()-timer1>250) && (millis()-timer1<1000)) digitalWrite(LED1, LOW);
if (millis()-timer1>1000) timer1=millis();
}
//und das dann noch für led2
//(globale) variablen definieren
Geht vielleicht auch einfacher, ist aber ein ansatz
Hallo,
mein Lösungsansatz wäre folgender: Du hast 4 Zustandsänderungen pro Millisekunde. Also machst Du Dir einen Timerinterrupt der 4000 mal pro Sekunde überläuft. In der Timerroutine zählst Du von eins bis vier. Bei 1 schaltest Du die erste LED an, bei 2 schaltest Du alle LEDs aus, bei 3 schaltest Du die andere LED an, bei 4 schaltest Du wieder alle LEDs aus und lässt den Zähler wieder von vorne starten.
Gruß,
Ralf
Dann muss ich mich erstmal in den Timern und Interrupts einlesen, da hab ich noch kein Plan davon. beeinflusst der Interrupt negativ mein Programm? Was bedeuted das Übelaufen bei Interrupt?
http://playground.arduino.cc/Code/Timer http://playground.arduino.cc/Main/MsTimer2
Schau mal hier kannst du den Libaries alle 250µs eine eigne Funktion aufrufen.
Innerhalb der Funktion zählst du dann bis 4.
Bei 0 machst du die R LEDan
Bei 1 wieder aus
Bei 2 IR Led an
Bei 3 IR Led aus
Bei 4 setzt du den Zähler als erstes auf null und dann fängt es bei 0 wieder an.
Das Problem an den verlinkten Timer-Libraries ist jedoch, dass diese soweit ich weiß noch den Millisekundenbereich abdecken, nicht aber die Mikrosekunden.
Schau Dir mal meinen Blog an. Am einfachsten wäre es eins der POV Sketche umzufrisieren. POV Reloaded | Blinkenlight
Problemchen ist, daß der Timer in einem 1ms Raster läuft, Du aber 250us brauchst. Dazu würde ich einfach die Takterzeugung aus dem Beispiel hier: Phase detection | Blinkenlight
ISR(TIMER2_COMPA_vect) {
process_one_sample();
}
void initTimer2() {
// Timer 2 CTC mode, prescaler 64
TCCR2B = (1<<WGM22) | (1<<CS22);
TCCR2A = (1<<WGM21);
// 249 + 1 == 250 == 250 000 / 1000 = (16 000 000 / 64) / 1000
OCR2A = 249;
// enable Timer 2 interrupts
TIMSK2 = (1<<OCIE2A);
}
void stopTimer0() {
// ensure that the standard timer interrupts will not
// mess with msTimer2 (that is: avoid undesirable jitter)
// implies that delay and millis will not work anymore
TIMSK0 = 0;
}
Schau dir mal das Datenblatt des Prozessors an. Und ließ da den Abschnitt zu den Timern. Da ist erklärt was die Register wie TCCR2B und OCR2A bedeuten und was die Bits darin (wie WGM22) genau machen.
Da geht auch das Atmega328 Datenblatt ab Seite 94 (der Mega funktioniert genauso, aber hat mehr Timer):
Ab Seite 158 werden die Register des Timer2 beschrieben.
Zu Code wie diesem hier:
(1<<WGM21)
WGM21 (Waveform Generation Mode Bit 1 Timer2) ist Bit 1 im TCCR2A (Timer/Counter Control Register A, Timer 2). Diese Konstante im Code hat daher den Wert 1. Man schiebt also "1" einmal nach Links, wodurch Bit 1 gesetzt wird. Das verordert man mit allen anderen Bits die auch gesetzt werden sollen und weißt den Wert dem Register zu.
WGM21 schaltet den Timer in den CTC Modus (Clear Timer on Compare Match).
Hier ist mir aber nicht klar wozu da noch WGM22 gesetzt wird. WGM21 + 22 sind laut Datenblatt Seite 160 "reserved". Wobei Udo da auch vergessen hat die Prescaler Bits anzupassen. Prescaler 32 ist laut Seite 162 CS21 + CS20. Also:
TCCR2B = (1<<CS21) | (1<<CS20);
Für die Länge des Takts sind der Prescaler wichtig (die CS = Clock Select Bits). Das ist der Wert durch den der Prozessortakt geteilt wird und das Output Compare Register OCRA2. Im CTC Modus wird der Wert des Timers mit dem Compare Register verglichen und bei Übereinstimmung ein Interrupt ausgelöst. Je niedriger dieser Wert, desto schneller wird also der Interrupt ausgelöst.
TIMSK2 ist das Timer Interrupt Mask Register. Da werden einfach die Interrupts aktiviert. Und OCIE2A steht für Output Compare Match A Interrupt Enable Timer 2. Siehe Seite 163
void stopTimer0() {
// ensure that the standard timer interrupts will not
// mess with msTimer2 (that is: avoid undesirable jitter)
// implies that delay and millis will not work anymore
TIMSK0 = 0;
}
also wäre jetzt der Prescale für 250 µs gesetzt.
Allerdings kann ich nichts mit "process_one_sample();" anfangen
Im Anschluss müsste ich dann immer einen Interrupt mit meinen 250µs auslösen , zählen und die ledzustände zuweisen?
Im Anschluss müsste ich dann immer einen Interrupt mit meinen 250µs auslösen
Der Interrupt wird automatisch ausgelöst wenn das Timer Counter Register den Wert des Compare Registers erreicht. Deshalb wird ja OCIE2A gesetzt. Gleichzeitig wird das Counter Register auf Null zurückgesetzt.
Der 124 Wert wurde oben auch genannt, aber im Code auch nicht angepasst. Deshalb solltest du nicht nur abschreiben sondern auch verstehen was hier gemacht wird
Statt process_one_sample() machst du einfach deine eigene ISR. Du kannst testweise z.B. mal einen Ausgangspin toggeln und dann die Frequenz messen.
Wenn du wie vorgeschlagen, eine Variable zählst und auswertest muss das so ähnlich aussehen. Normale if-else-Abfragen gehen natürlich auch:
volatile byte counter = 0;
ISR(TIMER2_COMPA_vect)
{
counter = counter + 1 % 4;
switch(counter)
{
case 0: ...
break;
case 1: ...
break;
case 2: ...
break;
case 3: ...
break;
}
}
Dankeschon mal für eure Hilfe, es passiert schon mal ansatz weise was :
Die Frequenz liegt aber bei ca 2 hz , und die Impulsdauer bei ca 2ms, was muss denn noch geändert werden?
Da vermute ich einen OrderOfOperations-Fehler. Der avr-gcc Compiler macht Punkt vor Strich (wie alle C/C++ Derivate), hier eine ausführliche Erläuterung
counter = counter + 1 % 4; //rechnet zuerst 1%4, das ist immer 1 und addiert das zu counter.
Die Pulse entstehen dann nur dadurch, dass du counter als byte deklariert hast, dadurch gibts dann alle paar Interrupts einen Überlauf.
Mach für den Anfang mal nur das hier in der ISR bis die Frequenz stimmt:
digitalWrite(led1, !digitalRead(led1));
Das sollte den LED Pin immer toggeln. Wobei beide Funktionen recht langsam sind. Aber so langsam sollten sie auch nicht sein. Die brauchen glaube ich 50-60 Taktzyklen.
attachInterrupt ist eine Arduino Funktion die man hier nicht braucht. Außerdem hattest du die falsch verwendet. Korrekterweise gibt man da nur einen Function-Pointer auf die ISR an. Hier machen wir das aber mit AVR-Befehlen direkt.