Timer0 zu langsam?

Gast #1282109
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;

}
Gast #1282127
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);
}
#1282131
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
Gast #1282135
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!
Gast #1282138
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

Antwort schreiben

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.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.