Forum: Compiler & IDEs Problem: Stoppuhr in C (Interrupts und Pull-Ups)


von Robert K. (mr_insanity)


Lesenswert?

Hallo,

ich habe ein kleines Problem mit einem Programm. Und zwar habe ich eine 
Stoppuhr gebaut und der Prototyp funktioniert schon. Bei dem habe ich 
die Interrupt Pins mit einem Pull-Down Widerstand versehen und die 
Interrupts auf Rising Edge eingestellt. Nun habe ich das ganze mit 
großen 7-Segment-Anzeigen aufgebaut und dachte mir ich spare mir die 
Pull-Down Widerstände und nutze die internen Pull-Up widerstände. Also 
habe ich die Inetrrupts auf Falling Edge gestellt. Jetzt habe ich das 
Problem dass sich das Teil nicht mehr starten lässt. Ich habe schon viel 
rumprobiert, aber ich habe leider noch zu wenig Erfahrung mit C.

Vielen Dank schonmal für jegliche Hilfe!
1
//Stoppuhr
2
3
#include <avr/io.h>
4
#include <avr/interrupt.h>
5
#include <util/delay.h>
6
7
8
volatile unsigned char running;
9
volatile unsigned char zahl[10]; //Array in denen die Portausgaben für die Zahlen 0-9 gespeichert ist
10
volatile unsigned char sek[4];   //Parameter für zahl
11
volatile unsigned char i;        //Zählvariable für sek
12
volatile unsigned int counter;   // <- Zählervariable MUSS Integer sein, da > 255 gezählt wird
13
14
15
//Timer und Interrupt Initialisierung
16
int interrupt_init(void)
17
{
18
  TCNT0 = 0x00;  //Timer0 mit 0 initialisieren (00000000)
19
  TIMSK = 0x01;  //Timer0 Overflow Interrupt aktivieren (00000001)
20
  
21
  MCUCR = 0x02;  //Falling Edge Interrupt an INT0 aktivieren (00000011)
22
  MCUCSR = 0x00; //Falling Edge Interrupt an INT2 aktivieren (01000000)
23
  GICR = 0x60;   //Interrupt auf INT0 und INT2 aktivieren (01100000)
24
  
25
  return 0;
26
}
27
//-----------------------------------
28
29
30
//Konstanten und Portkonfiguration
31
int const_init(void)
32
{
33
                  //Pull-Up an
34
                  //      |
35
                  //     \|/
36
  zahl[0] = 0x7F; //(01111111)
37
  zahl[1] = 0x0E; //(00001110) 
38
  zahl[2] = 0xB7; //(10110111)
39
  zahl[3] = 0x9F; //(10011111)
40
  zahl[4] = 0xCE; //(11001110)
41
  zahl[5] = 0xDD; //(11011101)
42
  zahl[6] = 0xFD; //(11111101)
43
  zahl[7] = 0x0F; //(00001111)
44
  zahl[8] = 0xFF; //(11111111)
45
  zahl[9] = 0xDF; //(11011111)
46
  
47
  DDRA = 0xFF; //alle Pins Ausgang (11111111)
48
  DDRB = 0xFB; //Pin 2 (INT2) Eingang, Rest Ausgang (11111011)
49
  DDRC = 0xFF; //alle Pins Ausgang (11111111)
50
  DDRD = 0xFB; //Pin 2 (INT0) Eingang, Rest Ausgang (11111011)
51
    
52
  //alle Ports zeigen 0 an
53
  PORTA = zahl[0];  //Port für 10er Sekunden
54
  PORTB = zahl[0];  //Port für Sekunden
55
  PORTC = zahl[0];  //Port für 1/10 Sekunden
56
  PORTD = zahl[0];  //Port für 1/100 Sekunden
57
  
58
  running = 0;
59
  
60
  return 0;
61
}
62
//-----------------------------------
63
64
65
//Hauptprogramm
66
int main(void)
67
{
68
  interrupt_init();
69
  const_init();
70
  
71
  sei();
72
73
  while(1) {
74
  
75
    PORTA = zahl[sek[0]];
76
    PORTB = zahl[sek[1]]; 
77
    PORTC = zahl[sek[2]];
78
    PORTD = zahl[sek[3]];
79
  }
80
}
81
//-----------------------------------
82
83
//Funktion zum Tastenentprellen <- Ist für Tastendruck gegenüber GND programmiert.
84
inline unsigned char debounce(volatile unsigned char *port, volatile unsigned char pin)
85
{
86
    if (!(*port & (1 << pin)))  //Taste gedrückt --> Pin auf GND gezogen
87
    {
88
        /* Pin wurde auf GND-Potential gezogen, 100ms warten   */
89
        _delay_ms(50);  // max. 262.1 ms / F_CPU in MHz
90
        _delay_ms(50); 
91
        if (*port & (1 << pin))  //Taste losgelassen --> Pin wieder über Pull-Up aud 1
92
        {
93
            /* Anwender Zeit zum Loslassen des Tasters geben */
94
            _delay_ms(50);
95
            _delay_ms(50); 
96
            return 1;
97
        }
98
    }
99
    return 0;
100
}
101
//------------------------------------
102
103
//ISR für Timer
104
ISR(TIMER0_OVF_vect)
105
{          
106
  counter++;
107
  
108
  //if (counter > 625) //16MHz ohne Prescaler: (16000000/256)/625=100 --> 1/100sek Auflösung
109
  if (counter > 624)
110
  {
111
    sek[0]++;
112
    counter = 0;
113
  }
114
  
115
  for(i = 0; i < 4; i++)
116
  {
117
    if (sek[i] > 9)
118
    {
119
      sek[i]=0;
120
      sek[i+1]++;
121
    }
122
    if (sek[3] > 9)
123
    {
124
      sek[0] = 0;
125
      sek[1] = 0;
126
      sek[2] = 0;
127
      sek[3] = 0;
128
    }
129
  }
130
}
131
//-----------------------------------
132
133
134
//ISR für Start/Stop
135
ISR(INT0_vect)
136
{
137
  if (debounce(PIND, PD2))
138
  {
139
    if(running == 0)
140
    {
141
      TCCR0 = 0x01; //Timer ohne Prescaler (siehe S.80 im Datenblatt) (00000001)  
142
      running = 1;  //Indikator für "läuft"
143
    }
144
    else
145
    {
146
      TCCR0 = 0x00; //Timer0 aus (00000000)
147
      running = 0;  //Indikator für "läuft nicht"
148
    }
149
  }
150
}
151
//-----------------------------------
152
153
154
//ISR für Reset
155
ISR(INT2_vect)
156
{
157
  TCCR0 = 0x00; //Timer0 deaktivieren (00000000)
158
  
159
  //alle Anzeigen auf 0
160
  PORTA = zahl[0];
161
  PORTB = zahl[0];
162
  PORTC = zahl[0];
163
  PORTD = zahl[0];
164
  
165
  running = 0;  //Indikator für "läuft nicht"
166
}
167
//-----------------------------------

von Johannes M. (johnny-m)


Lesenswert?

Der Aufruf der debounce-Funktion hat in dem Interrupt Handler nichts zu 
suchen. Außerdem ist hoffentlich klar, dass die Taster bei der 
Konfiguration auch andersrum (gegen GND) angeschlossen werden müssen...

von Matt (Gast)


Lesenswert?

Hast Du an den Tastern evtl. Kondensatoren, die Dir die Pins nach 
Systemstart zunächst auf GND ziehen? Wenn ja, bau vor dem global 
interrupt enable eine Verzögerung ein.

von Marco G. (stan)


Lesenswert?

Robert Knipp wrote:
>
1
> ...
2
>   MCUCSR = 0x00; //Falling Edge Interrupt an INT2 aktivieren (01000000)
3
>

da passt Hex- und Binärdarstellung nicht zusammen, Absicht?

von Johannes M. (johnny-m)


Lesenswert?

Ich frage mich überhaupt, warum Du den Taster mit einem externen 
Interrupt abfragst. Das ist völlig unnötig, v.a. dann, wenn Du sowieso 
einen Timer laufen hast, der einen 10 ms-Takt macht. Taster-Abfrage über 
externe Interrupts ist unsinnig.

von Robert K. (mr_insanity)


Lesenswert?

>Außerdem ist hoffentlich klar, dass die Taster bei der
>Konfiguration auch andersrum (gegen GND) angeschlossen werden müssen...

Ist natürlich klar. Wurde auch entsprechend geändert.


>Hast Du an den Tastern evtl. Kondensatoren, die Dir die Pins nach
>Systemstart zunächst auf GND ziehen?

Nein, habe ich nicht.


>>   MCUCSR = 0x00; //Falling Edge Interrupt an INT2 aktivieren (01000000)
>da passt Hex- und Binärdarstellung nicht zusammen, Absicht?

Ups, das war keine Absicht. Habs vergessen in der Binärdarstellung zu 
ändern


>Ich frage mich überhaupt, warum Du den Taster mit einem externen
>Interrupt abfragst.

Wie macht man es denn sonst? Hatte aber bisher auch gut funktioniert.

von Johannes M. (johnny-m)


Lesenswert?

Robert Knipp wrote:
>>Ich frage mich überhaupt, warum Du den Taster mit einem externen
>>Interrupt abfragst.
>
> Wie macht man es denn sonst? Hatte aber bisher auch gut funktioniert.
Indem man alle 10-20 ms den betreffenden Pin auf seinen Zustand hin 
abfragt (z.B. mit Hilfe eines Timer-Interrupts, deshalb auch der Hinweis 
auf Deinen ohnehin laufenden 10-ms-Takt) und bei einer Änderung des 
Pinszustandes ein Flag setzt. Dann fallen auch die blödsinnigen 
Wartezeiten mit _delay_XX weg (die innerhalb eines Interrupt Handlers eh 
nix zu suchen haben). Ein Tasterdruck ist kein Ereignis, auf das der µC 
unverzüglich (d.h. innerhalb von wenigen CPU-Takten) reagieren können 
muss. Im Gegenteil: Externe Interrupts sind viel zu schnell dafür, 
weshalb man dann noch viel Aufwand für die Entprellung treiben muss. Bei 
einer zyklischen Abfrage alle paar 10 ms hat man die Wartezeit 
automatisch drin und der µC kann in der Zwischenzeit andere Dinge 
erledigen. Bei Deiner Version verlierst Du sogar bei jedem Tastendruck 
10 Timer-Overflow-Interrupts, weil das System durch die 
debounce-Funktion im Interrupt-Handler für 100 ms komplett blockiert 
ist! Und da der menschliche Bediener gar nicht in der Lage ist, eine 
Taste so kurz und schnell zu betätigen, dass der µC bei einer Abfrage 
z.B. alle 20 oder 30 ms das nicht mitbekommt, genügt das völlig.

von Robert K. (mr_insanity)


Lesenswert?

Ich habes jetzt mal so gemacht. Läuft aber auch nicht. Zeigt genau wie 
vorher nur 0 an.
1
//Stoppuhr
2
3
#include <avr/io.h>
4
#include <avr/interrupt.h>
5
#include <util/delay.h>
6
7
8
volatile unsigned char running;
9
volatile unsigned char zahl[10]; //Array in denen die Portausgaben für die Zahlen 0-9 gespeichert ist
10
volatile unsigned char sek[4];   //Parameter für zahl
11
volatile unsigned char i;        //Zählvariable für sek
12
volatile unsigned int counter;// <- Zählervariable MUSS Integer sein, da > 255 gezählt wird
13
14
15
//Timer und Interrupt Initialisierung
16
int interrupt_init(void)
17
{
18
  TCNT0 = 0x00;  //Timer0 mit 0 initialisieren (00000000)
19
  TIMSK = 0x01;  //Timer0 Overflow Interrupt aktivieren (00000001)
20
  
21
  return 0;
22
}
23
//-----------------------------------
24
25
26
//Konstanten und Portkonfiguration
27
int const_init(void)
28
{
29
  zahl[0] = 0x7F; //(01111111)
30
  zahl[1] = 0x0E; //(00001110) 
31
  zahl[2] = 0xB7; //(10110111)
32
  zahl[3] = 0x9F; //(10011111)
33
  zahl[4] = 0xCE; //(11001110)
34
  zahl[5] = 0xDD; //(11011101)
35
  zahl[6] = 0xFD; //(11111101)
36
  zahl[7] = 0x0F; //(00001111)
37
  zahl[8] = 0xFF; //(11111111)
38
  zahl[9] = 0xDF; //(11011111)
39
  
40
  DDRA = 0xFF; //alle Pins Ausgang (11111111)
41
  DDRB = 0xFB; //Pin 2 (INT2) Eingang, Rest Ausgang (11111011)
42
  DDRC = 0xFF; //alle Pins Ausgang (11111111)
43
  DDRD = 0xFB; //Pin 2 (INT0) Eingang, Rest Ausgang (11111011)
44
    
45
  //alle Ports zeigen 0 an
46
  PORTA = zahl[0];  //Port für 10er Sekunden
47
  PORTB = zahl[0];  //Port für Sekunden
48
  PORTC = zahl[0];  //Port für 1/10 Sekunden
49
  PORTD = zahl[0];  //Port für 1/100 Sekunden
50
  
51
  running = 0;
52
  
53
  return 0;
54
}
55
//-----------------------------------
56
57
58
//Hauptprogramm
59
int main(void)
60
{
61
  interrupt_init();
62
  const_init();
63
  
64
  sei();
65
66
  while(1) {
67
  
68
    PORTA = zahl[sek[0]];
69
    PORTB = zahl[sek[1]]; 
70
    PORTC = zahl[sek[2]];
71
    PORTD = zahl[sek[3]];
72
  }
73
}
74
//-----------------------------------
75
76
77
//ISR für Timer
78
ISR(TIMER0_OVF_vect)
79
{    
80
  if ( !(PINB & (1<<PINB2)) )
81
    {
82
        StartStop();
83
    }
84
    
85
  if ( !(PIND & (1<<PIND2)) )
86
  {
87
      Reset();
88
  }
89
    
90
  counter++;
91
  
92
  //if (counter > 625) //16MHz ohne Prescaler: (16000000/256)/625=100 --> 1/100sek Auflösung
93
  if (counter > 624)
94
  {
95
    sek[0]++;
96
    counter = 0;
97
  }
98
  
99
  for(i = 0; i < 4; i++)
100
  {
101
    if (sek[i] > 9)
102
    {
103
      sek[i]=0;
104
      sek[i+1]++;
105
    }
106
    if (sek[3] > 9)
107
    {
108
      sek[0] = 0;
109
      sek[1] = 0;
110
      sek[2] = 0;
111
      sek[3] = 0;
112
    }
113
  }
114
}
115
//-----------------------------------
116
117
118
inline StartStop(void)
119
{
120
  
121
    if(running == 0)
122
    {
123
        TCCR0 = 0x01; //Timer ohne Prescaler (siehe S.80 im Datenblatt) (00000001)  
124
        running = 1;  //Indikator für "läuft"
125
    }
126
    else
127
    {
128
        TCCR0 = 0x00; //Timer0 aus (00000000)
129
        running = 0;  //Indikator für "läuft nicht"
130
    }
131
}
132
//-----------------------------------
133
134
135
inline Reset(void)
136
{
137
  TCCR0 = 0x00; //Timer0 deaktivieren (00000000)
138
  
139
  //alle Anzeigen auf 0
140
  PORTA = zahl[0];
141
  PORTB = zahl[0];
142
  PORTC = zahl[0];
143
  PORTD = zahl[0];
144
  
145
  running = 0;  //Indikator für "läuft nicht"
146
}
147
//-----------------------------------

von Johannes M. (johnny-m)


Lesenswert?

Robert Knipp wrote:
>
1
> //ISR für Timer
2
> ISR(TIMER0_OVF_vect)
3
> {
4
>   if ( !(PINB & (1<<PINB2)) )
5
>     {
6
>         StartStop();
7
>     }
8
> 
9
>   if ( !(PIND & (1<<PIND2)) )
10
>   {
11
>       Reset();
12
>   }
13
>
Das wird auch nicht so laufen, wie es soll. Du musst schon auf 
Änderungen abfragen (sprich: Du musst Dir den Zustand bei der jeweils 
vorherigen Abfrage merken). Auf die Weise wie oben wird bei einem 
Tastendruck die betreffende Funktion alle 10 ms aufgerufen, bis Du den 
Taster wieder loslässt (was möglicherweise nicht im Sinne des Erfinders 
ist).

Wenn Du nur wissen möchtest, ob ein Taster seit der letzten Abfrage 
gedrückt wurde (und das Wieder-Loslassen Dich nicht interessiert), dann 
genügt z.B. eine einfache UND-Verknüpfung des alten Zustandes mit dem 
Komplement des neuen.

von Robert K. (mr_insanity)


Lesenswert?

Also ich raffs nicht mehr. Es will immer noch nicht. So siehts jetzt 
aus:
1
volatile unsigned int start;
2
volatile unsigned int rst;
3
4
...
5
6
ISR(TIMER0_OVF_vect)
7
{    
8
  if ( (!(PINB & (1<<PINB2))) & (start == 0) )
9
    {
10
        StartStop();
11
        start = 1;
12
    }
13
    if ( (PINB & (1<<PINB2)) & start )
14
    {
15
        start = 0;
16
    }
17
    
18
    if ( (!(PIND & (1<<PIND2))) & (rst == 0) )
19
    {
20
        Reset();
21
        rst = 1;
22
    }
23
    if ( (PIND & (1<<PIND2)) & rst )
24
    {
25
        rst = 0;
26
    }
27
28
...

von Johannes M. (johnny-m)


Lesenswert?

Robert Knipp wrote:
>
1
>   if ( (!(PINB & (1<<PINB2))) & (start == 0) )
2
>     {
3
>         StartStop();
4
>         start = 1;
5
>     }
6
>
Mit einem bitweisen UND an der zweiten Stelle wird das so auch u.U. 
nichts. Da musst Du schon ein logisches UND nehmen (ein "&&"). (Obwohl 
es in diesem Fall sogar funktionieren dürfte, weil beide Seiten 
Wahrheitswerte sind).

von Robert K. (mr_insanity)


Lesenswert?

Also langsam bin ich echt am verzweifeln. Habe das '&' durh ein '&&' an 
den besagten Stellen ersetzt und auch noch einen anderen Controller 
ausprobiert. Funktionieren tuts aber immer noch nicht.

von Matthias L. (Gast)


Lesenswert?

Ich mache Flankenerkennungen immer (ungefähr) so:
1
ISR(TIMER0_OVF_vect)
2
{    
3
  static _PINBLast;
4
  if (    (  ( PINB     & (1<<PINB2)) == 0 ) 
5
       && (  (_PINBLast & (1<<PINB2)) != 0 )  )
6
    {  // negative Flanke
7
        StartStop();
8
        start = 1;
9
    }
10
....
11
12
13
 _PINBLast = PINB;
14
}

von Robert K. (mr_insanity)


Lesenswert?

Also ich habe jetzt mal den Timer von Anfang an gestartet und dann läuft 
die Uhr auch erstmal. Was ich merkwürdig finde, ist dass dann Start/Stop 
und Reset genau einmal funktionieren und dann steht die Uhr. Wenn ich 
den Timer nich am Anfang starte lässt sich die Uhr auch nicht wenigstens 
starten.

von Robert K. (mr_insanity)


Lesenswert?

Vielleicht noch jemand eine Idee?

von Robert K. (mr_insanity)


Angehängte Dateien:

Lesenswert?

Jetzt habe ich mal alle 4 Anzeigen an die Schaltung angeschlossen 
(hattees vorher nur mit einer ausprobiert), aber nun leuchten nicht alle 
Segmente. Woran kann das denn liegen. Bin ziemlich ratlos. An den 
Segmenten die nicht leuchten sind die Ports auch nicht geschaltet. Wie 
man im Programmtext sieht, sollten aber alle Anzeigen eine 8 anzeigen.
Hier der aktuelle Code und mal der Schalteplan.
1
//Stoppuhr
2
3
#include <avr/io.h>
4
#include <avr/interrupt.h>
5
#include <util/delay.h>
6
7
8
volatile unsigned char running = 0;
9
volatile unsigned char zahl[10]; //Array in denen die Portausgaben für die Zahlen 0-9 gespeichert ist
10
volatile unsigned char sek[4];   //Parameter für zahl
11
volatile unsigned char i;        //Zählvariable für sek
12
volatile unsigned int counter;   // <- Zählervariable MUSS Integer sein, da > 255 gezählt wird
13
volatile unsigned char start = 0;
14
volatile unsigned char rst = 0;
15
16
17
//Timer und Interrupt Initialisierung
18
int interrupt_init(void)
19
{
20
  TCNT0 = 0x00;  //Timer0 mit 0 initialisieren (00000000)
21
  TIMSK = 0x01;  //Timer0 Overflow Interrupt aktivieren (00000001)
22
  
23
  return 0;
24
}
25
//-----------------------------------
26
27
28
//Konstanten und Portkonfiguration
29
int const_init(void)
30
{
31
  zahl[0] = 0x7F; //(01111111)
32
  zahl[1] = 0x0E; //(00001110) 
33
  zahl[2] = 0xB7; //(10110111)
34
  zahl[3] = 0x9F; //(10011111)
35
  zahl[4] = 0xCE; //(11001110)
36
  zahl[5] = 0xDD; //(11011101)
37
  zahl[6] = 0xFD; //(11111101)
38
  zahl[7] = 0x0F; //(00001111)
39
  zahl[8] = 0xFF; //(11111111)
40
  zahl[9] = 0xDF; //(11011111)
41
  
42
  DDRA = 0xFF; //alle Pins Ausgang (11111111)
43
  DDRB = 0xFB; //Pin 2 (INT2) Eingang, Rest Ausgang (11111011)
44
  DDRC = 0xFF; //alle Pins Ausgang (11111111)
45
  DDRD = 0xFB; //Pin 2 (INT0) Eingang, Rest Ausgang (11111011)
46
    
47
  //alle Ports zeigen 0 an
48
  PORTA = zahl[8];  //Port für 10er Sekunden
49
  PORTB = zahl[8];  //Port für Sekunden
50
  PORTC = zahl[8];  //Port für 1/10 Sekunden
51
  PORTD = zahl[8];  //Port für 1/100 Sekunden
52
  
53
  running = 0;
54
  
55
  return 0;
56
}
57
//-----------------------------------
58
59
60
//Hauptprogramm
61
int main(void)
62
{
63
  interrupt_init();
64
  const_init();
65
  
66
  sei();
67
    //TCCR0 = 0x01;
68
69
  while(1) {
70
  
71
    PORTA = zahl[sek[0]];
72
    PORTB = zahl[sek[1]]; 
73
    PORTC = zahl[sek[2]];
74
    PORTD = zahl[sek[3]];
75
  }
76
}
77
//-----------------------------------
78
79
int StartStop(void)
80
{
81
  
82
    if(running == 0)
83
    {
84
        TCCR0 = 0x01; //Timer ohne Prescaler (siehe S.80 im Datenblatt) (00000001)  
85
        running = 1;  //Indikator für "läuft"
86
    }
87
    else
88
    {
89
        TCCR0 = 0x00; //Timer0 aus (00000000)
90
        running = 0;  //Indikator für "läuft nicht"
91
    }
92
    
93
    return 0;
94
}
95
//-----------------------------------
96
97
98
int Reset(void)
99
{
100
  TCCR0 = 0x00; //Timer0 deaktivieren (00000000)
101
  
102
  //alle Anzeigen auf 0
103
  PORTA = zahl[0];
104
  PORTB = zahl[0];
105
  PORTC = zahl[0];
106
  PORTD = zahl[0];
107
  
108
  running = 0;  //Indikator für "läuft nicht"
109
    
110
    return 0;
111
}
112
//-----------------------------------
113
114
115
//ISR für Timer
116
ISR(TIMER0_OVF_vect)
117
{    
118
  if ( (!(PINB & (1<<PINB2))) && (start == 0) )
119
    {
120
        StartStop();
121
        start = 1;
122
    }
123
    if ( (PINB & (1<<PINB2)) && start )
124
    {
125
        start = 0;
126
    }
127
    
128
    if ( (!(PIND & (1<<PIND2))) && (rst == 0) )
129
    {
130
        Reset();
131
        rst = 1;
132
    }
133
    if ( (PIND & (1<<PIND2)) && rst )
134
    {
135
        rst = 0;
136
    }
137
    
138
  counter++;
139
  
140
  //if (counter > 625) //16MHz ohne Prescaler: (16000000/256)/625=100 --> 1/100sek Auflösung
141
  if (counter > 624)
142
  {
143
    sek[0]++;
144
    counter = 0;
145
  }
146
  
147
  for(i = 0; i < 4; i++)
148
  {
149
    if (sek[i] > 9)
150
    {
151
      sek[i]=0;
152
      sek[i+1]++;
153
    }
154
    if (sek[3] > 9)
155
    {
156
      sek[0] = 0;
157
      sek[1] = 0;
158
      sek[2] = 0;
159
      sek[3] = 0;
160
    }
161
  }
162
}
163
//-----------------------------------

von Robert K. (mr_insanity)


Angehängte Dateien:

Lesenswert?

Und hier das Board.
Vielleicht liegts ja auch daran

von johannes (Gast)


Lesenswert?

Naja, wenn du den Timer stoppst, dann wird natürlich auch kein 
Overflow-Interrupt mehr ausgelöst und somit funktioniert die 
Tastererkennung nicht mehr. Einfach einen zweiten Timer für die 
Tastenabfrage, der immer läuft. Oder die Tasterabfrage in die 
Main-Schleife, dann musst du dich allerdings noch um die Entprellung 
kümmern.

von Robert K. (mr_insanity)


Lesenswert?

OK, das macht Sinn. Danke für den Tip. Noch ne Idee warum die Ports 
nicht geschaltet werden?

Wie ist das denn bei so einer Stoppuhr überhaupt mit dem 
Tastenentprellen? Wenn die Entprellroutine erst nach 100ms meldet dass 
die Taste gedrückt ist, dann ist es doch gar nicht möglich auf 1/100 
Sekunde genau zu stoppen, oder?

von johannes (Gast)


Lesenswert?

Natürlich kannst du auf 1/100 genau messen und noch viel genauer, 
letztendlich kannst du Genauigkeiten annähernd 1/Prozessor-Takt messen. 
Du kannst ja auf die erste Flanke des Tasters messen und dann musst du 
nur sicherstellen, dass durch das Prellen des Tasters, der Timer nicht 
dauernd ein und aus geschaltet wird, also darf der Timer erst nach 
einigen ms wieder eingeschaltet werden - was aber ja kein Problem 
darstellt, da ein Mensch sowieso nicht im ms-Bereich die Stoppuhr ein- 
und ausschaltet. Willst du schneller messen, dann kommt das Signal 
normalerweise sowieso von einer elektronischen Quelle (z.B. 
Lichtschranke) und die prellen nicht.

> Wie man im Programmtext sieht, sollten aber alle Anzeigen eine 8 anzeigen.
Nein, die Segmente zeigen das an, was beim initalisieren in dem 
sek-Array steht (siehe main-while) - die 8 bekommst du nie zu Gesicht.
Ich würde daher vorher das sek-Array und counter mit 0 initialisieren, 
da man bei C nie weiß was in den Variablen steht und somit ein sek[0]++ 
und counter++ nicht unbedingt das macht, was man erwartet.
(Die Zählvariable i kann man auch direkt in der for-Schleife 
daklarieren, muss nicht global, schon gar nicht volatile sein.)

von Robert K. (mr_insanity)


Lesenswert?

Habe das sek-Array und den counter jetzt mit 0 initialisiert. Nun wird 
am Anfang auch eine 0 (oder was auch immer man will) zuverlässig 
angezeigt. Nur mit dem Start und Stop wills immer noch nicht. So siehts 
jetzt aus:
1
...
2
3
int main(void)
4
{
5
  interrupt_init();
6
  const_init();
7
  
8
  sei();
9
10
  while(1)
11
  {
12
    if ( (!(PINB & (1<<PINB2))) && (start == 0) )
13
    {
14
      StartStop();
15
      start = 1;
16
      _delay_ms(100);  //Tastenentprellung
17
    }
18
    if ( (PINB & (1<<PINB2)) && start )
19
    {
20
      start = 0;
21
    }
22
    
23
    if ( (!(PIND & (1<<PIND2))) && (rst == 0) )
24
    {
25
      Reset();
26
      rst = 1;
27
    }
28
    if ( (PIND & (1<<PIND2)) && rst )
29
    {
30
      rst = 0;
31
    }
32
  
33
    PORTA = zahl[sek[0]];  //Port für 10er Sekunden
34
    PORTB = zahl[sek[1]];  //Port für Sekunden
35
    PORTC = zahl[sek[2]];  //Port für 1/10 Sekunden
36
    PORTD = zahl[sek[3]];  //Port für 1/100 Sekunden
37
  }
38
}
39
40
...

von Peter (Gast)


Lesenswert?

du fragst immer noch nur den Pegel des Eingangs ab. Du darfst aber nur 
auf einen Wechsel des Pegels reagieren, sonst wir ununterbrochen 
StartStop aufgerufen, während du den Taster drückst.

Matthias Lipinsky (lippy) hats dir schon gezeigt, wies geht:
1
static _PINBLast;
2
  if (    (  ( PINB     & (1<<PINB2)) == 0 ) 
3
       && (  (_PINBLast & (1<<PINB2)) != 0 )  )
4
    {  // negative Flanke
5
        StartStop();
6
        start = 1;
7
    }
8
....
9
10
11
 _PINBLast = PINB;

von Robert K. (mr_insanity)


Lesenswert?

Also eigentlich läuft es jetzt. Um den Flankenwechsel festzustellen 
benutze ich doch die start und die rst Variable.

von Robert K. (mr_insanity)


Lesenswert?

Habs jetz nochmal so geändert wie Matthias Lipinsky (lippy) es 
beschrieben hatte. Geht auch super und der Code ist noch etwas kürzer 
und übersichtlicher.

Vielen Dank nochmal an jeden der so gut weiter geholfen hat!

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.