Ihr hattet recht. Der Fehler lag an der falschen Berechnung der Zeitdifferens.
So ist es richtig.
Code:
if(counter_neu > counter_alt){
time_delta = counter_neu - counter_alt;} // ermittel die Zeitdifferenz
else{
time_delta = (65535-counter_alt) + counter_neu;} // ermittel die Zeitdifferenz
Damit andere auch etwas davon haben hier der gesammte Code für einen Mega16. Ich verwende das ATmega16 Testboard v2.0 von kreatives-chaos.com
main.c
Code:
/**
* Mit hilfe dieses Programmes soll die Drehzal
* über ein UART interfase am PC ansgegeben werden.
* Dazu wird die Drehzal wie folgt ermittelt:
*
* Zeit(Timer0) zwischen zwei Impulsen
*
*
* Hierzu wird bei einen Externen Interrupt(INT0),
* die bisher vergangene Zeit des Timers0 über UART ausgegeben
*
**/
#include <avr/interrupt.h>
#include <stdint.h> // integerwerte wie uint8_t, uint16_t
#include <stdlib.h> // itoa
#include "timer0.h" // einbinden der Header datei für Timer0
#include "uart.h" // einbinden der Header datei für UART
//nicht vergessen die Passenden C Dateien in der Makefile zu schreiben
#define STATUS_LED1 PB3 // PIN der on-board Status-Led
#define STATUS_LED2 PB2 // Pin der on-board Status_Led
void init(void); // allgemeine Initialisierung
void auswerten(void); // Status Ausgabe über UART
volatile uint16_t counter_alt; // alter Timerstand
volatile uint16_t counter_neu; // neuer Timerstand
volatile uint16_t time_delta; // Zeitdifferens
volatile uint16_t m1,m2,m3,m4,m5,m6,m7,m8,m9,m0; //Mittelwertbildung
volatile uint8_t sm;
int main(void){
init(); // Allgemeine Port initialisierung
timer0_init(); // Timer0 initialisieren
uart_init(); // UART initialisieren
sei(); //global Interrupts Aktivieren
uart_putc('*'); //senden eines einzelenen Zeichen
uart_puts(" UART inizialisierung ... OK \n\r\n\r"); //sendet einen string
/*uart_puts("* Drehzahl1\r\n* Mit hilfe dieses Programmes soll die Drehzal \r\n");
uart_puts("* ueber ein UART interfase am PC ansgegeben werden.\r\n* Hierfuer wird die Drehzal wie folgt ermittelt. \r\n");
uart_puts("* Zeit(Timer0) zwischen zwei Impulsen\r\n");
uart_puts("* Hierzu wird alle durch einen Externen Interrupt(INT0) \r\n");
uart_puts("* Die Bisher vergangene Zeit des Timers0 über UART ausgegeben\r\n");
*/
while(1)
{ }
//never reached i hope ;)
}
void init(void)
{
/* STATUS_LED1 und 2 als Ausgang */
DDRB |= (1 << STATUS_LED1) | (1 << STATUS_LED2);
PORTB &= ~((1 << STATUS_LED1) | (1 << STATUS_LED2));
/* INT0 init */
DDRD &= ~(1<<PD2); //PORTD.2 als Eingang
PORTD |= (1<<PD2); //PORTD.2 mit Pullup
GICR |= (1<<INT0); // External Interrupt Request 0 Enable
MCUCR |= (1<<ISC01)|(1<<ISC01); // Die steigende Flanke an INT0 erzeugt einen Interrupt.
/* globale Variablen vorbelegen */
counter_alt = 0;
counter_neu = 0;
m1=m2=m3=m4=m5=m6=m7=m8=m9=m0=0;
}
void auswerten(void)
{
/* gibt Zählerstand über UART aus */
unsigned char s[7]; // max -65536 entspricht 7 Zeichen
uart_puts("Drehzahl: "); // Textausgabe
utoa(time_delta, s, 10); // Uint_16 in Asci-String wandeln
uart_puts(s); // Textausgabe
uart_puts(" \r"); // Textausgabe
}
// 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 = (65535-counter_alt) + counter_neu;} // ermittel die Zeitdifferenz
/* gleitender Mittelwert über 10 Messungen */
//m9=m8;m8=m7;m7=m6;m6=m5;m5=m4;m4=m3;m3=m2;m2=m1;m1=m0;m0=time_delta;
//time_delta=(m1+m2+m3+m4+m5+m6+m7+m8+m9+m0)/10;
counter_alt = counter_neu; // Merke mir die Uhrzeit für die nächste Messung
}
timer0.c
Code:
#include <avr/io.h>
#include <avr/interrupt.h>
#include "timer0.h"
/* Timer0 initialisieren */
void timer0_init(void)
{
/* alle 1,48ms Überlauf.Einstellen der Frequenz auf 675Hz ( Prescaler = 64 * 256 bis Überlauf ) */
TCCR0 |= ((1<<CS01) | (1<<CS00));// Prescaler 64, entspricht 5,8usec und 1,48ms bis überlauf
/* Interrupts für Timer0 aktivieren */
TIMSK |= (1<<TOIE0);
DDRB |= (1<<PB3); // toggel led
timer0_counter_D1=0; // sezte den Anfangswert
timer0_counter=0; // sezte den Anfangswert
}
/* 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 % 30){ // alle 44ms
}else {
auswerten(); // den Wert über UART ausgeben
}
if( (timer0_counter >= 255)){ // alle 380ms
PORTB ^=(1<<PB3); // eine LED getoggelt
}
}
Lesezeichen