Hallo zusammen,
ich beschäftige mich noch nicht so lange mit dem Arduino und bastle gerade an einem kleinen Projekt:
Über zwei Sensoren wird jeweils ein Interrupt ausgelöst und eine Zeit gemessen. Danach wird die Zeitdifferenz berechnet und daraus die Geschwindigkeit, mit der bspw. ein Objekt A an diesen Sensoren vorbei bewegt.
Mit Hilfe dieser Geschwindigkeit soll nun die verbleibende Zeit berechnet werden, die das Objekt A benötigt, um ein weiteres Objekt B in einem konstanten Abstand zu erreichen.
Dieser letzte Schritt soll über einen Timer Interrupt geschehen, der dann die Interrupt Routine auslösen soll, wenn die Zeit abgelaufen ist und sich das Objekt A bei Objekt B befinden müsste.
Der Vergleichswert des Compare Match Registers soll und muss dabei variabel sein, da man nicht mit Gewissheit voraussagen kann, mit welcher Geschwindigkeit sich Objekt A bewegt.
Die Frage ist: wie realisiere ich das? ![]()
Ich habe folgenden Ansatz. Das Problem ist, dass die Timer Interrupt Routine nicht nach der vorgegeben Zeit aktiviert, sondern viel zu spät.
// Zeitmessung
volatile bool start = false;
volatile bool ende = false;
volatile double startzeit = 0;
volatile double endzeit = 0;
volatile double vergangene_zeit = 0;
double abstand_sensoren = 0.0255;
double abstand_sensor_objektB = 0.5;
double geschwindigkeit;
// Zeit bis A B erreicht
volatile double zeit_bis_B;
volatile double compare_match;
// INPUTS
// interruptPins (digital)
const int sensor_1 = 2;
const int sensor_2 = 3;
void setup() {
pinMode(sensor_1, INPUT);
pinMode(sensor_2, INPUT);
attachInterrupt(digitalPinToInterrupt(lichtschranke_1), zeitmessung_start, HIGH);
attachInterrupt(digitalPinToInterrupt(lichtschranke_2), zeitmessung_ende, HIGH);
Serial.begin(9600);
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0;
// Prescaler einstellen (1024)
TCCR1B |= (1 << CS12) | (1 << CS10);
}
ISR(TIMER1_COMPA_vect) {
Serial.println("BIN DA");
}
void loop() {
// damit die loop nicht die ganze Zeit durchrennt
delay(100);
}
void zeitmessung_start() {
startzeit = millis();
start = true;
}
void zeitmessung_ende() {
endzeit = millis();
ende = true;
berechnung();
}
void berechnung() {
start = false;
ende = false;
// in ms
vergangene_zeit = endzeit - startzeit;
geschwindigkeit = abstand_sensoren / vergangene_zeit;
// in s
zeit_bis_B = (abstand_sensor_objektB / geschwindigkeit)/1000;
// 16 MHz und Prescaler 1024
compare_match = (zeit_bis_B*16000000)/1024;
timer();
}
void timer() {
// Vergleichswert setzen
OCR1A = compare_match;
// Timer aktivieren
TCCR1B |= (1 << WGM12);
TIMSK1 |= (1 << OCIE1A);
}
Ich habe bereits ausprobiert, ob das Compare Match Register evtl. keine variable Zuweisung mag, aber selbst wenn ich ihm direkt 15624 (entspricht 1s) zuweise, macht er das selbe.
(also OCR1A = 15624;)
Ich weiß auch, dass man millis() eigentlich nicht in den Interrupts verwenden soll, aber ich wüsste nicht, wie ich es anders anstellen soll.
Testweise habe ich die Interrupts rausgenommen und es mit festen Werten getestet:
// Zeitmessung
volatile bool start = false;
volatile bool ende = false;
volatile double startzeit = 0;
volatile double endzeit = 0;
volatile double vergangene_zeit = 0;
double abstand_sensoren = 0.0255;
double abstand_sensor_objektB = 0.5;
double geschwindigkeit;
// Zeit bis A B erreicht
volatile double zeit_bis_B;
volatile double compare_match;
int i = 0;
// INPUTS
// interruptPins (digital)
//const int sensor_1 = 2;
//const int sensor_2 = 3;
void setup() {
//pinMode(sensor_1, INPUT);
//pinMode(sensor_2, INPUT);
//attachInterrupt(digitalPinToInterrupt(lichtschranke_1), zeitmessung_start, HIGH);
//attachInterrupt(digitalPinToInterrupt(lichtschranke_2), zeitmessung_ende, HIGH);
Serial.begin(9600);
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0;
// Prescaler einstellen (1024)
TCCR1B |= (1 << CS12) | (1 << CS10);
}
ISR(TIMER1_COMPA_vect) {
Serial.println("BIN DA");
}
void loop() {
// damit ich nicht die ganze Console voll habe, nur einmal
if (i == 0) {
i ++;
zeitmessung_start();
Serial.println("Start");
delay(50);
zeitmessung_ende();
Serial.println("Ende");
}
}
void zeitmessung_start() {
startzeit = millis();
start = true;
}
void zeitmessung_ende() {
endzeit = millis();
ende = true;
berechnung();
}
void berechnung() {
start = false;
ende = false;
// in ms
vergangene_zeit = endzeit - startzeit;
geschwindigkeit = abstand_sensoren / vergangene_zeit;
// in s
zeit_bis_B = (abstand_sensor_objektB / geschwindigkeit)/1000;
// 16 MHz und Prescaler 1024
compare_match = (zeit_bis_B*16000000)/1024;
timer();
}
void timer() {
// Vergleichswert setzen
OCR1A = compare_match;
// Timer aktivieren
TCCR1B |= (1 << WGM12);
TIMSK1 |= (1 << OCIE1A);
}
Ich hoffe ihr wisst so ungefähr was ich meine.
Achja, hier noch meine Ausgabe:
16:15:43.798 -> Start
16:15:43.866 -> Ende
16:15:47.960 -> BIN DA
16:15:48.929 -> BIN DA
16:15:49.919 -> BIN DA
usw. danach klappts halt gut, aber der erste ist viel zu spät
Liebe Grüße,
Marc