Forum: Mikrocontroller und Digitale Elektronik TIMER0 beim LPC2134(ARM), Uvision(Keil)


von Sergey S. (Firma: ARM LPC2134, uVision3, in C) (serik00)


Lesenswert?

Hallo bin Anfänger und brauche eure Hilfe.
Stichwort-Timer.
Ich will den Timer so konfigurieren, das er jede Sekunde die LEDs 
(P1.24,P1.23) ein und ausschaltet.
Ich weiß der Code ist ziemlich ausbaufähig ist.


TIMER0 Initialisierung:
1
int init_timer0 (void) 
2
{
3
//Timer0 ist 32 bit und läuft mit Quarzfrequenz Fosc (XTAL) 11.059200, CCLK (CLOCK) 55.296000
4
//Timer zählt bis 2 hoch 32  durch Prescaler
5
   T0PC =                    //Prescaler einstellen
6
    T0MR0 = ;                            // 1Sec 
7
    T0MCR = ;                                 // Interrupt and Reset on MR0
8
    T0TCR = 1;                                 // Timer0 Counter and Prescale Counter Enable
9
  //tc IRQ defineiren
10
    VICVectAddr0 = (unsigned long)tc0;          // set interrupt vector in 0
11
    VICVectCntl0 = 0x20 | 4;                    // use it for Timer 0 Interrupt
12
    VICIntEnable = 0x00000010;                  // Enable Timer0 Interrupt
13
  return ERR_OK;
14
}

Hier wird tco IRQ aufgerufen und die LEDs ein und ausgeschaltet:
1
void tc0 (void) __irq 
2
{
3
  IODIR1  =   0x03000000;         /* LEDs P1.24,P1.23 defined as Outputs  */ 
4
  IODIR1  =   0x00000000;
5
    T0IR = 1;                                // Clear interrupt flag
6
    VICVectAddr = 0;                            // Acknowledge Interrupt
7
}

Für Vorschläge bin ich sehr dankbar.

von Kai F. (k-ozz)


Lesenswert?

1
int init_timer0 (void)
2
{
3
  IO1DIR |= ((1 << 23) | (1 << 24));          // LEDs auf Ausgang setzen
4
  IO1SET = ((1 << 23) | (1 << 24));           // LEDs ausschalten
5
  //Timer0 ist 32 bit und läuft mit Quarzfrequenz Fosc (XTAL) 11.059200, CCLK (CLOCK) 55.296000
6
  //Timer zählt bis 2 hoch 32  durch Prescaler
7
  T0PC = 0;                                   //Prescaler einstellen
8
  T0MR0 = 55295999;                           // 1Sec
9
  T0MCR = 0x03;                               // Interrupt and Reset on MR0
10
  T0TCR = 1;                                  // Timer0 Counter and Prescale Counter Enable
11
  //tc IRQ defineiren
12
  VICVectAddr0 = (unsigned long)tc0;          // set interrupt vector in 0
13
  VICVectCntl0 = 0x20 | 4;                    // use it for Timer 0 Interrupt
14
  VICIntEnable = 0x00000010;                  // Enable Timer0 Interrupt
15
  return ERR_OK;
16
}
17
18
void tc0 (void) __irq
19
{
20
  if (IO1PIN & (1 << 23))                     // sind LEDs momentan aus?
21
    IO1CLR = ((1 << 23) | (1 << 24));         // dann anschalten
22
  else
23
    IO1SET = ((1 << 23) | (1 << 24));         // sonst ausschalten
24
  T0IR = 1;                                  // Clear interrupt flag
25
  VICVectAddr = 0;                           // Acknowledge Interrupt
26
}

Der Timer wird von PCLK getaktet, d.h. er läuft entweder mit CCLK, mit 
CCLK/2 oder CCLK/4. Entsprechend muß der Wert für T0MR0 angepasst 
werden.
Wenn die ISR 1x pro Sekunde aufgerufen werden soll, so muß T0MR0 = 
PCLK-1 sein.
Als Alternative kann man die ISR z.B. auch 1x pro ms, d.h. mit 1kHz 
aufrufen lassen und eine globale Zählervariable inkrementieren und diese 
beim erreichen von 1000 wieder auf 0 zurücksetzen und die LEDs dann 
umschalten.

von Sergey S. (Firma: ARM LPC2134, uVision3, in C) (serik00)


Lesenswert?

Vielen Dank für den Beitrag!
Ich versuche hier die andere vom Kai vorgeschlagene Lösung.
Klappt nicht ganz. ich denke es liegt an der IRQ-Routine.
Hat jemand eine Idee?
1
  T0IR = 0x000000FF;              //TIMER0 Interrupt Register, Disable all Interrupts  
2
    VICIntEnable = 0x00000000;                  // Disable Timer0 
3
    T0TCR = 2;                    // Timer Counter and Prescale Counter are reset
4
  T0CTCR = 0x00000000;             // Choise for TIMER
5
  T0PR = 0x00000229;              //Prescaler auf 99,98 KHz
6
  T0MR0 = 0x0063;                    // Timer0 Match Register, 0x63 (dez. 99, Teiler 100), ergibt Match mit 999,8 Hz (1ms)
7
    T0MCR = 0x03;                               // Interrupt and Reset on MR0
8
    T0TCR = 1;                                  // Timer Counter and Prescale Counter Enable
9
    VICVectAddr0 = (unsigned long)tc0;          // set interrupt vector in 0 ISR=tc0
10
    VICVectCntl0 = 0x20 | 4;                    // use it for Timer 0 Interrupt
11
    VICIntEnable = 0x00000010;                  // Enable Timer0 Interrupt
12
13
14
  IO1DIR |= ((1 << 24) | (1 << 25));          // LEDs auf Ausgang setzen
15
    IO1SET = ((1 << 24) | (1 << 25));           // LEDs ausschalten
1
void tc0 (void) __irq
2
{
3
  short int timeval;
4
     for(timeval=0; timeval<=1000; timeval++)
5
     {
6
         if (timeval==1000)
7
    {
8
            if (IO1PIN & (1 << 24))                       // sind LEDs momentan aus?
9
    
10
               IO1CLR = ((1 << 24) | (1 << 25));         // dann anschalten
11
           else
12
                IO1SET = ((1 << 24) | (1 << 25));         // sonst ausschalten
13
               T0IR = 1;                                // Clear interrupt flag
14
               VICVectAddr = 0;       
15
    }   
16
   }
17
  timeval = 0;
18
}

von holger (Gast)


Lesenswert?

Du sollst timeval nicht in einer for() Schleife
im Interrupt hochzählen, sondern nur einmal pro Interrupt.
Also 1000 Timerinterrupts abwarten.

von Sergey S. (Firma: ARM LPC2134, uVision3, in C) (serik00)


Lesenswert?

Danke. Verstanden.
1
short int timeval = 0;     //gloabale Variable
2
3
void tc0 (void) __irq
4
{
5
  timeval++;
6
    
7
  if (timeval==1000)
8
  {
9
    if (IO1PIN & (1 << 24))                       // sind LEDs momentan aus?
10
      IO1CLR = ((1 << 24) | (1 << 25));         // dann anschalten
11
         else
12
      IO1SET = ((1 << 24) | (1 << 25));         // sonst ausschalten
13
            T0IR = 1;                                // Clear interrupt flag
14
            VICVectAddr = 0;     
15
      timeval = 0;  //Variable wieder zurücksetzen    
16
   }  
17
}

Die Variable timeval wurde global deklariert (also vor der Funktion), 
sowie  Kai F. es auch geschrieben hat.

Also die IRQ wird aufgerufen.
Die Variable timeval wird von 0 auf eine inkrementiert.
Das wars.
Bei 2. Durchlauf wird die Variable nicht mehr inkrementiert.

von holger (Gast)


Lesenswert?

>  if (timeval==0)

Das ist leider falsch. Denk mal drüber nach.
Da stimmt auch noch einiges mehr nicht.

von Sergey S. (Firma: ARM LPC2134, uVision3, in C) (serik00)


Lesenswert?

Also diese Aussage (short int timeval = 0;) setzt die globale Variable 
timeval jedesmal auf 0. richtig?

Die timevar wird zwar einmal erhöht aber dann wieder auch 0 gesetzt.
Und kommt so nie auf 1000.

Also sollte ich doch die globale Variable nur deklarieren:
short int timeval;

Aber irgendwo muss ich die doch initiieren, also eine 0 zuweisen.

Die If-Abfrage funktioniert, wenn ich Wert auf 1000 setze, dann wird die 
Abfrage ausgeführt.

1
short int timeval;
2
3
void tc0 (void) __irq
4
{
5
  timeval++;
6
7
  if (timeval==1000)
8
  {
9
    if (IO1PIN & (1 << 24))                       // sind LEDs momentan aus?
10
      IO1CLR = ((1 << 24) | (1 << 25));         // dann anschalten
11
         else
12
      IO1SET = ((1 << 24) | (1 << 25));         // sonst ausschalten
13
            T0IR = 1;                                 // Clear interrupt flag
14
            VICVectAddr = 0;     
15
      timeval = 0;  //Variable wieder zurücksetzen    
16
   }  
17
18
}

von holger (Gast)


Lesenswert?

>Also diese Aussage (short int timeval = 0;) setzt die globale Variable
>timeval jedesmal auf 0. richtig?

Falsch. Nur am Programmstart wird sie auf 0 gesetzt.

>Also sollte ich doch die globale Variable nur deklarieren:
>short int timeval;
>
>Aber irgendwo muss ich die doch initiieren, also eine 0 zuweisen.

Das macht der Compiler schon für dich.
Wenn du es mit Gürtel und Hosenträger möchtest,
kannst du es aber auch selber machen.

von Sergey S. (Firma: ARM LPC2134, uVision3, in C) (serik00)


Lesenswert?

Nee, Gürtel reicht:)

Aber dann müsste es doch funktioneiren!?

die variable timevar wird global deklariert und auf 0 gesetzt.

Bei jedem IRQ Aufruf wird diese um eins erhöht.

Wenn Timeval == 1000 ist, dann wird die If-Abfrage ausgeführt und die 
Variable wieder auf 0 gesetzt.

So sollte es funktionieren, tut es aber nicht.
Der neue Wert muss nach jeder Inkrementierung zurückgegeben werden.
Das passiert nicht. Richtig?
Wo liegt der Fehler?

von holger (Gast)


Lesenswert?

>Wo liegt der Fehler?

Zwei Programmzeilen stehen nicht dort wo sie
hingehören ;)

von Sergey S. (Firma: ARM LPC2134, uVision3, in C) (serik00)


Lesenswert?

Sagen Sie mir es schon.
Ich will zum Mittag essen gehen.
Dann kann ich mir ruhigem Gewissen essen:)
Ich in programmiere c seit einer Woche.

von holger (Gast)


Lesenswert?

>Sagen Sie mir es schon.

Es hat was mit dem Interrupthandling zu tun.

von Sergey S. (Firma: ARM LPC2134, uVision3, in C) (serik00)


Lesenswert?

1
T0IR = 0x000000FF;              //TIMER0 Interrupt Register, Disable all Interrupts  
2
VICIntEnable = 0x00000000;                  // Disable Timer0 
3
T0TCR = 2;                    // Timer Counter and Prescale Counter are reset
4
T0CTCR = 0x00000000;             // Choise for TIMER
5
T0PR = 0x00000229;              //Prescaler auf 99,98 KHz
6
T0MR0 = 0x0063;                    // Timer0 Match Register, 0x63 (dez. 99, Teiler 100), ergibt Match mit 999,8 Hz (1ms)
7
T0MCR = 0x03;                               // Interrupt and Reset on MR0
8
T0TCR = 1;                                  // Timer Counter and Prescale Counter Enable
9
VICVectAddr0 = (unsigned long)tc0;          // set interrupt vector in 0 ISR=tc0
10
VICVectCntl0 = 0x20 | 4;                    // use it for Timer 0 Interrupt
11
VICIntEnable = 0x00000010;                  // Enable Timer0 Interrupt
Also liegt es jetzt nicht an IRQ, sondern an Timer Initiierung?
MR0 - Interrupt reset? Richtig?
T0IR = 0xFF;
Was noch?

von holger (Gast)


Lesenswert?

>Also liegt es jetzt nicht an IRQ, sondern an Timer Initiierung?

Es liegt an der IRQ. Dort wird (theoretisch) etwas nur
alle 1000 mal ausgeführt, was jedesmal ausgeführt werden muß.
So, jetzt geh ICH essen ;)

von Sergey S. (Firma: ARM LPC2134, uVision3, in C) (serik00)


Lesenswert?

Und hats geschmekt?

ja klar!
Der IR flag muss jedesmal gesetzt werden um interrupt wieder zu löschen
und die VICVectAddr muss wieder freigegeben werden.
Und zwar bei jedem Aufruf der IRQ!

Vielen Dank!
1
void tc0 (void) __irq
2
{  
3
   timeval++;
4
  if (timeval==1000)
5
  {
6
    if (IO1PIN & (1 << 24))                       // sind LEDs momentan aus?
7
      IO1CLR = ((1 << 24) | (1 << 25));         // dann anschalten
8
         else
9
      IO1SET = ((1 << 24) | (1 << 25));         // sonst ausschalten
10
11
      timeval = 0;  //Variable wieder zurücksetzen        
12
   }
13
   T0IR = 1;                                 // Clear interrupt flag
14
     VICVectAddr = 0;       
15
}



Ist diese Lösung sinnvoll?
Denn hier wird IRQ-Routine ständig aufgerufen.
Wird damit nicht die CPU belastet?

Beitrag #5409767 wurde von einem Moderator gelöscht.
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.