Forum: Mikrocontroller und Digitale Elektronik Timer, Interrupt, Taster, C


von Sebastian (Gast)


Lesenswert?

Guten Abend,

ich baue momentan eine kleine Binäruhr mit einem Atmega8. Die Idee war 
eine Einfache Binäruhr (Minuten 0-59, Stunde 0-11,, 2LEDs für Sekunden) 
und diese über 2 Taster( Stunde+1, Minute+1) einzustellen. Die Binäruhr 
fängt auch schon an zu zählen das Problem liegt daran dass ich die 
Uhrzeit nicht Einstellen kann. Die Taster sind PD5 und PD2 mit dem µC 
verbunden, PullDown Wiederstände gehen von dort auf Ground.
1
#define F_CPU 8000000UL
2
3
#include <avr/io.h>
4
#include <avr/interrupt.h>
5
#include <avr/sleep.h>
6
#include <inttypes.h>
7
#include <util/delay.h>
8
#include <stdlib.h>
9
10
unsigned char sekunden = 0;
11
unsigned char minuten = 0;
12
unsigned char stunden = 0;
13
14
ISR(TIMER1_COMPA_vect){
15
  sekunden++;
16
17
  if(sekunden==60){
18
    sekunden = 0;
19
    minuten++;
20
  }
21
  if(minuten == 60){
22
    minuten = 0;
23
    stunden++;
24
  }
25
  if(stunden == 12){
26
    stunden = 0;
27
  }
28
  PORTC = minuten;
29
  PORTB = stunden;
30
  if(sekunden==0 || sekunden == 30){ PORTD ^= (1<<PD6); }
31
  PORTD ^= (1<<PD7);
32
}
33
34
int timer (void)
35
{
36
  if(sekunden == 60)
37
  {
38
    minuten++;
39
    sekunden = 0;
40
  }
41
  if(minuten == 60)
42
  {
43
    stunden++;
44
    minuten = 0;
45
  }
46
  return 0;
47
}
48
49
int main (void)
50
{
51
  DDRC = 0b00111111; // LED minute
52
  DDRB = 0b00001111; // LED stunde
53
  DDRD = 0b11000000; // LED sekunde
54
  PORTD &= ~(1<<PD2);
55
  PORTD &= ~(1<<PD5);
56
57
  
58
  //16Bit-Timer für Zeitzählung
59
  TCCR1B |= (1 << WGM12);                //CTC Modus
60
  TCCR1B |= (1 << CS12) | (0 << CS11) | (1 << CS10);   //Prescaler 1024
61
  OCR1A = 7812;                      //Compare Wert setzen
62
  TIMSK = (1<<OCIE1A);   //Interrupt bei Compare Match
63
  sei();            //Interrputs aktivieren
64
    
65
  while(1){
66
67
    if( PIND & (1<<PD2)){
68
      minuten++;  
69
    }
70
    if( PIND & (1<<PD5)){
71
      stunden++;
72
      }
73
    if(minuten>=60){
74
      stunden++;
75
    }
76
    if(stunden>=12){
77
      stunden = 0;
78
    }
79
    PORTC = minuten;
80
    PORTB = stunden;
81
    _delay_ms(100);
82
    
83
  }
84
  return 0;
85
  
86
}


Hardwaremäßig funktioniert alles (nachgemessen mit Multimeter etc.). Es 
kann gut sein dass die Uhr nicht genau Zählt, dies ist bekannt und wird 
später behoben.(Externer Quarz etc.)

Lg Sebastian

von Sebastian (Gast)


Lesenswert?

Die While-Schleife im main wird ausgeführt, wenn ich einen Taster drücke 
passiert jedoch nichts. An was könnte das liegen?

von S. Landolt (Gast)


Lesenswert?

Habe ich das richtig verstanden: die Taster liegen zwischen uC-Pin und 
Vcc?

von Schaltplanleser (Gast)


Lesenswert?

Sebastian schrieb:
> Die Taster sind PD5 und PD2 mit dem µC
> verbunden, PullDown Wiederstände gehen von dort auf Ground.

Das solltest du mit einem Schaltplan verdeutlichen da es
sonst keiner versteht. Oder viele missverstehen und raten.

von Sebastian (Gast)


Angehängte Dateien:

Lesenswert?

S. Landolt schrieb:
> Habe ich das richtig verstanden: die Taster liegen zwischen uC-Pin und
> Vcc?

Ja das stimmt wie man hier auf dem Bild sehen kann

von S. Landolt (Gast)


Lesenswert?

Fehlt da nicht 'volatile' für sekunden minuten stunden?

von Sebastian (Gast)


Lesenswert?

S. Landolt schrieb:
> Fehlt da nicht 'volatile' für sekunden minuten stunden?

Ich hab mal volatile davor geschrieben. Scheint als wäre es hier nötig, 
doch warum eigentlich? Es sollte doch kein Problem sein auf eine Globale 
Variable zuzugreifen? Oder irre ich mich hier?

von Nop (Gast)


Lesenswert?

1) was macht die Routine timer() ? Ist das nicht redundant zur ISR?

2) fehlendes volatile bei stunden, minuten und sekunden wurde ja schon 
angemerkt.

3) die Taster sind nicht entprellt.

4) wenn es dann mal funktioniert (mit volatile), wird ein Tasterdruck 
die Uhr scheinbar "zufällig" verstellen, weil in jedem 
Schleifendurchlauf der Portpin gesetzt ist, und diese Schleife wird 
zigtausendmal jede Sekunde durchlaufen.

von Nop (Gast)


Lesenswert?

Sebastian schrieb:
> Scheint als wäre es hier nötig, doch warum eigentlich?

Das ist immer nötig, wenn Du Variablen zwischen Applikation und 
Interrupt teilst, weil der Kontrollfluß nicht linear ist.

von S. Landolt (Gast)


Lesenswert?

an Sebastian:
Das kann ich leider nicht beantworten, kann kein C; ich lese nur 
regelmäßig mit, und das fehlende 'volatile' im Zusammenhang mit ISRs 
scheint ein häufiger Fehler zu sein.

an Nop:
die Punkte 3 und 4 werden so halbwegs durch das
_delay_ms(100);
in der main umgangen.

von R. F. (rfr)


Lesenswert?

Triffst du denn auch mit dem Einlesevorgang den Zeitpunkt, an dem die 
Taste gedrückt ist?

Gruss

Robert

von Schaltplanleser (Gast)


Lesenswert?

Nop schrieb:
> weil in jedem
> Schleifendurchlauf der Portpin gesetzt ist, und diese Schleife wird
> zigtausendmal jede Sekunde durchlaufen.

Nö, nur ca zehnmal pro Sekunde, weil er ein _delay_ms(100)
in der Schleife hat.

von Nop (Gast)


Lesenswert?

S. Landolt schrieb:

> die Punkte 3 und 4 werden so halbwegs durch das
> _delay_ms(100);
> in der main umgangen.

Stimmt, zumindest das Prellen. Aber es wird schwerlich möglich sein, die 
Stunden und Minuten um genau eins vorzustellen. Das müßte man dann so 
machen, daß man den Port abfragt und nur dann eins weiterstellt, falls 
der jeweilige Portzustand im vorigen Durchlauf null war (speichert man 
in einer Statusvariable).

Der genaue Grund, wieso volatile nötig ist, ist die Optimierung des 
C-Compilers. Wenn der Kontrollfluß nicht zusammenhängend ist (wie bei 
Applikation/Interrupt), optimiert er da u.U. ungewollt Zugriffe weg.

Typisches Symptom: mit -O0 (ohne Optimierung) geht es, mit Optimierung 
(egal ob auf Zeit oder Codegröße) geht es nicht mehr.

von Sebastian (Gast)


Lesenswert?

Nop schrieb:
> 1) was macht die Routine timer() ? Ist das nicht redundant zur
> ISR?

Ja, wird noch entfernt

> 2) fehlendes volatile bei stunden, minuten und sekunden wurde ja schon
> angemerkt.
>
> 3) die Taster sind nicht entprellt.

Die Taster entprelle ich mal wenn ich zeit habe. Bis es so weit ist muss 
ich ohne klarkommen. durch das delay fällt es nicht so sehr auf.

> 4) wenn es dann mal funktioniert (mit volatile), wird ein Tasterdruck
> die Uhr scheinbar "zufällig" verstellen, weil in jedem
> Schleifendurchlauf der Portpin gesetzt ist, und diese Schleife wird
> zigtausendmal jede Sekunde durchlaufen.

Wird durch das _delay_ms(100); begrenzt. Es ist bewusst so gemacht dass 
ein schnelles verstellen möglich ist.

Mit Interrupts habe ich mich noch nicht so viel auseinandergesetzt daher 
warscheinlich das fehlende volatile.

Danke an alle. Hat mir sehr geholfen. Noch einen schönen Abend :)

von Rita (Gast)


Lesenswert?

Sebastian schrieb:
> Die Taster entprelle ich mal wenn ich zeit habe. Bis es so weit ist muss
> ich ohne klarkommen. durch das delay fällt es nicht so sehr auf.

Dauert doch nicht lange?

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.