Forum: Mikrocontroller und Digitale Elektronik PIC18F Werte frieren irgendwann ein


von danny_0678 (Gast)


Angehängte Dateien:

Lesenswert?

Hallo an alle,

hab ein Programm für ein E-Kart geschrieben. MPLAB im C code.

Läuft soweit gut aber nach einiger Zeit >5 min frieren die Werte im 
Display und PWM ein. Eine LED in verschieden Teilen -auch ISR- blinkt 
weiter. Das Programm läuft somit.

Hab mal das Gas auf x Wert geestzt und nach dem einfrieren war der x 
Wert der PWM auch fest was sehr ungünstig wäre ;-).

Anbei der wesentliche Code. Hat jemand Ideen woran es hängen könnte?

Vielen Dank
1
volatile unsigned int AN0;              // 0 -> 65535
2
volatile unsigned char AN0_offset = 185;      // 0 -> 255 Offset wert immer nur minimal wert nehmen
3
volatile unsigned int AN0_max = 876;        // 0 -> 65535
4
volatile unsigned short ERG;            // 0 -> 65535 ANO entspricht DC
5
6
volatile unsigned int DC_max = 1010;        // 0 -> 65535
7
volatile unsigned int DC_alt = 0;          // 0 -> 65535
8
volatile unsigned int DC_act = 0;          // 0 -> 65535
9
volatile unsigned char DC_speed = 20;        // 0 -> 255
10
11
volatile unsigned int SW_Z = 0;            // 0 -> 65535 Zähler Intervall
12
volatile unsigned int SW_Intervall = 290;      // 0 -> 65535 Intervallwert 1/5000* Wert = Intervall  
13
14
volatile unsigned char Gas = 0;            // 0 -> 255
15
16
volatile unsigned float AN0_DC;            // Kommazahl Umrechnung ANO zu Duty cycle
17
18
19
//-----------------------------------------------------------------------------------------------------------------//
20
21
22
LCD_ON = 1;
23
24
Delay10KTCYx(100);                  // 0,2 s delay
25
26
OpenXLCD(FOUR_BIT & LINES_5X7 );
27
while( BusyXLCD() ) { }
28
29
SetDDRamAddr((unsigned char) 0);                 // 1. Zeile im Display
30
                    
31
putrsXLCD(( char*)"Willkommen NIC");
32
33
SetDDRamAddr((unsigned char) 40);                 // 2. Zeile im Display
34
                  
35
putrsXLCD(( char*)"E-Kart Version 1");
36
37
38
      Delay10KTCYx(250);                  // 0,5 s delay
39
40
41
AN0_DC = (float) 1024/ (AN0_max - AN0_offset);              //Schrittweite berechnen DC entspricht AN0
42
43
44
45
while (1) 
46
  { 
47
48
  ClrWdt()                              // clear Watchdog
49
50
    
51
      SetChanADC( ADC_CH0);                    // Gaspedal Auswertung
52
      ConvertADC();
53
      while( BusyADC() ){}
54
      AN0 = ReadADC();
55
56
      if (AN0 == AN0_offset)                    // Nullrechnung vermeiden
57
        {
58
        ERG  = (float)AN0_DC * (AN0 - AN0_offset + 3);
59
        }
60
        else
61
        {
62
        ERG  = (float)AN0_DC * (AN0 - AN0_offset);
63
        }
64
  
65
66
67
      strcpypgm2ram(LCDdata1, "                ");
68
        LCDdata1[0] = AN0 /1000+'0'; // Tausenderstelle
69
        LCDdata1[1] =  (AN0  % 1000) / 100 + '0'; // Hunderterstelle
70
        LCDdata1[2] =  (AN0  % 100) / 10 + '0'; // Zehnerstelle
71
        LCDdata1[3] =  AN0  % 10 + '0'; // Einnerstelle
72
73
//      LED = !LED;                          // blinkt trotzdem bei Fehler
74
75
        LCDdata1[5] = DC_act  /1000+'0'; // Tausenderstelle
76
        LCDdata1[6] =  (DC_act   % 1000) / 100 + '0'; // Hunderterstelle
77
        LCDdata1[7] =  (DC_act   % 100) / 10 + '0'; // Zehnerstelle
78
        LCDdata1[8] =  DC_act   % 10 + '0'; // Einnerstelle
79
80
        LCDdata1[11] = ERG  /1000+'0'; // Tausenderstelle
81
        LCDdata1[12] =  (ERG   % 1000) / 100 + '0'; // Hunderterstelle
82
        LCDdata1[13] =  (ERG   % 100) / 10 + '0'; // Zehnerstelle
83
        LCDdata1[14] =  ERG   % 10 + '0'; // Einnerstelle  
84
85
86
87
88
89
90
91
      SetDDRamAddr((unsigned char) 0);                 // 1. Zeile im Display  
92
      putsXLCD( LCDdata1);
93
94
      LED = !LED;                            // blinkt trotzdem bei Fehler
95
96
      SetDDRamAddr((unsigned char) 40);                 // 2. Zeile im Display
97
      putrsXLCD(( char*)"AN0  Speed ERG  ");
98
                          
99
100
  }  
101
102
}
103
104
105
//--------------------------------------------------------------------------------------------------------// 
106
// High priority interrupt vector 
107
#pragma code InterruptVectorHigh = 0x08 
108
void 
109
InterruptVectorHigh (void) 
110
{ 
111
_asm 
112
   goto InterruptHandlerHigh                       //jump to interrupt routine 
113
_endasm 
114
} 
115
//--------------------------------------------------------------------------------------------------------// 
116
// High priority interrupt routine 1 Hz
117
#pragma code 
118
#pragma interrupt InterruptHandlerHigh 
119
120
121
void 
122
InterruptHandlerHigh () 
123
{ 
124
125
  if (INTCONbits.TMR0IF)                         // Timer 0
126
 
127
      {
128
      INTCONbits.TMR0IF = 0;                       //clear interrupt flag
129
      INTCONbits.GIEH = 0;                                   //disable interrupts   
130
//      LED = !LED;
131
      WriteTimer0(26475);                     // war 80 , bei 3 h 2 sek zu schnell
132
      INTCONbits.GIEH = 1;                            //enable interrupts
133
134
      }  
135
}
136
137
 
138
//--------------------------------------------------------------------------------------------------------// 
139
// Low priority interrupt vector 
140
#pragma code InterruptVectorLow = 0x18 
141
void 
142
InterruptVectorLow (void) 
143
{ 
144
_asm 
145
   goto InterruptHandlerLow                       //jump to interrupt routine 
146
_endasm 
147
} 
148
//--------------------------------------------------------------------------------------------------------// 
149
// Low priority interrupt routine 
150
#pragma code 
151
#pragma interrupt InterruptHandlerLow 
152
153
154
void 
155
InterruptHandlerLow () 
156
{ 
157
158
if (PIR1bits.TMR1IF)
159
         {
160
      PIR1bits.TMR1IF = 0;                    //clear interrupt flag Timer 1
161
      }   
162
163
if  (PIR1bits.TMR2IF)                          //Timer 2 Interrupt 5 kHz aller 0,2 ms (200µs)
164
      {
165
      INTCONbits.GIEH = 0;                          //disable interrupts
166
      PIR1bits.TMR2IF = 0;                      //clear interrupt flag 
167
      SW_Z ++;
168
      
169
170
        if (SW_Z == SW_Intervall)
171
          {
172
          SW_Z = 0;                      // Zähler zurück setzen
173
174
//          LED = !LED;
175
176
          if(ERG < 10)                    //kleiner
177
            {
178
            DC_act = 0;
179
            Gas =0;
180
            }
181
  
182
          if(ERG  >= 10)                    //größer gleich
183
            {
184
            if( Gas == 0)              
185
              {
186
              DC_act = 10;
187
              Gas =1;
188
              }
189
              else
190
              {
191
              DC_alt = DC_act;
192
              DC_act = (int) DC_alt + DC_speed;              
193
                if(DC_act >= DC_max )
194
                {
195
                DC_act = DC_max;
196
                }
197
              }
198
          if (ERG < DC_act)
199
            {
200
            DC_act = ERG;
201
            }
202
203
          }
204
205
          SetDCPWM1(DC_act);
206
      
207
        }
208
209
210
211
212
213
214
215
      INTCONbits.GIEH = 1;                          //enable interrupts
216
      }
217
218
219
220
221
if (INTCON3bits.INT1IF)
222
      {
223
      INTCON3bits.INT1IF = 0;                       //clear interrupt flag int_solar_dach
224
      }
225
226
227
228
if (INTCON3bits.INT2IF)
229
      {
230
       INTCON3bits.INT2IF = 0;                       //clear interrupt flag int_puffer_wt
231
      }  
232
233
}

: Bearbeitet durch Moderator
von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

danny_0678 schrieb:
> Das Programm läuft somit.
> Hat jemand Ideen woran es hängen könnte?
Wenn das Programm läuft kanns eigentlich nur die Hardware sein...

> Anbei der wesentliche Code.
Zeigt genau dieser wesentliche Code den wesentlichen Fehler?

> while( BusyADC() ){}
Hups, sowas in der Main-Loop artet schnell mal ein einen Deadlock aus. 
Hast du noch mehr davon?

> Anbei der wesentliche Code.
Bitte wie in der Bedienungsanleitung über jeder Textbox beschrieben die 
[c]-Tags verwenden.

: Bearbeitet durch Moderator
von danny_0678 (Gast)


Lesenswert?

Hallo und danke,

Die Zeile

while( BusyADC() ){}

Steht in so jeder Zeile von PIC18 Code beim ADC im Netz. Der Controller 
muss ja warten, bis das Ergebnis vorliegt.

Hardware schließ ich eigentlich aus, die läuft ja 5 -10 min, da kann es 
ja nur der Code sein denk ich. Bloß was ? im Code ?

Danke.

von Jens (Gast)


Lesenswert?

danny_0678 schrieb:
> Hardware schließ ich eigentlich aus, die läuft ja 5 -10 min, da kann es
> ja nur der Code sein denk ich. Bloß was ? im Code ?

> ...
> Delay10KTCYx(250);                  // 0,5 s delay
> ...

Sorry, aber wenn ich sowas lese, bekomme ich immer Plaque.
Du läßt den µC eine halbe Sekunde warten nur um was auf das Display zu 
schreiben? Das muss schiefgehen. Ich bin insgesamt kein Freund von 
Delay. Alles was über ein paar NOPs hinausgeht mache ich über Timer oder 
frage in der Main-Loop das entsprechende Flag oder Register ab.

Die Idee mit der LED als Heartbeat kann man machen, wenn die aber in der 
ISR steckt, zeigt die nur, dass die ISR angesprungen wird.

von danny_0678 (Gast)


Lesenswert?

danny_0678 schrieb:
> while (1)

Hallo, ja das ist 0,5 s nur einmalig, da es vor der

while (1)

Schleife ist und nur nach dem Start 1x durchlaufen wird.

Ansonsten ist im Hauptprogramm eigentlich kein Delay weiter als das vom 
ADC.

Grüße

von danny_0678 (Gast)


Lesenswert?

> Die Idee mit der LED als Heartbeat kann man machen, wenn die aber in der
> ISR steckt, zeigt die nur, dass die ISR angesprungen wird.

Die LED war auch im Hauptprogramm vorhanden, welches beim Fehler 
durchlaufen wird.

von picfan (Gast)


Lesenswert?

Hallo,
hast du schon mal das errata DB angeschaut?

von Toby P. (Gast)


Lesenswert?

Mir wäre die Interrupt Routine zu lang. Kann sein das der nächste schon 
ansteht wenn du Sie.verlassen willst. Dann funzt alles in der Routine 
aber wenig außerhalb.

Wozu ist das asm Goto am Anfang der Routine?

von Toby P. (Gast)


Lesenswert?

Evtl. stört auch ein Int. das LCD Timing. Dann hängen die sich gern mal 
auf.

von Klaus (Gast)


Lesenswert?

Toby P. schrieb:
> Mir wäre die Interrupt Routine zu lang. Kann sein das der nächste schon
> ansteht wenn du Sie.verlassen willst. Dann funzt alles in der Routine
> aber wenig außerhalb.

Das wäre kein wirkliches Problem, da wird dann ein Interrupt 
ausgelassen. Aber gegen Ende des Handlers werden die Interrupte enabled, 
wenn also inzwischen ein weiterer Interrupt passiert ist, geht er wieder 
in den Handler. Und das solange, bis der Stack aufgeraucht ist. Es 
sollte also sowohl das sinnlose Disablen der Interrupte am Anfang als 
auch schädliche Enablen gegen Ende des Handlers raus.

Toby P. schrieb:
> Wozu ist das asm Goto am Anfang der Routine?

Ich kenne zwar die PIC18 nicht, aber weder bei den PIC16 noch bei den 
PIC24 habe ich je irgendwas in Assembler im Interruptkontext gebraucht. 
Das erledigt alles der Compiler. Ich denke, das ist bei den PIC18 
genauso.

MfG Klaus

von Volker S. (vloki)


Lesenswert?

Klaus schrieb:
> Ich kenne zwar die PIC18 nicht, aber weder bei den PIC16 noch bei den
> PIC24 habe ich je irgendwas in Assembler im Interruptkontext gebraucht.
> Das erledigt alles der Compiler. Ich denke, das ist bei den PIC18
> genauso

Kommt auf den Compiler an. Das hier ist wohl für den C18 geschrieben und 
da passt das so.

von MaNi (Gast)


Lesenswert?

danny_0678 schrieb:
> while( BusyADC() ){}
>
> Steht in so jeder Zeile von PIC18 Code beim ADC im Netz. Der Controller
> muss ja warten, bis das Ergebnis vorliegt.

Die machen oft einfache Beispiele. Ist nicht immer der "Beste" Weg.
Du hast jetzt nicht den genauen Controller Typ genannt, aber 
normalerweise hat jeder Controller einen Freerunning / Auto-Conversion 
oder ähnlich genannten Mode. Du triggerst den ADC in der Main. Du hast 
also keine spezielle Anforderung an eine äquidistante Abtastung oder 
Synchronisierung. Wieso lässt Du den ADC also nicht einfach 
selbsttriggernd laufen und greifst in deiner Endlosschleife einfach ins 
Ergebnisregister? Dann brauchst Du an der Stelle nicht warten.


Da der Controller keine FPU zu haben scheint würde ich mir die unnötige 
Float Rechnung sparen. Hat zwar nichts mit Deinem Problem zu tun, aber 
ist unnötig.

Der Heart-Beat wurde ja schon erwähnt. In der ISR macht der keinen Sinn.
Mach ihn mal in die Main, evtl. runtergeteilt. Dann siehst Du ob deine 
Main wirklich noch durchlaufen wird.

Evtl. könntest Du mal noch im Watchdog ISR eine LED anschalten oder ein 
Pin Toggeln. Dann würde man auch sehen ob der Zuschlägt. Dann würde ich 
aber auch gleich noch die Watchdog Zeit auf eine kleinere Zeit als 65 
Sekunden setzen.

Grüße
MaNi

von picfan (Gast)


Lesenswert?

Hallo,
irgendwie habe ich noch in Erinnerung, dass einige Pic18 Probleme mit 
den high/low Interrupts machen:
https://www.microchip.com/forums/m685200.aspx
Gruss

von Volker S. (vloki)


Lesenswert?

Volker S. schrieb:
> Kommt auf den Compiler an. Das hier ist wohl für den C18 geschrieben und
> da passt das so.

Ok, jetzt habe ich noch mal genauer in meine alten Unterlagen geschaut.
Das passt doch nicht ganz ;-)

Beim low-priority IR sollte das pragma interrupt*low* stehen
1
#pragma interruptlow InterruptHandlerLow

Das könnte natürlich fatale Folgen auf das Context Saving haben...

: Bearbeitet durch User
von Toby P. (Gast)


Lesenswert?

Klaus schrieb:
> habe ich je irgendwas in Assembler im Interruptkontext gebraucht.

Hab da noch mal drüber nachgedacht, macht Sinn weil durch das goto die 
Routine in einen sinnvollen Speicherbereich verlegt werden kann.

Ob das Interrupt enablen nötig ist weiß ich nicht. Streng genommen muss 
das der RTI Befehl machen da sonst die Routine mehrfach aufgerufen 
werden kann und der Stack überläuft.

von Toby P. (Gast)


Lesenswert?

MaNi schrieb:
> Wieso lässt Du den ADC also nicht einfach selbsttriggernd laufen

Der er dann auf das ready flag warten muss ist das imo unwichtig. Der 
ADC hängt sich ja nicht auf und hat seine max.  conversion time.

Ich würde als erstes die Interrupts vorm LCD schreiben diasablen und 
danach wieder freigeben.

LCD's haben fast  immer Timingprobleme und was mit einen Typ läuft geht 
mit dem anderer nicht.

von Toby P. (Gast)


Lesenswert?

danny_0678 schrieb:
> Hab mal das Gas auf x Wert geestzt und nach dem einfrieren war der x
> Wert der PWM auch fest was sehr ungünstig wäre ;-).

So etwas würde ich immer eigensicher bauen. Also min.  ein Monoflop das 
durch die Main getriggert wird.

So als Idee ist auch eine Variable ganz nett die durch jeden 
Programmteil hochgezählt wird. Wenn dann am Ende der Wert falsch ist was 
aus dem Ruder gelaufen.

von Klaus (Gast)


Lesenswert?

Toby P. schrieb:
> Hab da noch mal drüber nachgedacht, macht Sinn weil durch das
> goto die Routine in einen sinnvollen Speicherbereich verlegt
> werden kann.

Das erledigt das #pragma, das setzt den JMP an die Interruptadresse.

Volker S. schrieb:
> Beim low-priority IR sollte das pragma interrupt*low* stehen
> #pragma interruptlow InterruptHandlerLow

Toby P. schrieb:
> Ob das Interrupt enablen nötig ist weiß ich nicht. Streng genommen
> muss das der RTI Befehl machen da sonst die Routine mehrfach
> aufgerufen werden kann und der Stack überläuft.

Es macht auch der Return from Interrupt (RETI) und das enablen ist nicht 
nur nicht nötig sondern schädlich.

MfG Klaus

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

danny_0678 schrieb:
> Steht in so jeder Zeile von PIC18 Code beim ADC im Netz.
Trotzdem Murks, seine Rechenzeit so totzuschlagen (wie bei einem delay() 
im ms-Bereich auch).

> Der Controller muss ja warten, bis das Ergebnis vorliegt.
Nein, er muss nur nachschauen, ob der Wandler fertig ist. Das ist ganz 
grundlegend was anderes.

Bei meinen Programmen läuft der Prozessor immer schnellstmöglich durch 
die Hauptschleife. Mehr als 10ms darf er dafür niemals brauchen. Und 
abhängig von den gerade herrschenden Bedingungen führt er Aktionen aus: 
wenn der ACD grade frei ist, wird die nächste Wandlung gestartet, wenn 
grad wieder eine Sekunde um ist, dann wird das vom Timerinterrupt mit 
einem Flag angezeigt und ich mache das, was jede Sekunde nötig ist. Und 
dann werden die entprellten Eingänge abgefragt, und entsprechend 
reagiert. Und wenn eine Aktion länger dauern oder gar Abwarten nötig 
machen würde, dann wird sie in mehrere Schritte aufgeteilt (Stichwort 
FSM, Zustandsautomat).

Toby P. schrieb:
> Der ADC hängt sich ja nicht auf und hat seine max.  conversion time.
Wenn ihn nicht zufällig irgendwo in einer ISR wer abschaltet...

: Bearbeitet durch Moderator
von Volker S. (vloki)


Lesenswert?

Klaus schrieb:
> Es macht auch der Return from Interrupt (RETI) und das enablen ist nicht
> nur nicht nötig sondern schädlich.

Ja, da sollte man die Finger weg lassen ;-)



Volker S. schrieb:
> Beim low-priority IR sollte das pragma interrupt*low* stehen:
> #pragma interruptlow InterruptHandlerLow
>
> Das könnte natürlich fatale Folgen auf das Context Saving haben...

Der PIC18 hat zwei IR-Vektoren aber nur einen Satz Shadow Register zum 
automatischen Sichern des Context. Beim HighPriority IR werden 
Arbeitsregister W, STATUS und das Bankselect Register BSR automatisch in 
diese Shadow Register gesichert. Beim LowPriority nicht, da muss man das 
selbst (der Compiler) machen.

Der PIC18 Befehl RETFIE hat noch einen Parameter, der bestimmt ob beim 
Rücksprung ein Restore aus den Shadowregistern stattfindet. Deshalb muss 
man (der Compiler) auch beim Rücksprung wissen, ob es eine low- oder 
eine high-Priority Routine war.

: Bearbeitet durch User
von danny_0678 (Gast)


Lesenswert?

Hallo an alle Und danke für die zahlreichen Rückmeldung. Ich muss mir 
erst einmal in Ruhe alles anschauen und verdauen was ihr so kommentiert 
habt ? und würde mich melden. Vielen Dank noch einmal für die 
zahlreichen Postings. Grüße

von N. M. (mani)


Lesenswert?

Toby P. schrieb:
> MaNi schrieb:
>> Wieso lässt Du den ADC also nicht einfach selbsttriggernd laufen
>
> Der er dann auf das ready flag warten muss ist das imo unwichtig.

Ich weiß jetzt nicht wie das bei genanntem Pic ist, aber die neueren 
Controller die ich benutze Puffern das meist doppelt. Sprich, man kann 
da jederzeit reinfassen. Ohne warten.

von PicRakete (Gast)


Lesenswert?

Viele gute Hinweise gab es ja schon ..., bei der bescheidenen Code 
Quality und geringen Code Size würde ich unbedingt die Structure 
überarbeiten!

1. nach xc8 portieren, dazu brauchst du vielleicht einen Tag, also 
machbar, ... ich würde das in 20 Minuten bei dem Spielcode hinbiegen 
können.

2. den Simulator nutzen und die Hinweise einarbeiten, sprich die viele 
Redundance beseitigen, ich bekomme hier fast Augenkrebs.

3. z.B. den ungünstigen itoa Code, da mit Division, in die Tonne hauen 
und mein Beispiel (ungetestet :-)) mal anschauen.

4. eine serielle Ausgabe einbauen, damit du besser beobachten kannst, 
z.b. ob das LCD sich aufhängt oder der Code.

5. die vielen guten Hinweise hier, auch komplett umsetzten. Die sind im 
Prinzip eigentlich alle nur Basic, sprich dein Code ist weit darunter 
...
1
#ifdef XPRINTF_32
2
    #define xprintf_t uint32_t // max=4294967296
3
#else
4
    #define xprintf_t uint16_t // max=65535
5
#endif
6
7
#ifdef XPRINTF_32
8
   static const uint32_t dv[] =
9
   {1000000000UL, 100000000UL, 10000000UL, 1000000UL,
10
   100000UL, 10000UL, 1000UL, 100UL, 10UL, 1UL};
11
#else
12
   static const uint16_t dv[] = {10000U, 1000U, 100U, 10U, 1U};
13
#endif
14
15
//*************************************************************************
16
void xprintDEC(xprintf_t x, const xprintf_t *pdv) {
17
//*************************************************************************
18
   char c;
19
   xprintf_t d;
20
   if (x) {
21
      while (x < *pdv) ++pdv;
22
      do {
23
         d = *pdv++, c = '0';
24
         while (x >= d) ++c, x -= d;
25
         PUTC(c);
26
      } while (!(d & 1));
27
   } 
28
   else PUTC('0');
29
}

von PicRakete (Gast)


Lesenswert?

...  der Hinweis kam ja schon, der Code ist voll von Mursks, noch so ein 
Beispiel, wo du den Überblick verloren hast, nested Interrupts kann der 
Pic18 nicht und höher als High Prio gehts auch nicht mit den ISR.

??? INTCONbits.TMR0IF = 0;                       //clear interrupt flag
??? INTCONbits.GIEH = 1;                            //enable interrupts

Der Code ist grundsätzlich ohne Struture, einfach nur geradeaus runter 
geschrieben, ... du brauchst mehr Verständnis vom PIC18 und den HW 
Resourcen - Datenblatt intensive lesen!
1
InterruptHandlerHigh () 
2
{ 
3
4
  if (INTCONbits.TMR0IF)                         // Timer 0
5
 
6
      {
7
      INTCONbits.TMR0IF = 0;                       //clear interrupt flag
8
      INTCONbits.GIEH = 0;                                   //disable interrupts   
9
//      LED = !LED;
10
      WriteTimer0(26475);                     // war 80 , bei 3 h 2 sek zu schnell
11
      INTCONbits.GIEH = 1;                            //enable interrupts
12
13
      }  
14
}

von PicRakete (Gast)


Lesenswert?

PicRakete schrieb:

> ??? INTCONbits.TMR0IF = 0;                       //clear interrupt flag
> ??? INTCONbits.GIEH = 1;                            //enable interrupts

gemeint war:

INTCONbits.GIEH = 0;                                   //disable 
interrupts
INTCONbits.GIEH = 1;                            //enable interrupts

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.