Forum: Mikrocontroller und Digitale Elektronik 8051:Timer - Reload und Teilerfaktoren


von R. B. (rabis)


Lesenswert?

Hi,

meine Uhr läuft viel zu schnell, doch warum?
Ich benutze Timer0 im Modus2 (8Bit,Autoreload)
Prozessor: AT89S8253 mit 22,1184 Mhz und x2 Mode

Nun zur Berechnung:
22118400 / 6   = 3686400  ( 6 wegen x1 Mode, sonst 12)
3686400  / 192 = 19200    ( Reload für Timer0 (256-64) = 0xC0 )
19200    / 64  = 300      ( tick1-Zähler in Interrupt-Routine)
300      /  3  = 100      ( tick2-Zähler in Interrupt-Routine)
100      / 100 = 1 s      ( ms-Zähler    in Interrupt-Routine)

Da müsste dann doch 1 s rauskommen, dacht ich mir ABER es funktioniert 
so
nicht. Selbst wenn ich den tick2 Teiler auf 6 verdopple ist noch zu 
schnell. Bei 12 ists zu langsam...
Die Baudrate (Timer1, reload 0xFA, 38400 Baud) funktioniert doch auch, 
wo ist der Knoten bei Timer0 bzw. in der Berechnung???

Danke für Eure Tipps!

Rabis

von R. W. (quakeman)


Lesenswert?

Zeig mal den dazugehörigen Code. Ansonsten können wir auch nur raten, 
wodran das Problem liegt. ;)

von R. B. (rabis)


Lesenswert?

Ja, gerne

main.h:
1
//--------------------------------------------------------------------
2
// Defines
3
4
#ifndef __MAIN
5
  #define __MAIN
6
#endif
7
8
#define x2                     1           // 0 or 1 , x2 mode
9
#define XtalFreq               22118400
10
#define Baudrate               38400       // 19200
11
//#define TH0_RELOAD             0x0
12
//#define TL0_RELOAD             0x0
13
#define ON        0
14
#define OFF       1
15
#define LED_GN   P0_0
16
#define LED_YE   P0_1
17
#define LED_RD   P0_2
18
#define Beeper   P0_3
19
20
//--------------------------------------------------------------------
21
22
__sbit __at (0x2F) BIT2F;
23
24
//--------------------------------------------------------------------

main.c
1
//--------------------------------------------------------------------
2
#include "./main.h"
3
#ifdef __MAIN
4
 #include <at89s8253.h>
5
 #include <stdio.h>            
6
 #include <serial_IO.h>
7
#endif 
8
//--------------------------------------------------------------------
9
unsigned char tick1,tick2,msec,seconds,minutes,hours,RELOAD_T0;
10
//--------------------------------------------------------------------
11
// Function: Timer 0 Initialisierung
12
13
void Timer0_Init (void) {
14
  TMOD  |= 0x02;            // Timer 0 Mode 2, 8 Bit Autoreload
15
  RELOAD_T0 = 192;
16
  TL0    = RELOAD_T0;
17
  TH0    = RELOAD_T0;        // TL0 reload value;
18
  IP     = 0x00;            // Interruptprioritaet  
19
  ET0    = 1;               // Timer 0 Interrupt EIN 
20
}
21
22
//--------------------------------------------------------------------
23
// Function: Timer 0 Interrupt
24
25
void Timer0_ISR (void) interrupt TF0_VECTOR using 1 {
26
  tick1++;
27
  if (tick1 == 64){
28
     tick1 = 0;
29
     tick2++;     
30
     if (tick2 == 12) {
31
        tick2 = 0;
32
        msec++;      
33
        if (msec == 100) {
34
           msec = 0;
35
           seconds++;
36
           LED_YE = !LED_YE; 
37
           BIT2F = 1;    
38
           if (seconds == 60) {
39
              seconds = 0;
40
              minutes++; 
41
              if (minutes == 60) {
42
                 minutes = 0;
43
                 hours++; 
44
                 if (hours == 24) {
45
                    hours = 0;
46
                 }  
47
              } 
48
           } 
49
        } 
50
     } 
51
  }          
52
}
53
54
//--------------------------------------------------------------------
55
// Function: Main
56
57
void main (void) { 
58
  unsigned char z;
59
#if (x2 == 1)
60
  CLKREG = 0x01;          // x2 mode
61
#else
62
  CLKREG = 0x00;
63
#endif 
64
  Beeper = ON;
65
  Timer0_Init();
66
  EA     = 1;             // Alle Interrupts EIN   
67
  TR0    = 1;             // Start Timer 0  
68
          
69
  inituart((unsigned int)(256-((XtalFreq/Baudrate)*(x2+1)/192)));  // Timer1
70
  printf_fast(__DATE__);putchar(',');
71
  printf_fast(__TIME__);
72
  printf_fast("\r\n>");
73
  
74
  BIT2F  = 0;
75
  LED_GN = ON;
76
  while(1) {
77
   if (BIT2F) {  
78
      LED_GN = !LED_GN; 
79
      printf_fast("%2d:%2d:%2d\r\n",hours,minutes,seconds);
80
      BIT2F = 0;
81
   }
82
   if (SIO_RI) {
83
    switch (SIO_SBUF) {
84
      case 's'  :  SIO_RI = 0;
85
                   printf_fast("\r\nUhr stellen (00:00:00):\r\n>"); 
86
                   TR0 = 0;   // STOP Timer 0
87
                   z = getchar(); putchar(z); hours = (z - 48)*10;
88
                   z = getchar(); putchar(z); hours = hours + (z -48);
89
                   putchar(':');
90
                   z = getchar(); putchar(z); minutes = (z - 48)*10;
91
                   z = getchar(); putchar(z); minutes = minutes + (z -48);
92
                   putchar(':');
93
                   z = getchar(); putchar(z); seconds = (z - 48)*10;
94
                   z = getchar(); putchar(z); seconds = seconds + (z -48);
95
                   printf_fast(" -> [ENTER]\r\n");
96
                   tick1  = tick2 = msec = 0;
97
                   TL0    = RELOAD_T0;        // TL0 reload value;
98
                   z = getchar();                   
99
                   TR0 = 1;
100
                   break; 
101
      default   :  break; 
102
    }
103
    // SIO_RI = 0;              
104
   }               
105
  } 
106
}
107
  
108
//--------------------------------------------------------------------
109
//--------------------------------------------------------------------

So siehts mit SDCC aus ...

Rabis

von Wilhelm S. (willi67)


Lesenswert?

Moin

Wie es aussieht hast du die Behfelslaufzeiten nicht berücksichtig was 
bei Timer- und Interrupptfunktionen zu verschiebungen von 1 bis 4 
taketen je durchlauf führen kann.

Ich emfehle dir die timer0 Zeitsequenz bis in den millisekunden bereich 
in Assembler zu programieren dann hast du einen genauen wert von dem du 
aus alle weiteren abläufe steuern kannst

mfg

von R. B. (rabis)


Lesenswert?

@willi67
Hmm, mit Timer0 im Modus2 und Autoreload(!) sollte es m.E. keine 
Verschiebung geben, es sei denn die Interruptroutine wäre zu lang - in 
assmbler sieht das bei SDCC so aus:
1
                            615 ;  -----------------------------------------
2
                            616 ;   function Timer0_ISR
3
                            617 ;  -----------------------------------------
4
   00D8                     618 _Timer0_ISR:
5
                    000A    619   ar2 = 0x0a
6
                    000B    620   ar3 = 0x0b
7
                    000C    621   ar4 = 0x0c
8
                    000D    622   ar5 = 0x0d
9
                    000E    623   ar6 = 0x0e
10
                    000F    624   ar7 = 0x0f
11
                    0008    625   ar0 = 0x08
12
                    0009    626   ar1 = 0x09
13
   00D8 C0 E0               627   push  acc
14
   00DA C0 D0               628   push  psw
15
   00DC 75 D0 08            629   mov  psw,#0x08
16
                            630 ;  ./main.c:27: tick1++;
17
   00DF 05 10               631   inc  _tick1
18
                            632 ;  ./main.c:28: if (tick1 == 64){
19
   00E1 74 40               633   mov  a,#0x40
20
   00E3 B5 10 39            634   cjne  a,_tick1,00113$
21
                            635 ;  ./main.c:29: tick1 = 0;
22
   00E6 75 10 00            636   mov  _tick1,#0x00
23
                            637 ;  ./main.c:30: tick2++;     
24
   00E9 05 11               638   inc  _tick2
25
                            639 ;  ./main.c:31: if (tick2 == 12) {
26
   00EB 74 0C               640   mov  a,#0x0C
27
   00ED B5 11 2F            641   cjne  a,_tick2,00113$
28
                            642 ;  ./main.c:32: tick2 = 0;
29
   00F0 75 11 00            643   mov  _tick2,#0x00
30
                            644 ;  ./main.c:33: msec++;      
31
   00F3 05 12               645   inc  _msec
32
                            646 ;  ./main.c:34: if (msec == 100) {
33
   00F5 74 64               647   mov  a,#0x64
34
   00F7 B5 12 25            648   cjne  a,_msec,00113$
35
                            649 ;  ./main.c:35: msec = 0;
36
   00FA 75 12 00            650   mov  _msec,#0x00
37
                            651 ;  ./main.c:36: seconds++;
38
   00FD 05 13               652   inc  _seconds
39
                            653 ;  ./main.c:37: LED_YE = !LED_YE; 
40
   00FF B2 81               654   cpl  _P0_1
41
                            655 ;  ./main.c:38: BIT2F = 1;    
42
   0101 D2 2F               656   setb  _BIT2F
43
                            657 ;  ./main.c:39: if (seconds == 60) {
44
   0103 74 3C               658   mov  a,#0x3C
45
   0105 B5 13 17            659   cjne  a,_seconds,00113$
46
                            660 ;  ./main.c:40: seconds = 0;
47
   0108 75 13 00            661   mov  _seconds,#0x00
48
                            662 ;  ./main.c:41: minutes++; 
49
   010B 05 14               663   inc  _minutes
50
                            664 ;  ./main.c:42: if (minutes == 60) {
51
   010D 74 3C               665   mov  a,#0x3C
52
   010F B5 14 0D            666   cjne  a,_minutes,00113$
53
                            667 ;  ./main.c:43: minutes = 0;
54
   0112 75 14 00            668   mov  _minutes,#0x00
55
                            669 ;  ./main.c:44: hours++; 
56
   0115 05 15               670   inc  _hours
57
                            671 ;  ./main.c:45: if (hours == 24) {
58
   0117 74 18               672   mov  a,#0x18
59
   0119 B5 15 03            673   cjne  a,_hours,00113$
60
                            674 ;  ./main.c:46: hours = 0;
61
   011C 75 15 00            675   mov  _hours,#0x00
62
   011F                     676 00113$:
63
   011F D0 D0               677   pop  psw
64
   0121 D0 E0               678   pop  acc
65
   0123 32                  679   reti
Wenn ich das in ASM programmiere bin ich nicht besser

von Peter D. (peda)


Lesenswert?

R. B. schrieb:
> RELOAD_T0 = 192;

Das ergibt dann aber 256 - 192 = 64 Zyklen Interruptrate.

RELOAD_T0 = -192;


Peter

von R. B. (rabis)


Lesenswert?

@Peter
Danke!
RELOAD_T0 = 256-192;
So mags SDCC und die Interruptroutine läßt sich noch verkürzen:
1
//--------------------------------------------------------------------
2
// Function: Timer 0 Interrupt
3
4
void Timer0_ISR (void) interrupt TF0_VECTOR using 1 {
5
  tick1++;
6
  if (tick1 == 192){
7
     tick1 = 0;
8
     msec++;         
9
        if (msec == 100) {
10
           msec = 0;
11
           seconds++;
12
           LED_YE = !LED_YE; 
13
           BIT2F = 1;    
14
           if (seconds == 60) {
15
              seconds = 0;
16
              minutes++; 
17
              if (minutes == 60) {
18
                 minutes = 0;
19
                 hours++; 
20
                 if (hours == 24) {
21
                    hours = 0;
22
                 }  
23
              } 
24
           } 
25
        } 
26
  }          
27
}
Problem gelöst, herrlicher Wochenendausgang!
Dank an alle!
Rabis

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.