mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Timer hängt zeitweise


Autor: Lokus Pokus (derschatten)
Datum:

Bewertung
0 lesenswert
nicht 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:
  cntTicks++;
  if(cntTicks == nFireTime)                  // Ist Variable <nFireTime> mal 10ms
  {
    repeatFire ^= 0x01;                      // Wechselt PortC.0 nach Zeit von 0 auf 1
    cntTicks = 0;
  }

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.

// ************************************************************************
// *                                                                      *
// *                             Arcade Stick                             *
// *                         Tastenprogrammierung                         *
// *                                                                      *
// ************************************************************************
 
#include <avr/eeprom.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <util/delay.h>

#ifndef F_CPU
#define F_CPU      1000000                  // Processor Takt-Frequenz definieren
#warning kein F_CPU definiert
#endif

// Tasteneingänge definieren
// =========================
#define KEY_DDR         DDRB
#define KEY_PORT        PORTB
#define KEY_PIN         PINB
#define KEY0            6
#define KEY1            7
#define KEY2            0
#define KEY3            1
#define KEY4            2
#define KEY5            3
#define KEY6            4
#define KEY7            5
#define ALL_KEYS        (1<<KEY0 | 1<<KEY1 | 1<<KEY2 | 1<<KEY3 | 1<<KEY4 | 1<<KEY5 | 1<<KEY6 | 1<<KEY7)

// Tastendrückwiederholungsdauer definieren
// ========================================
#define REPEAT_MASK     (1<<KEY0 | 1<<KEY1)
#define REPEAT_START    50                               // nach 500ms
#define REPEAT_NEXT     20                              // alle 200ms

// Segment und Tasten-Ausgänge definieren
// ======================================
#define SEGMENT_DDR    DDRD
#define SEGMENT_PORT  PORTD
#define OUT_DDR         DDRC
#define OUT_PORT        PORTC
#define OUT1            0
#define OUT2            1
#define OUT3            2
#define OUT4            3
#define OUT5            4
#define OUT6            5
#define ALL_OUT      (1<<OUT1 | 1<<OUT2 | 1<<OUT3 | 1<<OUT4 | 1<<OUT5 | 1<<OUT6)

#define LED0      (1<<PC0)
#define LED1      (1<<PC1)
#define LED2      (1<<PC2)
#define LED3      (1<<PC3)
#define LED4      (1<<PC4)
#define LED5      (1<<PC5)

#define NR_KONFIGS    9
#define NR_KEYS      6
#define DELAY      300

uint8_t KonfigPattern[NR_KONFIGS][NR_KEYS] PROGMEM =
  {
    {LED0,LED1,LED2,LED3,LED4,LED5},            // Konfiguration 1
    {LED0,LED2,LED4,LED1,LED3,LED5},            // Konfiguration 2
    {LED1,LED0,LED3,LED2,LED4,LED5},            // Konfiguration 3
    {LED0,LED2,LED4,LED1,LED3,LED5},            // Konfiguration 4
    {LED0,LED2,LED4,LED1,LED3,LED5},            // Konfiguration 5
    {LED0,LED2,LED4,LED1,LED3,LED5},            // Konfiguration 6
    {LED0,LED2,LED4,LED1,LED3,LED5},            // Konfiguration 7
    {LED0,LED2,LED4,LED1,LED3,LED5},            // Konfiguration 8
    {LED0,LED2,LED4,LED1,LED3,LED5},            // Konfiguration 9
   };

volatile uint8_t key_state;                    // Entprellt und invertierte Tastenstatus:
                                // Bit=1 -> Taste wurde gedrückt
volatile uint8_t key_press;                    // Tastendruck registriert
volatile uint8_t key_rpt;                    // Tastendruckdauer
volatile uint8_t nKonfig;                    // Tasten-Konfiguration
volatile uint8_t nFire = 0;                    // Dauerfeuer-Konfiguration
volatile uint8_t nFireTime = 12;                // Dauerfeuer-Zeit
volatile uint8_t repeatFire;
volatile uint8_t nSelect = 0;                  // Select-Taste
volatile uint8_t Marker;                    // Speichermarkierung im 7-Segment
volatile uint8_t Summe;

unsigned char led = 0xFF;
uint8_t eeKonfigByte;                      // EEPROM Konfigurationsvariable

// Zeichentabelle für 7-Segment
// ============================
const unsigned char Tabelle[] PROGMEM = {192, 249, 164, 176, 153, 146, 130, 248, 128, 144};

// Timer Interrupt von 10ms definieren
// ===================================
ISR(TIMER0_OVF_vect)
{
  static uint8_t ct0, ct1, rpt, cntTicks;
  uint8_t i;

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

  i = key_state ^ ~KEY_PIN;                  // Taste geändert?
  ct0 = ~(ct0 & i);                      // resete oder zähle CT0
  ct1 = ct0 ^ (ct1 & i);                    // resete oder zähle CT1
  i &= ct0 & ct1;                        // Überlauf gezählt?
  key_state ^= i;                        // dann Entprellstatus ändern
  key_press |= key_state & i;                  // 0->1: Tastendruck erkannt

  if((key_state & REPEAT_MASK) == 0)              // Überprüfe Tastenwiederholfunktion
    rpt = REPEAT_START;                    // Starte Verzögerung
  if(--rpt == 0)
  {
    rpt = REPEAT_NEXT;                    // Wiederhole Verzögerung
    key_rpt |= key_state & REPEAT_MASK;
  }

  cntTicks++;
  if(cntTicks == nFireTime)                  // Ist Variable <nFireTime> mal 10ms
  {
    repeatFire ^= 0x01;                      // Wechselt PortC.0 nach Zeit von 0 auf 1
    cntTicks = 0;
  }
}

// Überprüfen, ob eine Taste gedrückt wurde.
// Jede gedrückte Taste wird nur einmal gemeldet
// =============================================
uint8_t get_key_press(uint8_t key_mask)
{
  cli();                            // Interrupts deaktivieren
  key_mask &= key_press;                    // Tasten auslesen
  key_press ^= key_mask;                    // Tasten löschen
  sei();                            // Interrupts aktivieren
  return key_mask;
}

// Erfolgt ein längerer Tastendruck, so wird nach einiger Zeit
// der Tastendruck automatisch wieder verworfen.
// ===========================================================
uint8_t get_key_rpt(uint8_t key_mask)
{
  cli();                            // Interrupts deaktivieren
  key_mask &= key_rpt;                    // Tasten auslesen
  key_rpt ^= key_mask;                    // Tasten löschen
  sei();                            // Interrupts aktivieren
  return key_mask;
}

// Kurzer Tastendruck
// ==================
uint8_t get_key_short(uint8_t key_mask)
{
  cli();                            // Interrupts deaktivieren
  return get_key_press(~key_state & key_mask);
}

// Langer Tastendruck
// ==================
uint8_t get_key_long(uint8_t key_mask)
{
  return get_key_press(get_key_rpt(key_mask));
}

// Einschaltsequenz, Initialisierung der Ports
// ===========================================
void init()
{

// Ports initialisieren
// --------------------
  OUT_DDR |= ALL_OUT;                      // Controller als Ausgang definieren
  KEY_DDR |= ALL_KEYS;                    // Tastenports als Ausgang definieren

// LED-Test
// --------
  for (uint8_t LED=1; LED<=32;)
  {
    KEY_PORT = ~LED;                    // Untere 8 Bit auf Taster-PORT B ausgegeben
    LED=LED<<1;                        // LED um 1 Bit weiterschieben
    _delay_ms(DELAY);
  }
  KEY_PORT=0xF6;
  _delay_ms(DELAY);
  KEY_PORT=0xED;
  _delay_ms(DELAY);
  KEY_PORT=0xDB;
  _delay_ms(DELAY);
  KEY_PORT=0xF8;
  _delay_ms(DELAY);
  KEY_PORT=0xC7;
  _delay_ms(DELAY);
  KEY_PORT=0xFF;
  _delay_ms(DELAY);
  KEY_PORT=0xC0;
  _delay_ms(DELAY);
  KEY_PORT=0xFF;
  _delay_ms(DELAY);
  KEY_PORT=0xC0;
  _delay_ms(DELAY);
  KEY_PORT=0xFF;
  _delay_ms(DELAY);

// Segment-Test
// ------------

//     1
//     -
// 32| 64|2
//     -
// 16| 8 |4
//     -
  SEGMENT_DDR = 0xFF;                      // 7-Segmentports als Ausgang definieren

  for (uint8_t LED=1; LED<=64;)
  {
    SEGMENT_PORT = ~LED;                  // Untere 8 Bit auf 7-Segment-PORT D ausgegeben
    LED=LED<<1;                        // Segment um 1 Bit weiterschieben
    _delay_ms(DELAY);
  }

// Interrupt aktvieren
// -------------------
  TCCR0 = (1<<CS02)|(1<<CS00);                // Teilen bei 1024
  TIMSK = 1<<TOIE0;                      // TimerInterrupt aktivieren

// Ports für Funktion setzen
// -------------------------
  KEY_DDR &= ~ALL_KEYS;                    // Tastenports als Eingang definieren
  KEY_PORT |= ALL_KEYS;                    // Tastenports PullUp
}

int main(void)
{
  init();                            // Einschaltsequenz starten

  nKonfig = eeprom_read_byte(&eeKonfigByte);          // Aktuellen Wert aus EEPROM auslesen
  Marker = nKonfig;                      // EEPROM-Wert für Marker speichern

  sei();                            // Interrupts aktivieren

  while(1)
  {
    Summe = 0;

    if(!(KEY_PIN & 0x01))                  // Wenn Taste PortB.0 auf HIGH
      Summe |= pgm_read_byte(&KonfigPattern[nKonfig-1][0]);
    if(!(KEY_PIN & 0x02))                  // Wenn Taste PortB.1 auf HIGH
      Summe |= pgm_read_byte(&KonfigPattern[nKonfig-1][1]);
    if(!(KEY_PIN & 0x04))                  // Wenn Taste PortB.2 auf HIGH
      Summe |= pgm_read_byte(&KonfigPattern[nKonfig-1][2]);
    if(!(KEY_PIN & 0x08))                  // Wenn Taste PortB.3 auf HIGH
      Summe |= pgm_read_byte(&KonfigPattern[nKonfig-1][3]);
    if(!(KEY_PIN & 0x10))                  // Wenn Taste PortB.4 auf HIGH
      Summe |= pgm_read_byte(&KonfigPattern[nKonfig-1][4]);
    if(!(KEY_PIN & 0x20))                  // Wenn Taste PortB.5 auf HIGH
      Summe |= pgm_read_byte(&KonfigPattern[nKonfig-1][5]);

    if(nFire != 0)
    { 
      OUT_PORT = Summe | repeatFire;
    }
    else
    {
      OUT_PORT = Summe;
    }

    if(nSelect == 0)
    {
      SEGMENT_PORT = pgm_read_byte(&Tabelle[nKonfig]);  // Konfigurationswert an 7-Segment übergeben
      if (nKonfig == Marker)
      {
        SEGMENT_PORT = pgm_read_byte(&Tabelle[nKonfig]) & ~(1 << 7);
      }
    }
    else
    {
      SEGMENT_PORT = pgm_read_byte(&Tabelle[nFire]);    // Dauerfeuerwert an 7-Segment übergeben
    }

    if(get_key_short(1<<KEY0))                // kurzer Tastendruck (PinB.6)
    {
      if(nSelect == 0)                  // Ist Konfiguration gewählt
      {
        SEGMENT_PORT = 0x8E;              // Buchstabe: F  anzeigen
        nSelect = 1;
        _delay_ms(DELAY);
        SEGMENT_PORT = pgm_read_byte(&Tabelle[nFire]);  // aktuellen Dauerfeuerwert am 7-Segment anzeigen
      }
      else
      {
        SEGMENT_PORT = 0xC6;              // sonst Buchstabe: C anzeigen
        nSelect = 0;
        _delay_ms(DELAY);
        SEGMENT_PORT = pgm_read_byte(&Tabelle[nKonfig]);// aktuellen Konfigurationswert am 7-Segment anzeigen
      }
    }

    if(get_key_short(1<<KEY1))                // kurzer Tastendruck (PinB.7)
    {
      if(nSelect == 0)
      {
        if(nKonfig < 9)                  // Konfigurationswert kleiner als 8,
        {
          nKonfig++;                  // Wert erhöhen
        }
        else
        {
          nKonfig = 1;                // ansonsten zu ersten Wert
        }
      }
      else
      {
        if(nFire < 9)                  // Dauerfeuerwert kleiner als 8,
        {
          nFire++;                  // Wert erhöhen
          nFireTime--;
        }
        else
        {
          nFire = 0;                  // ansonsten zu letzten Wert
          nFireTime = 12;
        }
      }
    }

    if(get_key_long(1<<KEY1) && (nSelect == 0))        // langer Tastendruck
    {
      eeprom_write_byte(&eeKonfigByte, nKonfig);      // Wert in EEPROM speichern
      Marker = nKonfig;                  // EEPROM-Wert für Marker speichern
    }
  }
}

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>  if(cntTicks == nFireTime)           // Ist Variable <nFireTime> mal

Versuchs mal mit

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

Autor: Oliver Ju. (skriptkiddy)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Manfred W.:

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

gruß skriptkiddy

Autor: Lokus Pokus (derschatten)
Datum:

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

Funktioniert 1A! Danke!

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.