www.mikrocontroller.net

Forum: Compiler & IDEs ATTiny3 Servoimpulse lesen


Autor: hoschi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich versuche Servoimpulse aus dem Empfänger auzuwerten.
Ich glaube aber das mein Ablauf zu ungenau ist.
Ich verwende PIN1 INT0 interrupt und den Timer0 /64 clk.
der Tiny13 läuft bei 4,8MHz.

steigende Flanke löst interrupt aus
ich warte mit delay 1000µs (weil es erst dann intressant wird)
schalte den Timer ein
warte bis PIN1 0 wird
schate den Timer ab
übergebe den Wert.

Irgendwie ist das zu ungenau, kann das sein ?

Sollte ich die Impulse generell anders auswerten ?

viele Grüße
Martin

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hoschi schrieb:

> steigende Flanke löst interrupt aus
> ich warte mit delay 1000µs (weil es erst dann intressant wird)

Vergiss diesen Schritt.
Der delay ist ungefähr 1000µs, aber nicht exakt. Und wenn dir da dann 
auch noch ein Interrupt in der Delayzeit dazwischenfunkt, dann kannst du 
auch gleich eine Sanduhr nehmen um 1 Sekunde abzuwarten.

> schalte den Timer ein
> warte bis PIN1 0 wird
> schate den Timer ab
> übergebe den Wert.
>
> Irgendwie ist das zu ungenau, kann das sein ?
>
> Sollte ich die Impulse generell anders auswerten ?

Starte den Timer, zähle die Overflows und rechne ein wenig.

Autor: hoschi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
aah, dann kann der delay auch wenn er in der interrupt Routine gerufen 
wird vom Interrupt unterbrochen werden weil es eine Funktion ist ?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hoschi schrieb:
> aah, dann kann der delay auch wenn er in der interrupt Routine gerufen
> wird vom Interrupt unterbrochen werden weil es eine Funktion ist ?

Solage du nicht selbst mittels sei() die Interrupts freigibst, bist du 
in einer ISR vor weiteren Interrupt Aufrufen geschützt. Trotzdem macht 
man das nicht, dass man in einem Interrupt auf etwas längere Zeit 
wartet.


Ansonsten: Code zeigen hilft.

(Warum denkst du eigentlich, dass das zu ungenau ist)

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Bei clk/64 und 4,8MHz wird die max. 1ms lange Servoposition in 75 
Schritte aufgelöst. Die 1ms Verzögerung zu Anfang braucht es damit dann 
nicht, bei max 2.1ms Servopulslänge zählt der Timer höchstens bis 158. 
Das gibt niemals einen Overflow.

Ob 75 Schritte ausreichend sind, musst du natürlich selber wissen.

Oliver

Autor: hoschi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ok, vielen Dank für die Tipps.

Dann wäre der neue Programmablauf in etwa so:
INT0 auf steigende Flanke

Bei INT0
Timer0 = 0
Timer einschalten mit passendem Teiler (oder evtl. keinem)
fallende/steigende INT0 Flanke umschalten

bei fallender Flanke :
Timer ausschalten
Überläufe auswerten und endwert übergeben
Überlaufzähler zurückstezen


Bei INT Timer overflow
Überläuf zählen

Autor: hoschi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hier mal mein Code versuch.
#include "main.h"

volatile int impuls;
volatile int tmr_ov;

int main (void) {


  GIMSK = (1<<INT0);    // | (1<<PCIE);         //INT0 enable PINchg enable
  MCUCR = (1<<ISC00) | (1<<ISC01);             //interrupt auf INT0 steigende Flanke


  DDRB &= ~( 1 << DDB1 );                // Eingänge definieren
  DDRB = (1 << DDB2) | (1 << DDB3 ) | (1 << DDB4 );              // Ausgang definieren

  sei();

while (1) {


  if (impuls <= 130 && (impuls>=10) ) {    // Werte müssen noch angepasst werden
    PORTB |= (1<<PB2);
    }
    else PORTB &= ~(1<<PB2);         // Pin PB2 und Pin PB3 "low"


  if (impuls >= 170) {            // Werte müssen noch angepasst werden
    PORTB |= (1<<PB3);
    }
    else PORTB &= ~(1<<PB3);         // Pin PB2 und Pin PB3 "low"
  }
}



ISR(INT0_vect) {
  TCNT0=0;                // Timer 0 auf 0

  if  (CS00 == 0) {              
      TCCR0B = (1<<CS00);          // Timer 0 Prozessortakt (4,8Mhz) / 1    //timer 0 start
    MCUCR = (1<<ISC01);          // interrupt auf INT0 fallende Flanke
  }


  if  (CS00 == 1) {  
    TCCR0B &= ~(1<<CS00);        // Timer 0 stop
      MCUCR = (1<<ISC00) | (1<<ISC01);   // interrupt auf INT0 steigende Flanke

    impuls=tmr_ov;            // Wert an globale Variable evtl noch Berechnung
    tmr_ov=0;              // Overflow Zähler auf null
  }

PORTB ^= ( 1 << PB4 );            // INT und Impulseingang Überwachung  
}


ISR(TIM0_OVF_vect) {            // Timer overflow interrupt
  tmr_ov++;
}

ich habe leider meine Testhardware nicht hier, kann das erst am Abend 
testen. Ich bin auch noch Anfänger bei dem Programmieren, ich bemühe 
mich aber kenne aber nicht viele Tricks.

Jetzt müsste noch in etwa ausgerechnet werden wie hoch die gemessenen 
Werte sein können.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hoschi schrieb:

>   if  (CS00 == 0) {

CS00 ist immer 0.
CS00 ist nichts anderes als ein Makro, welches die Bitnummer für das 
'CS00' Bit im Timerkonfiguratinsregister hinter einem Namen kaschiert
#define CS00  0
so stehts irgendwo in den Header Files.
Da dem aber so ist, wird dieser Vergleich immer TRUE ergeben.

>   if  (CS00 == 1) {

wohingegen, dieser niemals TRUE sein wird


(OK. Ich verallgemeinere. Auf allen AVR Prozessoren die ich kenne, liegt 
CS00 an der Bitposition 0 und genau genommen muss das nicht unbedingt so 
sein)
  if  (CS00 == 0) {              
      TCCR0B = (1<<CS00);          // Timer 0 Prozessortakt (4,8Mhz) / 1    //timer 0 start
    MCUCR = (1<<ISC01);          // interrupt auf INT0 fallende Flanke
Yep. Genau das ist einer der richtigen Wege.
    impuls=tmr_ov;            // Wert an globale Variable evtl noch Berechnung
    tmr_ov=0;              // Overflow Zähler auf null
Warum Overflow?
Warum nicht erst mal den Timerstand selber?

Autor: hoschi (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ah, ok danke, du meinst dann warscheinlich eher so:
#include "main.h"

volatile int impuls;
volatile int tmr_ov;
volatile int flanke;

int main (void) {


  GIMSK = (1<<INT0);    // | (1<<PCIE);         //INT0 enable PINchg enable
  MCUCR = (1<<ISC00) | (1<<ISC01);             //interrupt auf INT0 steigende Flanke


  DDRB &= ~( 1 << DDB1 );                // Eingänge definieren
  DDRB = (1 << DDB2) | (1 << DDB3 ) | (1 << DDB4 );              // Ausgang definieren

  sei();

while (1) {


  if (impuls <= 130 && (impuls>=10) ) {    // Werte müssen noch angepasst werden
    PORTB |= (1<<PB2);
    }
    else PORTB &= ~(1<<PB2);         // Pin PB2 und Pin PB3 "low"


  if (impuls >= 170) {            // Werte müssen noch angepasst werden
    PORTB |= (1<<PB3);
    }
    else PORTB &= ~(1<<PB3);         // Pin PB2 und Pin PB3 "low"
  }
}

ISR(INT0_vect) {
  TCNT0=0;                // Timer 0 auf 0

  if  (flanke == 0) {  
    flanke = 1;            
    TCCR0B = (1<<CS00);          // Timer 0 Prozessortakt (4,8Mhz) / 1    //timer 0 start
    MCUCR = (1<<ISC01);          // interrupt auf INT0 fallende Flanke
  }
    else {  
      flanke = 0;
      TCCR0B &= ~(1<<CS00);        // Timer 0 stop
      MCUCR = (1<<ISC00) | (1<<ISC01);   // interrupt auf INT0 steigende Flanke

      impuls=(tmr_ov*256)+TCNT0;      // Wert an globale Variable evtl noch Berechnung
      tmr_ov=0;              // Overflow Zähler auf null
    }

PORTB ^= ( 1 << PB4 );            // INT und Impulseingang Überwachung  
}


ISR(TIM0_OVF_vect) {            // Timer overflow interrupt
  tmr_ov++;
}

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hoschi schrieb:
> ah, ok danke, du meinst dann warscheinlich eher so:

Fast

Welchen Wert wird wohl TCNT0 hier

>
>     else {
>       flanke = 0;
>       TCCR0B &= ~(1<<CS00);        // Timer 0 stop
>       MCUCR = (1<<ISC00) | (1<<ISC01);   // interrupt auf INT0 steigende Flanke
> 
>       impuls=(tmr_ov*256)+TCNT0;      // Wert an globale Variable evtl noch Berechnung
>

haben, nachdem du hier

>
> ISR(INT0_vect) {
>   TCNT0=0;                // Timer 0 auf 0
>
den TCNT0 immer auf 0 gesetzt hast :-)

(OK, das ist jetzt ein trivialer Bug. Aber im Grunde: Ja, so sollte das 
fürs erste funktionieren)

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.