Forum: Mikrocontroller und Digitale Elektronik attiny2313 Timer0 - Digitale Uhrzeit


von Patrick (Gast)


Lesenswert?

Hallo Leute,

ich möchte eine Digitale Uhrzeit anzeigen das funtkioniert soweit 
allerdings geht meine uhr vor und ich weiß nicht weshalb.
Ich muss es mit dem Timer0 machen daher ich vom Timer1 den Capture Mode 
benötige.

vielen dank!

Mein Code:
1
#define F_CPU 16000000UL
2
#include <avr/io.h>
3
#include "lcd-routines.h"
4
#include <util/delay.h>
5
#include <avr/interrupt.h>
6
7
/* LCD Control */
8
#define LCD_CNTRL_PORT  PORTD
9
#define LCD_CNTRL_DDR  DDRD
10
#define LCD_CNTRL_PIN  PIND
11
12
#define ButtonA    0
13
#define ButtonB    1
14
15
/*Function Declarations*/
16
void Init_Timer();
17
void LCD_update_time();
18
 
19
/*Global Variables Declarations*/
20
volatile char hours = 0;
21
volatile char minutes = 0;
22
volatile char seconds = 0;
23
volatile unsigned char overflowCounter = 0;
24
25
int main(void)
26
{
27
  lcd_init();
28
  Init_Timer();
29
  LCD_CNTRL_PORT = (1<<ButtonA | 1<<ButtonB);
30
  sei();
31
 
32
  while(1)
33
    { 
34
    if(!(LCD_CNTRL_PIN & (1<<ButtonB)))
35
    {
36
      hours++;
37
      if(hours > 23)
38
      hours = 0;
39
    }
40
    if(!(LCD_CNTRL_PIN & (1<<ButtonA)))
41
    {
42
      minutes++;
43
      if(minutes > 59)
44
      minutes = 0;
45
    }
46
    _delay_ms(50);
47
  }
48
}
49
50
void Init_Timer()
51
{
52
  TCCR0A = 0;
53
  TCCR0B|= (1<<CS02)|(1<<CS00); //Prescale 1024
54
  TIMSK |= (1<<TOIE0); //Timer0: Overflow Interrupt
55
}
56
57
void LCD_update_time()
58
{
59
  unsigned char temp;
60
  
61
  lcd_clear();
62
  lcd_setcursor(2,4);
63
  
64
  itoa(hours/10,temp,10);
65
  lcd_string(temp);
66
  itoa(hours%10,temp,10);
67
  lcd_string(temp);
68
  lcd_string(":");
69
  
70
  itoa(minutes/10,temp,10);
71
  lcd_string(temp);
72
  itoa((minutes%10),temp,10);
73
  lcd_string(temp);
74
  lcd_string(":");
75
  
76
  itoa(seconds/10,temp,10);
77
  lcd_string(temp);
78
  itoa(seconds%10,temp,10);
79
  lcd_string(temp);
80
}
81
82
ISR (TIMER0_OVF_vect)
83
{
84
  /*
85
  16Mhz
86
  16000000/1024 = 15.625Hz
87
  15625/255 = 61 Overflows pro sekunde 
88
  1 overflow nach 16ms  
89
  */
90
  
91
  overflowCounter++;
92
  if (overflowCounter >= 4)
93
  {
94
    overflowCounter = 0;
95
    seconds++;
96
    if(seconds == 60)
97
    {
98
      seconds = 0;
99
      minutes++;
100
    }
101
    if(minutes == 60)
102
    {
103
      minutes = 0;
104
      hours++;
105
    }
106
    if(hours > 23)
107
    {
108
      hours = 0;
109
    }
110
    
111
    LCD_update_time();
112
  }
113
}

: Bearbeitet durch User
von spess53 (Gast)


Lesenswert?

Hi

>Ich muss es mit dem Timer0 machen daher ich vom Timer1 den Capture Mode
>benötige.

Dann nimm für Timer0 den CTC-Mode.

>  15625/255 = 61 Overflows pro sekunde

->15625/256

MfG Spess

von Patrick (Gast)


Lesenswert?

hmm ok, ich steh momentan etwas auf der leitung...

15625/256 = 61 Overflows pro sekunde
1/61 = 16ms

bisher hab ich die Overflows mitgezählt, jetzt müsste ich das dann 
umdrehen ?
das macht ja keinen unterschied oder ?
1
TCCR0A =(1<<WGM01);
2
TCCR0B|= (1<<CS02)|(1<<CS00); //Prescale 1024
3
OCR0A = 4;
4
5
ISR (TIMER0_COMPA_vect)
6
{
7
  seconds++;
8
  miliseconds = 0;
9
  if(seconds == 60)
10
  {
11
    minutes++;
12
    seconds = 0;
13
  }
14
  if(minutes == 60)
15
  {
16
    hours++;
17
    minutes = 0;
18
  }
19
  if(hours == 24)
20
  {
21
    hours = 0;
22
  }
23
}

: Bearbeitet durch User
von spess53 (Gast)


Lesenswert?

Hi

>1/61 = 16ms

Das sind aber nicht genau 16ms.

Wenn du Timer0 im CTC-Mode mit einem Prescaler von 64 und mit OCR0A=0xF9 
betreibst, bekommst du einen OCR0A-Interrupt genau alle 1ms. In der 
Interrupt-Routine zählst du bis 1000. Damit hast du deine Sekunde.

Entweder du setzt dann ein Flag und arbeitest die Uhrroutinen im 
Hauptprogramm ab oder machst das gleich im Interrupt. Hängt davon ab, 
wie zeitkritisch dein Programm ist.

MfG Spess

von Tom (Gast)


Lesenswert?

Patrick schrieb:
> ich möchte eine Digitale Uhrzeit anzeigen das funtkioniert soweit
> allerdings geht meine uhr vor und ich weiß nicht weshalb.

Vielleicht läuft dein Takt mit einer anderen Frequenz, als du glaubst. 
Miss mal genau nach.

von Mein grosses V. (vorbild)


Lesenswert?

Tom schrieb:
> Vielleicht läuft dein Takt mit einer anderen Frequenz, als du glaubst.
> Miss mal genau nach.

Nein, das tut er nicht. Die Antwort hat Spess doch gerade geliefert.

: Bearbeitet durch User
von Patrick (Gast)


Lesenswert?

zeitkritisch eher nicht.

aber ein sekunden takt bekomme ich damit nicht, jetzt wär sie viel zu 
langsam.
1
#define F_CPU 16000000UL
2
#include <avr/io.h>
3
#include "lcd-routines.h"
4
#include <util/delay.h>
5
#include <avr/interrupt.h>
6
7
/* LCD Control for Time  */
8
#define LCD_CNTRL_PORT  PORTD
9
#define LCD_CNTRL_DDR  DDRD
10
#define LCD_CNTRL_PIN  PIND
11
12
#define ButtonA    0
13
#define ButtonB    1
14
15
/*Function Declarations*/
16
void Init_Timer();
17
void LCD_update_time();
18
 
19
/*Global Variables Declarations*/
20
volatile char hours = 0;
21
volatile char minutes = 0;
22
volatile char seconds = 0;
23
volatile int miliseconds = 0;
24
25
int main(void)
26
{
27
  lcd_init();
28
  Init_Timer();
29
  LCD_CNTRL_PORT = (1<<ButtonA | 1<<ButtonB);
30
  sei();
31
 
32
  while(1)
33
    { 
34
    if(!(LCD_CNTRL_PIN & (1<<ButtonB)))
35
    {
36
      hours++;
37
      if(hours > 23)
38
      hours = 0;
39
    }
40
    if(!(LCD_CNTRL_PIN & (1<<ButtonA)))
41
    {
42
      minutes++;
43
      seconds = 0;
44
      if(minutes > 59)
45
      minutes = 0;
46
    }
47
    _delay_ms(50);
48
  }
49
}
50
51
void Init_Timer()
52
{
53
    TCCR0A =(1<<WGM01); //CTC Mode
54
    TCCR0B |= (1<<CS01) | (1<<CS00); // Prescaler 64
55
    OCR0A=0xF9; //249
56
    TIMSK |= (1<<OCIE0A);
57
}
58
59
void LCD_update_time()
60
{
61
  unsigned char temp;
62
  
63
  lcd_clear();
64
  lcd_setcursor(2,4);
65
  
66
  itoa(hours/10,temp,10);
67
  lcd_string(temp);
68
  itoa(hours%10,temp,10);
69
  lcd_string(temp);
70
  lcd_string(":");
71
  
72
  itoa(minutes/10,temp,10);
73
  lcd_string(temp);
74
  itoa((minutes%10),temp,10);
75
  lcd_string(temp);
76
  lcd_string(":");
77
  
78
  itoa(seconds/10,temp,10);
79
  lcd_string(temp);
80
  itoa(seconds%10,temp,10);
81
  lcd_string(temp);
82
}
83
84
ISR (TIMER0_COMPA_vect)
85
{
86
  /*
87
  ((16000000/64)/1000)  = 250
88
  TCNT0 = OCR0A = 250-1
89
  ist (250 Schritte), d.h. genau alle 1 ms
90
  */
91
  miliseconds++;
92
  if(miliseconds == 1000)
93
  {
94
    seconds++;
95
    miliseconds = 0;
96
    if(seconds == 60)
97
    {
98
      minutes++;
99
      seconds = 0;
100
    }
101
    if(minutes == 60)
102
    {
103
      hours++;
104
      minutes = 0;
105
    }
106
    if(hours == 24)
107
    {
108
      hours = 0;
109
    }
110
    LCD_update_time();  
111
  }
112
}

: Bearbeitet durch User
von Tom (Gast)


Lesenswert?

Mein grosses V. schrieb:
> Nein, das tut er nicht. Die Antwort hat Spess doch gerade geliefert.

Du hast die Gangabweichung durch die Frequenzabweichung wegen grober 
Fehler nur noch nicht entdeckt. Der von Spess genannte Fehler ist nur 
die Spitze des Eisberges. Solange du nicht verrätst, wie doll deine Uhr 
genau vorgeht, kann man erstmal nur auf Standardfehlern abklopfen.

von Patrick (Gast)


Lesenswert?

bei if(miliseconds == 1000) dauertert es bis 1s kommt ca. 10s

bei if(miliseconds == 100) dauertert es bis 1s kommt < 1s ca. 600ms

ich komme auf keine 100% sekunde ...

von spess53 (Gast)


Lesenswert?

Hi

>bei if(miliseconds == 1000) dauertert es bis 1s kommt ca. 10s

>bei if(miliseconds == 100) dauertert es bis 1s kommt < 1s ca. 600ms

>ich komme auf keine 100% sekunde ...

Dann solltest du mal deine Fuses überprüfen.

MfG Spess

von Patrick (Gast)


Lesenswert?

bei denen hab nie etwas umgestellt also 1s dauert momentan 14s - 15s 
(gemessen)

von Bastler (Gast)


Lesenswert?

Die 16MHz kommen

   [ ] aus einen Quarz

??

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Patrick schrieb:
> aber ein sekunden takt bekomme ich damit nicht, jetzt wär sie viel zu
> langsam.

 Ohne "lcd-routines.h" geht deine Uhr ganz genau. Also, "lcd-routines.h"
 auf Interrupt sperren oder ähnliches prüfen.

 Auch:
1
  miliseconds++;
2
  if(miliseconds >= 1000)   // Oder: if(miliseconds > 999)
3
  {
4
    seconds++;
5
    miliseconds = 0;
6
    if(seconds == 60)
7
    {
8
      minutes++;
9
      seconds = 0;
10
      if(minutes == 60)
11
      {
12
        hours++;
13
        minutes = 0;
14
        if(hours == 24)
15
        {
16
          hours = 0;
17
        }
18
      }
19
    LCD_update_time();
20
    }
21
  }

: Bearbeitet durch User
von Patrick (Gast)


Lesenswert?

Zur Ansteuerung vom LCD Display nuzte ich diesen Code, der sieht aber ok 
aus.

http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/LCD-Ansteuerung

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Patrick schrieb:
> bei denen hab nie etwas umgestellt also 1s dauert momentan 14s - 15s
> (gemessen)

 Dann läuft dein Tiny wahrscheinlich mit internem Takt von 1MHz.

von Patrick (Gast)


Lesenswert?

ich habe aber 16Mhz eingestellt weshalb sollte er mit 1Mhz laufen ?
#define F_CPU 16000000UL

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Patrick schrieb:
> Zur Ansteuerung vom LCD Display nuzte ich diesen Code, der sieht aber ok
> aus.
>
> http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/LCD-Ansteuerung

 LCD-Display Routinen weglassen, lass deinen Tiny nur eine LED im
 Sekundentakt an- und ausmachen, dann siehst du es genau.

von spess53 (Gast)


Lesenswert?

Hi

>ich habe aber 16Mhz eingestellt weshalb sollte er mit 1Mhz laufen ?
>#define F_CPU 16000000UL

Damit sagst du nur dem Compiler, das dein Controller mit 16MHz laufen 
soll. Aber den Takt vom Controller musst du erst über die Fuses 
einstellen.

MfG Spess

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

Patrick schrieb:
> ich habe aber 16Mhz eingestellt weshalb sollte er mit 1Mhz laufen ?
> #define F_CPU 16000000UL

 Du hast gar nichts eingestellt, du hast nur dem GCC mitgeteilt, dass
 du glaubst, dass die CPU Geschwindigkeit 16MHz ist.


spess53 schrieb:
> Dann solltest du mal deine Fuses überprüfen.
>
> MfG Spess

von Marc V. (Firma: Vescomp) (logarithmus)


Lesenswert?

spess53 schrieb:
> Damit sagst du nur dem Compiler, das dein Controller mit 16MHz laufen
> soll. Aber den Takt vom Controller musst du erst über die Fuses
> einstellen.

 LOL.
 Du bist einfach zu schnell...

von Bastler (Gast)


Lesenswert?

Default Clock t2313 ist wie bei fast allen AVR's 8Mhz über 1:8 Teiler 
ergibt 1MHz. Wenn man stattdessen dem Compiler 16MHz mitteilt, dann baut 
der nur eventuelle Wartenschleifen anders. Was er nicht kann ist der 
Hardware einen 16MHz Quarz hinzuzufügen. Was er auch nicht kann, denn er 
kennt ja die Hardware nicht: die Fuses für Quarzbetrieb anpassen und die 
DIV8 Fuse rausnehmen.
Alle Spekulationen über die errechnete Uhrzeit sind vergebene Mühe, wenn 
sich diese auf eine nur grob bekannte Frequenz von ca. 1MHz +-10% 
bezieht.

von Pauline (Gast)


Lesenswert?

Patrick schrieb:
> ich habe aber 16Mhz eingestellt weshalb sollte er mit 1Mhz laufen ?

Dem Compiler hast du einen Bären aufgebunden - sonst nichts.

von Patrick (Gast)


Lesenswert?

ja das habe ich nicht gewusst mit dem F_CPU ich ging davon aus das ich 
damit die frequenz einstellen kann aber wozu ist das dann gut ?

Bastler schrieb:
> Default Clock t2313 ist wie bei fast allen AVR's 8Mhz über 1:8 Teiler
> ergibt 1MHz.

Somit muss ich mit 1Mhz und 1ms einen prescaler von 8 verwenden.
laut dem AVR Calculator hätte ich dann einen Fehler von 0%

http://www.b9.com/elect/avr/kavrcalc/

TCCR0A = 0; //CTC Mode
TCCR0B |= (1<<WGM01) | (1<<CS01); // Prescaler 8
OCR0A=124;
TIMSK = (1<<OCIE0A);

von spess53 (Gast)


Lesenswert?

Hi

>ja das habe ich nicht gewusst mit dem F_CPU ich ging davon aus das ich
>damit die frequenz einstellen kann aber wozu ist das dann gut ?

Z.B. wenn der Compiler ein Delay ausrechnen muss.

>TCCR0A = 0; //CTC Mode
>TCCR0B |= (1<<WGM01) | (1<<CS01); // Prescaler 8

WGM01 befindet sich in TCCR0A

MfG Spess

von Patrick (Gast)


Lesenswert?

achso für die Delays ist es also relevant aber nicht für den Timer das 
ist gut zu wissen. danke

von Bastler (Gast)


Lesenswert?

"meine LED blinkt 8 mal zu langsam" ist eben ein häufig anzutreffendes 
Problem. Aber schön wenn man Dir weiterhelfen konnte ;-)

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.