Hallo, ich habe ein Problem mit meinem Programm welches die Laufzeit zwischen zwei Impulsen messen soll. Ich sende einen Impuls über die Funktion void senden und aktivieren den Overflow von Timer1 und den CAPT_VECT. Wenn nun der ein Impuls am PIN0 detektiert wird der ISR CAPT_VECT aufgerufen und mir der Zählerwert per UART gesendet: Funktioniert auch. Falls jedoch kein Impuls innerhalb des ersten Overflows detektiert wird soll mit ein Fehler ausgegeben werden. Wenn ich nun den Timer1 Overflow aktivieren springt mein Programm auch in den Routine rein jedoch kommt es da nicht mehr heraus und sendet mir nun immer den Fehler auch wenn wieder Impulse am PINB ankommen. Anbei sende ich euch mal den Code da ich nun seid 2h nicht mehr weiter komme. Wenn ich den Timer1 Overflow nicht mehr aktiviere kommen ordentliche Wert. Wenn keine Impulse mehr ankommen steht dann halt immer die 65536 da. //-----------------------------LIBRARYS---- #include <avr/io.h> // Standard AVR LIBRARY #include <avr/interrupt.h> // fuer Interrupt-Funktion #include <stdlib.h> // fuer UTOA-Funktion //--------------------------VARIABLEN_FUER_INTERRUPT volatile uint8_t timer1_low, timer1_high; // Speichervariable fuer Laufzeit volatile uint16_t num_ovf; // Speichervariable fuer Impulsbreite volatile uint16_t num_ovf_t1; // Speichervariable fuer volatile uint16_t send_complete; // Speichervariable fuer volatile uint8_t pause_senden; // Warten mit Messdatensenden uint16_t time; //------------------------------DEFINES------ #define FOSC 16000000 // Clock Speed #define BAUD 9600 // Uebertragungsrate #define MYUBRR FOSC/16/BAUD-1 // #define SENDEPIN PINB4 // Sendepin #define SENDEPORT PORTB // Sendeport #define SENDEDAUER 0xf0 // Impulsbreite #define PAUSE 100 // Programmpause #define VERZOEGERUNG 3 // Interne Laufzeit herausrechnen //------------------------------INTERRUPT-SERVICE-ROUTIN-- ISR(TIMER1_CAPT_vect) // Interrupt wird bei steigender Flanke am PORTB0 ausgeloest { timer1_low = ICR1L; // Auslesen des Low-Registers timer1_high = ICR1H; // Auslesen des High-Registers TIMSK1 &= ~(1<<TOIE1); // Timer1 Overflow deaktivieren TCNT1 = 0x00; //PORTB |= (1<<PORTB5); // zum testen } ISR(TIMER1_OVF_vect) // Ueberlauf für Laufzeitmessung { num_ovf_t1=1; //PORTB |= (1<<PORTB5); //Zum testen } ISR(TIMER0_COMPA_vect) // Interrupt um den Sendevorgang abzuschließen { SENDEPORT &= ~(1<<SENDEPIN); // Sendepin wieder loeschen send_complete = 1; } ISR(TIMER2_OVF_vect) // Interrupt fuer erneutes Senden des Impulses { num_ovf++; // Variable wird mit jedem Ueberlaufen um eis erhoeht } //---------------------------------FUNKTIONEN------------- void senden() // Sendeimpuls erzeugen und Laufzeitzaehler starten { TCNT1 = 0; SENDEPORT |= 1<<SENDEPIN; // Sendepin auf High setzen TCNT1 = 0x00; // Timer1 zuruecksetzen TCNT0 = 0x00; // Timer0 zuruecksetzen TIMSK0 |= 1<<OCIE0A; // Interrupt fuer TIMER0A aktivieren TIMSK1 |= 1<<TOIE1; // Overflow aktivieren fuer Timer1 while(send_complete != 1) // While-Schleife send_complete = 0; // Zuruecksetzen des Flags send_complete TIMSK0 &= ~(1<<OCIE0A); // Interrupt fuer TIMER0A deaktivieren pause_senden=1; } void timer0_init() //Timer0 fuer die Impulsbreite Initialisieren { send_complete = 0; //Variable zum setzen eines Flags wodurch ein der Interrupt TCCR0A = 0x00; //Zur Sicherheit alle Bits des Timer-Control Registers B auf 0 setzen TCCR0B = 0x00; //Zur Sicherheit alle Bits des Timer-Control Registers A auf 0 setzen TCCR0B |= 1<<CS00; //Vorteiler wird auf eins eingestellt TCNT0 = 0x00; //Timer0 wird zurueckgesetzt OCR0A = SENDEDAUER; //Interrupt wird beim ueberschreiten von SENDEDAUER ausgeloest return; } void timer1_init() //Pin-Change am ICP aktueller Zaehlerstand wird ICR1 Register gesichert { TCCR1A = 0x00; //Konfigurationsregister wird zurueckgesetzt TCCR1B = 0x00; //Konfigurationsregister wird zurueckgesetzt TCCR1B |= 1<<ICES1; //ICES1=1 gesetzt Reaktion auf steigende Flanke, ICES1=0 Reaktion auf fallende Flanke TCCR1B |= 1<<CS10; //Vorteiler wird auf eins eingestellt TIMSK1 = 1<<ICIE1; //Interrupts fuer den Input-Capture aktivieren } void timer2_init() //Timer2 zum Neustarten der Programmroutine { num_ovf = 0; //Zaehlervariable fuer die Overflows TCCR2A = 0x00; //Konfigurationsregister wird zurueckgesetzt TCCR2B = 0x00; //Konfigurationsregister wird zurueckgesetzt TCCR2B |= 1<<CS00 | 1<<CS01 | 1<<CS02; //Vorteiler wird auf 1024 eingestellt TCNT2 = 0x00; //Timer2 wird zurueckgesetzt TIMSK2 |= 1<<TOIE2; //Aktiviere Overflow fuer Timer2 } //----------------------------MESSDATEN_SENDEN_UEBER_USART-- void uart_send_number(uint16_t number_to_send) // Funktion UART_send fuer ein 8-Bit langes Datenwort { char string_to_send[16]; //Array, welches Zeichenweise die einzelnen Ziffern sendet utoa(number_to_send,string_to_send,10); //Umwandlung Zahl zu einem Array, ermöglicht einzelnes senden uart_send_string(string_to_send); //erstelle einen Zeiger, welche auf das Array char_to_send zeigt } void uart_send_string(char *p_string_to_send) // Funktion UART_send fuer ein 8-Bit langes Datenwort { while(*p_string_to_send) { while (!(UCSR0A & (1<<UDRE0))) {} // warten bis das Sende-Register leer ist UDR0 = *p_string_to_send; p_string_to_send++; } } void USART_Init( unsigned int ubrr) // Konfiguration USART-Schnittstelle { /*Set baud rate */ UBRR0H = (uint_fast16_t)(ubrr>>8); UBRR0L = (uint_fast16_t)ubrr; /*Enable receiver and transmitter */ UCSR0B = (1<<RXEN0)|(1<<TXEN0); /* Set frame format: 8data, 2stop bit */ UCSR0C = (1<<USBS0)|(3<<UCSZ00); } //-------------------------HAUPTPROGRAMM------------------ int main(void) { timer0_init(); // Funktionsaufruf timer1_init(); // Funktionsaufruf timer2_init(); // Funktionsaufruf USART_Init(MYUBRR); // Funktionsaufruf timer1_low = 0x00; // Speicherwariable auf null setzen timer1_high = 0x00; // Speichervariable auf null setzen time = 0; // Uebergabevariable fuer den Laufzeitmesswert pause_senden= 0; // Null setzen DDRB = 0xf0; // Def. Ein-/Ausgaenge SENDEPORT = 0x00; // Ausgaenge zuruecksetzen PINB &= ~(1<<PINB0); sei(); // Interrupts aktivieren while(1) { senden(); while(pause_senden!=1){}; //Warte, so lange, bis die festgelegte Wartezeit vorbei ist if(num_ovf_t1==0) //Laufzeit senden wenn Zähler nicht übergelaufen ist { uart_send_number(num_ovf_t1); uart_send_string("\n\r"); time = timer1_high; time = time<<8; time |= timer1_low; time = time-VERZOEGERUNG; uart_send_string("Aktueller Stand: "); uart_send_number(time); uart_send_string("\n\r"); } else { //Zähler übergelaufen keinen Impuls detektiert uart_send_string("Fehler"); uart_send_string("\n\r"); } while (num_ovf < PAUSE){} //Warte, so lange, bis die festgelegte Wartezeit vorbei ist pause_senden=0; //Zuruecksetzen time = 0; //Zuruecksetzen timer1_high = 0; //Zuruecksetzen timer1_low = 0; //Zuruecksetzen num_ovf_t1 = 0; //Zuruecksetzen num_ovf = 0; //Zuruecksetzen PORTB &= ~(1<<PORTB5); } }
Hi, Chrisso, Deinen Code habe ich mit der Einstellung "AtMega328" ohne Fehlermeldungen kompilieren und linken können. Mit "PIN0" meinst Du wohl den ICP1 auf PortB, Pin0. Was sagt Atmel-Studio denn in seinem Debugging? Dafür sind debugWIRE und JTAG-ICE doch da! Die sind billiger als mein Stundensatz, multipliert mit der Zeit, die ich bräuchte, um Deinen Code Schritt für Schritt im Geiste zu simulieren. > Wenn ich nun den Timer1 Overflow aktivieren springt mein Programm auch > in den Routine rein jedoch kommt es da nicht mehr heraus Auf die Schnelle ist mir nur aufgefallen: In der Routine "void timer1_init(void)" setzt Du "TIMSK1 = 1<<ICIE1;", aber ohne dabei den anderen Interrupt abzuschalten. Ist das Absicht? Ciao Wolfgang Horn
hallo, Vielen Dank für deinen Beitrag. Ja also ich aktiviere ja beide interrupts einmal für den timer1 ovf und capt_vect ovf falls kein Impuls innerhalb der vorgegebenen Zeit delektiert wurde und capt_vect für die detektion innerhalb der Zeit.
Ja, C.M., so habe ich das verstanden, > > Ja also ich aktiviere ja beide > interrupts einmal für den timer1 ovf und capt_vect ovf falls kein Impuls > innerhalb der vorgegebenen Zeit delektiert wurde und capt_vect für die > detektion innerhalb der Zeit. So hast Du das Problem beschrieben: "Wenn ich nun den Timer1 Overflow aktivieren springt mein Programm auch in den Routine rein jedoch kommt es da nicht mehr heraus und sendet mir nun immer den Fehler auch wenn wieder Impulse am PINB ankommen." Der Verdacht: Dies "nicht mehr raus" hat etwas zu tun mit dem doppelten Interrupt. So etwas würde ich mir gerne ansehen mit einem einfachen Pulsgenerator oder einem doppelten, das können auch zwei Tasten am STK500 sein, und einem Debugger, der Einzelschritte zulässt. Das Ansehen der Mediziner, der Ärzte, kommt auch weniger von deren Spekulationen, als vielmehr von ihrem Stethoskop, ihrem Spatel, ihrem Augenspiegel und ihren Instrumenden für die komplizierteren Fälle. Deshalb ist das Debugging der nächste sinnvolle Schritt. Sollte ein Könner das rein mental in seinem Kopf nachvollziehen und einen Fehler so einkreisen und finden können, dann verschwendet er in diesem Forum seine Arbeitskraft, denn solche Diagnosefähigkeiten werden viel höhrer bezahlt als Programmierfähigkeiten. Ciao Wolfgang Horn
Hallo Wolfgang, Vielen Dank für deinen Beitrag wenn auch etwas abschweifend. Was ein Programmierer die Stunde kosten kann ist mir bekannt jedoch habe ich mir durch das Forum erhofft dass ein langjähriger Programmierer zufällig meinen falschen Denkansatz bei dem Programmcode erkannt und mir einen Tipp geben kann.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.