Forum: Mikrocontroller und Digitale Elektronik Timer0 zu langsam?


von Bruno (Gast)


Lesenswert?

Hallo habe folgende Code und komme nicht mehr klar.

Timer 0 sollte doch alle 800000/1/256=31250 ausgeführt werden. Also 
32250/2= 15625Hz Warum leuchtet bei der Siebensegmentanzeige aber die 
Einerstelle immer heller bei einer Refreshrate von 15kHz?

Danke
Bruno

Code
// WINAVR 20090306
// AVR Studio 4.16.628

#include <avr/io.h>
#include <avr/interrupt.h>

volatile uint8_t tausender, hunderter, zehner, einer;
volatile uint16_t wert;

#define maxwert 999

const int8_t numbers [10] =
{
//   1gfedcba
   0b10111111,     //0
   0b10000110,     //1
   0b11011011,     //2
   0b11001111,     //3
   0b11100110,     //4
   0b11101101,     //5
   0b11111101,     //6
   0b10000111,     //7
   0b11111111,     //8
   0b11101111,     //9
};

void out_zahl(uint8_t wertig, uint8_t stelle)
{
  // Ausschalten sonst nachleuchten der Zahl
  PORTB = 0b00000000;
  PORTD = 1 << stelle;
  // Neue Zahl ausgeben
  PORTB = numbers[wertig];
  PORTD = 1 << stelle;
}

void out_nummer()
{

  for(int8_t position=4; position>=0; position--)
    {
      switch (position)
      {
        case 3:
        {
          // out_zahl(tausender, 3);
          break;
        }
        case 2:
        {
          out_zahl(hunderter, 2);
          break;
        }
        case 1:
        {
          out_zahl(zehner, 1);
          break;
        }
        case 0:
        {
          out_zahl(einer, 0);
          break;
        }
      }
    }

}


// Timer 0 - 8 Bit Overflow
ISR (TIMER0_OVF_vect)
{
  // Anzeige erneuern
  out_nummer();
  // Timer hochstellen
}

// Timer 1 - 16 Bit
// Zähler um eins erhöhen
ISR (TIMER1_OVF_vect)
{
  // Maximaler zähler
  if (wert == maxwert)
    {
      wert=0;
    }

  // Eins hoch
  wert++;

  uint16_t auswert;
  auswert = wert;

  // tausender
  tausender = auswert/1000;
  auswert = auswert%1000;

  // hunderter
  hunderter = auswert/100;
  auswert = auswert%100;

  // zehner
  zehner = auswert/10;

  // einer
  einer = auswert%10;

}

int main(void)
{
  // Port C 4 auf Ausgang
  DDRD |= (1 << DDD0) | (1 << DDD1) | (1 << DDD2) | (1 << DDD3) | (0 << 
DDD4) | (0 << DDD5) | (0 << DDD6) | (0 << DDD7);
  // Port B alles auf Ausgang
  DDRB |= (1 << DDB0) | (1 << DDB1) | (1 << DDB2) | (1 << DDB3) | (1 << 
DDB4) | (1 << DDB5) | (1 << DDB6) | (1 << DDB7);

  // Variablen init
  wert = 0;
  einer = 0;
  zehner = 0;
  hunderter = 0;
  tausender= 0;

  // Ausgabe neu zeichnen
  // Timer 0
  // Prescaler = 1 Clock Takt!!!
  TCCR0 |= (1 << CS00) | (0 << CS01) | (0 << CS02) ;
  // Prescaler =  8 Clock Takt!!!
  // TCCR0 |= (0 << CS00) | (1 << CS01) | (0 << CS02) ;
  // Prescaler =  64 Clock Takt!!!
  // TCCR0 |= (1 << CS00) | (1 << CS01) | (0 << CS02) ;
  // Prescaler =  256 Clock Takt!!!
  // TCCR0 |= (0 << CS00) | (0 << CS01) | (1 << CS02) ;
  // Prescaler = 1024
  // TCCR0 |= (1 << CS00) | (0 << CS01) | (1 << CS02) ;

  // Hochzählen
  // Timer 1
  // Prescaler = 1 Clock Takt!!!
  // TCCR1B |= (1 << CS00) | (0 << CS01) | (0 << CS02) ;
  // Prescaler =  8 Clock Takt!!!
  // TCCR1B |= (0 << CS00) | (1 << CS01) | (0 << CS02) ;
  // Prescaler =  64 Clock Takt!!!
  TCCR1B |= (1 << CS00) | (1 << CS01) | (0 << CS02) ;
  // Prescaler =  256 Clock Takt!!!
  // TCCR1B= (0 << CS00) | (0 << CS01) | (1 << CS02) ;
  // Prescaler = 1024
  // TCCR1B= (1 << CS00) | (0 << CS01) | (1 << CS02) ;

  // TIMER Interrupt Maske Timer 0 und Timer 1 bei Overfow
  TIMSK |= (1 << TOIE0) | (1 << TOIE1);

  sei();  //IRQ ein

  // Timer 0 hochstellen für OVF
  // TCNT0=253;

  // Timer 0 für COMP
  OCR0 = 128;

  while(1)
    {
      // nothing
    }
  return 0;

}

von Bruno (Gast)


Lesenswert?

Danke
aber manchmal ist zu schnell eben zu schnell!

Bruno

void out_zahl(uint8_t wertig, uint8_t stelle)
{
  // Ausschalten sonst nachleuchten der Zahl
  PORTB = 0b00000000;
  PORTD = 1 << stelle;
  // Neue Zahl ausgeben
  PORTB = numbers[wertig];
  PORTD = 1 << stelle;
  delay_ms(5);
}

von Peter D. (peda)


Lesenswert?

Bruno schrieb:
> void out_zahl(uint8_t wertig, uint8_t stelle)
> ...
>   delay_ms(5);

Prust, Lach.
out_zahl wird im Interrupt aufgerufen, da sind Delays streng verboten!

Aber etwas recht hast Du, 15kHz ist viel zu schnell, da können sich 
schon Programmlaufzeiten bemerkbar machen.

Für 4 Digits reichen 400Hz völlig.


Peter

von Matthias L. (Gast)


Lesenswert?

Weil deine AUsgaberoutine Unsinn ist.

Du tust pro Interrupt (T0) alle Segmente für 5ms anzeigen, danach den 
Int. verlassen.

Das heißt, alle Segmente, außer dem ersten, werden 5ms angezeigt, die 
erste solange bis der Int wieder kommt.

Das ist Müll.

So funktioniert keine Multiplexausgabe!

von avr (Gast)


Lesenswert?

Das Problem ist, daß er im Interrupt immer
alle 5 Ziffern ausgibt
>  for(int8_t position=4; position>=0; position--)
und die letzte dann stehenbleibt.

Richtig ist im Interrupt (400 Hz für 4 Digits mehr als
ausreichend) eine Ziffer einschalten, dann im nächsten
Aufruf diese aus- und die nächste einschalten.
Die Ziffern haben dann alle einen Duty von 1:3 (und etwas
Verarbeitungszeiten).


gruß avr

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.