PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Selbstgebastelte Delay-Funktion



schamp
06.07.2005, 09:36
Hi zusammen !

Hab mir eine delay-Funktion selbstgebastelt. Verwende dafür den 8 Bit Timer0. Für ein Delay von 1 Sekunde brauch ich bei einer fosc von 4 Mhz und nem Prescaler-Wert von 8 ca. 1953 Timeroverflows (Formeln siehe Quellcode).
In der ISR dekrementiere ich dann diese 1953 und warte dabei in einer Endlosschleife, bis das ganze auf Null ist (damit wäre dann ca. 1 Sekunde vergangen).
Dummerweise wird die while(1)-Schleife in der delay()-Funktion anscheinend nie verlassen, da die LED nicht blinkt... :-k
Hat jemand ne Ahnung warum ??

Gruß schamp


#include <iom88.h>
#include <ina90.h>

#define DLY_1_SEC 1953 // Formula: Time for one Timer0 Overflow t=(Prescalevalue*256)/fosc
// Prescalevalue=8, fosc=4MHz --> t=0,512 msec for one overflow
// To get a delay of 1 sec --> 1sec/0,512msec=1953 overflows are needed

volatile unsigned int pause_timer; // must be volatile or the interrupt routine will not change the value

void delay_init(void);

void delay(int tvalue);

__task void main(void)
{

delay_init();

while(1)
{
delay(DLY_1_SEC);
PORTB ^= (1<<PB0); // toggle LED
}
}


void delay_init(void)
{
DDRB = 0xff; // set for all outputs
PORTB = 0xff; // turn off all leds

TCCR0B |= (1 << CS01); // Timer clock = system clock / 8
}



// Generates an interrupt every 0.512 ms for fosc = 4 MHz and prescale of 8

#pragma vector=TIMER0_OVF_vect
__interrupt void tim0_ovf(void)
{
// Decrement timer if timer is not 0
//if (pause_timer != 0)
pause_timer--;
}


void delay(int tvalue)
{
pause_timer = tvalue;

TIMSK0 |= (1<<TOIE0); // Enable T/C0 overflow interrupt

__enable_interrupt(); // enable interrupts

while(1)
{
if(pause_timer == 0) break;
}

__disable_interrupt(); // disable interrupts
}

PicNick
06.07.2005, 10:12
Tja, seh nur das eine Problem, daß der Zähler ja ein INT ist, also zwei Bytes verglichen werden müssen, und beim dekremetieren ebenso.
da kann es schon ein durcheinander geben.
Probier mal so: in der ISR solange dekrementieren, bis Null ist, dann den Timer disablen.
In der While(1) fragst du nur, ob der Timer noch läuft (TIMSK)

schamp
07.07.2005, 10:42
habs jetzt so abgeändert, LED blinkt auch.. allerdings net im Sekundentakt. Falsch gerechnet ?!?! ](*,)


#include <iom88.h>
#include <ina90.h>

#define DLY_1_SEC 1953 // Formula: Time for one Timer0 Overflow t=(Prescalevalue*256)/fosc
// Prescalevalue=8, fosc=4MHz --> t=0,512 msec for one overflow
// To get a delay of 1 sec --> 1sec/0,512msec=1953 overflows are needed

volatile unsigned int pause_timer; // must be volatile or the interrupt routine will not change the value

void delay_init(void);

void delay(int tvalue);

__task void main(void)
{
delay_init();

while(1)
{
delay(DLY_1_SEC);
PORTB ^= (1<<PB0); // toggle LED
}
}


void delay_init(void)
{
DDRB = 0xff; // set for all outputs
PORTB = 0xff; // turn off all leds

TCCR0B |= (1 << CS01); // Timer clock = system clock / 8
}



// Generates an interrupt every 0.512 ms for fosc = 4 MHz and prescale of 8

#pragma vector=TIMER0_OVF_vect
__interrupt void tim0_ovf(void)
{
// Decrement timer if timer is not 0
pause_timer--;
if(pause_timer ==0)
{
TIMSK0 &=~(1<<TOIE0); // Disable T/C0 overflow interrupt
TIFR0 |= (1<<TOV0); // Clear T/C0 overflow flag
}
}


void delay(int tvalue)
{
pause_timer = tvalue;

TIMSK0 |= (1<<TOIE0); // Enable T/C0 overflow interrupt

__enable_interrupt(); // enable interrupts

while(1)
{
if(!(TIMSK0 & (1<<TOIE0))) break;
}

__disable_interrupt(); // disable interrupts
}

PicNick
07.07.2005, 10:48
Ich glaub, das is kein Clear, sondern ein set ?


TIFR0 |= (1<<TOV0); // ?????????????

TIFR0 &= ~(1<<TOV0); // Clear T/C0 overflow flag

schamp
07.07.2005, 10:51
Im Datenblatt steht aber Logic 1 um zu clearen.. :-k
probiers trotzdem ma aus

edit: macht kein unterschied, sieht so aus als wärns ca. 10 sec delay o.O

schamp
09.07.2005, 13:13
@Picnick:

Hab die Delay-Funktion auf meinem Mega16 implementiert und diese ausgerechneten 1953 für eine Sekunde Delay verwendet...
Was meinst was dabei rausgekommen ist ? :mrgreen:
Ziemlich genau Sekundentakt, das Programm ist also so funktionsfähig.
Beim Mega88 mit selben Einstellungen eben leider nicht. Damit erklären sich dann auch die Übertragungsfehler mit dem Mega88 bei unserem Software-UART.
Stellt sich nur noch die Frage woran das liegt und wie man das behebt.. :-s
Das Atmel mit dem Timer0 beim Mega88 Mist gebaut hat kann nicht wirklich sein oder ?!

PicNick
09.07.2005, 15:13
Hi,
Seit ich komputer kenne, glaub' ich an alles.
Ich schau mir in der Richtung mal das Datenblatt an.

schamp
09.07.2005, 16:46
Hab im Datenblatt dazu leider nicht wirklich was gefunden. Evtl. hab ich auch ein kleines, aber wichtiges Detail übersehen (hoff ich zumindest.. :D)
Bin scho gspannt ob du da was findest [-o<
Am Montag werd ich dann auch mal den zweiten 8 Bit Timer vom Mega88 ausprobieren. Ma schaun was dabei rauskommt...

schamp
11.07.2005, 10:52
Problem gelöst:

Lag an einem Fusebit welches beim ATmega88 standardmäßig gesetzt ist. Und zwar wird dann Clock nochmals intern um den Faktor 8 runtergeteilt.... :roll:

schamp
12.07.2005, 10:34
Gibts eigentlich eine Möglichkeit sekundengenaue Delays zu erzeugen ohne (Timer-)Ints ??

PicNick
12.07.2005, 11:02
logo. du brauchst nur eine definierte Anzahl von Cycles zu erzeugen, dann isses so genau wie eben das Quartz.
Aber das ist einen Erbsenzählerei *pfuigack*

schamp
12.07.2005, 11:14
hm hab bei der jetzigen delay Funktion nämlich prob, wenn z.b. in der Wartezeit was empfangen werden soll.. denn da bin ich ja mitten inner Timer0-ISR.
Oder funktioniert das trotzdem ? Ist halt nicht so schön wenn ISR durch nen anderen Interrupt unterbrochen wird... :-s

Könnt man den Watchdog evtl auch irgndwie für sowas verwenden ?
Dann hätte man gleichzeitig noch System Reset wenns Programm ins Nirwana läuft ?

PicNick
12.07.2005, 11:26
Watchdog: für das isser da.
Interruptus Interrupt: Man muß es halt berücksichtigen. Die Synchronisation von Events hält einige Freuden bereit.
Timer versucht man halt so zu konfigurieren, daß sie möglichst lang in der Hardware bleiben, also autonom laufen, egal, was sonst passiert.
Tscha, wenn man einen MC richtig ausquetschen will, wird die Sache kantig.

schamp
12.07.2005, 11:35
oki 8-[

Werd mir ma noch den Watchdog reinziehn. Und ein bischen über den Programmablauf und Synchronisation von den Ints sinnieren :-)