www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik INPUT CAPTURE Problem


Autor: Micha S. (e-tec)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Morgen,

hab ein Problem mit dem IPC, funktioniert einfach nicht.
Erst mal eine allgemeine Frage, kann man den IPC pin mit einer zu hohen 
frequenz zerstören (~200kHz)? habe im db leider nichts gefunden.

mein erster versuch lief ganz gut, also funktioniert hat es schon mal 
(if periode > 20, lass led blinken).

code sieht wie folgt aus:

DDR und Port init:
void init(void)
{

// 7-bit port D               654.3210
   DDRD   = 0x7F;          // 111.1111 -> all pins from port D as output.
   PORTD  = 0x00;          // 000.0000 -> push pull output LOW

// Config IPC Pin as Input
   DDRD  &= ~(1 << PD6);   // Input Capture Pin

// 8-bit port B               7654.3210
   DDRB   = 0x80;          // 1000.0000 -> all Pins from port B (except 7) as input 
   PORTB  = 0x60;          // 0110.0000 -> Pin 7 push pull out low, pin 5,6 input with pull 
                           //              up, pin 0,1,2,3,4 input without pull up.
}

Init Timer 1 (16bit)
// Timer 1, 16bit, prescaler 8, cycle time 65,536ms
void init_timer1(void)
{
   TCCR1A   = 0x00;
   TCCR1B  |=  (1<<ICNC1) | (1<<ICES1) | (1<<CS11) ; // IC pos edge, Prescaler 8
   TCCR1C   = 0x00;

   TIMSK   |=  (1<<TOIE1) | (1<<ICIE1);            // overflow int. enable, input capture interrupt 
                                                   // enabled
   TCNT1L   = 0x00;
   TCNT1H   = 0x00;
}

ISR Capture
// Input Capture
ISR(TIMER1_CAPT_vect)
{
   cli();                     // disable Interrupts

   TIFR |= (1 << ICF1);       // reset IPC flag
   t1_ipc_new =  ICR1;        // Read IPC register

   ui8 t1_cnt_new = t1_counter8;
   ui8 factor_ovl = 0u;

   if(t1_cnt_new >= t1_cnt_old)
   {
      factor_ovl  = t1_cnt_new - t1_cnt_old;
   }
   else
   {
      factor_ovl  = t1_cnt_old + UI8MAX - t1_cnt_new;
   }

   period_time = MAX_CNT_16bit * factor_ovl + t1_ipc_new - t1_ipc_old;

   // set reference values
   t1_cnt_old = t1_cnt_new;
   t1_ipc_old = t1_ipc_new;

   sei();                     // enable Interrupts
}

hoffe euch fällt was auf!!!
bin grad echt ratlos :(

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Micha S. schrieb:

> hab ein Problem mit dem IPC, funktioniert einfach nicht.
> Erst mal eine allgemeine Frage, kann man den IPC pin mit einer zu hohen
> frequenz zerstören (~200kHz)? habe im db leider nichts gefunden.

Frequenz weiss ich nicht, Zerstörung kommt auf die Schaltung an. Bei dem 
folgenden problematischen Code schaltest du PD6 erstmal kurz auf Ausgang 
und LOW bevor du PD6 auf Eingang und hochohmig (ohne Pullup) schaltest. 
Das kann je nach angeschlossener HW (Versorgung mit niedrigem 
Serienwiderstand oder starker Ausgang HIGH > max. Strom eines IO-Ports) 
tödlich für den PD6 sein.

// 7-bit port D               654.3210
   DDRD   = 0x7F;          // 111.1111 -> all pins from port D as 
output.
   PORTD  = 0x00;          // 000.0000 -> push pull output LOW

// Config IPC Pin as Input
   DDRD  &= ~(1 << PD6);   // Input Capture Pin

Ich würde an PD6 zunächst eine Funktionskontrolle mit Beispielprogrammen 
aus der Codekiste machen z.B. mit einem Blinkprogramm für eine LED um 
die Funktion Ausgang zu prüfen und mit einem Tasterprogramm um die 
Funktion Eingang zu prüfen.

Autor: Micha S. (e-tec)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
danke erst mal für die schnelle antwort!

Daran denke ich auch gerade, sollte erst einmal den pin testen. hatte 
gestern einen interessanten effekt (warum auch immer), der gesamte port 
streikte nach einer recht hohen frequenz >200kHz. könnte sein er ist 
zerstört.
die signaltreiber schaltung liefert ~0 oder 4,3V (Vcc = 5V), reicht also 
für die flanken.

so,schon geändet :)
// 7-bit port D               654.3210
   DDRD   = 0x3F;          // 011.1111 -> all pins from port D as output, pin 6 as input (IPC).
   PORTD  = 0x00;          // 000.0000 -> push pull output LOW

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Tu das :-)

Und lass das cli()/sei() und die Zeile "TIFR |= (1 << ICF1);"in der ISR 
weg. Die haben dort nichts zu suchen. Die ISR bzw. der 
Interruptmechanismus des AVR kümmern sich um diese Punkte. Das Problem 
bei hohen Frequenzen hängt IMHO damit zusammen: Der Problemcode erlaubt 
zu früh, d.h. vor Verlassen der ISR, einen neuen Aufruf der ISR. Damit 
läuft mehr oder minder schnell der Stack über und der AVR in einen 
Resetzustand.

Autor: Micha S. (e-tec)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das die ISR beim Ausfhren ihr flag löscht ist klar (fand es optisch 
schöner :)) aber die routinen wusste ich nicht das die abgeschaltet 
werden. wenn jetzt ein ISR mit höherer prio kommt wird er dann nicht 
unterbrochen? ist ne verständnisfrage, im moment ist der capt mein 
höchster interner.
oh frage erübrigt sich, höher sind nur die externen und reset (tiny2313)

hoffe es geht so, nächste alternative ist der nächste controller 
(gestern hats ja auch funktioniert...:)

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Schädlich ist vor allem das sei() vor dem Return der ISR. Zwischen sei() 
und Return kann bei gelöschtem Flag der nächste Interrupt zuschlagen und 
die geretteten Daten der aktuell laufenden und jetzt unterbrochenen ISR 
hängen unaufgeräumt auf dem Stack rum. Das sind jede Menge Register des 
Anwendungsprogramms...! Und beim nächsten Interrupt in 5 µs (200 kHz) 
werden die nächsten Daten auf dem Stack gepackt und nicht mehr 
runtergeladen...

Autor: Micha S. (e-tec)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok hab ich rausgeschmissen, klar einen stack overflow wäre das letzte wo 
ich jetzt brauch!
habe den controller gewechselt aber es geht immer noch nict :(

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

Bewertung
0 lesenswert
nicht lesenswert
Dann poste bitte dein vollständiges Programm.

Autor: Micha S. (e-tec)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
der rest funktioniert einwandfrei, werde es dir per mail schicken.

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

Bewertung
0 lesenswert
nicht lesenswert
Micha S. schrieb:
> der rest funktioniert einwandfrei, werde es dir per mail schicken.

SChicks nicht per Mail. Da schau ich mir das nicht an.
Poste es hier rein als Attachment.

Der Rest ist auch nicht unbedingt uninteressant. zb Gibst du den 
Overflow Interrupt ebenfalls frei. Aber: Hast du einen Handler dafür?
Wie genau sind die Variablen definiert?

All das kann ich im kompletten Porgramm leicht nachsehen. Postest du 
aber nur Ausschnitte muss immer lästgi nachgefragt werden. Daher: 
Kompletter Code ist meistens die bessere Wahl. Da sehen wir dann was 
Sache ist und mussen weder nachfragen noch uns fehlende Details 
erfinden.

Autor: Micha S. (e-tec)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ja das stimmt. ist eine projektarbeit für die schule, wenn mein prof das 
programm online sucht und was findet gibt das einen anschiss oder 
schlimmer weil er denkt es sei geklaut, ebensowenig erlaubt er 
fremdhilfe.

also vars sind als volatile definiert, ovr isr ja, code hier:
// ISR Vars
volatile ui8   t0_counter8  = 0u; //unsigned char
volatile ui8   t1_counter8  = 0u;
volatile ui16  t1_ipc_new   = 0u; // u short
volatile ui16  t1_ipc_old   = 0u;
volatile ui8   t1_cnt_old   = 0u;
volatile ui32  period_time  = 0u; //u.long


ISR(TIMER1_OVF_vect)
{
//   TIFR |= (1 << TOV1);          // reset Overflow Flag
   if(bit_is_set(global_flag, t1_counter8_overflow))
   {
      t1_counter8  = 0u;         // set counter to zero
      clrbit(global_flag,t1_counter8_overflow) // reset overflow flag
   }
   else
   if(t1_counter8 == UI8MAX)     // Capture variable overflow
   {
      setbit(global_flag,t1_counter8_overflow) // set overflow flag
      
   }
   else
   {
      t1_counter8 ++ ;           // increment counter
   }
}
oder einfach nur
t1_counter8 ++ :)

Autor: Micha S. (e-tec)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Keiner mehr ne idee???
das komische ist das es im debugger einwandfrei funktioniert.

Autor: ulrich (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Zumindest der alte AVR Simulator ist bei der Reihenfolge in der 
Interrupts ausgeführt werden nicht ganz korrekt (Ausführung nach dem 
Auftreten des Interrupt signals). Die Hardware kümmert sich aber nicht 
darum welches Interruptflag zu erst gesetzt wurde, sondern geht nur 
danach welche Bits gesetzt sind.
Daduch kann es passieren das ICP Interrupts schon vor dem Overflow 
Interrupt ausgeführt wird, obwohl er eigentlich erst später dran ist.

Die Interrupt Flags werden schon von der Hardware zurückgesetzt.

Sonst gibt halt: Selber denken muss man auch mal üben.

Autor: Micha S. (e-tec)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ulrich schrieb:
> Sonst gibt halt: Selber denken muss man auch mal üben.

Ja da bin ich grad dran, was mich irritiert ist das der erste versuch 
funktioiert hat. egal, habe es jetzt etwas anders gemacht aber vom 
prinzip ist es das gleiche. timer 0 läuft als zeitstempel (32,768ms) und 
timer 2 als flankenzähler, somit ist grob gesagt:
zeitstempel / anzahl flanken = periodenzeit

trotzdem danke an euch alle ;)

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.