Autor Thema: Taktquelle für Timer0 (PIC18F45K22)  (Gelesen 15232 mal)

Offline Edson

  • Sr. Member
  • ****
  • Beiträge: 410
    • Profil anzeigen
Re:Taktquelle für Timer0 (PIC18F45K22)
« Antwort #15 am: März 01, 2012, 14:40:12 Nachmittag »
Doch, das geht schon. Es gibt gute Argumente, die Aufgabe anders zu lösen als es die Beispiele auf deinem Zettel zeigen - aber Aufgabe ist Aufgabe, und lösbar ist sie allemal. Man muss halt davon ausgehen dürfen, dass die Taste entprellt ist. Dann kann man auch einen Interrupt benutzen. Ich denke, die Aufgabe soll zeigen das bestimmte Funktionen so umgesetzt werden können, dass es egal ist ob die CPU in einer Endlosschleife hängt (wie im Beispiel) oder ganz was anderes macht. Wenn wir fertig sind, passiert alles innerhalb der ISR und verhält sich so wie es verlangt wird.

Fang doch nochmal damit an, den Timer0 so einzustellen, dass er alle 1ms einen Interrupt auslöst. Dazu musst du den Haupttakt (FOSC) kennen und ausrechnen, welche Einstellungen nötig sind.
Dann kannst du schonmal in der ISR einen Code schreiben, mit dem du feststellst ob der Interrupt vom Taster (INT0) oder Timer0 ausgelöst wurde.

Wenn du das hast und noch nicht weiterkommst, können wir hier schrittweise weitermachen.


Viel Erfolg!

Gruß,
Edson

Offline Austrianer

  • Newbie
  • *
  • Beiträge: 30
    • Profil anzeigen
Re:Taktquelle für Timer0 (PIC18F45K22)
« Antwort #16 am: März 01, 2012, 15:10:09 Nachmittag »
Vorerst VIELEN DANK für die Hilfestellung!!!

Zitat
Fang doch nochmal damit an, den Timer0 so einzustellen, dass er alle 1ms einen Interrupt auslöst. Dazu musst du den Haupttakt (FOSC) kennen und ausrechnen, welche Einstellungen nötig sind.

Mit diesem Satz, hast du genau mein Problem angesprochen. Ich habe bis jetzt nur den Internal Oscillator (INTOSC) verwendet. Mit diesem habe ich keinen Interrupt (alle 1ms) auslösen können.

Laut deinem Text, benötige ich für die Lösung FOSC, PLL, Primary Clock !? Mit PLL würde ich den Takt vervierfachen. Was für einen Sinn hätte das?

Welchen PIC-Takt und Zähler benötige ich, um den Überlauf des Zählers (TMR0IF-->1) alle 1ms zu erhalten?
« Letzte Änderung: März 01, 2012, 16:04:02 Nachmittag von Austrianer »

Offline Edson

  • Sr. Member
  • ****
  • Beiträge: 410
    • Profil anzeigen
Re:Taktquelle für Timer0 (PIC18F45K22)
« Antwort #17 am: März 01, 2012, 16:55:49 Nachmittag »
Ich habe bis jetzt nur den Internal Oscillator (INTOSC) verwendet. Mit diesem habe ich keinen Interrupt (alle 1ms) auslösen können.

Oh, da scheint es noch Verständnisprobleme zu geben. Du bringst Primärtakt und Timerperipherie durcheinander. Du hast also schonmal INTOSC als primären Taktgeber eingestellt, das ist soweit in Ordnung wenn nichts anderes verlangt wurde. Jetzt zum Timer, der so konfiguriert werden kann, dass er von der primären Taktquelle gespeist wird. Dafür ist das Bit namens T0CS im Register T0CON auf logisch 0 zu setzen.

Wenn du ins Datenblatt auf Seite 159 bis 161 schaust, siehst du die Beschreibung der T0CON Bits und ein Blockdiagram, das die Funktion des Timers beschreibt (einmal im 8-Bit Modus und einmal im 16-Bit Modus, die Funktionsweise ist aber prinzipiell identisch, wie man sieht). Das Signal oben links stellt den Primärtakt (FOSC/4) dar. Dieser wird auf einen Multiplexer geführt, der es ermöglicht zwischen zwei Taktquellen umzuschalten. Der dünne Strich, der vom Multiplexer nach unten weggeht, zeigt das T0CS-Bit das die Umschaltung ermöglicht.

Erst dahinter kommt der Prescaler und dahinter erst die eigentlichen Timer-Register. In diesem Diagramm siehst du auch, dass rechts ein Ausgang für den Überlauf weggeht. Dort wird das Interrupt-Ereignis ausgelöst, der primäre Takt hat damit nichts zu schaffen.

Wenn du das verstanden hast wird dir vieles einfacher erscheinen.

Nochmal vereinfachend zusammengefasst:

Der primäre Takt bestimmt, wie schnell die CPU arbeitet.
Die Timer werden benutzt, um zeitgesteuerte Ereignisse auszulösen.

Gruß,
Edson

Offline Edson

  • Sr. Member
  • ****
  • Beiträge: 410
    • Profil anzeigen
Re:Taktquelle für Timer0 (PIC18F45K22)
« Antwort #18 am: März 01, 2012, 17:04:14 Nachmittag »
Welchen PIC-Takt und Zähler benötige ich, um den Überlauf des Zählers (TMR0IF-->1) alle 1ms zu erhalten?

Das kann man ausrechnen. Normalerweise geht es aber anders herum: Du hast einen gegebenen Takt, den du so herunter teilst, dass das entsprechende Interval entsteht.

Geh das doch mal gedanklich mit den 8MHz INTOSC durch. Welcher Timer-Modus ist dann angebracht, reichen 8 oder nimmt man doch besser 16 Bit? Wie komme ich auf die Einstellungen die die geringste Abweichung von der Sollfrequenz erzeugen?

Gruß,
Edson

Offline Austrianer

  • Newbie
  • *
  • Beiträge: 30
    • Profil anzeigen
Re:Taktquelle für Timer0 (PIC18F45K22)
« Antwort #19 am: März 02, 2012, 11:01:13 Vormittag »
Das heißt, ich benötige einen Takt von etwa 1000Hz. Dann kann ich den Timer nach beliebiger Anzahl von Takten (1Takt = 1ms), überlaufen lassen.

Wenn ich den Timer nach 100ms überlaufen lassen möchte, muss der Zähler bei 100Takten das Zählen beenden und beim 101 Takt überlaufen oder?

z.B.:

1MHz / 4 = 0,25MHz

0,25MHz / 256 = 976,5625Hz
« Letzte Änderung: März 02, 2012, 11:06:16 Vormittag von Austrianer »

Offline Edson

  • Sr. Member
  • ****
  • Beiträge: 410
    • Profil anzeigen
Re:Taktquelle für Timer0 (PIC18F45K22)
« Antwort #20 am: März 02, 2012, 13:09:05 Nachmittag »
Beide Teile deines vorigen Beitrags sind für sich gesehen nicht ganz falsch, passen aber nicht zueinander.

Konzentrieren wir uns auf den zweiten Teil, wo du schon annähernd auf dem richtigen Weg bist.
Gehen wir also von einem 1MHz Oszillator am primären Takteingang aus, dann stimmt deine Rechnung und der Timer wird alle 1,024ms einen Interrupt auslösen wenn der Prescaler nicht aktiviert ist (also FOSC/4 am Timereingang anliegen).
Da keine Angabe über die Genauigkeit vorliegt, sollte das erstmal passen. Es geht zwar noch genauer, aber das findest du bestimmt selbst noch raus.

Für das Programm in der ISR spielt das jetzt keine Rolle, ob 1,02 oder 1,00ms zwischen zwei Interrupt-Ereignissen liegen. Du brauchst Speicherplatz für den Parameter time_ms, der an die Funktion übergeben wird und in der ISR als Zähler fungiert. Am besten reservierst du den Platz gleich zweimal, damit die Zählroutine immer wieder mit dem gewünschten Wert geladen werden kann.

Das sollte dann etwa so aussehen:
// globale Variablen
volatile unsigned int blink_wert;
volatile unsigned int blink_wert_zaehler;

...

void isr()
{
    if(!--blink_wert_zaehler)
    {
        blink_wert_zaehler = blink_wert;
        LATD = ~LATD;
    }
}

...


void Blink(unsigned int time_ms)
{
    blink_wert = time_ms;
    blink_wert_zaehler = blink_wert;
}

void main()
{
    ... // internen Oszillator für 1MHz konfigurieren
    ... // Timer initialisieren, Interrupt erlauben
    // Port D für LEDs initialisieren: (siehe Datenblatt, Seite 148)
    LATD = 0x00;
    TRISD = 0x00;
    ANSELD = 0x00;

    ... // Interrupts global zulassen (lies die Beschreibung von GIE und PEIE im INTCON Register)
    
    Blink(100);
    while(1);    // Endlosschleife
}


An einigen Stellen musst du selbst noch Code hinzufügen bzw. herausfinden was da noch zu erledigen ist. Wir wollen ja am Ende auch die Zusatzaufgabe lösen.

Gruß,
Edson

P.S. Den Code nicht einfach per Copy/Paste übernehmen, er ist nicht getestet und soll nur der Veranschaulichung dienen.
« Letzte Änderung: März 03, 2012, 13:57:22 Nachmittag von Edson »

Offline Austrianer

  • Newbie
  • *
  • Beiträge: 30
    • Profil anzeigen
Re:Taktquelle für Timer0 (PIC18F45K22)
« Antwort #21 am: März 02, 2012, 22:34:42 Nachmittag »
Die erste Aufgabenstellung ist zu 90% erfüllt. Es sollten nur mehr kleine Änderungen (Formatierung, Funktionsauslagerung, ...) notwendig sein oder habe ich etwas übersehen?

Ich kann der Funktion blink() einen Wert (in ms) für die Leucht- und Dunkelzeit übergeben.

 :D Vielen DANK für die Hilfe :D

//globale Variablen
unsigned int blink_wert;
unsigned int counter=0;

void blink(unsigned int time_ms)
{
 //Timer0
 T0CON.PSA=1;
 T0CON.T0CS=0;
 T0CON.T08BIT=1;
 T0CON.TMR0ON=1;

 blink_wert=time_ms;
}

void interrupt(void)
{
 counter++;
 
 if(counter==blink_wert)
 {
  LATD=~LATD;
  counter=0;
 }
 
 INTCON.TMR0IF=0;
}

void main()
{
 //PORTD
 TRISD=0x00;
 LATD=0x00;
 
 //Internal Oscillator
 OSCCON.SCS0=0; //Bit ist unknown
 OSCCON.SCS1=1;
 OSCCON.OSTS=0;
 OSCCON.IRCF0=1;
 OSCCON.IRCF1=1;
 OSCCON.IRCF2=0;
 
 //Interrupt
 INTCON.TMR0IE=1;
 INTCON.GIE=1;
 
 while(1)
 {
  blink(60000); //Uebergabe der Leucht- und Dunkelzeit in ms
 }
}

Offline Austrianer

  • Newbie
  • *
  • Beiträge: 30
    • Profil anzeigen
Re:Taktquelle für Timer0 (PIC18F45K22)
« Antwort #22 am: März 03, 2012, 11:07:46 Vormittag »
Der Code sollte jetzt passen:

//globale Variablen
volatile unsigned int blink_wert;
volatile unsigned int counter=0;

void blink(unsigned int time_ms)
{
 //Timer0
 T0CON.PSA=1;
 T0CON.T0CS=0;
 T0CON.T08BIT=1;
 T0CON.TMR0ON=1;

 blink_wert=time_ms;
}

void interrupt(void)
{
 counter++;
 
 if(counter==blink_wert)
 {
  LATD=~LATD;
  counter=0;
 }
 
 INTCON.TMR0IF=0;
}

void init(void)
{
 //PORTD
 TRISD=0x00;
 LATD=0x00;

 //Internal Oscillator
 OSCCON.SCS0=0; //Bit ist unknown
 OSCCON.SCS1=1;
 OSCCON.OSTS=0;
 OSCCON.IRCF0=1;
 OSCCON.IRCF1=1;
 OSCCON.IRCF2=0;

 //Interrupt
 INTCON.TMR0IE=1;
 INTCON.GIE=1;
}

void main()
{
 init();
 
 while(1)
 {
  blink(1000); //Uebergabe der Leucht- und Dunkelzeit in ms
 }
}

Warum ist es notwendig, für die globalen Variablen "volatile" zu verwenden?

Offline Edson

  • Sr. Member
  • ****
  • Beiträge: 410
    • Profil anzeigen
Re:Taktquelle für Timer0 (PIC18F45K22)
« Antwort #23 am: März 03, 2012, 14:04:18 Nachmittag »
Zitat
Warum ist es notwendig, für die globalen Variablen "volatile" zu verwenden?

Eigentlich ist es nur für die Variable blink_wert nötig, weil diese theoretisch im Hauptprogramm geändert werden könnte und der Compiler dies nicht automatisch voraussetzt. Da du "counter" in der ISR initialisierst und nur dort verwendest, ist die volatile-Deklaration dort nicht nötig.

Gruß,
Edson

Offline Austrianer

  • Newbie
  • *
  • Beiträge: 30
    • Profil anzeigen
Re:Taktquelle für Timer0 (PIC18F45K22)
« Antwort #24 am: März 03, 2012, 15:43:08 Nachmittag »
Habe ich soeben entfernt.

Vielleicht kannst du mir bitte bei der zweiten Aufgabenstellung noch einmal unter die Arme greifen?  :-[

Benötige ich bei diesem Vorhaben einen Low_Interrupt und einen Hight_Interrupt?
« Letzte Änderung: März 04, 2012, 20:20:18 Nachmittag von Austrianer »

Offline Edson

  • Sr. Member
  • ****
  • Beiträge: 410
    • Profil anzeigen
Re:Taktquelle für Timer0 (PIC18F45K22)
« Antwort #25 am: März 05, 2012, 10:12:27 Vormittag »
Zitat
Benötige ich bei diesem Vorhaben einen Low_Interrupt und einen Hight_Interrupt?

Nein. Du hast ja gesehen wie man ein Interrupt-Flag am Ende der ISR zurücksetzt. Du kannst auch ein oder mehrere Interrupt-Flags zu Beginn der ISR abfragen um rauszufinden welches Ereignis ausgelöst hat.

Offline Austrianer

  • Newbie
  • *
  • Beiträge: 30
    • Profil anzeigen
Re:Taktquelle für Timer0 (PIC18F45K22)
« Antwort #26 am: März 05, 2012, 17:26:05 Nachmittag »
Das ist mein Lösungsansatz für die erweiterte Aufgabenstellung.

Zur Info: RB0 (Taster) --> Pull Down

//globale Variablen
volatile unsigned int blink_wert;

void blink(unsigned int time_ms)
{
 //Timer0
 T0CON.PSA=1;
 T0CON.T0CS=0;
 T0CON.T08BIT=1;
 T0CON.TMR0ON=1;

 blink_wert=time_ms;
}

void interrupt(void)
{
 static unsigned int counter=0;
 
 if(INTCON.INT0IF==1)
 {
  LATD=0xFF;
  INTCON.TMR0IE=0;
  INTCON.INT0IF=0;
 }
 else if(INTCON.TMR0IF==1)
 {
  counter++;
  if(counter==blink_wert)
  {
   LATD=~LATD;
   counter=0;
  }
  INTCON.TMR0IF=0;
 }
}

void init(void)
{
 //PORTD
 TRISD=0x00;
 LATD=0x00;

 //Internal Oscillator
 OSCCON.SCS0=0; //Bit ist unknown
 OSCCON.SCS1=1;
 OSCCON.OSTS=0;
 OSCCON.IRCF0=1;
 OSCCON.IRCF1=1;
 OSCCON.IRCF2=0;

 //Interrupt
 INTCON.TMR0IE=1;
 INTCON.GIE=1;
 
 //INT0 ???
 INTCON.INT0IE=1;
 INTCON2.RBPU=1;
 INTCON2.INTEDG0=1;
}

void main()
{
 init();
 blink(2000); //Uebergabe der Leucht- und Dunkelzeit in ms
 while(1);
}
« Letzte Änderung: März 08, 2012, 16:14:59 Nachmittag von Austrianer »

Offline Austrianer

  • Newbie
  • *
  • Beiträge: 30
    • Profil anzeigen
Re:Taktquelle für Timer0 (PIC18F45K22)
« Antwort #27 am: März 07, 2012, 10:08:04 Vormittag »
Leider funktioniert es nicht.

INTCON.INT0IF wird nich 1 wenn RB0 (Taster) gedrückt.

Bin ich am richtigem Weg?
« Letzte Änderung: März 07, 2012, 15:19:00 Nachmittag von Austrianer »

Offline Edson

  • Sr. Member
  • ****
  • Beiträge: 410
    • Profil anzeigen
Re:Taktquelle für Timer0 (PIC18F45K22)
« Antwort #28 am: März 08, 2012, 11:27:23 Vormittag »
Zitat
Zur Info: RB0 (Taster) --> Pull Down

Was soll das bedeuten? Wir hatten doch gesagt, wenn die Taste an einen Interrupt-Eingang geht, muss sie in Hardware entprellt sein. Ein PullDown-Widerstand leistet das nicht und ist obendrein total überflüssig, wofür hast du denn eigentlich die integrierten PullUp-Widerstände an PORTB dazu geschalten?

Erstmal muss die Hardware und ihr Verhalten definiert sein, dann kommt die Software.

Gruß,
Edson

Offline Austrianer

  • Newbie
  • *
  • Beiträge: 30
    • Profil anzeigen
Re:Taktquelle für Timer0 (PIC18F45K22)
« Antwort #29 am: März 08, 2012, 12:31:12 Nachmittag »
Guten Tag,

es handelt sich dabei um die ersten sinnlosen Gehversuche.


Mein RB0 ist jetzt ohne Pull-Up-R und Pull-Down-R (Entwicklungsboard).

Die integrierten Pull-Up-R am PORTB sind ebenfalls nicht mehr aktiv.


Mit dem Begriff Hardware meinst du den PIC oder?



« Letzte Änderung: März 08, 2012, 12:34:22 Nachmittag von Austrianer »

 


* Recent Topics