Forum: Mikrocontroller und Digitale Elektronik Taster - externen Interrupt Problem


von daniel san (Gast)


Lesenswert?

Hi,

vorab was das Programm tun sollte.

Wird er Blaue Taster (INT0, PD2) gedrückt wird die enstprechende ISR 
aufgerufen dort soll immer ein Flag erhöht werden.

Beim 1. Tastendruck soll "menue" auf 1 gesetzt werden, so dass in der 
Main in der switch-case der Part "Set_Time" ausgeführt wird, toogle dort 
Testweise einen Portpin PD0 um zu sehen, das er auch da reinspringt.

Nur leider tut das Programm mir nicht den gefallen.
Ich weiß das der Taster prellt, und habe deswegen in der ISR die ext. 
Interrupts abgeschaltet, die externen INTpins als Ausgang geschaltet und 
zusätzlich die entsprechenden Flags gelöscht, da sonst ja wieder ein 
neuer ISR Aufruf erfolgt.

Nur klappt das nicht und ich weiß nicht was ich falsch mache.

Prellen hardewaremäßig beheben geht leider nicht mehr.

Ich möchte das gerne mit Interrupts lösen.

Ich hoffe mir kann jemand von euch helfen.

Ich danke euch!

Hardware:
ATTiny2313, läuft mit 1MHz

Code:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <util/delay.h>
4
#include <stdint.h> 
5
6
#ifndef F_CPU
7
#define F_CPU 1000000      // processor clock frequency
8
#warning kein F_CPU definiert
9
#endif
10
11
//****************************************************
12
/*  Pinbelegung:
13
14
   Output:
15
  PB5 - A
16
  PB4 - B
17
  PB3 - DP
18
  PB2 - C
19
  PB1 - D
20
  PB0 - E
21
  PB6 - F
22
  PB7 - G
23
24
  PD0 - Relais
25
  PD1 - Summer
26
27
  PD6 - min  
28
  PD5 - sek_1
29
  PD4 - sek_2
30
  
31
  Input:
32
  (auf fallende Flanke triggern - Taster wird gedrückt)
33
  PD3(INT1) - tast_rot
34
  PD2(INT0) - tast_bl  
35
  
36
  Clock:
37
  CKSEL = 01000 = Internal 8MHz RC
38
  CKDIV = 8
39
40
  Internal 8MHz / 8div = 1MHz
41
42
*/
43
//****************************************************
44
45
// 7-Segment-Anzeige 0 - 9:
46
//0 a,b,c,d,e,f
47
#define NULL 0b01110111
48
//1 a,b,c
49
#define EINS 0b00010100 
50
//2 a,b,d,e,g
51
#define ZWEI 0b10110011
52
//3 a,b,c,d,g
53
#define DREI 0b10110110
54
//4 b,c,f,g
55
#define VIER 0b11010100
56
//5 a,c,d,f,g
57
#define FUENF 0b11100110
58
//6 a,c,d,e,f,g
59
#define SECHS 0b11100111
60
//7 a,b,c,g
61
#define SIEBEN 0b00110100
62
//8 a,b,c,d,e,f,g
63
#define ACHT 0b11110111
64
//9 a,b,c,d,f,g
65
#define NEUN 0b11110110
66
// - - -
67
#define STRICH 0b10000000
68
69
//****************************************************
70
71
uint16_t cnt;
72
uint8_t flag;
73
uint8_t menue;
74
75
uint8_t t1;
76
uint8_t t2;
77
uint8_t t3;
78
79
uint8_t sek;
80
uint8_t min;
81
uint8_t sek1;
82
uint8_t sek2;
83
int zahlen[11]={NULL,EINS,ZWEI,DREI,VIER,FUENF,SECHS,SIEBEN,ACHT,NEUN,STRICH};
84
85
enum mode {SET_TIME, START, STOP};
86
  
87
enum mode menue;
88
89
ISR(INT0_vect)
90
//Taster Blau >> SET_TIME
91
{
92
  flag++;
93
94
  if(flag==1)
95
  {
96
    menue++;
97
98
    GIMSK &= ~( (1<<INT1) | (1<<INT0) ); //disable ext ints
99
    DDRD |= (1<<PD3) | (1<<PD2); //Portpins als Ausgang wegen Prellvorgang
100
101
  }
102
103
104
  EIFR |= (1<<INTF1) | (1<<INTF0); //ext. int flag löschen
105
106
}
107
108
ISR(INT1_vect) 
109
//Taster Rot einstellen des Wertes für die 3 Segmentanzeigen (Min(einstellig), Sek (2stellig))
110
{
111
 //todo...
112
}
113
114
ISR(TIMER1_COMPA_vect)
115
// wird jede 1sek. aufgerufen
116
{
117
  
118
  sek++;
119
120
  if(sek==60)
121
  {
122
    min++;
123
    sek=0;
124
  }
125
  else if(min>9)
126
  {
127
    min=0;
128
  }
129
130
}
131
132
ISR(TIMER0_COMPA_vect)
133
// wird alle 4ms aufgerufen für die 7-seg Anzeigen
134
{
135
  cnt++;
136
137
  if(cnt==1)
138
  {
139
    PORTB=0;
140
    PORTD &= ~(1<<PD4);
141
    PORTD &= ~(1<<PD5);
142
    _delay_us(2);
143
144
    PORTB = zahlen[t1];
145
    PORTB |= (1<<PB3);
146
    PORTD |= (1<<PD6);
147
  }
148
  else if(cnt==2)
149
  {
150
    PORTD &= ~(1<<PD6);
151
    PORTD &= ~(1<<PD4);
152
    _delay_us(2);
153
154
    PORTB = zahlen[t2];
155
    PORTD |= (1<<PD5);
156
  }
157
  else if(cnt==3)
158
  {
159
    PORTD &= ~(1<<PD5);
160
    PORTD &= ~(1<<PD6);
161
    _delay_us(2);
162
163
    PORTB = zahlen[t3];
164
    PORTD |= (1<<PD4);
165
  }
166
  else if(cnt>3)
167
  {
168
    cnt=0;
169
  }
170
171
} 
172
173
int main(void)
174
{
175
  cnt=0;
176
  min=0;
177
  sek1=0;
178
  sek2=0;
179
  t1=0,t2=0,t3=0;
180
  flag=0;
181
  
182
183
  //----------------------------------------------------------
184
  //PORTB/D configuration
185
  //----------------------------------------------------------
186
187
  DDRB = 0xff; //PORTB Output
188
  PORTB = 0x00;
189
190
  DDRD |= (1<<PD6) | (1<<PD5) | (1<<PD4) | (1<<PD1) | (1<<PD0); //PD6-4,1-0 Out    
191
  DDRD &= ~( (1<<PD3) | (1<<PD2) );
192
193
  PORTD &= ~((1<<PD3) | (1<<PD2)); //Pull-Up deaktivieren, falls gesetzt
194
  PORTD = 0x00;
195
196
  _delay_us(2);
197
198
  PORTD &= ~((1<<PD6) | (1<<PD5) | (1<<PD4));
199
  _delay_us(2);
200
201
  //----------------------------------------------------------
202
  //Timer configuration
203
  //----------------------------------------------------------
204
205
  //Timer1 - CTC-Mode Top=OCR1A
206
  TCCR1B |= (1<<WGM12);
207
208
  //Timer1 - top-value
209
  OCR1A = 15625; //1sec
210
211
  //internal clock | div64, gleichzeit counter starten!
212
  TCCR1B |= (1<<CS11) | (1<<CS10);
213
214
  //Timer0 - CTC-Mode Top=OCR0A
215
  TCCR0A |= (1<<WGM01);
216
  
217
  //div64 >> 1MHz/1024=976,5625Hz
218
  TCCR0B |= (1<<CS02) | (1<<CS00); 
219
  
220
  //Timer0 - top-value
221
  OCR0A = 4; // 156 ca. 10ms | 24 ca. 24ms
222
223
  //enable Timer 0 output compare A match interrupt
224
  //TIMSK |= (1<<OCIE0A) | (1<<OCIE1A);
225
  TIMSK |= (1<<OCIE0A);
226
  
227
  //----------------------------------------------------------
228
  //external interrupt configuration (taster)
229
  //----------------------------------------------------------
230
231
  //INT1, INT0 any change + enable
232
  MCUCR |= (1<<ISC11) | (1<<ISC01);
233
  GIMSK |= (1<<INT1) | (1<<INT0);
234
  
235
  //----------------------------------------------------------
236
237
  menue=-1;
238
239
  sei();  //enable global ints
240
241
  while(1)
242
  {
243
244
    switch (menue)
245
    {
246
      case 0:
247
        
248
        PORTD |= (1<<PD0);
249
        _delay_ms(100);
250
        PORTD &= ~(1<<PD0);
251
252
        t1=2;
253
        t2=2;
254
        t3=2;
255
          
256
        EIFR |= (1<<INTF1) | (1<<INTF0);
257
        GIMSK |= (1<<INT1) | (1<<INT0); //enable ext ints
258
        DDRD &= ~( (1<<PD3) | (1<<PD2) ); //Tasterpins als Input
259
260
261
      break;
262
263
      case 1:
264
      break;
265
266
      case 2:
267
      break;
268
269
      default:
270
      break;
271
    }
272
    
273
274
  }
275
276
}

von Karl H. (kbuchegg)


Lesenswert?

daniel san schrieb:

>
> Prellen hardewaremäßig beheben geht leider nicht mehr.
>
> Ich möchte das gerne mit Interrupts lösen.

Warum? Es gibt keinen Grund dafür! (So wie es meistens keinen Grund gibt 
um Taster mittels Interrupt auszuwerten. Aus irgendeinem Grund hält sich 
dieser Mythos beständig und ist nicht auszurotten. Der einzige Grund für 
Interrupts mit Tastern wäre wenn der µC aus dem Tiefschlaf geholt werden 
muss. Aber ansonsten braucht kein Mensch dafür Interrupts. Das macht 
alles nur noch komplizierter)

Du hast mit

ISR(TIMER0_COMPA_vect)

einen perfekten Platz um eine softwaremässige Entprellung einzubauen

Entprellung
ganz unten, die C Routinen (das Timer Vorladen lässt du einfach weg)

Edit: Und bevor du fragst - mit diesen Entprell-Routinen kriegst du 
einen automatischen Autorepeat frei Haus mitgeliefert. Gerade bei 
Einstell-Dingen wie deinen, ist das sehr praktisch. Einfach auf den 
Knopf drücken und die Zahl wird gemächlich ganz von alleine größer 
solange du den Taster gedrückt hältst.

von daniel san (Gast)


Lesenswert?

Hi

Karl Heinz Buchegger schrieb:


> Du hast mit
>
> ISR(TIMER0_COMPA_vect)
>
> einen perfekten Platz um eine softwaremässige Entprellung einzubauen
>
> Entprellung
> ganz unten, die C Routinen

hi ja ich kenne diese Seite,

sprichst du von der Komfortroutine?

ich finde die Entprellung vom Dannegger aufwendig und kompliziert.


Hatte mir das schon mal angeguckt, aber der Code ist verwirrend 
geschrieben, finde ich. Da wird in einer Funktion noch drei weitere 
Funktionen aufgerufen.

Verstanden habe ich den noch nicht...

Bevor ich das Problem auf ein anderes verlagere, würde ich trotzdem 
gerne wissen was bei mir falsch ist. Vielleicht seh ich dann ein was 
einfacher ist ;)

von Karl H. (kbuchegg)


Lesenswert?

daniel san schrieb:
> Hi
>
> Karl Heinz Buchegger schrieb:
>
>
>> Du hast mit
>>
>> ISR(TIMER0_COMPA_vect)
>>
>> einen perfekten Platz um eine softwaremässige Entprellung einzubauen
>>
>> Entprellung
>> ganz unten, die C Routinen
>
> hi ja ich kenne diese Seite,
>
> sprichst du von der Komfortroutine?
>
> ich finde die Entprellung vom Dannegger aufwendig und kompliziert.

Sie ist überhaupt nicht aufwendig.
Über kompliziert kann man streiten. Ja, sie ist nicht leicht zu 
durchschauen. Das macht allerdings in diesem Falle nichts. Dafür 
funktioniert sie einfach zu gut. Dieses Stück Software ist eines der 
wenigen, von dem ich sagen würde: Egal ob du sie verstehst oder nicht - 
nutze sie.

> Hatte mir das schon mal angeguckt, aber der Code ist verwirrend
> geschrieben, finde ich. Da wird in einer Funktion noch drei weitere
> Funktionen aufgerufen.

Das zentrale Element ist das hier
1
  i = key_state ^ ~KEY_PIN;                       // key changed ?
2
  ct0 = ~( ct0 & i );                             // reset or count ct0
3
  ct1 = ct0 ^ (ct1 & i);                          // reset or count ct1
4
  i &= ct0 & ct1;                                 // count until roll over ?
5
  key_state ^= i;                                 // then toggle debounced state
6
  key_press |= key_state & i;                     // 0->1: key press detect
7
 
8
  if( (key_state & REPEAT_MASK) == 0 )            // check repeat function
9
     rpt = REPEAT_START;                          // start delay
10
  if( --rpt == 0 ){
11
    rpt = REPEAT_NEXT;                            // repeat delay
12
    key_rpt |= key_state & REPEAT_MASK;
13
  }

das kommt in deine ISR ans Ende mit rein.

Und das wars dann bei dir auch schon.

Die #define davor übernimmst du noch und passt sie an deine 
Gegebenheiten an#
1
#define KEY_DDR         DDRD
2
#define KEY_PORT        PORTD
3
#define KEY_PIN         PIND
4
#define KEY_BLUE        2
5
#define KEY_RED         3
6
#define ALL_KEYS        (1<<KEY_BLUE | 1<<KEY_RED)
7
 
8
#define REPEAT_MASK     (1<<KEY_RED)          // repeat: nur bei Rot
9
#define REPEAT_START    50                    // after 500ms
10
#define REPEAT_NEXT     20                    // every 200ms

und die Funktionen übernimmst du so wie sie sind
1
///////////////////////////////////////////////////////////////////
2
//
3
// check if a key has been pressed. Each pressed key is reported
4
// only once
5
//
6
uint8_t get_key_press( uint8_t key_mask )
7
{
8
  cli();                                          // read and clear atomic !
9
  key_mask &= key_press;                          // read key(s)
10
  key_press ^= key_mask;                          // clear key(s)
11
  sei();
12
  return key_mask;
13
}
14
 
15
///////////////////////////////////////////////////////////////////
16
//
17
// check if a key has been pressed long enough such that the
18
// key repeat functionality kicks in. After a small setup delay
19
// the key is reported being pressed in subsequent calls
20
// to this function. This simulates the user repeatedly
21
// pressing and releasing the key.
22
//
23
uint8_t get_key_rpt( uint8_t key_mask )
24
{
25
  cli();                                          // read and clear atomic !
26
  key_mask &= key_rpt;                            // read key(s)
27
  key_rpt ^= key_mask;                            // clear key(s)
28
  sei();
29
  return key_mask;
30
}

Fertig ist deine Entprellung. (Portpins noch auf Eingang und 
gegebenenfalls einen Pullup dafür einschalten wenn du keinen externen 
hast)

In der mainloop heißt es dann
1
  while(1)
2
  {
3
    // TAste blau gedrückt: Einstellmodus
4
    if( get_key_press( 1<<KEY_BLUE ) ) {
5
      menu++;
6
      if( menu == 4 )
7
        menu = 0;
8
    }
9
10
    // Taste rot gedrückt: Zeit weiterschalten
11
    // dabei ist auch Autorepeat erlaubt
12
    if( get_key_press( 1 <<KEY_RED ) || get_key_rpt( 1<<KEY_RED ) ) {
13
      // je nach Einstellmodus
14
      // menu gleich 0 ist normal: keine Einstellung
15
      if( menu == 1 )
16
        t1++;
17
      else if( menu == 2 )
18
        t2++;
19
      else if( menu == 3 )
20
        t3++;
21
      }
22
    }
23
  }
einfacher gehts wirklich nimmer diese Funktionen zu verwenden.

Eine Sache auf 3 Minuten und du hast erstklassig funktionierende Tasten.

von daniel san (Gast)


Lesenswert?

Ok danke dir, bin gerade dabei den Code vom Dannegger nachzuvollziehen.

Bei Fragen melde ich mich hier nochmal.

von Karl H. (kbuchegg)


Lesenswert?

daniel san schrieb:


> Bevor ich das Problem auf ein anderes verlagere, würde ich trotzdem
> gerne wissen was bei mir falsch ist. Vielleicht seh ich dann ein was
> einfacher ist ;)

Das müsste man jetzt genauer analysieren.

von Karl H. (kbuchegg)


Lesenswert?

Deine ISR sieht dann so aus (deine multiplext nämlich 1:4 anstelle von 
1:3)
1
ISR(TIMER0_COMPA_vect)
2
// wird alle 4ms aufgerufen für die 7-seg Anzeigen + Entprellung
3
{
4
  static uint8_t ct0, ct1, rpt;
5
  uint8_t i;
6
7
  PORTB = 0;
8
  PORTD &= ~(1<<PD4);
9
  PORTD &= ~(1<<PD5);
10
  PORTD &= ~(1<<PD6);
11
12
  cnt++;
13
  if( cnt == 3 )
14
    cnt = 0;
15
16
  switch( cnt ) {
17
    case 0:
18
      PORTB = zahlen[t1] | (1<<PB3);
19
      PORTD |= (1<<PD6);
20
      break;
21
22
    case 1:
23
      PORTB = zahlen[t2];
24
      PORTD |= (1<<PD5);
25
      break;
26
27
    case 2:
28
      PORTB = zahlen[t3];
29
      PORTD |= (1<<PD4);
30
      break;
31
  }
32
33
  // Tastenpins einlesen und entprellen
34
  i = key_state ^ ~KEY_PIN;                       // key changed ?
35
  ct0 = ~( ct0 & i );                             // reset or count ct0
36
  ct1 = ct0 ^ (ct1 & i);                          // reset or count ct1
37
  i &= ct0 & ct1;                                 // count until roll over ?
38
  key_state ^= i;                                 // then toggle debounced state
39
  key_press |= key_state & i;                     // 0->1: key press detect
40
 
41
  if( (key_state & REPEAT_MASK) == 0 )            // check repeat function
42
     rpt = REPEAT_START;                          // start delay
43
  if( --rpt == 0 ){
44
    rpt = REPEAT_NEXT;                            // repeat delay
45
    key_rpt |= key_state & REPEAT_MASK;
46
  }
47
}

von daniel san (Gast)


Lesenswert?

Hi ich hab das nun soweit angepasst.

Leider wird die untere if-Abfrage aus der main nie bearbeitet , kann den 
blauen Taster so oft drücken wie ich will :(

Es sollte beim betätigen des blauen Tasters menue um 1 erhöht werden und 
anschließend sollen nacheinanchder die Anzeigen - Werte eingestellt 
werden.

1. Taster blau betätigt:

case 1:

i=1
Anzeige:
| - | 0 | 0 |

Taster rot Zahl einstellen 0-9

Solange warten bis mit Taster blau bestätigt

i=2
Anzeige:
| 2 . | - | 0

wieder die gleiche Prozedur

i=3
Anzeige:
| 2. | 1 | - |

...
1
if(get_key_press(1<<KEY_BLUE)) // wird nie ausgeführt auch wenn blauer Taster mehrmals gedrückt
2
{
3
   menue++;
4
5
   PORTD |= (1<<PD0);
6
7
   if(menue>3)
8
   {
9
  menue=0;
10
   }
11
}


Hier der gesamte Code:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <util/delay.h>
4
#include <stdint.h> 
5
6
#ifndef F_CPU
7
#define F_CPU 1000000      // processor clock frequency
8
#warning kein F_CPU definiert
9
#endif
10
11
//****************************************************
12
/*  Pinbelegung:
13
14
   Output:
15
  PB5 - A
16
  PB4 - B
17
  PB3 - DP
18
  PB2 - C
19
  PB1 - D
20
  PB0 - E
21
  PB6 - F
22
  PB7 - G
23
24
  PD0 - Relais
25
  PD1 - Summer
26
27
  PD6 - min  
28
  PD5 - sek_1
29
  PD4 - sek_2
30
  
31
  Input:
32
  (auf fallende Flanke triggern - Taster wird gedrückt)
33
  PD3(INT1) - tast_rot
34
  PD2(INT0) - tast_bl  
35
  
36
  Clock:
37
  CKSEL = 01000 = Internal 8MHz RC
38
  CKDIV = 8
39
40
  Internal 8MHz / 8div = 1MHz
41
42
*/
43
//****************************************************
44
45
// 7-Segment-Anzeige 0 - 9:
46
//0 a,b,c,d,e,f
47
#define NULL 0b01110111
48
//1 a,b,c
49
#define EINS 0b00010100 
50
//2 a,b,d,e,g
51
#define ZWEI 0b10110011
52
//3 a,b,c,d,g
53
#define DREI 0b10110110
54
//4 b,c,f,g
55
#define VIER 0b11010100
56
//5 a,c,d,f,g
57
#define FUENF 0b11100110
58
//6 a,c,d,e,f,g
59
#define SECHS 0b11100111
60
//7 a,b,c,g
61
#define SIEBEN 0b00110100
62
//8 a,b,c,d,e,f,g
63
#define ACHT 0b11110111
64
//9 a,b,c,d,f,g
65
#define NEUN 0b11110110
66
// - - -
67
#define STRICH 0b10000000
68
69
//****************************************************
70
71
#define KEY_DDR         DDRD
72
#define KEY_PORT        PORTD
73
#define KEY_PIN         PIND
74
#define KEY_BLUE        2
75
#define KEY_RED         3
76
#define ALL_KEYS        (1<<KEY_BLUE | 1<<KEY_RED)
77
 
78
#define REPEAT_MASK     (1<<KEY_RED)            // repeat: nur bei Rot
79
#define REPEAT_START    50                      // after 500ms
80
#define REPEAT_NEXT     20                      // every 200ms
81
82
volatile uint8_t key_state;            // debounced and inverted key state:
83
                                                // bit = 1: key pressed
84
volatile uint8_t key_press;                     // key press detect
85
 
86
volatile uint8_t key_rpt;                       // key long press and repeat
87
88
uint16_t cnt;
89
uint8_t flag;
90
91
uint8_t t1;
92
uint8_t t2;
93
uint8_t t3;
94
95
uint8_t sek;
96
uint8_t min;
97
uint8_t sek1;
98
uint8_t sek2;
99
int zahlen[11]={NULL,EINS,ZWEI,DREI,VIER,FUENF,SECHS,SIEBEN,ACHT,NEUN,STRICH};
100
101
//enum mode {SET_TIME=1, START=2, STOP=3};
102
  
103
//enum mode menue;
104
105
ISR(TIMER1_COMPA_vect)
106
// wird jede 1sek. aufgerufen
107
{
108
  
109
  sek++;
110
111
  if(sek==60)
112
  {
113
    min++;
114
    sek=0;
115
  }
116
  else if(min>9)
117
  {
118
    min=0;
119
  }
120
121
}
122
123
ISR(TIMER0_COMPA_vect)
124
// wird alle 4ms aufgerufen für 7-seg Anzeige
125
{
126
  static uint8_t ct0, ct1, rpt;
127
    uint8_t i;
128
129
  cnt++;
130
131
  if(cnt==1)
132
  {
133
    PORTB=0;
134
    PORTD &= ~(1<<PD4);
135
    PORTD &= ~(1<<PD5);
136
    _delay_us(2);
137
138
    PORTB = zahlen[min];
139
    PORTB |= (1<<PB3);
140
    PORTD |= (1<<PD6);
141
  }
142
  else if(cnt==2)
143
  {
144
    PORTD &= ~(1<<PD6);
145
    PORTD &= ~(1<<PD4);
146
    _delay_us(2);
147
148
    PORTB = zahlen[sek1];
149
    PORTD |= (1<<PD5);
150
  }
151
  else if(cnt==3)
152
  {
153
    PORTD &= ~(1<<PD5);
154
    PORTD &= ~(1<<PD6);
155
    _delay_us(2);
156
157
    PORTB = zahlen[sek2];
158
    PORTD |= (1<<PD4);
159
  }
160
  else if(cnt>3)
161
  {
162
    cnt=0;
163
  }
164
165
  i = key_state ^ ~KEY_PIN;                       // key changed ?
166
    ct0 = ~( ct0 & i );                             // reset or count ct0
167
    ct1 = ct0 ^ (ct1 & i);                          // reset or count ct1
168
    i &= ct0 & ct1;                                 // count until roll over ?
169
    key_state ^= i;                                 // then toggle debounced state
170
    key_press |= key_state & i;                     // 0->1: key press detect
171
 
172
    if( (key_state & REPEAT_MASK) == 0 )            // check repeat function
173
  {
174
      rpt = REPEAT_START;                          // start delay
175
  }
176
177
    if( --rpt == 0 )
178
  {
179
      rpt = REPEAT_NEXT;                            // repeat delay
180
      key_rpt |= key_state & REPEAT_MASK;
181
  }
182
183
} 
184
185
///////////////////////////////////////////////////////////////////
186
//
187
// check if a key has been pressed. Each pressed key is reported
188
// only once
189
//
190
uint8_t get_key_press( uint8_t key_mask )
191
{
192
  cli();                                          // read and clear atomic !
193
  key_mask &= key_press;                          // read key(s)
194
  key_press ^= key_mask;                          // clear key(s)
195
  sei();
196
  return key_mask;
197
}
198
 
199
///////////////////////////////////////////////////////////////////
200
//
201
// check if a key has been pressed long enough such that the
202
// key repeat functionality kicks in. After a small setup delay
203
// the key is reported being pressed in subsequent calls
204
// to this function. This simulates the user repeatedly
205
// pressing and releasing the key.
206
//
207
uint8_t get_key_rpt( uint8_t key_mask )
208
{
209
  cli();                                          // read and clear atomic !
210
  key_mask &= key_rpt;                            // read key(s)
211
  key_rpt ^= key_mask;                            // clear key(s)
212
  sei();
213
  return key_mask;
214
}
215
 
216
///////////////////////////////////////////////////////////////////
217
218
int main(void)
219
{
220
  cnt=0;
221
  min=0;
222
  sek1=0;
223
  sek2=0;
224
  t1=0,t2=0,t3=0;
225
  flag=0;
226
227
  uint8_t menue;
228
  
229
230
  //----------------------------------------------------------
231
  //PORTB/D configuration
232
  //----------------------------------------------------------
233
234
  DDRB = 0xff; //PORTB Output
235
  PORTB = 0x00;
236
237
  DDRD |= (1<<PD6) | (1<<PD5) | (1<<PD4) | (1<<PD1) | (1<<PD0); //PD6-4,1-0 Out    
238
  DDRD &= ~( (1<<PD3) | (1<<PD2) );
239
240
  PORTD &= ~((1<<PD3) | (1<<PD2)); //Pull-Up deaktivieren, falls gesetzt
241
  PORTD = 0x00;
242
243
  _delay_us(2);
244
245
  PORTD &= ~((1<<PD6) | (1<<PD5) | (1<<PD4));
246
  _delay_us(2);
247
248
  //----------------------------------------------------------
249
  //Timer configuration
250
  //----------------------------------------------------------
251
252
  //Timer1 - CTC-Mode Top=OCR1A
253
  TCCR1B |= (1<<WGM12);
254
255
  //Timer1 - top-value
256
  OCR1A = 15625; //1sec
257
258
  //internal clock | div64, gleichzeit counter starten!
259
  TCCR1B |= (1<<CS11) | (1<<CS10);
260
261
  //Timer0 - CTC-Mode Top=OCR0A
262
  TCCR0A |= (1<<WGM01);
263
  
264
  //div64 >> 1MHz/1024=976,5625Hz
265
  TCCR0B |= (1<<CS02) | (1<<CS00); 
266
  
267
  //Timer0 - top-value
268
  OCR0A = 4; // 4
269
270
  //enable Timer 0 output compare A match interrupt
271
  //TIMSK |= (1<<OCIE0A) | (1<<OCIE1A);
272
  TIMSK |= (1<<OCIE0A);
273
  
274
  //----------------------------------------------------------
275
  //external interrupt configuration (taster)
276
  //----------------------------------------------------------
277
278
  //INT1, INT0 any change + enable
279
//  MCUCR |= (1<<ISC11) | (1<<ISC01);
280
//  GIMSK |= (1<<INT1) | (1<<INT0);
281
  
282
  //----------------------------------------------------------
283
284
  menue=0;
285
286
  sei();  //enable global ints
287
288
  while(1)
289
  {
290
291
    switch (menue)
292
    {
293
      case 1:
294
        
295
        PORTD &= ~(1<<PD0);        
296
297
        //t1=10;
298
        //t2=10;
299
        //t3=10;
300
301
        for(int i=1;i<=3;i++)
302
        {
303
                      
304
          if(i==1)
305
          {
306
            t1=10;  //Strich 1.Anzeige          
307
308
            while(!get_key_press(1<<KEY_BLUE))
309
            {
310
              if( get_key_press(1<<KEY_RED) || get_key_rpt(1<<KEY_RED) )
311
              {
312
                t1++;
313
                if(t1>9)
314
                {
315
                  t1=0;
316
                }
317
              }
318
            }
319
          }
320
          else if(i==2)
321
          {
322
            t2=10;  //Strich 2.Anzeige
323
324
            while(!get_key_press(1<<KEY_BLUE))
325
            {
326
              if( get_key_press(1<<KEY_RED) || get_key_rpt(1<<KEY_RED) )
327
              {
328
                t2++;
329
                if(t2>9)
330
                {
331
                  t2=0;
332
                }
333
              }
334
            }
335
          }
336
          else if(i==3)
337
          {
338
            
339
            t3=10;  //Strich 3.Anzeige
340
            
341
            while(!get_key_press(1<<KEY_BLUE))
342
            {
343
              if( get_key_press(1<<KEY_RED) || get_key_rpt(1<<KEY_RED) )
344
              {
345
                t3++;
346
                if(t3>9)
347
                {
348
                  t3=0;
349
                }
350
              }
351
            }
352
          }
353
354
        }
355
356
      break;
357
358
      case 2:
359
      break;
360
361
      case 3:
362
      break;
363
364
      default:
365
      break;
366
    }
367
368
    if(get_key_press(1<<KEY_BLUE))
369
    {
370
      menue++;
371
372
      PORTD |= (1<<PD0);
373
374
      if(menue>3)
375
      {
376
        menue=0;
377
      }
378
    }    
379
380
  }
381
382
}

von Karl H. (kbuchegg)


Lesenswert?

>    switch (menue)
>    {
>      case 1:

Wie wird die variable menu jemals wieder 0?

Dein Programm ist viel zu kompliziert und du verlierst dich jetzt in der 
Komplexität.

Du brauchst eine Variation davon
1
  while(1)
2
  {
3
    // TAste blau gedrückt: Einstellmodus
4
    if( get_key_press( 1<<KEY_BLUE ) ) {
5
      menu++;
6
      if( menu == 4 )
7
        menu = 0;
8
    }
9
10
    // Taste rot gedrückt: Zeit weiterschalten
11
    // dabei ist auch Autorepeat erlaubt
12
    if( get_key_press( 1 <<KEY_RED ) || get_key_rpt( 1<<KEY_RED ) ) {
13
      // je nach Einstellmodus
14
      // menu gleich 0 ist normal: keine Einstellung
15
      if( menu == 1 )
16
        t1++;
17
      else if( menu == 2 )
18
        t2++;
19
      else if( menu == 3 )
20
        t3++;
21
      }
22
    }
23
  }

d.h. es gibt nur eine einzige while Schleife und das ist die 
Hauptschleife.
Innerhalb derer wickelst du alles ab. Hör auf in Dingen wie "solange 
Taste gedrückt" zu denken. Dein Programm ist in einem Zustand 
(ausgedrückt durch die Variable menu) und Tastendrücke
a) verändern diesen Zustand
b) lösen abhängig vom Zustand Aktionen aus.

Wenn du haben willst, dass nach einem Druck auf blau eine der Stellen 
einen Strich anzeigt, dann schreib das auch so

1
  while(1)
2
  {
3
    // TAste blau gedrückt: Einstellmodus
4
    if( get_key_press( 1<<KEY_BLUE ) ) {
5
      menu++;
6
      if( menu == 4 )
7
        menu = 0;
8
9
      if( menu == 1 )
10
        t1 = 10;
11
      else if( menu == 2 )
12
        t2 = 10;
13
      else if( menu == 3 )
14
        t3 = 10;
15
    }
16
17
    // Taste rot gedrückt: Zeit weiterschalten
18
    // dabei ist auch Autorepeat erlaubt
19
    if( get_key_press( 1 <<KEY_RED ) || get_key_rpt( 1<<KEY_RED ) ) {
20
      // je nach Einstellmodus
21
      // menu gleich 0 ist normal: keine Einstellung
22
      if( menu == 1 )
23
        t1++;
24
      else if( menu == 2 )
25
        t2++;
26
      else if( menu == 3 )
27
        t3++;
28
      }
29
    }
30
  }


Deine ganze for-Schleifen Konstruktion ist viel zu kompliziert.
1
   for( i = 0; i < 3; ++i ) {   // gewöhn dir an, dass in C bei 0 begonnen
2
                                // wird zu zählen!
3
     if( i == 0 )
4
       mach was A
5
6
     else if( i == 1 )
7
       mach was B
8
9
     else if( i == 2 )
10
       mach was C
11
  }

ist doch eine komplizierte Umschreibung für
1
    mach was A
2
    mach was B
3
    mach was C

dazu brauchst du keine Schleife, wenn du dann erst recht wieder in der 
Schleife je nach Schleifenvariable unterschiedliche "mach was" ausführen 
lassen willst. Da kannst du einfach die nacheinander abzuarbeitenden 
Teile auch untereinander schreiben und in genau der Reihenfolge werden 
sie dann abgearbeitet.

von Karl H. (kbuchegg)


Lesenswert?

>   PORTD &= ~((1<<PD3) | (1<<PD2)); //Pull-Up deaktivieren, falls gesetzt
>  PORTD = 0x00;

Wie sind deine Taster verschaltet?
Hast du externe Pullups?

von daniel san (Gast)


Lesenswert?

Hi,

Karl Heinz Buchegger schrieb:
>>             while(!get_key_press(1<<KEY_BLUE))
>
> Du kannst das nicht so machen.
> Denn der blaue Taster ist ja nur einmal gedrückt.
> Das war ja der Sinn der ganzen Übung.

ok das geht bei der Funktion nicht, stimmt.

Aber das Problem ist ja was anderes er führt ja nichtmal das aus
1
if( get_key_press( 1<<KEY_BLUE ) ) {
2
      menu++;
3
      if( menu == 4 )
4
        menu = 0;
5
6
      if( menu == 1 )
7
        t1 = 10;
8
      else if( menu == 2 )
9
        t2 = 10;
10
      else if( menu == 3 )
11
        t3 = 10;
12
    }

hab deine Main mal 1zu1 wie im obigen Beitrag drüber kopiert und 
ausprobiert, bei keinem einzigen Tastendruck des blauen Tasters wird in 
die if-anweisung ausgeführt.

von daniel san (Gast)


Lesenswert?

Hi ja externe Pullups

von daniel san (Gast)


Lesenswert?

1
DDRB = 0xff; //PORTB Output
2
PORTB = 0x00;
3
4
DDRD |= (1<<PD6) | (1<<PD5) | (1<<PD4) | (1<<PD1) | (1<<PD0); //PD6-4,1-0 Out

PD3 und PD2 sind ja im Anfangszustand automatisch auf 0 eingestellt, 
laut DB

von daniel san (Gast)


Lesenswert?

Die Funktion von Dannegger geht ja vom invertierten Zustand also Pullups 
aus.

Bei tasterbetätigung liegt eine 0 am PIN-Port

von Karl H. (kbuchegg)


Lesenswert?

daniel san schrieb:

>
> Aber das Problem ist ja was anderes er führt ja nichtmal das aus

Ja, hab ich zu spät mitgekriegt.

: Wiederhergestellt durch User
von Karl H. (kbuchegg)


Lesenswert?

> Hi ja externe Pullups

ok.
laut deinem Kommentar schalten die Tasten nach Masse. Stimmt das auch?

von Karl H. (kbuchegg)


Lesenswert?

daniel san schrieb:
> Die Funktion von Dannegger geht ja vom invertierten Zustand also Pullups
> aus.
>
> Bei tasterbetätigung liegt eine 0 am PIN-Port

Ja. Ist richtig.
So werden Tasten auch üblicherweise beschaltet. Dann braucht man nämlich 
keinen externen Pullup (und drumm frag ich dich dauernd danach)

Funktionieren deine Tasten anders rum?

von daniel san (Gast)


Lesenswert?

Messe direkt im Pin-Port PD3 bzw. PD2 .

Bei unbetätigtem Taster, ein High Signal gemessen.

Sobald ich diesen betätige wird auf Masse gezogen.

von Karl H. (kbuchegg)


Lesenswert?

daniel san schrieb:
> Messe direkt im Pin-Port PD3 bzw. PD2 .
>
> Bei unbetätigtem Taster, ein High Signal gemessen.
>
> Sobald ich diesen betätige wird auf Masse gezogen.

OK.
Ist schon mal die halbe Miete.

Lass mich nochmal den Code durchgehen. Ich seh mal zu, dass ich hier bei 
mir was nachstellen kann.

> ausprobiert, bei keinem einzigen Tastendruck des blauen Tasters wird in
> die if-anweisung ausgeführt.

OK.
dann solltest du erst mal testen, ob deine Taster überhaupt 
funktionieren.
(Deine Anzeige ist ja da, d.h. der Interrupt wird aufgerufen)


In der Zwischenzeit kannst du ja mal verifizieren, ob deine Tasten auch 
programmtechnisch funktionieren.
1
#include <avr/io.h>
2
3
int main()
4
{
5
  DDRB = 0xFF;
6
  DDRD = ( 1 << PD5 );
7
8
  PORTB = 0x00;
9
  PORTD = ( 1<<PD5 );
10
11
  while( 1 ) {
12
13
    if( PIND & ( 1 << PD3 ) )
14
      PORTB = 0xFF;
15
    else
16
      PORTB = 0x00;
17
  }
18
}

auf die Taste latschen und auf deiner 7-Segment müsste 1 Segment 
komplett aufleuchten.

von daniel san (Gast)


Lesenswert?

Hi ich hab mal die Taster mal ans Oszi gehängt um zu gucken ob die 
Prellen, sollte doch im 200us Bereich liegen?

Ich sehe da kein Prellen...

Also nackten Pull-up mit R=10k aufgebaut und auf fallende Flanke 
getriggert.

von daniel san (Gast)


Lesenswert?

So einen Taster nutze ich, kann mir nicht vorstellen das diese prellfrei 
sind.

http://www.csd-electronics.de/de/index.htm

Best.Nr.: 35-TREB01

Teste gleich ma dein Code zwecks Tastert-test

von Karl H. (kbuchegg)


Lesenswert?

daniel san schrieb:
> Hi ich hab mal die Taster mal ans Oszi gehängt um zu gucken ob die
> Prellen, sollte doch im 200us Bereich liegen?
>
> Ich sehe da kein Prellen...

Sie werden Prellen.
Wenn nicht heute dann in 2 Wochen oder 2 Monaten.

von daniel san (Gast)


Lesenswert?

ALso Taster geht, die 2.Anzeige die an PD5 hängt geht aus.

Ich vermute dadruch das mein Taster nicht so dolle prellt das ganze von 
Dannegger nicht funktioniert. ..Vermutung

von Karl H. (kbuchegg)


Lesenswert?

daniel san schrieb:
> ALso Taster geht, die 2.Anzeige die an PD5 hängt geht aus.
>
> Ich vermute dadruch das mein Taster nicht so dolle prellt das ganze von
> Dannegger nicht funktioniert. ..Vermutung

Nein.
:-)

Der Code geht natürlich auch, wenn die Taster nicht prellen :-)

von Klaus D. (kolisson)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Der Code geht natürlich auch, wenn die Taster nicht prellen :-)

Das mach doch richtig Lust, demnächst mal wieder einen Beitrag zu 
schreiben.
Der Titel könnte lauten:
"Habe fertigen Hexcode mit Entprellroutine von Autor: peter dannegger,
.. kann Software nicht ändern , suche entsprechende Prelltasten,
.... wo bestellen ?"

Das wäre doch schön , oder ?

Gruss Klaus

von daniel san (Gast)


Lesenswert?

Hm warum es nicht funktioniert ..hmmmm.

Taster gehen ja, habs getestet, sonst ist nicht viel an meinem Programm 
dran.

Worin sich mein Code unterscheid, ISR wird alle 4ms statt 10ms 
aufgerufen und folgende Zeile habe ich nicht

TCNT0 = (uint8_t)(int16_t)-(F_CPU / 1024 * 10e-3 + 0.5);  // preload for 
10ms

aber daran wirds wohl nicht liegen.

von Hannes L. (hannes)


Lesenswert?

Nur gut, dass es Assembler gibt, und Peters Entprellroutine in ASM...
Da versteht man, was man tut, da macht das Programmieren Spaß...

Duck & weg...

...

von Karl H. (kbuchegg)


Lesenswert?

OK. Ich musste auf einem Mega16 testen und dann ins blaue auf einen 2313 
umschreiben

Probier das mal
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <stdint.h> 
4
5
#ifndef F_CPU
6
#define F_CPU 1000000      // processor clock frequency
7
#warning kein F_CPU definiert
8
#endif
9
10
// 7-Segment-Anzeige 0 - 9:
11
//0 a,b,c,d,e,f
12
#define NULL 0b01110111
13
//1 a,b,c
14
#define EINS 0b00010100 
15
//2 a,b,d,e,g
16
#define ZWEI 0b10110011
17
//3 a,b,c,d,g
18
#define DREI 0b10110110
19
//4 b,c,f,g
20
#define VIER 0b11010100
21
//5 a,c,d,f,g
22
#define FUENF 0b11100110
23
//6 a,c,d,e,f,g
24
#define SECHS 0b11100111
25
//7 a,b,c,g
26
#define SIEBEN 0b00110100
27
//8 a,b,c,d,e,f,g
28
#define ACHT 0b11110111
29
//9 a,b,c,d,f,g
30
#define NEUN 0b11110110
31
// - - -
32
#define STRICH 0b10000000
33
34
//****************************************************
35
36
#define KEY_DDR         DDRD
37
#define KEY_PORT        PORTD
38
#define KEY_PIN         PIND
39
#define KEY_BLUE        2
40
#define KEY_RED         3
41
#define ALL_KEYS        (1<<KEY_BLUE | 1<<KEY_RED)
42
 
43
#define REPEAT_MASK     (1<<KEY_RED)            // repeat: nur bei Rot
44
#define REPEAT_START    50                      // after 500ms
45
#define REPEAT_NEXT     20                      // every 200ms
46
47
volatile uint8_t key_state;            // debounced and inverted key state:
48
                                                // bit = 1: key pressed
49
volatile uint8_t key_press;                     // key press detect
50
 
51
volatile uint8_t key_rpt;                       // key long press and repeat
52
53
int zahlen[11]={NULL,EINS,ZWEI,DREI,VIER,FUENF,SECHS,SIEBEN,ACHT,NEUN,STRICH};
54
55
56
ISR(TIMER0_COMPA_vect)
57
// wird alle 4ms aufgerufen für 7-seg Anzeige
58
{
59
  static uint8_t ct0, ct1, rpt;
60
  uint8_t i;
61
62
  i = key_state ^ ~KEY_PIN;                       // key changed ?
63
  ct0 = ~( ct0 & i );                             // reset or count ct0
64
  ct1 = ct0 ^ (ct1 & i);                          // reset or count ct1
65
  i &= ct0 & ct1;                                 // count until roll over ?
66
  key_state ^= i;                                 // then toggle debounced state
67
  key_press |= key_state & i;                     // 0->1: key press detect
68
69
  if( (key_state & REPEAT_MASK) == 0 )            // check repeat function
70
  {
71
      rpt = REPEAT_START;                          // start delay
72
  }
73
74
  if( --rpt == 0 )
75
  {
76
      rpt = REPEAT_NEXT;                            // repeat delay
77
      key_rpt |= key_state & REPEAT_MASK;
78
  }
79
} 
80
81
///////////////////////////////////////////////////////////////////
82
//
83
// check if a key has been pressed. Each pressed key is reported
84
// only once
85
//
86
uint8_t get_key_press( uint8_t key_mask )
87
{
88
  cli();                                          // read and clear atomic !
89
  key_mask &= key_press;                          // read key(s)
90
  key_press ^= key_mask;                          // clear key(s)
91
  sei();
92
  return key_mask;
93
}
94
 
95
///////////////////////////////////////////////////////////////////
96
//
97
// check if a key has been pressed long enough such that the
98
// key repeat functionality kicks in. After a small setup delay
99
// the key is reported being pressed in subsequent calls
100
// to this function. This simulates the user repeatedly
101
// pressing and releasing the key.
102
//
103
uint8_t get_key_rpt( uint8_t key_mask )
104
{
105
  cli();                                          // read and clear atomic !
106
  key_mask &= key_rpt;                            // read key(s)
107
  key_rpt ^= key_mask;                            // clear key(s)
108
  sei();
109
  return key_mask;
110
}
111
 
112
///////////////////////////////////////////////////////////////////
113
114
int main(void)
115
{
116
  uint8_t cnt = 0;
117
118
  DDRB = 0xFF;
119
  DDRD = ( 1 << PD5 );
120
121
  PORTB = 0xFF;
122
  PORTD = ( 1<<PD5 ) | ( 1 << KEY_RED ) | ( 1 << KEY_BLUE );
123
124
  TCCR0A |= (1<<WGM01);
125
  OCR0A = 4; // 4
126
  TIMSK |= (1<<OCIE0A);
127
  TCCR0B |= (1<<CS02) | (1<<CS00); 
128
129
  sei();  //enable global ints
130
131
  while( 1 ) {
132
133
    if( get_key_press( 1 << KEY_RED ) ) {
134
      cnt++;
135
      if( cnt == 10 )
136
        cnt = 0;
137
    }
138
139
    if( get_key_press( 1 << KEY_BLUE ) ) {
140
      cnt--;
141
      if( cnt == 0xFF )
142
        cnt = 9;
143
    }
144
145
    PORTB = zahlen[ cnt ];
146
  }
147
}

Dieselbe mittlere Anzeige zeigt wieder eine Zahl an und durch Druck auf 
Rot bzw. Blau kann sie erhöht/verringert werden.

von Karl H. (kbuchegg)


Lesenswert?

Wenn dieses Testprogramm funktioniert (sollte es eigentlich), dann 
arbeite damit weiter und bau es in die Richtung aus, die du haben 
willst.

Irgendwo in deinem Programm hast du dich verfranst, ich seh aber nichts 
augenfälliges. Das ist mir schon etwas zu verworren und ausserdem muss 
ich gleich weg. Ich bin aber morgen vormittag wieder da.

Zwischendurch immer wieder testen! Nicht zuviel ungetesteten Code auf 
einmal.

von daniel san (Gast)


Lesenswert?

Hi danke dir!

Mit deinen Programm klappt es... warum bei mir nicht .

Morgen werde ich das mal mit meinem vergleichen.

Bis dahin n schönen Abend noch!

von daniel san (Gast)


Lesenswert?

Hi also hab auf Basis deines Codes etwas erweitert.

Da passiert es schon wieder. Wenn ich den unteren Codeabschnitt in die 
ISR packe die alle 4ms angesprungen wird, wird wie schon zuvor nicht 
mehr auf Tastendruck reagiert.......
1
ISR(TIMER0_COMPA_vect)
2
// wird alle 4ms aufgerufen für 7-seg Anzeige
3
{
4
  static uint8_t ct0, ct1, rpt;
5
  uint8_t i;
6
7
  i = key_state ^ ~KEY_PIN;                       // key changed ?
8
  ct0 = ~( ct0 & i );                             // reset or count ct0
9
  ct1 = ct0 ^ (ct1 & i);                          // reset or count ct1
10
  i &= ct0 & ct1;                                 // count until roll over ?
11
  key_state ^= i;                                 // then toggle debounced state
12
  key_press |= key_state & i;                     // 0->1: key press detect
13
14
  if( (key_state & REPEAT_MASK) == 0 )            // check repeat function
15
  {
16
      rpt = REPEAT_START;                          // start delay
17
  }
18
19
  if( --rpt == 0 )
20
  {
21
      rpt = REPEAT_NEXT;                            // repeat delay
22
      key_rpt |= key_state & REPEAT_MASK;
23
  }
24
25
  cnt++;
26
27
  if(cnt==1)
28
  {
29
    PORTB=0;
30
    PORTD &= ~(1<<PD4);
31
    PORTD &= ~(1<<PD5);
32
   // _delay_us(2);
33
34
    PORTB = zahlen[t1];
35
    PORTB |= (1<<PB3);
36
    PORTD |= (1<<PD6);
37
  }
38
  else if(cnt==2)
39
  {
40
    PORTD &= ~(1<<PD6);
41
    PORTD &= ~(1<<PD4);
42
    //_delay_us(2);
43
44
    PORTB = zahlen[t2];
45
    PORTD |= (1<<PD5);
46
  }
47
  else if(cnt==3)
48
  {
49
    PORTD &= ~(1<<PD5);
50
    PORTD &= ~(1<<PD6);
51
   // _delay_us(2);
52
53
    PORTB = zahlen[t3];
54
    PORTD |= (1<<PD4);
55
  }
56
  else if(cnt>3)
57
  {
58
    cnt=0;
59
  }
60
}

Ich habe in der while nur cnt durch t1 ersetzt, sonst nichts geändert.

Ich versteh nicht woran es liegen soll...., muss was mit dem 
TIMER0_COMPA_vect ISR zu tun haben da ich dort nur mein Codeabschnitt 
zur aktualisierung der Anzeigen reingepackt hab.

Hier der gesamte Code:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <stdint.h> 
4
5
#ifndef F_CPU
6
#define F_CPU 1000000      // processor clock frequency
7
#warning kein F_CPU definiert
8
#endif
9
10
// 7-Segment-Anzeige 0 - 9:
11
//0 a,b,c,d,e,f
12
#define NULL 0b01110111
13
//1 a,b,c
14
#define EINS 0b00010100 
15
//2 a,b,d,e,g
16
#define ZWEI 0b10110011
17
//3 a,b,c,d,g
18
#define DREI 0b10110110
19
//4 b,c,f,g
20
#define VIER 0b11010100
21
//5 a,c,d,f,g
22
#define FUENF 0b11100110
23
//6 a,c,d,e,f,g
24
#define SECHS 0b11100111
25
//7 a,b,c,g
26
#define SIEBEN 0b00110100
27
//8 a,b,c,d,e,f,g
28
#define ACHT 0b11110111
29
//9 a,b,c,d,f,g
30
#define NEUN 0b11110110
31
// - - -
32
#define STRICH 0b10000000
33
34
//****************************************************
35
36
#define KEY_DDR         DDRD
37
#define KEY_PORT        PORTD
38
#define KEY_PIN         PIND
39
#define KEY_BLUE        2
40
#define KEY_RED         3
41
#define ALL_KEYS        (1<<KEY_BLUE | 1<<KEY_RED)
42
 
43
#define REPEAT_MASK     (1<<KEY_RED)            // repeat: nur bei Rot
44
#define REPEAT_START    50                      // after 500ms
45
#define REPEAT_NEXT     20                      // every 200ms
46
47
volatile uint8_t key_state;            // debounced and inverted key state:
48
                                                // bit = 1: key pressed
49
volatile uint8_t key_press;                     // key press detect
50
 
51
volatile uint8_t key_rpt;                       // key long press and repeat
52
53
int zahlen[11]={NULL,EINS,ZWEI,DREI,VIER,FUENF,SECHS,SIEBEN,ACHT,NEUN,STRICH};
54
55
uint8_t t1,t2,t3;
56
uint8_t cnt;
57
58
59
ISR(TIMER0_COMPA_vect)
60
// wird alle 4ms aufgerufen für 7-seg Anzeige
61
{
62
  static uint8_t ct0, ct1, rpt;
63
  uint8_t i;
64
65
  i = key_state ^ ~KEY_PIN;                       // key changed ?
66
  ct0 = ~( ct0 & i );                             // reset or count ct0
67
  ct1 = ct0 ^ (ct1 & i);                          // reset or count ct1
68
  i &= ct0 & ct1;                                 // count until roll over ?
69
  key_state ^= i;                                 // then toggle debounced state
70
  key_press |= key_state & i;                     // 0->1: key press detect
71
72
  if( (key_state & REPEAT_MASK) == 0 )            // check repeat function
73
  {
74
      rpt = REPEAT_START;                          // start delay
75
  }
76
77
  if( --rpt == 0 )
78
  {
79
      rpt = REPEAT_NEXT;                            // repeat delay
80
      key_rpt |= key_state & REPEAT_MASK;
81
  }
82
83
  cnt++;
84
85
  if(cnt==1)
86
  {
87
    PORTB=0;
88
    PORTD &= ~(1<<PD4);
89
    PORTD &= ~(1<<PD5);
90
   // _delay_us(2);
91
92
    PORTB = zahlen[t1];
93
    PORTB |= (1<<PB3);
94
    PORTD |= (1<<PD6);
95
  }
96
  else if(cnt==2)
97
  {
98
    PORTD &= ~(1<<PD6);
99
    PORTD &= ~(1<<PD4);
100
    //_delay_us(2);
101
102
    PORTB = zahlen[t2];
103
    PORTD |= (1<<PD5);
104
  }
105
  else if(cnt==3)
106
  {
107
    PORTD &= ~(1<<PD5);
108
    PORTD &= ~(1<<PD6);
109
   // _delay_us(2);
110
111
    PORTB = zahlen[t3];
112
    PORTD |= (1<<PD4);
113
  }
114
  else if(cnt>3)
115
  {
116
    cnt=0;
117
  }
118
} 
119
120
///////////////////////////////////////////////////////////////////
121
//
122
// check if a key has been pressed. Each pressed key is reported
123
// only once
124
//
125
uint8_t get_key_press( uint8_t key_mask )
126
{
127
  cli();                                          // read and clear atomic !
128
  key_mask &= key_press;                          // read key(s)
129
  key_press ^= key_mask;                          // clear key(s)
130
  sei();
131
  return key_mask;
132
}
133
 
134
///////////////////////////////////////////////////////////////////
135
//
136
// check if a key has been pressed long enough such that the
137
// key repeat functionality kicks in. After a small setup delay
138
// the key is reported being pressed in subsequent calls
139
// to this function. This simulates the user repeatedly
140
// pressing and releasing the key.
141
//
142
uint8_t get_key_rpt( uint8_t key_mask )
143
{
144
  cli();                                          // read and clear atomic !
145
  key_mask &= key_rpt;                            // read key(s)
146
  key_rpt ^= key_mask;                            // clear key(s)
147
  sei();
148
  return key_mask;
149
}
150
 
151
///////////////////////////////////////////////////////////////////
152
153
int main(void)
154
{
155
  cnt = 0;
156
  t1=0,t2=0,t3=0;
157
158
  DDRB = 0xFF;
159
160
  PORTB = 0xFF;
161
  PORTD |= ( 1<<PD6 ) | ( 1 << PD5 ) | ( 1 << PD4 );
162
163
  TCCR0A |= (1<<WGM01);
164
  OCR0A = 4; // 4
165
  TIMSK |= (1<<OCIE0A);
166
  TCCR0B |= (1<<CS02) | (1<<CS00); 
167
168
  sei();  //enable global ints
169
170
  while( 1 ) 
171
  {
172
173
    if( get_key_press( 1 << KEY_RED ) ) {
174
      t1++;
175
      if( t1 == 10 )
176
        t1 = 0;
177
    }
178
179
    if( get_key_press( 1 << KEY_BLUE ) ) {
180
      t1--;
181
      if( t1 == 0xFF )
182
        t1 = 9;
183
    }
184
185
   // PORTB = zahlen[ cnt ];
186
  }
187
}

von daniel san (Gast)


Lesenswert?

Hi, also hab grad ein volatile vor der deklaration der globalen 
Variablen: uint8_t t1,t2,t3 gesetzt nun funktionierts aber warum??

volatile uint8_t t1,t2,t3;
volatile uint8_t cnt;

Kannst du mir das vielleicht erklären?

von daniel san (Gast)


Lesenswert?

Volatile sagt ja den compile das er nicht optimieren soll, aber in 
welchen Zusammenhang hat das hier zu tun?

von Hannes L. (hannes)


Lesenswert?

daniel san schrieb:
> in
> welchen Zusammenhang hat das hier zu tun?

Globaler Zugriff auf Variablen...

...

von Karl H. (kbuchegg)


Lesenswert?

daniel san schrieb:
> Hi, also hab grad ein volatile vor der deklaration der globalen
> Variablen: uint8_t t1,t2,t3 gesetzt nun funktionierts aber warum??
>
> volatile uint8_t t1,t2,t3;
> volatile uint8_t cnt;
>
> Kannst du mir das vielleicht erklären?

http://www.mikrocontroller.net/articles/FAQ#Was_hat_es_mit_volatile_auf_sich

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.