PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Problem mit timer



RedEagle
03.01.2007, 13:53
Ich möchte mit einem ATmega32 (bei 16MHz) eine LED blinken lassen.
Dazu habe ich den code von Roboternetz genommen und leicht verändert.

Allerdings blinken die LEDs nicht im Sekundentakt:


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


#ifndef F_CPU
#define F_CPU (1000000*16) //Die *16 wurden von mir hinzugefügt
#endif

#define IRQS_PER_SECOND 2000 /* 500 µs */
#define IRQS_PER_10MS (IRQS_PER_SECOND / 100)

///////////////////////////////////////////////////////////////////////////////////////////////

static volatile uint8_t timer_10ms;

void timer1_init();
void wait_10ms (const uint8_t);

////////////////////////////////////////////////////////////////////////////////////////////////

void main()
{
uint16_t i,j,k,l; //zähler

DDRC = 0xFF;//An C liegen die LEDs
PORTC = 0x02;//LEDs aus

DDRA = 0xFF;
PORTA= 0x00;

DDRB = 0xFF;
PORTB= 0x00;

DDRD = 0xFF;
PORTD= 0x00;


timer1_init();
sei();

while (1)
{

// LED an
PORTC |= 0xF0;

// 1 Sekunde warten
for(l=0; l<0xFFFF; l++){
for(k=0; k<0xFFFF; k++){
for(j=0; j<0xFFFF; j++){
for(i=0; i<0xFFFF; i++){ wait_10ms (255);
}}}}

// LED aus
PORTC &= 0x0F;

// 1 Sekunde warten
for(l=0; l<0xFFFF; l++){
for(k=0; k<0xFFFF; k++){
for(j=0; j<0xFFFF; j++){
for(i=0; i<0xFFFF; i++){ wait_10ms (255);
}}}}
}

return;
}

//-----------------------------------------------------------------------------------------------

void timer1_init()
{
TCCR1A = 0;

#if defined (CTC1) && !defined (WGM12)
TCCR1B = (1 << CTC1) | (1 << CS10);
#elif !defined (CTC1) && defined (WGM12)
TCCR1B = (1 << WGM12) | (1 << CS10);
#endif

OCR1A = (unsigned short) ((unsigned long) F_CPU / IRQS_PER_SECOND-1);

#if defined (TIMSK1)
TIMSK1 |= (1 << OCIE1A);
#elif defined (TIMSK)
TIMSK |= (1 << OCIE1A);
#endif
}

//-----------------------------------------------------------------------------------------------

void wait_10ms (const uint8_t t)
{
timer_10ms = t;
while (timer_10ms);
}


/////////////////////////////////////////////////////////////////////////
SIGNAL (SIG_OUTPUT_COMPARE1A)
{
static uint8_t interrupt_num_10ms;

if (++interrupt_num_10ms == IRQS_PER_10MS)
{
interrupt_num_10ms = 0;

if (timer_10ms != 0)timer_10ms--;
}

return;
}



wo istz das Problem??

RedEagle
04.01.2007, 22:32
Hi...
Keiner ne idee?? Bin schon die ganze zeit am suchen...

derzeitiger stand

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


#ifdef F_CPU
#undef F_CPU
#endif
#define F_CPU (1000000*16)
#define MHZ *1000000




// und IRQS_PER_SECOND ein Vielfaches von 100.
// Ausserdem muss gelten F_CPU / IRQS_PER_SECOND <= 65536
#define IRQS_PER_SECOND 1000
// Anzahl IRQs pro 10 Millisekunden
#define IRQS_PER_10MS (IRQS_PER_SECOND / 100)




///////////////////////////////////////////////////////////////////////////////////////////////

// Zähler-Variable. Wird in der ISR erniedrigt und in wait_10ms benutzt.
static volatile uint16_t timer;

// Prototypen
void timer1_init();
void wait (const uint16_t);

////////////////////////////////////////////////////////////////////////////////////////////////

void main()
{

DDRC = 0xFF;//An C liegen die LEDs
PORTC = 0x02;//LEDs aus


// Timer1 initialisieren
timer1_init();

// Interrupts aktivieren
sei();

while (1)
{

// LED an
PORTC |= 0xF0;

// 1 Sekunde warten
wait(50000);

// LED aus
PORTC &= 0x0F;

// 1 Sekunde warten
wait(50000);
}

return;
}

//-----------------------------------------------------------------------------------------------

void timer1_init()
{
// Timer1: keine PWM
TCCR1A = 0;

TCCR1B = (1 << WGM12) | (1 << CS10);

OCR1A = (unsigned short) ((unsigned long) (16 MHZ) / IRQS_PER_SECOND - 1);

TIMSK |= (1 << OCIE1A);
}

//-----------------------------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////

void wait(const uint16_t t)
{
timer = t;
while (timer);
}


////////////////////////////////////////////////////////////////////////

SIGNAL (SIG_OUTPUT_COMPARE1A)
{
static uint8_t interrupt_num;

if(++interrupt_num == IRQS_PER_SECOND/100) //eine Zeiteinheit vergangen (10ms/100ms)
{
interrupt_num = 0;

if(timer != 0)timer--;
}
}


warum funktioniert das nicht??

SprinterSB
05.01.2007, 16:53
Die 4-fach-Schleife durchläuft (2^16)^4 = 1.8e19 mal die wait_10ms (255).
wait_10ms (255) wartet 255*10ms also 2.55 Sekunden.

Insgesamt wartet die 4-Schleife also 4.7e19 Sekunden = ca. 1.5e12 Jahre, das ist etwa das 300-fache Alter der Erde...

RedEagle
05.01.2007, 18:39
Darauf bib ich auch gekommen.
Aber warum blinken die LEDs dann so schnell, das es wie schwaes leuchten aussieht??
=> weit_10ms wartet keine 10ms, sondern nur ein bruchteil, aber warum??

ogni42
05.01.2007, 20:14
Falls Du Optimierungen eingeschaltet hat, wird der Compiler Dir Deine while-Schleife wegoptimieren.

SprinterSB
06.01.2007, 11:13
Ich seh nicht, daß da was wegoptimiert wird.

Versuch mal die Klammer um #define F_CPU wegzulassen. Bzw funktioniert der Originalcode? Mit 16MHz-Quarz sollte der flott aber noch erkennbar blinken. Ansonsten nur die 1000000 durch ne 16000000 ersetzen.

Funktioniert der Beispielcode von
https://www.roboternetz.de/wissen/index.php/HEX_Beispiel-Dateien_f%C3%BCr_AVR
?

Zuden gibt es einen Fehler inder wait (uint16_t)

https://www.roboternetz.de/wissen/index.php/Fallstricke_bei_der_C-Programmierung#Nicht-atomarer_Code

ogni42
06.01.2007, 14:52
Ja, aber so wie der Code aussieht werden die LEDs nur per wait im Zeitverhalten gesteuert. Der Timerinterrupt hat da keine Auswirkungen.

wait() wartet in der jetzigen Implementierung natürlich ewig.