attiny2313 Timer0 - Digitale Uhrzeit

Gast #4218782
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
}
Gast #4218827
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
}
Gast #4218838
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
Gast #4218870
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
}
Gast #4218896
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.
Gast #4218912
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
(Firma: Vescomp) #4218925
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
  }
Gast #4218946
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
Gast #4219212
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.
Gast #4220799
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);
Gast #4220834
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

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren