Hallo, ich arbeite mich gerade in das Thema C für µC ein und arbeite mit einem PIC18F46K22. Beim Thema Timer und Oscillator bin ich jetzt auf ein Problem gestoßen an dem ich nicht weiterkomme. Mein Programm soll mit dem loslassen eines Öffners den Timer0 im 16bit Mode starten. Wird der Öffner dann wieder betätigt soll die Zeit gestoppt und auf einem LC-Display angezeigt werden. Die Entwicklungsumgebung ist das PICDEM 2 PLUS, PICkit3 und der C18 Compiler. Die Werte die mir das Display ausgibt sollen im µsec sein, ergeben jedoch keinen Sinn. ______________________________________________________________________ ______________________________________________________________________ ______________________________________________________________________ _______ #include <p18f46k22.h> #include <delays.h> #include <stdio.h> #include <string.h> #include "Lcd.h" //#include <timers.h> #pragma config FOSC = INTIO7 #define Zeitfaktor 2048 // 1 Takt sind 2048µs da HFINTOSC auf 500kHz unsigned long ulongint_Zeit = 0x0; //für die vom Timer gezählte Zeit unsigned char uchar_Timerstart = 0; char char_Zeit[16]=""; int i; /*---------------------------------------------------------------------- ------ ----- ----- ----- Initialisierung ----- ----- ----- ------------------------------------------------------------------------ ---*/ void init (void) { //internen Oszillator konfigurieren OSCCONbits.IRCF=0b010; // HFINTOSC interner Takt auf 500kHz // -> CLKOUT = 125kHz //PORT B als Ausgang konfigurieren LATB=0x00; //PORTB komplett auf 0 ANSELB=0x00; //Eingänge analog sperren, digital aktiv TRISB=0x01; //PORTB als Ausgang, PortB0 (RB0) als Eingang //PORT D als Ausgang für LCD-Display LATD=0x00; ANSELD = 0x00; TRISD=0x00; //TIMER0 konfigurieren // T0CONbits.TMR0ON = 0; // Stop the timer T0CONbits.T08BIT = 0; // Run in 16-bit mode T0CONbits.T0CS = 0; // Use system clock (CLKOUT) to increment timer T0CONbits.PSA = 0; // A prescaler is assigned for Timer0 T0CONbits.T0PS2 = 1; // Use a 1:256 prescaler T0CONbits.T0PS1 = 1; T0CONbits.T0PS0 = 1; // initialisiere LCD-Dsiplay LCDInit(); LCDWriteStr(" STOPPUHR"); } // Funktion um Highbyte und Lowbyte zu addieren unsigned long High_and_Low (char char_High, char char_Low) { char adl= char_High; char adh= char_Low; unsigned long result = adh*256; result=result+adl; return result; } /*---------------------------------------------------------------------- ------ ----- ----- ----- MAIN ----- ----- ----- ------------------------------------------------------------------------ ---*/ void main(void) { init(); while(1) { if (PORTBbits.RB0==0 && uchar_Timerstart == 0) // starte Timer // mit Tastendruck { uchar_Timerstart=1; // statt Startschleife kann jetzt // Stoppschleife durchlaufen LCDClear(); LCDGoto(0,0); LCDWriteStr(" START"); while (PORTBbits.RB0 == 0) {} T0CONbits.TMR0ON = 1; // Start Timer nach loslassen Taster } // stoppe Timer mit Tastendruck, speichere Timerwert in Variable und setze // Timerwert wieder auf 0 if (PORTBbits.RB0 == 0 && uchar_Timerstart == 1) { T0CONbits.TMR0ON = 0; // Stop the timer // so hat es nicht funktioniert: // ulongint_Zeit + TMR0H; // Timer_Highwert // ulongint_Zeit = ulongint_Zeit << 8; // Schiebe ein Byte nach links damit Highbyte von Timer auch im Highbyte von uint_Zeit steht // ulongint_Zeit = ulongint_Zeit + TMR0L; // Timer Lowwert in den Lowbereich von uint_Zeit // TMR0H=0; TMR0L=0; // Timer auf Anfang // ulongint_Zeit = ulongint_Zeit * Zeitfaktor; //mit der Funktion funktioniert es ulongint_Zeit = High_and_Low(TMR0H, TMR0L) * Zeitfaktor; TMR0H=0; TMR0L=0; // Reset Timer0 LCDClear(); LCDGoto(0,0); ultoa(ulongint_Zeit, char_Zeit); // Integer to Ascii // (String) i=0; while (char_Zeit[i] != 0x00) // Solange nicht NUL { LCDPutChar(char_Zeit[i]); i++; } LCDGoto(0,1); LCDWriteStr("Microsekunden"); ulongint_Zeit = 0x0000; ultoa(ulongint_Zeit, char_Zeit); // Integer to Ascii (String) // char_Zeit wieder auf "NUL" Delay10KTCYx(2); uchar_Timerstart=0; // statt Stoppschleife // kann jetzt wieder // Startschleife laufen } } } ______________________________________________________________________ ______________________________________________________________________ ______________________________________________________________________ _______ Ich würde mich über Hilfe und Anregungen freuen. Thorsten
Das nächste Mal bitte Syntax Highlighting verwenden:
1 | [c]C-Code[/c] |
Thorsten Rohde schrieb: > ergeben > jedoch keinen Sinn. Kannst du das genauer spezifizieren? Edit: Thorsten Rohde schrieb: > unsigned long High_and_Low (char char_High, char char_Low) > { > char adl= char_High; > char adh= char_Low; > [...] > ulongint_Zeit = High_and_Low(TMR0H, TMR0L) * Zeitfaktor; Ein Blick ins Datenblatt (FIGURE 11-2) zeigt, dass es besser wäre TMR0L als erstes zu lesen. Thorsten Rohde schrieb: > TMR0H=0; TMR0L=0; // Reset Timer0 Beim löschen passt die Reihenfolge
Danke schon mal für die schnelle Antwort, das mit dem Syntax Highlighting kannte ich noch nicht da ich mich gestern erst hier angemeldet habe. Das auslesen von Timer0 High und Low habe ich von der Reihenfolge geändert und auch gleich noch einen Fehler in meiner Funktion zum Addieren beider gefunden, da hatte ich High- und Lowwert auch vertauscht. Nun zum spezifizieren des Verhaltens: Wenn ich das richtig verstanden habe lege ich mit
1 | OSCCONbits.IRCF=0b010; |
meinen Takt auf 125kHz. Mit dem Prescaler auf 1:256 komme ich dann auf einen Wert von 2048µsec pro Zählerwert, müsste also nur den Wert des Zählers * 2048 rechnen und bekomme die abgelaufene Zeit. Wenn ich ein Rechteck auf meinen Eingang gebe startet der Timer bei steigender Flanke und stoppt bei der nächsten fallenden. Bei 10Hz müssten das also 0,05sec bzw. 50.000 µsec sein. Das Ergebnis des Programms ist 49.152 µsec, passt also eigentlich. Bei 1Hz sollten es 500.000 µsec sein. Das Ergebnis ist allerdings 4.294.946.816 µsec, also vollkommen falsch. Bei 100Hz kommt statt 5000 der Wert 2048 und bei 50Hz statt 10.000 der Wert 6144.
Hier der Code aktualisiert und mit Syntax Highlightning
1 | #include <p18f46k22.h> |
2 | #include <delays.h> |
3 | #include <stdio.h> |
4 | #include <string.h> |
5 | #include "Lcd.h" |
6 | //#include <timers.h>
|
7 | |
8 | #pragma config FOSC = INTIO7
|
9 | |
10 | #define Zeitfaktor 2048 // 1 Takt sind 2048µs da HFINTOSC auf 500kHz
|
11 | |
12 | unsigned long ulongint_Zeit = 0x0; //für die vom Timer gezählte Zeit |
13 | unsigned char uchar_Timerstart = 0; |
14 | char char_Zeit[16]=""; |
15 | int i; |
16 | |
17 | /*----------------------------------------------------------------------------
|
18 | ----- -----
|
19 | ----- Initialisierung -----
|
20 | ----- -----
|
21 | ---------------------------------------------------------------------------*/
|
22 | void init (void) |
23 | {
|
24 | //internen Oszillator konfigurieren
|
25 | OSCCONbits.IRCF=0b010; //HFINTOSC interner Takt auf 500kHz -> CLKOUT = 125kHz |
26 | |
27 | //PORT B als Ausgang konfigurieren
|
28 | LATB=0x00; //PORTB komplett auf 0 |
29 | ANSELB=0x00; //Eingänge analog sperren, digital aktiv |
30 | TRISB=0x01; //PORTB als Ausgang, PortB0 (RB0) als Eingang |
31 | |
32 | //PORT D als Ausgang für LCD-Display
|
33 | LATD=0x00; |
34 | ANSELD = 0x00; |
35 | TRISD=0x00; |
36 | |
37 | //TIMER0 konfigurieren
|
38 | //
|
39 | T0CONbits.TMR0ON = 0; // Stop the timer |
40 | T0CONbits.T08BIT = 0; // Run in 16-bit mode |
41 | T0CONbits.T0CS = 0; // Use system clock (CLKOUT) to increment timer |
42 | T0CONbits.PSA = 0; // A prescaler is assigned for Timer0 |
43 | T0CONbits.T0PS2 = 1; // Use a 1:256 prescaler |
44 | T0CONbits.T0PS1 = 1; |
45 | T0CONbits.T0PS0 = 1; |
46 | |
47 | // initialisiere LCD-Dsiplay
|
48 | LCDInit(); |
49 | LCDWriteStr(" STOPPUHR"); |
50 | }
|
51 | |
52 | // Funktion um Highbyte und Lowbyte zu addieren
|
53 | unsigned long Low_and_High (char char_Low, char char_High) |
54 | {
|
55 | char adh= char_High; |
56 | char adl= char_Low; |
57 | unsigned long result = adh*256; |
58 | result=result+adl; |
59 | return result; |
60 | }
|
61 | |
62 | /*----------------------------------------------------------------------------
|
63 | ----- -----
|
64 | ----- MAIN -----
|
65 | ----- -----
|
66 | ---------------------------------------------------------------------------*/
|
67 | void main(void) |
68 | {
|
69 | init(); |
70 | while(1) |
71 | {
|
72 | if (PORTBbits.RB0==0 && uchar_Timerstart == 0) // starte Timer durch Taste lösen |
73 | {
|
74 | uchar_Timerstart=1; //statt Startschleife kann jetzt Stoppschleife durchlaufen |
75 | LCDClear(); |
76 | LCDGoto(0,0); |
77 | LCDWriteStr(" START"); |
78 | while (PORTBbits.RB0 == 0) {} |
79 | T0CONbits.TMR0ON = 1; // Start the timer nach loslassen Taster |
80 | }
|
81 | |
82 | if (PORTBbits.RB0 == 0 && uchar_Timerstart == 1) //stoppe Timer mit Tastendruck, speichere Timerwert in Variable und setze Timerwert wieder auf 0 |
83 | {
|
84 | T0CONbits.TMR0ON = 0; // Stop the timer |
85 | |
86 | // so hat es nicht funktioniert:
|
87 | // ulongint_Zeit + TMR0H; // Timer_Highwert
|
88 | // ulongint_Zeit = ulongint_Zeit << 8; // Schiebe ein Byte nach links damit Highbyte von Timer auch im Highbyte von uint_Zeit steht
|
89 | // ulongint_Zeit = ulongint_Zeit + TMR0L; // Timer Lowwert in den Lowbereich von uint_Zeit
|
90 | // TMR0H=0; TMR0L=0; // Timer auf Anfang
|
91 | // ulongint_Zeit = ulongint_Zeit * Zeitfaktor;
|
92 | |
93 | ulongint_Zeit = Low_and_High(TMR0L, TMR0H) * Zeitfaktor; //mit der Funktion funktioniert es |
94 | |
95 | TMR0H=0; TMR0L=0; // Reset Timer0 |
96 | LCDClear(); |
97 | LCDGoto(0,0); |
98 | |
99 | ultoa(ulongint_Zeit, char_Zeit); // Integer to Ascii (String) |
100 | i=0; |
101 | while (char_Zeit[i] != 0x00) // Solange nicht NUL |
102 | {
|
103 | LCDPutChar(char_Zeit[i]); |
104 | i++; |
105 | }
|
106 | LCDGoto(0,1); |
107 | LCDWriteStr("Microsekunden"); |
108 | |
109 | ulongint_Zeit = 0x0000; |
110 | ultoa(ulongint_Zeit, char_Zeit); // Integer to Ascii (String) char_Zeit wieder auf "NUL" |
111 | Delay10KTCYx(20); |
112 | uchar_Timerstart=0; // statt Stoppschleife kann jetzt wieder Startschleife laufen |
113 | }
|
114 | }
|
115 | }
|
Thorsten Rohde schrieb: > > Bei 1Hz sollten es 500.000 µsec sein. Das Ergebnis ist allerdings > 4.294.946.816 µsec, also vollkommen falsch. > > Bei 100Hz kommt statt 5000 der Wert 2048 und bei 50Hz statt 10.000 der > Wert 6144. Das Problem dürfte die wilder Herumrechnerei mit unsigned long und unsigned char sein. unsigned long kann maximal 4.294.967.296 sein, zieht man davon deine errechneten 4.294.946.816 ab, bleiben genau 20480 übrig - zufälligerweise genau das 10 fache deines "Zeitfaktors 2048 !? Die anderen Ergebnisse: Bei einem theoretischen Wert von 5000µs und einer Zeitbasis von 2048µs zählt der Timer genau bis 1. Selbes git bei 10000µs, da zählt der Timer bis 3. Renchnen musst du mit Timer + 1. Wieso 2048 und 6144? Der Timer erhöht sich um 1 wenn der Prescaler überläuft. Also 0-2047µs = 0, 2048-4095µs = 1, ...... Also sind die beiden Zählerstände 1 bzw 3 - was auch die Werte 2048 und 6144 erklärt.
unsigned long habe ich gewählt da ich den 16bit Timerwert ja noch mit 2048 multipliziere. Timer +1 habe eingebaut, jetzt geht das ganze bis 1,9 Hz. Also bis der Timer den Wert 127 hat. Gehe ich mit der Zeit jetzt weiter hoch kommt als nächster Anzeigewert 4294707200. Der Zähle springt also theoretisch von 127 auf 2.097.024, also einen Wert der über dem Maximum eines 16bit Timers liegt.
Fehler gefunden:
1 | // Funktion um Highbyte und Lowbyte zu addieren
|
2 | unsigned long Low_and_High (char char_Low, char char_High) |
3 | {
|
4 | char adh= char_High; |
5 | char adl= char_Low; |
6 | unsigned long result = adh*256; |
7 | result=result+adl; |
8 | return result; |
9 | }
|
ich habe TMR0L und TMR0H als char übergeben, es muss jedoch unsigned char sein.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.