Forum: Mikrocontroller und Digitale Elektronik Probleme beim Blinklicht mit Atmega8


von dex (Gast)


Lesenswert?

ich versuche mich im moment an einem Blinklicht mit 3 LEDs, einem taster 
und einem Atmega8. für den Taster habe ich die Komfort-Entprellfunktion 
hier aus dem Forum genommen und an mein Code angepasst.
MEin Code sieht so aus:
1
#include <stdint.h>
2
#include <avr/io.h>
3
#include <avr/delay.h>
4
#include <avr/interrupt.h>
5
 
6
#ifndef F_CPU
7
#define F_CPU           1000000                   // processor clock frequency
8
#warning kein F_CPU definiert
9
#endif
10
 
11
#define KEY_DDR         DDRD
12
#define KEY_PORT        PORTD
13
#define KEY_PIN         PIND
14
#define KEY0            0
15
#define KEY1            1
16
#define KEY2            2
17
#define ALL_KEYS        (1<<KEY0 | 1<<KEY1 | 1<<KEY2)
18
 
19
#define REPEAT_MASK     (1<<KEY1 | 1<<KEY2)       // repeat: key1, key2
20
#define REPEAT_START    50                        // after 500ms
21
#define REPEAT_NEXT     20                        // every 200ms
22
 
23
#define LED_DDR         DDRB
24
#define LED_PORT        PORTB
25
#define LED0            1
26
#define LED1            2
27
#define LED2            3
28
 
29
volatile uint8_t key_state;                                // debounced and inverted key state:
30
                                                  // bit = 1: key pressed
31
volatile uint8_t key_press;                                // key press detect
32
 
33
volatile uint8_t key_rpt;                                  // key long press and repeat
34
 
35
 
36
ISR( TIMER0_OVF_vect )                            // every 10ms
37
{
38
  static uint8_t ct0, ct1, rpt;
39
  uint8_t i;
40
 
41
  TCNT0 = (uint8_t)(int16_t)-(F_CPU / 1024 * 10e-3 + 0.5);  // preload for 10ms
42
 
43
  i = key_state ^ ~KEY_PIN;                       // key changed ?
44
  ct0 = ~( ct0 & i );                             // reset or count ct0
45
  ct1 = ct0 ^ (ct1 & i);                          // reset or count ct1
46
  i &= ct0 & ct1;                                 // count until roll over ?
47
  key_state ^= i;                                 // then toggle debounced state
48
  key_press |= key_state & i;                     // 0->1: key press detect
49
 
50
  if( (key_state & REPEAT_MASK) == 0 )            // check repeat function
51
     rpt = REPEAT_START;                          // start delay
52
  if( --rpt == 0 ){
53
    rpt = REPEAT_NEXT;                            // repeat delay
54
    key_rpt |= key_state & REPEAT_MASK;
55
  }
56
}
57
 
58
///////////////////////////////////////////////////////////////////
59
//
60
// check if a key has been pressed. Each pressed key is reported
61
// only once
62
//
63
uint8_t get_key_press( uint8_t key_mask )
64
{
65
  cli();                                          // read and clear atomic !
66
  key_mask &= key_press;                          // read key(s)
67
  key_press ^= key_mask;                          // clear key(s)
68
  sei();
69
  return key_mask;
70
}
71
 
72
///////////////////////////////////////////////////////////////////
73
//
74
// check if a key has been pressed long enough such that the
75
// key repeat functionality kicks in. After a small setup delay
76
// the key is reported being pressed in subsequent calls
77
// to this function. This simulates the user repeatedly
78
// pressing and releasing the key.
79
//
80
uint8_t get_key_rpt( uint8_t key_mask )
81
{
82
  cli();                                          // read and clear atomic !
83
  key_mask &= key_rpt;                            // read key(s)
84
  key_rpt ^= key_mask;                            // clear key(s)
85
  sei();
86
  return key_mask;
87
}
88
 
89
///////////////////////////////////////////////////////////////////
90
//
91
// check if a key is pressed right now
92
//
93
uint8_t get_key_state( uint8_t key_mask )
94
 
95
{
96
  key_mask &= key_state;
97
  return key_mask;
98
}
99
 
100
///////////////////////////////////////////////////////////////////
101
//
102
uint8_t get_key_short( uint8_t key_mask )
103
{
104
  cli();                                          // read key state and key press atomic !
105
  return get_key_press( ~key_state & key_mask );
106
}
107
 
108
///////////////////////////////////////////////////////////////////
109
//
110
uint8_t get_key_long( uint8_t key_mask )
111
{
112
  return get_key_press( get_key_rpt( key_mask ));
113
}
114
 
115
int main( void )
116
{ volatile int counter=0;
117
  LED_PORT = 0x00;
118
  LED_DDR = 0xFF;                     
119
 
120
  // Configure debouncing routines
121
  KEY_DDR &= ~ALL_KEYS;                // configure key port for input
122
  KEY_PORT |= ALL_KEYS;                // and turn on pull up resistors
123
 
124
  TCCR0 = (1<<CS02)|(1<<CS00);         // divide by 1024
125
  TCNT0 = (uint8_t)(int16_t)-(F_CPU / 1024 * 10e-3 + 0.5);  // preload for 10ms
126
  TIMSK |= 1<<TOIE0;                   // enable timer interrupt
127
 
128
  sei();
129
 
130
  while(1){
131
    if( get_key_short( 1<<KEY1 ))
132
      counter++;
133
    
134
 
135
    if( get_key_long( 1<<KEY1 ))
136
    counter=0;
137
   
138
   
139
   if(counter==0)
140
    LED_PORT = 0x00;
141
      
142
   
143
   if(counter==1)
144
    LED_PORT |= 1<<LED0;
145
    
146
    
147
      if(counter==2)
148
    LED_PORT |= (1<<LED0)| (1<<LED1);
149
    
150
    
151
      if(counter==3)
152
    LED_PORT |= (1<<LED0)| (1<<LED1) | (1<<LED2);
153
    _delay_ms(500);
154
    LED_PORT ^= (1<<LED0)| (1<<LED1) | (1<<LED2);
155
    
156
  
157
  }
158
}

zuerste hatte ich den selben Code ohne
1
_delay_ms(500);
2
LED_PORT ^= (1<<LED0)| (1<<LED1) | (1<<LED2);


und da hat es funktioniert wie er hofft, d.h zuerst sind alle LEDs aus, 
nach jedem tastendruck geht eine neue LED an und bei langem halten gehen 
sie wieder aus.

Wenn ich dann nur den delay reinmache passiert genau das selbe, jedoch 
gehen die LEDs verzögert an. das dürfte ja eigentlich nicht sein, da das 
delay nur in kraft tritt wenn der counter==3 ist und nicht schon bei 0,1 
und 2.

wenn ich dann noch zusätzlich
1
LED_PORT ^= (1<<LED0)| (1<<LED1) | (1<<LED2);

in die if(counter==3) einsetze dann macht die schaltung was komplett 
anderes als erwartet. geplant ist, dass beim dritten tastendruck alle 
LEDs einmal angehen und nach einer halben sekunde ausgehen.

was aber passiert ist, dass die LEDs zu beginn nur kurz aufflimmern, 
beim ersten Tastendruck leuchtet LED1 durchgehend und die anderen 
blinken. beim zweiten Tastendruck leuchten die ersten beiden durchgehenn 
und die letzte blinkt und beim letzten tastendruck leuchten alle 
durchgehend.

kann mir da einer helfen?

von Hubert G. (hubertg)


Lesenswert?

Fehlen da vielleicht ein paar Klammern?  {  }

von dex (Gast)


Lesenswert?

Hubert G. schrieb:
> Fehlen da vielleicht ein paar Klammern?  {  }

stimmt^^ und ich denke natürlich nicht an so etwas simples

passt jetzt soweit

Danke für die schnelle antwort

von dex (Gast)


Lesenswert?

hab jetzt nochmal eine Frage zum selben Problem wenn ich jetzt bei einem 
counter möchte dass die LEDs blinken füge ich folgenden Code ein
1
      if(counter==3)
2
      {
3
          LED_PORT |= (1<<LED0)| (1<<LED1) | (1<<LED2);
4
        while (counter==3)
5
        {
6
          
7
          _delay_ms(500);
8
          LED_PORT ^= (1<<LED0)| (1<<LED1) | (1<<LED2);
9
          
10
        }
11
        
12
    
13
      }

allerdings reagiert mein Code ab diesem Zustand nicht mehr auf die 
Tasten

weder langes drücken noch ein kurzer druck bewirken irgendwas. Kennst 
jemand ne mögliche ursache dafür?

von Hubert G. (hubertg)


Lesenswert?

dex schrieb:
> while (counter==3)

Warum das?

von J.-u. G. (juwe)


Lesenswert?

dex schrieb:
> allerdings reagiert mein Code ab diesem Zustand nicht mehr auf die
> Tasten
>
> weder langes drücken noch ein kurzer druck bewirken irgendwas. Kennst
> jemand ne mögliche ursache dafür?

Ja. Die while-Schleife bricht nie ab, da "counter" immer 3 bleibt (wird 
ja nirgendwo geändert).

von dex (Gast)


Lesenswert?

aber den änder ich doch durch den tastendruck wie bei den anderen 
abfragen auch. oder ist das etwas anderes? der tasten interrupt wird 
doch auch in der while schleife ausgeführt oder sehe ich das falsch?

von J.-u. G. (juwe)


Lesenswert?

dex schrieb:
> aber den änder ich doch durch den tastendruck wie bei den anderen
> abfragen auch. oder ist das etwas anderes? der tasten interrupt wird
> doch auch in der while schleife ausgeführt oder sehe ich das falsch?

Die Variable "counter" wird doch in Deiner Interrupt-Routine gar nicht 
geändert. Das passiert bei Deinem Programm doch in der "main"-Funktion. 
Und an diese Stellen der "main"-Funktion kommst Du nicht mehr, da Du in 
der while-Schleife festhängst. In dieser Schleife wertest Du doch gar 
keine Tastendrücke mehr aus.

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.