Xaver
15.11.2006, 16:54
Hi
Ich möchte die Drehzahl von zwei Motoren (RB40) mit hilfe eines Mega16 ermitteln.
An jedem Motor ist eine Lichtschranke als Taktgeber befestigt, die mit
jeder Umdrehung des Motor 8 Flanken (vier schwarze vier weize Flachen) erzeugt.
Um daraus die Drehzahl zu ermitteln gibt es ja zwei Methoden.
Zum einen Zählt man die Flagen während einer Festen Zeitspanne und
zum anderen misst man die Zeit, die zwischen zwei Flanken vergeht.
Die erste Variante habe ich bereits erfolgreich ausprobiert. Timer1 Zählte die Flankenwechsel
und timer0 rief diesen Werte alle 500ms ab. Die Werte wurden dann Über UART asugegeben.
Da ich aber timer1 für die Ansteuerung der Motoren benötige(PWM) und timer0
eh für Zeitliche Aufgaben gedacht ist, wollte ich die Variante zwei einmal Programieren.
Dazu habe ich mir Vorgestellt, dass ich mit jeder Flanke auf eine Uhr(timer0) schaue und
mir die Zeit Merke. Bei der nächsten Flanke bilde ich die differenz aus der neuen und
der alten Uhrzeit und erhalte so die Zeit zwischen den Flanken. Wie genau ich das machen
möchte hängt von der Einstellung der Uhr ab. Der timer0 macht 256 Schritte bis er einmal
rum ist, dabei dauer jeder Schritt 5,8us (11,059Mhz, und Prescaler von 64).
Also ist die Uhr nach 1,48ms einmal rum. Natürlich kann es vorkommen das die Uhr bereits
einmal rum ist, eh die zweite Flanke kommt. Dafür habe ich mir einem 16bit Merker erstellt,
der die Umrundungen der Uhr zwischen zwei Flanken zählt. Da ich die Uhr nicht stoppe, kann
ich auch zwei drehzahlen Gleichzeitig erfassen(allerdings zwei Merker).
So weit so gut..
Nun habe ich mir die Werte mal alle 50ms über UART ausgeben lassen und bekomme Regelmäßig
keine richtigen Ergebnisse( siehe Abbildung).
Jetzt die Frage an euch: Woran könnte dies liegen und wie kann ich es besser machen.
Erklärung zur abbildung:
die X-Achse zeigt die Messdauer in Sekunden
die Y-Achse die Zeit zwischen zwei Impulsen in usec
der Motor drehte ohne Lasst mit 12V, also mit etwa 5000U/min
daraus sollte eine Umdreung 12ms dauern und die impulsdauer 1,5ms
/* Interrupt Service Rountine bei Überlauf des Timer0 */
ISR(TIMER0_OVF_vect) /* veraltet: SIGNAL(SIG_OVERFLOW1) */
{
/* Interrupt Code */
timer0_counter++; // Merker für Überläufe des Timers
timer0_counter_D1++; // Merker für Überläufe des Timers, für die Drehzahl1
if(timer0_counter % 3){ // alle 4,4ms
}else{
//tasten(); // Aufruf zur tasten entprellung
}
if(timer0_counter % 30){ // alle 44ms
}else {
auswerten(); // den Wert über UART ausgeben
}
if( (timer0_counter >= 255)){ // alle 380ms
PORTB ^=(1<<PB3); // eine LED getoggelt
}
}
/*Interrupt Service Routine bei Flanke an int0(extern) */
ISR(INT0_vect)
{
PORTB ^=(1<<PB2); // Toggel Led, wildes blinken ist immer gut
counter_neu = (timer0_counter_D1*256) + TCNT0; // Merke mir die Uhrzeit
timer0_counter_D1=0; // sezte den Umrundungsmerker zurück
if(counter_neu > counter_alt){
time_delta = counter_neu - counter_alt;} // ermittel die Zeitdifferenz
else{
time_delta = counter_alt - counter_neu;} // ermittel die Zeitdifferenz
counter_alt = counter_neu; // Merke mir die Uhrzeit für die nächste Messung
}
Ich möchte die Drehzahl von zwei Motoren (RB40) mit hilfe eines Mega16 ermitteln.
An jedem Motor ist eine Lichtschranke als Taktgeber befestigt, die mit
jeder Umdrehung des Motor 8 Flanken (vier schwarze vier weize Flachen) erzeugt.
Um daraus die Drehzahl zu ermitteln gibt es ja zwei Methoden.
Zum einen Zählt man die Flagen während einer Festen Zeitspanne und
zum anderen misst man die Zeit, die zwischen zwei Flanken vergeht.
Die erste Variante habe ich bereits erfolgreich ausprobiert. Timer1 Zählte die Flankenwechsel
und timer0 rief diesen Werte alle 500ms ab. Die Werte wurden dann Über UART asugegeben.
Da ich aber timer1 für die Ansteuerung der Motoren benötige(PWM) und timer0
eh für Zeitliche Aufgaben gedacht ist, wollte ich die Variante zwei einmal Programieren.
Dazu habe ich mir Vorgestellt, dass ich mit jeder Flanke auf eine Uhr(timer0) schaue und
mir die Zeit Merke. Bei der nächsten Flanke bilde ich die differenz aus der neuen und
der alten Uhrzeit und erhalte so die Zeit zwischen den Flanken. Wie genau ich das machen
möchte hängt von der Einstellung der Uhr ab. Der timer0 macht 256 Schritte bis er einmal
rum ist, dabei dauer jeder Schritt 5,8us (11,059Mhz, und Prescaler von 64).
Also ist die Uhr nach 1,48ms einmal rum. Natürlich kann es vorkommen das die Uhr bereits
einmal rum ist, eh die zweite Flanke kommt. Dafür habe ich mir einem 16bit Merker erstellt,
der die Umrundungen der Uhr zwischen zwei Flanken zählt. Da ich die Uhr nicht stoppe, kann
ich auch zwei drehzahlen Gleichzeitig erfassen(allerdings zwei Merker).
So weit so gut..
Nun habe ich mir die Werte mal alle 50ms über UART ausgeben lassen und bekomme Regelmäßig
keine richtigen Ergebnisse( siehe Abbildung).
Jetzt die Frage an euch: Woran könnte dies liegen und wie kann ich es besser machen.
Erklärung zur abbildung:
die X-Achse zeigt die Messdauer in Sekunden
die Y-Achse die Zeit zwischen zwei Impulsen in usec
der Motor drehte ohne Lasst mit 12V, also mit etwa 5000U/min
daraus sollte eine Umdreung 12ms dauern und die impulsdauer 1,5ms
/* Interrupt Service Rountine bei Überlauf des Timer0 */
ISR(TIMER0_OVF_vect) /* veraltet: SIGNAL(SIG_OVERFLOW1) */
{
/* Interrupt Code */
timer0_counter++; // Merker für Überläufe des Timers
timer0_counter_D1++; // Merker für Überläufe des Timers, für die Drehzahl1
if(timer0_counter % 3){ // alle 4,4ms
}else{
//tasten(); // Aufruf zur tasten entprellung
}
if(timer0_counter % 30){ // alle 44ms
}else {
auswerten(); // den Wert über UART ausgeben
}
if( (timer0_counter >= 255)){ // alle 380ms
PORTB ^=(1<<PB3); // eine LED getoggelt
}
}
/*Interrupt Service Routine bei Flanke an int0(extern) */
ISR(INT0_vect)
{
PORTB ^=(1<<PB2); // Toggel Led, wildes blinken ist immer gut
counter_neu = (timer0_counter_D1*256) + TCNT0; // Merke mir die Uhrzeit
timer0_counter_D1=0; // sezte den Umrundungsmerker zurück
if(counter_neu > counter_alt){
time_delta = counter_neu - counter_alt;} // ermittel die Zeitdifferenz
else{
time_delta = counter_alt - counter_neu;} // ermittel die Zeitdifferenz
counter_alt = counter_neu; // Merke mir die Uhrzeit für die nächste Messung
}