www.mikrocontroller.net

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


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

Bewertung
0 lesenswert
nicht 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:
int init_timer0 (void) 
{
//Timer0 ist 32 bit und läuft mit Quarzfrequenz Fosc (XTAL) 11.059200, CCLK (CLOCK) 55.296000
//Timer zählt bis 2 hoch 32  durch Prescaler
   T0PC =                    //Prescaler einstellen
    T0MR0 = ;                            // 1Sec 
    T0MCR = ;                                 // Interrupt and Reset on MR0
    T0TCR = 1;                                 // Timer0 Counter and Prescale Counter Enable
  //tc IRQ defineiren
    VICVectAddr0 = (unsigned long)tc0;          // set interrupt vector in 0
    VICVectCntl0 = 0x20 | 4;                    // use it for Timer 0 Interrupt
    VICIntEnable = 0x00000010;                  // Enable Timer0 Interrupt
  return ERR_OK;
}

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

Für Vorschläge bin ich sehr dankbar.

Autor: Kai F. (k-ozz)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
int init_timer0 (void)
{
  IO1DIR |= ((1 << 23) | (1 << 24));          // LEDs auf Ausgang setzen
  IO1SET = ((1 << 23) | (1 << 24));           // LEDs ausschalten
  //Timer0 ist 32 bit und läuft mit Quarzfrequenz Fosc (XTAL) 11.059200, CCLK (CLOCK) 55.296000
  //Timer zählt bis 2 hoch 32  durch Prescaler
  T0PC = 0;                                   //Prescaler einstellen
  T0MR0 = 55295999;                           // 1Sec
  T0MCR = 0x03;                               // Interrupt and Reset on MR0
  T0TCR = 1;                                  // Timer0 Counter and Prescale Counter Enable
  //tc IRQ defineiren
  VICVectAddr0 = (unsigned long)tc0;          // set interrupt vector in 0
  VICVectCntl0 = 0x20 | 4;                    // use it for Timer 0 Interrupt
  VICIntEnable = 0x00000010;                  // Enable Timer0 Interrupt
  return ERR_OK;
}

void tc0 (void) __irq
{
  if (IO1PIN & (1 << 23))                     // sind LEDs momentan aus?
    IO1CLR = ((1 << 23) | (1 << 24));         // dann anschalten
  else
    IO1SET = ((1 << 23) | (1 << 24));         // sonst ausschalten
  T0IR = 1;                                  // Clear interrupt flag
  VICVectAddr = 0;                           // Acknowledge Interrupt
}

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.

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

Bewertung
0 lesenswert
nicht 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?
  T0IR = 0x000000FF;              //TIMER0 Interrupt Register, Disable all Interrupts  
    VICIntEnable = 0x00000000;                  // Disable Timer0 
    T0TCR = 2;                    // Timer Counter and Prescale Counter are reset
  T0CTCR = 0x00000000;             // Choise for TIMER
  T0PR = 0x00000229;              //Prescaler auf 99,98 KHz
  T0MR0 = 0x0063;                    // Timer0 Match Register, 0x63 (dez. 99, Teiler 100), ergibt Match mit 999,8 Hz (1ms)
    T0MCR = 0x03;                               // Interrupt and Reset on MR0
    T0TCR = 1;                                  // Timer Counter and Prescale Counter Enable
    VICVectAddr0 = (unsigned long)tc0;          // set interrupt vector in 0 ISR=tc0
    VICVectCntl0 = 0x20 | 4;                    // use it for Timer 0 Interrupt
    VICIntEnable = 0x00000010;                  // Enable Timer0 Interrupt


  IO1DIR |= ((1 << 24) | (1 << 25));          // LEDs auf Ausgang setzen
    IO1SET = ((1 << 24) | (1 << 25));           // LEDs ausschalten

void tc0 (void) __irq
{
  short int timeval;
     for(timeval=0; timeval<=1000; timeval++)
     {
         if (timeval==1000)
    {
            if (IO1PIN & (1 << 24))                       // sind LEDs momentan aus?
    
               IO1CLR = ((1 << 24) | (1 << 25));         // dann anschalten
           else
                IO1SET = ((1 << 24) | (1 << 25));         // sonst ausschalten
               T0IR = 1;                                // Clear interrupt flag
               VICVectAddr = 0;       
    }   
   }
  timeval = 0;
} 

Autor: holger (Gast)
Datum:

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

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

Bewertung
0 lesenswert
nicht lesenswert
Danke. Verstanden.
short int timeval = 0;     //gloabale Variable

void tc0 (void) __irq
{
  timeval++;
    
  if (timeval==1000)
  {
    if (IO1PIN & (1 << 24))                       // sind LEDs momentan aus?
      IO1CLR = ((1 << 24) | (1 << 25));         // dann anschalten
         else
      IO1SET = ((1 << 24) | (1 << 25));         // sonst ausschalten
            T0IR = 1;                                // Clear interrupt flag
            VICVectAddr = 0;     
      timeval = 0;  //Variable wieder zurücksetzen    
   }  
} 

 

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.

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>  if (timeval==0)

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

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

Bewertung
0 lesenswert
nicht 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.

short int timeval;

void tc0 (void) __irq
{
  timeval++;

  if (timeval==1000)
  {
    if (IO1PIN & (1 << 24))                       // sind LEDs momentan aus?
      IO1CLR = ((1 << 24) | (1 << 25));         // dann anschalten
         else
      IO1SET = ((1 << 24) | (1 << 25));         // sonst ausschalten
            T0IR = 1;                                 // Clear interrupt flag
            VICVectAddr = 0;     
      timeval = 0;  //Variable wieder zurücksetzen    
   }  

}      
   

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

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

Bewertung
0 lesenswert
nicht 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?

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Wo liegt der Fehler?

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

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

Bewertung
0 lesenswert
nicht 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.

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Sagen Sie mir es schon.

Es hat was mit dem Interrupthandling zu tun.

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

Bewertung
0 lesenswert
nicht lesenswert

T0IR = 0x000000FF;              //TIMER0 Interrupt Register, Disable all Interrupts  
VICIntEnable = 0x00000000;                  // Disable Timer0 
T0TCR = 2;                    // Timer Counter and Prescale Counter are reset
T0CTCR = 0x00000000;             // Choise for TIMER
T0PR = 0x00000229;              //Prescaler auf 99,98 KHz
T0MR0 = 0x0063;                    // Timer0 Match Register, 0x63 (dez. 99, Teiler 100), ergibt Match mit 999,8 Hz (1ms)
T0MCR = 0x03;                               // Interrupt and Reset on MR0
T0TCR = 1;                                  // Timer Counter and Prescale Counter Enable
VICVectAddr0 = (unsigned long)tc0;          // set interrupt vector in 0 ISR=tc0
VICVectCntl0 = 0x20 | 4;                    // use it for Timer 0 Interrupt
VICIntEnable = 0x00000010;                  // Enable Timer0 Interrupt


Also liegt es jetzt nicht an IRQ, sondern an Timer Initiierung?
MR0 - Interrupt reset? Richtig?
T0IR = 0xFF;
Was noch?

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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 ;)

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

Bewertung
0 lesenswert
nicht 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!
void tc0 (void) __irq
{  
   timeval++;
  if (timeval==1000)
  {
    if (IO1PIN & (1 << 24))                       // sind LEDs momentan aus?
      IO1CLR = ((1 << 24) | (1 << 25));         // dann anschalten
         else
      IO1SET = ((1 << 24) | (1 << 25));         // sonst ausschalten

      timeval = 0;  //Variable wieder zurücksetzen        
   }
   T0IR = 1;                                 // Clear interrupt flag
     VICVectAddr = 0;       
}      



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

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.