Forum: Mikrocontroller und Digitale Elektronik Timer hängt zeitweise


von Lokus P. (derschatten)


Lesenswert?

Grüß euch,
kann mir vielleicht jemand einen Tip geben warum die IF-Abfrage im Timer 
in dem Programm weiter unten, und zwar der Teil:
1
  cntTicks++;
2
  if(cntTicks == nFireTime)                  // Ist Variable <nFireTime> mal 10ms
3
  {
4
    repeatFire ^= 0x01;                      // Wechselt PortC.0 nach Zeit von 0 auf 1
5
    cntTicks = 0;
6
  }

bei schnelleren ändern der Variable "nFireTime" (Mittels Taster) 
manchmal hängen bleibt? Also der Ausgang bleibt dann längere Zeit auf HI 
oder LO bis er weiter blinkt.

1
// ************************************************************************
2
// *                                                                      *
3
// *                             Arcade Stick                             *
4
// *                         Tastenprogrammierung                         *
5
// *                                                                      *
6
// ************************************************************************
7
 
8
#include <avr/eeprom.h>
9
#include <avr/interrupt.h>
10
#include <avr/pgmspace.h>
11
#include <util/delay.h>
12
13
#ifndef F_CPU
14
#define F_CPU      1000000                  // Processor Takt-Frequenz definieren
15
#warning kein F_CPU definiert
16
#endif
17
18
// Tasteneingänge definieren
19
// =========================
20
#define KEY_DDR         DDRB
21
#define KEY_PORT        PORTB
22
#define KEY_PIN         PINB
23
#define KEY0            6
24
#define KEY1            7
25
#define KEY2            0
26
#define KEY3            1
27
#define KEY4            2
28
#define KEY5            3
29
#define KEY6            4
30
#define KEY7            5
31
#define ALL_KEYS        (1<<KEY0 | 1<<KEY1 | 1<<KEY2 | 1<<KEY3 | 1<<KEY4 | 1<<KEY5 | 1<<KEY6 | 1<<KEY7)
32
33
// Tastendrückwiederholungsdauer definieren
34
// ========================================
35
#define REPEAT_MASK     (1<<KEY0 | 1<<KEY1)
36
#define REPEAT_START    50                               // nach 500ms
37
#define REPEAT_NEXT     20                              // alle 200ms
38
39
// Segment und Tasten-Ausgänge definieren
40
// ======================================
41
#define SEGMENT_DDR    DDRD
42
#define SEGMENT_PORT  PORTD
43
#define OUT_DDR         DDRC
44
#define OUT_PORT        PORTC
45
#define OUT1            0
46
#define OUT2            1
47
#define OUT3            2
48
#define OUT4            3
49
#define OUT5            4
50
#define OUT6            5
51
#define ALL_OUT      (1<<OUT1 | 1<<OUT2 | 1<<OUT3 | 1<<OUT4 | 1<<OUT5 | 1<<OUT6)
52
53
#define LED0      (1<<PC0)
54
#define LED1      (1<<PC1)
55
#define LED2      (1<<PC2)
56
#define LED3      (1<<PC3)
57
#define LED4      (1<<PC4)
58
#define LED5      (1<<PC5)
59
60
#define NR_KONFIGS    9
61
#define NR_KEYS      6
62
#define DELAY      300
63
64
uint8_t KonfigPattern[NR_KONFIGS][NR_KEYS] PROGMEM =
65
  {
66
    {LED0,LED1,LED2,LED3,LED4,LED5},            // Konfiguration 1
67
    {LED0,LED2,LED4,LED1,LED3,LED5},            // Konfiguration 2
68
    {LED1,LED0,LED3,LED2,LED4,LED5},            // Konfiguration 3
69
    {LED0,LED2,LED4,LED1,LED3,LED5},            // Konfiguration 4
70
    {LED0,LED2,LED4,LED1,LED3,LED5},            // Konfiguration 5
71
    {LED0,LED2,LED4,LED1,LED3,LED5},            // Konfiguration 6
72
    {LED0,LED2,LED4,LED1,LED3,LED5},            // Konfiguration 7
73
    {LED0,LED2,LED4,LED1,LED3,LED5},            // Konfiguration 8
74
    {LED0,LED2,LED4,LED1,LED3,LED5},            // Konfiguration 9
75
   };
76
77
volatile uint8_t key_state;                    // Entprellt und invertierte Tastenstatus:
78
                                // Bit=1 -> Taste wurde gedrückt
79
volatile uint8_t key_press;                    // Tastendruck registriert
80
volatile uint8_t key_rpt;                    // Tastendruckdauer
81
volatile uint8_t nKonfig;                    // Tasten-Konfiguration
82
volatile uint8_t nFire = 0;                    // Dauerfeuer-Konfiguration
83
volatile uint8_t nFireTime = 12;                // Dauerfeuer-Zeit
84
volatile uint8_t repeatFire;
85
volatile uint8_t nSelect = 0;                  // Select-Taste
86
volatile uint8_t Marker;                    // Speichermarkierung im 7-Segment
87
volatile uint8_t Summe;
88
89
unsigned char led = 0xFF;
90
uint8_t eeKonfigByte;                      // EEPROM Konfigurationsvariable
91
92
// Zeichentabelle für 7-Segment
93
// ============================
94
const unsigned char Tabelle[] PROGMEM = {192, 249, 164, 176, 153, 146, 130, 248, 128, 144};
95
96
// Timer Interrupt von 10ms definieren
97
// ===================================
98
ISR(TIMER0_OVF_vect)
99
{
100
  static uint8_t ct0, ct1, rpt, cntTicks;
101
  uint8_t i;
102
103
  TCNT0 = (uint8_t)(int16_t)-(F_CPU / 1024 * 10e-3 + 0.5);
104
105
  i = key_state ^ ~KEY_PIN;                  // Taste geändert?
106
  ct0 = ~(ct0 & i);                      // resete oder zähle CT0
107
  ct1 = ct0 ^ (ct1 & i);                    // resete oder zähle CT1
108
  i &= ct0 & ct1;                        // Überlauf gezählt?
109
  key_state ^= i;                        // dann Entprellstatus ändern
110
  key_press |= key_state & i;                  // 0->1: Tastendruck erkannt
111
112
  if((key_state & REPEAT_MASK) == 0)              // Überprüfe Tastenwiederholfunktion
113
    rpt = REPEAT_START;                    // Starte Verzögerung
114
  if(--rpt == 0)
115
  {
116
    rpt = REPEAT_NEXT;                    // Wiederhole Verzögerung
117
    key_rpt |= key_state & REPEAT_MASK;
118
  }
119
120
  cntTicks++;
121
  if(cntTicks == nFireTime)                  // Ist Variable <nFireTime> mal 10ms
122
  {
123
    repeatFire ^= 0x01;                      // Wechselt PortC.0 nach Zeit von 0 auf 1
124
    cntTicks = 0;
125
  }
126
}
127
128
// Überprüfen, ob eine Taste gedrückt wurde.
129
// Jede gedrückte Taste wird nur einmal gemeldet
130
// =============================================
131
uint8_t get_key_press(uint8_t key_mask)
132
{
133
  cli();                            // Interrupts deaktivieren
134
  key_mask &= key_press;                    // Tasten auslesen
135
  key_press ^= key_mask;                    // Tasten löschen
136
  sei();                            // Interrupts aktivieren
137
  return key_mask;
138
}
139
140
// Erfolgt ein längerer Tastendruck, so wird nach einiger Zeit
141
// der Tastendruck automatisch wieder verworfen.
142
// ===========================================================
143
uint8_t get_key_rpt(uint8_t key_mask)
144
{
145
  cli();                            // Interrupts deaktivieren
146
  key_mask &= key_rpt;                    // Tasten auslesen
147
  key_rpt ^= key_mask;                    // Tasten löschen
148
  sei();                            // Interrupts aktivieren
149
  return key_mask;
150
}
151
152
// Kurzer Tastendruck
153
// ==================
154
uint8_t get_key_short(uint8_t key_mask)
155
{
156
  cli();                            // Interrupts deaktivieren
157
  return get_key_press(~key_state & key_mask);
158
}
159
160
// Langer Tastendruck
161
// ==================
162
uint8_t get_key_long(uint8_t key_mask)
163
{
164
  return get_key_press(get_key_rpt(key_mask));
165
}
166
167
// Einschaltsequenz, Initialisierung der Ports
168
// ===========================================
169
void init()
170
{
171
172
// Ports initialisieren
173
// --------------------
174
  OUT_DDR |= ALL_OUT;                      // Controller als Ausgang definieren
175
  KEY_DDR |= ALL_KEYS;                    // Tastenports als Ausgang definieren
176
177
// LED-Test
178
// --------
179
  for (uint8_t LED=1; LED<=32;)
180
  {
181
    KEY_PORT = ~LED;                    // Untere 8 Bit auf Taster-PORT B ausgegeben
182
    LED=LED<<1;                        // LED um 1 Bit weiterschieben
183
    _delay_ms(DELAY);
184
  }
185
  KEY_PORT=0xF6;
186
  _delay_ms(DELAY);
187
  KEY_PORT=0xED;
188
  _delay_ms(DELAY);
189
  KEY_PORT=0xDB;
190
  _delay_ms(DELAY);
191
  KEY_PORT=0xF8;
192
  _delay_ms(DELAY);
193
  KEY_PORT=0xC7;
194
  _delay_ms(DELAY);
195
  KEY_PORT=0xFF;
196
  _delay_ms(DELAY);
197
  KEY_PORT=0xC0;
198
  _delay_ms(DELAY);
199
  KEY_PORT=0xFF;
200
  _delay_ms(DELAY);
201
  KEY_PORT=0xC0;
202
  _delay_ms(DELAY);
203
  KEY_PORT=0xFF;
204
  _delay_ms(DELAY);
205
206
// Segment-Test
207
// ------------
208
209
//     1
210
//     -
211
// 32| 64|2
212
//     -
213
// 16| 8 |4
214
//     -
215
  SEGMENT_DDR = 0xFF;                      // 7-Segmentports als Ausgang definieren
216
217
  for (uint8_t LED=1; LED<=64;)
218
  {
219
    SEGMENT_PORT = ~LED;                  // Untere 8 Bit auf 7-Segment-PORT D ausgegeben
220
    LED=LED<<1;                        // Segment um 1 Bit weiterschieben
221
    _delay_ms(DELAY);
222
  }
223
224
// Interrupt aktvieren
225
// -------------------
226
  TCCR0 = (1<<CS02)|(1<<CS00);                // Teilen bei 1024
227
  TIMSK = 1<<TOIE0;                      // TimerInterrupt aktivieren
228
229
// Ports für Funktion setzen
230
// -------------------------
231
  KEY_DDR &= ~ALL_KEYS;                    // Tastenports als Eingang definieren
232
  KEY_PORT |= ALL_KEYS;                    // Tastenports PullUp
233
}
234
235
int main(void)
236
{
237
  init();                            // Einschaltsequenz starten
238
239
  nKonfig = eeprom_read_byte(&eeKonfigByte);          // Aktuellen Wert aus EEPROM auslesen
240
  Marker = nKonfig;                      // EEPROM-Wert für Marker speichern
241
242
  sei();                            // Interrupts aktivieren
243
244
  while(1)
245
  {
246
    Summe = 0;
247
248
    if(!(KEY_PIN & 0x01))                  // Wenn Taste PortB.0 auf HIGH
249
      Summe |= pgm_read_byte(&KonfigPattern[nKonfig-1][0]);
250
    if(!(KEY_PIN & 0x02))                  // Wenn Taste PortB.1 auf HIGH
251
      Summe |= pgm_read_byte(&KonfigPattern[nKonfig-1][1]);
252
    if(!(KEY_PIN & 0x04))                  // Wenn Taste PortB.2 auf HIGH
253
      Summe |= pgm_read_byte(&KonfigPattern[nKonfig-1][2]);
254
    if(!(KEY_PIN & 0x08))                  // Wenn Taste PortB.3 auf HIGH
255
      Summe |= pgm_read_byte(&KonfigPattern[nKonfig-1][3]);
256
    if(!(KEY_PIN & 0x10))                  // Wenn Taste PortB.4 auf HIGH
257
      Summe |= pgm_read_byte(&KonfigPattern[nKonfig-1][4]);
258
    if(!(KEY_PIN & 0x20))                  // Wenn Taste PortB.5 auf HIGH
259
      Summe |= pgm_read_byte(&KonfigPattern[nKonfig-1][5]);
260
261
    if(nFire != 0)
262
    { 
263
      OUT_PORT = Summe | repeatFire;
264
    }
265
    else
266
    {
267
      OUT_PORT = Summe;
268
    }
269
270
    if(nSelect == 0)
271
    {
272
      SEGMENT_PORT = pgm_read_byte(&Tabelle[nKonfig]);  // Konfigurationswert an 7-Segment übergeben
273
      if (nKonfig == Marker)
274
      {
275
        SEGMENT_PORT = pgm_read_byte(&Tabelle[nKonfig]) & ~(1 << 7);
276
      }
277
    }
278
    else
279
    {
280
      SEGMENT_PORT = pgm_read_byte(&Tabelle[nFire]);    // Dauerfeuerwert an 7-Segment übergeben
281
    }
282
283
    if(get_key_short(1<<KEY0))                // kurzer Tastendruck (PinB.6)
284
    {
285
      if(nSelect == 0)                  // Ist Konfiguration gewählt
286
      {
287
        SEGMENT_PORT = 0x8E;              // Buchstabe: F  anzeigen
288
        nSelect = 1;
289
        _delay_ms(DELAY);
290
        SEGMENT_PORT = pgm_read_byte(&Tabelle[nFire]);  // aktuellen Dauerfeuerwert am 7-Segment anzeigen
291
      }
292
      else
293
      {
294
        SEGMENT_PORT = 0xC6;              // sonst Buchstabe: C anzeigen
295
        nSelect = 0;
296
        _delay_ms(DELAY);
297
        SEGMENT_PORT = pgm_read_byte(&Tabelle[nKonfig]);// aktuellen Konfigurationswert am 7-Segment anzeigen
298
      }
299
    }
300
301
    if(get_key_short(1<<KEY1))                // kurzer Tastendruck (PinB.7)
302
    {
303
      if(nSelect == 0)
304
      {
305
        if(nKonfig < 9)                  // Konfigurationswert kleiner als 8,
306
        {
307
          nKonfig++;                  // Wert erhöhen
308
        }
309
        else
310
        {
311
          nKonfig = 1;                // ansonsten zu ersten Wert
312
        }
313
      }
314
      else
315
      {
316
        if(nFire < 9)                  // Dauerfeuerwert kleiner als 8,
317
        {
318
          nFire++;                  // Wert erhöhen
319
          nFireTime--;
320
        }
321
        else
322
        {
323
          nFire = 0;                  // ansonsten zu letzten Wert
324
          nFireTime = 12;
325
        }
326
      }
327
    }
328
329
    if(get_key_long(1<<KEY1) && (nSelect == 0))        // langer Tastendruck
330
    {
331
      eeprom_write_byte(&eeKonfigByte, nKonfig);      // Wert in EEPROM speichern
332
      Marker = nKonfig;                  // EEPROM-Wert für Marker speichern
333
    }
334
  }
335
}

von holger (Gast)


Lesenswert?

>  if(cntTicks == nFireTime)           // Ist Variable <nFireTime> mal

Versuchs mal mit

  if(cntTicks >= nFireTime)           // Ist Variable <nFireTime> mal

von Oliver J. (skriptkiddy)


Lesenswert?

@Manfred W.:

Längere Quelltexte gehören in den Anhang ;). Sonst wird der Thread 
schnell unübersichtlich.

gruß skriptkiddy

von Lokus P. (derschatten)


Lesenswert?

holger schrieb:
>>  if(cntTicks == nFireTime)           // Ist Variable <nFireTime> mal
>
> Versuchs mal mit
>
>   if(cntTicks >= nFireTime)           // Ist Variable <nFireTime> mal

Funktioniert 1A! Danke!

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.