Forum: Mikrocontroller und Digitale Elektronik AT90CAN128 ändert sein verhalten nach Resets.


von Mechatronk (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

Ich habe hier ein Projekt, bei welchem ich zu definiertem Zeitpunkt 
einen 2 ms langen Puls auslösen will.
Dazu verwende ich den Timer0 mit Prescaler 1024 und lasse ihn 30 Tics 
laufen, bis er in den Compare Interrupt läuft. Dort wird der Puls 
beendet und der Interrupt deaktiviert.
Bei Start des nächsten Pulses (getriggert durch die fallende Flanke des 
FGs) wird der Timer auf 0 gesetzt und der Interrupt wieder aktiviert.

Das Lustige ist, dass es nur manchmal funktioniert. In ca 70% der Fälle 
kommt ein nur ca 7 ns langer Puls durch. In den anderen 30% funktioniert 
es wie gedacht.
Nach einigen Resets des Controllers ändert sich das Verhalten, es 
springt wenn man oft genug resettet beliebig hin und her.

Ich verwenden einen AT90CAN128 auf dem AVR-CAN Board von Olimex, 
AVRstudio 4.18 mit WinAVR toolchain und den Olimex USB-JTAG ( Wobei das 
Jtag-Debugging nicht ganzfunktioniert, warum auch immer... ) unter Win10
Im Anhang die Oszi-Screenshots, nichts am Programm oder der Umgebung 
geändert, nur resettet.

Code:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
  
4
  
5
void PORT_Init()
6
{
7
  PORTA = 0b00000000;
8
  DDRA = 0b00000000;
9
10
  PORTB = 0b00000000;
11
  DDRB = 0b00000000;     
12
13
  PORTC = 0b00000000;
14
  DDRC = 0b00000000;
15
16
  PORTD = 0b00000000;
17
  DDRD = 0b00000100;     // PD0=INT0 Als Input um Hardware-Interrupt zu erzeugen PD2 als ZündOutput
18
19
  PORTE = 0b00010000;
20
  DDRE = 0b00010000;    //Led set as output (Bit4 = 1) 
21
    
22
  PORTF = 0b00000000;
23
  DDRF = 0b00000000;
24
  }
25
26
27
void Reg_Init(void)
28
  {
29
30
  EIMSK=0b00000001;  // External Asynchodous Interupt Pin 0 (PD0) Aktiviert
31
  EICRA=0b00000010;  // ISR 0 loest bei Fallender Flanke aus
32
33
  
34
    //Timer 0 für Schließwinkel
35
  TCCR0A=0b00000101; // kein PWM,kein Compare Match , prescaler 1024 -> 2ms = 30 Pulse
36
  TIMSK0=0b00000000; // erstmal kein Compare Match interrupt
37
  
38
  OCR0A=30;
39
  
40
  
41
  }
42
43
44
void WDT_off(void)
45
  {
46
  cli();
47
  /* Write logical one to WDCE and WDE */
48
  WDTCR = (1<<WDCE) | (1<<WDE);
49
  /* Turn off WDT */
50
  WDTCR = 0x00;
51
  }
52
53
54
int main()
55
  {
56
  WDT_off();
57
  PORT_Init();
58
  Reg_Init();
59
  
60
  sei();  // Alles Initialisiert, Interupts Freischalten
61
  
62
  while (1)
63
  
64
    {
65
    } 
66
  }
67
  
68
ISR(INT0_vect) // Interrupt von Pin 
69
  {  
70
  TCNT0   =0;
71
  TIMSK0 |=0b00000010; // Compare Match 0 interrupt an
72
  PORTD  |=  0b00000100; //Öffnen
73
  }
74
  
75
  
76
ISR(TIMER0_COMP_vect)  // 2ms-timer interrupt
77
  { 
78
  PORTD  &=1111111011; //Zünden
79
  TIMSK0 &=0b11111101; // Compare Match 0 interrupt aus
80
  }

: Bearbeitet durch User
von Fabi (Gast)


Lesenswert?

Das ist wahrlich ein Komischer Fehler. Schon die Stromversorgung des 
Controllers überprüft? Manchmal spinnt der etwas wenn beim Reset die 
Spannung einbricht.


Grüße

Fabi

von Karl H. (kbuchegg)


Lesenswert?

das
1
ISR(INT0_vect) // Interrupt von Pin 
2
  {  
3
  TCNT0   =0;
4
  TIMSK0 |=0b00000010; // Compare Match 0 interrupt an
5
  PORTD  |=  0b00000100; //Öffnen
6
  }

reicht nicht.
Du musst auch möglicherweise in der Zwischenzeit angefallene Interrupt 
Anforderungen löschen.
Nur weil du den Compare Match Interrupt deaktivierst, bedeutet das 
nicht, dass zwischenzeitlich angefallene Compare Matches nicht 
entsprechend registriert werden. Aktivierst du den Interrupt dann 
wieder, dann feuert der sofort.

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Mechatronk schrieb:
> TIMSK0 |=0b00000010; // Compare Match 0 interrupt an

Lösche mal davor das Pending-Flag durch Setzen.
1
TIFR0 = 1<<OCF0A;

von Karl H. (kbuchegg)


Lesenswert?

Und wenn man es ganz genau nimmt, müsste man auch noch den Zähler im 
Prescaler auf 0 zurück setzen. Da müsste man jetzt allerdings ins 
Datenblatt sehen, ob das beim 90CAN128 überhaupt möglich ist und welches 
Bit dafür in welchem Register zuständig ist. WEnn das nicht geht, dann 
hast du durch den hohen Vorteiler von 1024 da schon eine prinizpielle 
Ungenauigkeit in der Grössenordnung von maximal 1023 Takten.
Vergleichbar mit dem Rücksetzen einer Stoppuhr wobei nur die Minuten 
zurückgesetzt werden und nicht die Sekunden. Je nachdem wann genau die 
Zurücksetzt, hast du in weiterer Folge einen Fehler dergestallt, dass 
die abgelesenen Minuten um maximal 59 Sekunden falsch sein können.

von Mechatronk (Gast)


Lesenswert?

Danke, das war das Problem!
Mit
1
ISR(INT0_vect) // Interrupt von Pin 
2
  {  
3
  TCNT0=0;
4
  TIFR0 = 0b00000010;
5
  TIMSK0=  0b00000010; // Compare Match 0 interrupt an
6
  PORTD|=  0b00000100; //Öffnen
7
  }


Funktioniert es einwandfrei.

Da ich mehrere Timer in Verwendung habe, kann ich den Prescaler leider 
nicht resetten ohne die Anderen zu beeinflussen.
Für Menschen die irgendwann das Problem nochmal haben und auf diesen 
Thread Stoßen:

Wenn man bit 0 von GTCCR auf 1 setzt, wird der Prescaler resettet. Das 
bit wird automatisch wieder auf 0 gesetzt.

von Karl H. (kbuchegg)


Lesenswert?

Mechatronk schrieb:

>
1
> ISR(INT0_vect) // Interrupt von Pin
2
>   {
3
>   TCNT0=0;
4
>   TIFR0 = 0b00000010;
5
>   TIMSK0=  0b00000010; // Compare Match 0 interrupt an
6
>   PORTD|=  0b00000100; //Öffnen
7
>   }
8
> 
9
>

Tu dir selbst einen Gefallen und benutze an dieser Stelle keine 
Binärkonstanten! Atmel hat sich extra für jedes Bit einen Namen 
einfallen lassen und dieser Name steht dir in den Header Files zur 
Benutzung zur Verfügung.

Kein Mensch muss beispielsweise
1
   TIMSK0=  0b00000010; // Compare Match 0 interrupt an
schreiben, wenn er auch
1
   TIMSK0 =  (1 << OCIE0A);
schreiben kann. Das ist nicht nur weniger fehleranfällig, es ist auch im 
Datenblatt leichter zu finden und für den Kundigen viel leichter  zu 
lesen
1
O    Output
2
C    Compare
3
I    Interrupt
4
E    Enable
5
0    am Timer 0
6
A    und zwar am A Kanal (was ein Hinweis darauf ist, dass der Compare Wert
7
     über das OCR0A Register eingestellt wird)

zum einen brauchst du dann nicht unbedingt mehr den Kommentar (der 
falsch sein kann), zum anderen brauchst du in der Fehlersuche dann nicht 
mehr suchen, ob du vielleicht das falsche Bit erwischt hast. Die exakte 
Bitposition ist nämlich ziemlich uninteressant. Darum kümmert sich schon 
der Compiler, wenn du den Namen des Bits benutzt.

: Bearbeitet durch User
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.