Forum: Mikrocontroller und Digitale Elektronik INPUT CAPTURE Problem


von Micha S. (e-tec)


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:
1
void init(void)
2
{
3
4
// 7-bit port D               654.3210
5
   DDRD   = 0x7F;          // 111.1111 -> all pins from port D as output.
6
   PORTD  = 0x00;          // 000.0000 -> push pull output LOW
7
8
// Config IPC Pin as Input
9
   DDRD  &= ~(1 << PD6);   // Input Capture Pin
10
11
// 8-bit port B               7654.3210
12
   DDRB   = 0x80;          // 1000.0000 -> all Pins from port B (except 7) as input 
13
   PORTB  = 0x60;          // 0110.0000 -> Pin 7 push pull out low, pin 5,6 input with pull 
14
                           //              up, pin 0,1,2,3,4 input without pull up.
15
}

Init Timer 1 (16bit)
1
// Timer 1, 16bit, prescaler 8, cycle time 65,536ms
2
void init_timer1(void)
3
{
4
   TCCR1A   = 0x00;
5
   TCCR1B  |=  (1<<ICNC1) | (1<<ICES1) | (1<<CS11) ; // IC pos edge, Prescaler 8
6
   TCCR1C   = 0x00;
7
8
   TIMSK   |=  (1<<TOIE1) | (1<<ICIE1);            // overflow int. enable, input capture interrupt 
9
                                                   // enabled
10
   TCNT1L   = 0x00;
11
   TCNT1H   = 0x00;
12
}

ISR Capture
1
// Input Capture
2
ISR(TIMER1_CAPT_vect)
3
{
4
   cli();                     // disable Interrupts
5
6
   TIFR |= (1 << ICF1);       // reset IPC flag
7
   t1_ipc_new =  ICR1;        // Read IPC register
8
9
   ui8 t1_cnt_new = t1_counter8;
10
   ui8 factor_ovl = 0u;
11
12
   if(t1_cnt_new >= t1_cnt_old)
13
   {
14
      factor_ovl  = t1_cnt_new - t1_cnt_old;
15
   }
16
   else
17
   {
18
      factor_ovl  = t1_cnt_old + UI8MAX - t1_cnt_new;
19
   }
20
21
   period_time = MAX_CNT_16bit * factor_ovl + t1_ipc_new - t1_ipc_old;
22
23
   // set reference values
24
   t1_cnt_old = t1_cnt_new;
25
   t1_ipc_old = t1_ipc_new;
26
27
   sei();                     // enable Interrupts
28
}

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

von Stefan B. (stefan) Benutzerseite


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.

von Micha S. (e-tec)


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 :)
1
// 7-bit port D               654.3210
2
   DDRD   = 0x3F;          // 011.1111 -> all pins from port D as output, pin 6 as input (IPC).
3
   PORTD  = 0x00;          // 000.0000 -> push pull output LOW

von Stefan B. (stefan) Benutzerseite


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.

von Micha S. (e-tec)


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...:)

von Stefan B. (stefan) Benutzerseite


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...

von Micha S. (e-tec)


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 :(

von Karl H. (kbuchegg)


Lesenswert?

Dann poste bitte dein vollständiges Programm.

von Micha S. (e-tec)


Lesenswert?

der rest funktioniert einwandfrei, werde es dir per mail schicken.

von Karl H. (kbuchegg)


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.

von Micha S. (e-tec)


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:
1
// ISR Vars
2
volatile ui8   t0_counter8  = 0u; //unsigned char
3
volatile ui8   t1_counter8  = 0u;
4
volatile ui16  t1_ipc_new   = 0u; // u short
5
volatile ui16  t1_ipc_old   = 0u;
6
volatile ui8   t1_cnt_old   = 0u;
7
volatile ui32  period_time  = 0u; //u.long
8
9
10
ISR(TIMER1_OVF_vect)
11
{
12
//   TIFR |= (1 << TOV1);          // reset Overflow Flag
13
   if(bit_is_set(global_flag, t1_counter8_overflow))
14
   {
15
      t1_counter8  = 0u;         // set counter to zero
16
      clrbit(global_flag,t1_counter8_overflow) // reset overflow flag
17
   }
18
   else
19
   if(t1_counter8 == UI8MAX)     // Capture variable overflow
20
   {
21
      setbit(global_flag,t1_counter8_overflow) // set overflow flag
22
      
23
   }
24
   else
25
   {
26
      t1_counter8 ++ ;           // increment counter
27
   }
28
}
oder einfach nur
t1_counter8 ++ :)

von Micha S. (e-tec)


Lesenswert?

Keiner mehr ne idee???
das komische ist das es im debugger einwandfrei funktioniert.

von ulrich (Gast)


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.

von Micha S. (e-tec)


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 ;)

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
Noch kein Account? Hier anmelden.