Forum: Mikrocontroller und Digitale Elektronik PIC18F46K22 OSCON / FOSC / TIMER Probleme


von Thorsten R. (Firma: Robert Bosch GmbH) (thorsten_roh)


Lesenswert?

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

von Max H. (hartl192)


Lesenswert?

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

: Bearbeitet durch User
von Thorsten R. (Firma: Robert Bosch GmbH) (thorsten_roh)


Lesenswert?

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.

von Thorsten R. (Firma: Robert Bosch GmbH) (thorsten_roh)


Lesenswert?

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
}

von Chris B. (dekatz)


Lesenswert?

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.

von Thorsten R. (Firma: Robert Bosch GmbH) (thorsten_roh)


Lesenswert?

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.

von Thorsten R. (Firma: Robert Bosch GmbH) (thorsten_roh)


Lesenswert?

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
Noch kein Account? Hier anmelden.