Forum: Mikrocontroller und Digitale Elektronik PIC18F timer zählt nicht


von Patrick (Gast)


Lesenswert?

Hallo,

ich befasse mich zur Zeit mit dem PIC18F2420
Nun möchte ich, die Werte des Registers TMR0H auf 5 7-Segmentanzeigen 
ausgeben. Beim einschalten stehen aber alle Segmente dauerhaft auf 0.

Den Timer0 habe ich konfiguriert und er will einfach nicht anlaufen.

Als Takt benutze ich ein 4Mhz Quarz.

>>T0CONbits.T08BIT = 0;
  T0CONbits.T0CS = 1;
  T0CONbits.T0SE = 0;
  T0CONbits.PSA = 0;
  T0CONbits.T0PS2 = 1;
  T0CONbits.T0PS1 = 1;
  T0CONbits.T0PS0 = 1;
  T0CONbits.TMR0ON = 1;

>>while (1)
  {
  time = TMR0H;

  B = time / 10000;

  C = ( time - ( B * 10000) ) / 1000;

  D = ( time - ( B * 10000 ) - ( C * 1000 )) / 100;

  E = ( time - ( B * 10000 ) - ( C * 1000 ) - ( D * 100 )) / 10;

  F =  time - ( B * 10000 ) - ( C * 1000 ) -  (D * 100 ) -  ( E * 10 );

Der Wert des Registers TMR0H wird also geteilt und den Variablen von C-F 
zugeordnet, welche ich dann an PortC ausgeben kann, weil ich alle Werte 
in einem Array als Zahl für das 7-Segment zugeordnet habe.

Wieso zählt der Timer nicht?

Mfg Patrick

von Klaus (Gast)


Lesenswert?

Patrick schrieb:
> time = TMR0H;
>
>   B = time / 10000;

geraten: TMR0H wird nicht größer als 255

255/1000 ==> 0

MfG Klaus

von Patrick (Gast)


Lesenswert?

Danke für die schnelle Antwort.

Nehme ich jetzt den Wert 255 für TMR0H an, dann
hätte ich für das erste Segment den Wert C also "0".
Für das 2. Segment auch "0"
und für das 3. Segment "2"
das 4. den Wert "5"
und das 5. Segment schließlich auch "5"

Also kann es daran nicht liegen.
Selbst wenn ich jetzt den Programmcode geändert habe in:

>>B = time / 100;

  C = time - ( B * 100) / 10;

  D = time - ( C * 10 );

passt es nicht.

Zuvor habe ich einfach versucht, ein Segment zum blinken zum bringen, 
indem das Segment angeschaltet wird, sobald ein bestimmter Wert im 
Register TMR0H erreicht wurde.

Allerdings war das Segment dauerhaft am leuchten.

Desweiteren komme ich auf einen maximalen Zahlenwert von 65535 für das 
Register, da ich den Timer als 16bit definiert habe.

Mfg Patrick

von Klaus (Gast)


Lesenswert?

Ich kenn jetzt zwar diesen PIC nicht, aber TMR0H klingt, als ob es auch 
ein TMR0L gibt.

MfG Klaus

von Patrick (Gast)


Lesenswert?

Ja gibt es, bekomme aber mit beiden kein Ergebis.

Die Konfiguration stimmt aber soweit?

von K. D. (deka)


Lesenswert?

Patrick schrieb:
> Als Takt benutze ich ein 4Mhz Quarz.

Patrick schrieb:
> T0CONbits.T0CS = 1;

Also du hast 2 Quarze?

bit 5 T0CS: Timer0 Clock Source Select bit
1 = Transition on T0CKI pin
0 = Internal instruction cycle clock (CLKO)

Ich habe den Verdacht dass dein Timer garnicht läuft weil du am T0CKI 
keinen externen Oszillator dran hast. Wenn du den Versorgungstakt (Fosc) 
abgreifen willst solltest du dringend

T0CONbits.T0CS = 0;

wählen.

Ist dir das klar, was es mit dem TMR0 Oszillator auf sich hat? Das ist 
ein externer Takteingang, an dem man gewöhnlich einen Uhrenquarz 
anschließt falls man eine Zeitbasis für Uhrzeit braucht. Wenn du auf 
deinem Board aber nur einen Oszillator (Main-Oscillator) hast, dann 
darfst du nicht als Taktquelle für TMR0 den externen TMR0-Osziallator 
auswählen.

Patrick schrieb:
> Zuvor habe ich einfach versucht, ein Segment zum blinken zum bringen,
> indem das Segment angeschaltet wird, sobald ein bestimmter Wert im
> Register TMR0H erreicht wurde.
>
> Allerdings war das Segment dauerhaft am leuchten.

Das wäre auch wenn der Timer laufen würde nicht verwunderlich.

4.000.000 Hz / 4 = 1.000.000 Hz
1.000.000 Hz / 2^16 = 15,5 Hz
15,5 Hz * 2 = 31 Hz.

31 Hz das nimmt dein Auge als durchgehendes Leuchten wahr. Und das wäre 
der Worstcase. (min. Frequenz)
Ab 10 Hz darfst du davon ausgehen, dass dein Auge es nicht mehr als 
Blinken wahrnimmt sondern noch als Abstufung in der Helligkeit.

Patrick schrieb:
>>>while (1)
>   {
>   time = TMR0H;
>
>   B = time / 10000;
>
>   C = ( time - ( B * 10000) ) / 1000;
>
>   D = ( time - ( B * 10000 ) - ( C * 1000 )) / 100;
>
>   E = ( time - ( B * 10000 ) - ( C * 1000 ) - ( D * 100 )) / 10;
>
>   F =  time - ( B * 10000 ) - ( C * 1000 ) -  (D * 100 ) -  ( E * 10 );

Das ist ziemlicher Bullshit. Beschäftige dich lieber mit Interrupts und 
mach es dadrauf. So verschwendest du nur Ressourcen.

von TK (Gast)


Lesenswert?

Kann das evtl. ein Tücke vom Compiler sein?
Wenn ich mir ansehe:
B = time / 10000;
C = ( time - ( B * 10000) ) / 1000;
usw

dann kann ich mir vorstellen, dass der Compiler folgendes daraus macht:
C = ( time - ( (time / 10000) * 10000) ) / 1000;
C = (time - time) / 1000 = 0

Ich glaube, dass Klaus recht hat mit dem TMR0H und dem TMR0L Register.
Du müsstest dann auf beide Register zurückgreifen (256*TMR0H + TMR0L 
oder TMR0). Aber dafür müsste man wissen, welcher Compiler eingesetzt 
ist und wie dein weiterer Code aussieht (Deklarationen der Variablen)

Gruß
TK

von Patrick (Gast)


Lesenswert?

Danke für die Antwort erstmal.

Also das mit dem Takt-Engang habe ich soweit verstanden. Ich habe nicht 
hinzugefügt, dass ich bereits beide Varianten versucht habe. Also einmal 
mit externem und internem Takt. Beides hat kein Ergebnis geliefert.

Es könnte also sein, dass alles funktioniert hat, weil mein Segment 
dauerhaft am leuchten war. Dann kann es nurnoch sein, dass ich einen 
Fehler bei meiner Rechnung hatte weil ich ca. 5Hz anzeigen lassen 
wollte. Kann aber auch sein, dass ich da was nicht ganz verstanden habe.

Zum Thema "Interrupts" muss ich sagen, dass ich mich da noch nicht 
reingearbeitet habe, weil ich erst seit kurzem mit dem Pic arbeite.

Jetzt Frage ich mich nurnoch wie die Schaltung richtig aussieht, wenn 
ich ein Quarz als externen Takt nutze, weil ich glaube da hatte ich 
einen Fehler bei meiner Schaltung.

Mfg Patrick

von GroberKlotz (Gast)


Lesenswert?

1. TMR0H ist gebuffert, nicht direkt lesbar/beschreibbar und wird nur 
aktualisiert wenn TMR0L gelesen wird!
2. Zur BCD-Dekodierung muss das H-Byte + L-Byte als ganzer 16Bitwert zur 
Verfügung stehen, denn nur durch Teilen des H-Byte durch Tausender usw 
ergibt dies keine sinnvollen Tausenderstellen.
3. T0CON,T0CS = 1 erfordert einen extern zugeführten Takt an OSC1 damit 
ist nicht der übliche Quarzoscillator zwischen OSC1, OSC2 gemeint!

Patrick schrieb:
> Jetzt Frage ich mich nurnoch wie die Schaltung richtig aussieht, wenn
> ich ein Quarz als externen Takt nutze, weil ich glaube da hatte ich
> einen Fehler bei meiner Schaltung.

vgl. Datenblatt 2.0 OSCILLATOR CONFIGURATIONS
mfG
GroberKlotz

von Patrick (Gast)


Lesenswert?

TK schrieb:
> Kann das evtl. ein Tücke vom Compiler sein?
> Wenn ich mir ansehe:
> B = time / 10000;
> C = ( time - ( B * 10000) ) / 1000;
> usw
>
> dann kann ich mir vorstellen, dass der Compiler folgendes daraus macht:
> C = ( time - ( (time / 10000) * 10000) ) / 1000;
> C = (time - time) / 1000 = 0

Das dürft nicht falsch sein, weil ich zuvor ei Thermometer mit der 
Schaltung aufgebaut habe und dort die Werte aus dem ADC mit der selben 
Methode angezeigt habe. Das funktionierte einwandfrei.

TK schrieb:
> Ich glaube, dass Klaus recht hat mit dem TMR0H und dem TMR0L Register.
> Du müsstest dann auf beide Register zurückgreifen (256*TMR0H + TMR0L
> oder TMR0). Aber dafür müsste man wissen, welcher Compiler eingesetzt
> ist und wie dein weiterer Code aussieht (Deklarationen der Variablen)

Ich benutze den MCC18-Compiler

Wegen dem weiteren Code schreibe ich jetzt nur Teile hier rein, weil es 
sonst zu lang wird.


>>const char SSEG[] = {0b00011000,...)  //Anzeige auf dem 7-Seg

  TRISA = 0b00000001;
  TRISB = 0b00000000;
  TRISC = 0b00000000;

  void main(void)
  {

  T0CONbits.T08BIT = 0;    //Bit 6
  T0CONbits.T0CS = 0;      //Bit 5
  T0CONbits.T0SE = 0;      //Bit 4
  T0CONbits.PSA = 0;      //Bit 3
  T0CONbits.T0PS2 = 1;    //Bit 2
  T0CONbits.T0PS1 = 1;    //Bit 1
  T0CONbits.T0PS0 = 1;    //Bit 0
  T0CONbits.TMR0ON = 1;

  while (1)
  {

  time = TMR0H;

  B = time / 100;
  C = time - ( B * 100) / 10;
  D = time - ( C * 10 );

  Delay100TCYx(10);
  T1 = 1;
  PORTB = SSEG["B"];
  T5 = 0;

  Delay100TCYx(10);
  T5 = 1;
  PORTB = SSEG[C];
  T4 = 0;

  }

T1-T5 Sind alles Transistoren die die Segmente ansteuern und extern 
deklariert wurden. Das funktioniert aber.

von Patrick (Gast)


Lesenswert?

Folgendes habe ich erreicht:

ändere ich die Zeile:

>>timer = TMR0H;

in

>>timer = 256 * TMR0H + TMR0L;

so bekomme ich was angeziegt. Läuft nur ziemlich schnell. Was mich aber 
nicht groß stört. Allerdings habe ich eingestellt

>> T0CONbits.T0CS = 1

Entferne ich die Strippe am eingang RA5 zählt er weiter. Wieso?

von Michael S. (rbs_phoenix)


Lesenswert?

Patrick schrieb:
> Wegen dem weiteren Code schreibe ich jetzt nur Teile hier rein, weil es
> sonst zu lang wird.

Das glaub ich nicht. Was spricht denn dagegen, alles zu posten.

Patrick schrieb:
> PORTB = SSEG["B"];
> ...
> PORTB = SSEG[C];

Das erste dürfte falsch sein, da dann der Hexadezimalwert für das B 
genommen wird (ich glaube 66dezimal) und nicht der Wert von der 
Variable.


Patrick schrieb:
> Allerdings habe ich eingestellt
>
>>> T0CONbits.T0CS = 1

Für deine Anwendung sollte der Fosc reichen. Zum testen allemal.


Patrick schrieb:
> Entferne ich die Strippe am eingang RA5 zählt er weiter. Wieso?

Weil der Eingang offen ist und schwingt.

Patrick schrieb:
> Läuft nur ziemlich schnell.

Naja. Du hast jetzt die vollen 16bit (die auch "timer" hoffentlich hat). 
Also bist du ziemlich schnell über 1000 (0,256sek). Danach wird die 
nurnoch bullshit angezeigt.. denn B = time / 100 ist dann > 10. Und wie 
willst du eine 10 auf EINER 7-Segmentanzeige darstellen? Der Aufruf wäre 
also "PORTB = SSEG[ B];", somit z.B. SSED[10]. Das Array hat aber 
bestimmt nur die Indize 0-9. Also geht er über den Speicherbereich 
hinaus und nimmt Daten, die nicht dafür gedacht sind.

von Patrick N. (petzibaer69)


Lesenswert?

So, nun funktioniert alles.

Jetzt habe ich noch eine letzte Frage.

Damit es funktioniert, habe ich

>>timer = 256 * TMR0H + TMR0L;

in

>>timer = 128 * TMR0H + TMR0L;

eingestellt.

Die Anzeige fängt bei 0 an und hört bei 32k und ein paar kaputten auf. 
Ich schätze es sind 2^15 also 32768
Erwartet habe ich 2^16, da ich den Timer als 16 Bit nutze. Wie kommt das 
zustande und was hat die 128 in meiner Rechnung auf sich?

Mfg Patrick

von Klaus (Gast)


Lesenswert?

Patrick N. schrieb:
> was hat die 128 in meiner Rechnung auf sich?

Gute Frage. Wenn Bits oder Bytes zusammensetze, dann schiebe und odere 
ich. Also High-Byte um 8 nach links und Low-Byte dazugeodert.

MfG Klaus

von Patrick N. (petzibaer69)


Lesenswert?

Klaus schrieb:

> Gute Frage. Wenn Bits oder Bytes zusammensetze, dann schiebe und odere
> ich. Also High-Byte um 8 nach links und Low-Byte dazugeodert.

Sry aber diese Antwort verstehe ich grade nicht =)

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.