PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Timer für lange Laufzeiten



toetzel
17.11.2006, 10:05
Hallo,
ich möchte mit eine Timer lange Zeiten realisieren. Im berreich Minuten und Stunden.

Also habe ich den Timer mit Teiler 1024 gestartet heißt das ich rund 3,8 mal pro sec die 256 voll habe. Also 0,263 sec.

in einer If schleife Warten bis ich die 4 mal durchlaufen habe = 1,xxx sec. Genauigkeit reicht für meine Anwendung.

nun kann ich mit einer hochgezählten Variabele S eigendlich grob die Sec vorgen ( zumindest bis 32000 ) so die Theorie.



Nun meine Frage:
geht das auch eleganter und warum bekome ich in meiner Variable s nur secundenbruchteile abgebildet ( Wert 10 ca. 1 sec.)
Danke und Gruß

#include <avr/io.h>

int main(void)
{
int i;
int s;
i=0;
s=0;


DDRC = (1 << DDC0) |(1 << DDC1); // pin c0 und c1 als ausgang

for( ;; )//Endlosschleife
{

TCCR0 |= (1<<CS00)|(1<<CS02); //Teilung 1024 des Taktes
if(TCNT0==255){
i=i++;} // alle 0,2612 sec einen hochzählen 1Mhz/1024=976 976/256 = 3,8146 1/3,8146/1=0,2612

if(i==4){
s=s++;
i=0;} // s für sec alle 0,2612 sec mal 4 = 1,0448 variable s einen hochzählen

if(s==5000){
PORTC |= (1<<PC1);// Port C1 auf high

}

}
}

Cluni
17.11.2006, 14:43
Also erstmal wäre es schöner, wenn du den Timer im Interrupt laufen lassen würdest. Dort könntest du dir die einzelnen Zähler für hh:mm:ss ja hochzählen. In dieser Interrupt-Routine kannst du ja auch dann auf einen bestimmten Wert vergleichen und dann ein bestimmtes Bit setzen oder eine anderes Reaktion ausführen.

Den Vergleich macht man nicht von Hand im Hauptprogramm - wozu hat man denn die Timer und die Interruptsteuerung?!

Gruß, Bernd

SprinterSB
17.11.2006, 14:49
Eine Möglichkeit sind kaskadierte Countdown-Timer, klappt prima. Minuten, und Stunden hab ich (hoffentlich ohne Tippfehler) eben zugefügt.

In vivo und auf jeden Fall tippfehlerfrei im Projekt "eBook" (http://people.freenet.de/gjl/pub/ebook/index.html).

Die Timer zählen runter bis 0 und bleiben dann stehen. In der Applikation sieht man das und kann ihn wieder neu aufziehen falls notwendig.

Um 1 Minute zu warten wartest du übrigens besser 60*1 Sekunde als 1*1 Minute (ist genauer). Analog für andere Zeiten. Der Grund ist, daß die Auflösung der Sekunden 10ms ist, die Auflösung der Minuten aber nur 1 Sekunde.

timer.h

#ifndef _TIMER_H_
#define _TIMER_H_

#include <inttypes.h>

// Make sure that
//
// F_CPU / IRQS_PER_SECOND -1
//
// yields a sensible 16-bit value.
// The smaller the remainder of the division, the exacter
// the timer will operate.
#define IRQS_PER_SECOND 10000
#define IRQS_PER_10MS (IRQS_PER_SECOND / 100)

// Just add new members as needed
// all members are 8-bit countdown timers.
// They will decrement to 0 and then stop.
typedef struct
{
struct
{
// Internal use, do not change or remove.
// Used to track seconds and know when to
// decrement the elements of .sec
uint8_t timer_1s;

// used by wait_10ms
uint8_t wait_10ms;

// Keeps track of key strokes when displaying
// book/chapter/verse information
uint8_t key_timer;

// Slows down display of new letters/display shifts per sec
uint8_t ebook_delay;
} ms10;

struct
{
// Internal use, do not change or remove.
// Used to track minutes and know when to
// decrement the elements of .min
uint8_t timer_1m;

// config() will exit and restore ebook.eeprom if this
// countdown runs dry
uint8_t config_timeout;
} sec;

struct
{
// Internal use, do not change or remove.
// Used to track hours and know when to
// decrement the elements of .hour
uint8_t timer_1h;

// add own countdown timers here
} min;

struct
{
// add own countdown timers here
} hour;
} countdown_t;

// This structure holds several countdown timers.
// If a timer is 0 its value is not changed
// otherwise, its value is decremented
// - every 10ms (members of count.ms10)
// - every second (members of count.sec)
// - etc.
extern volatile countdown_t count;

// Waits at about 10ms
extern void wait_10ms (const uint8_t);

// Must be called once every 10ms to count down the members of count.
extern void job_timer_10ms();

// Initialize Timer1 to perform IRQS_PER_SECOND IRQs per second.
extern void init_timer1 (void);

#endif /* _TIMER_H_ */


timer.c

#include <avr/io.h>

#include "timer.h"

countdown_t volatile count;

static void down (uint8_t, uint8_t volatile *);

// wait t*10ms to (t+1)*10ms
void wait_10ms (const uint8_t t)
{
count.ms10.wait_10ms = 1+t;
while (count.ms10.wait_10ms)
;
}

// just a helper to job_timer_10ms
void down (uint8_t i, uint8_t volatile * cd)
{
do
{
uint8_t val = *(--cd) -1;

if (val != 0xff)
*cd = val;
} while (--i);
}

// count down a portion of count (every member as uint8_t)
#define DOWN(x) \
do \
{ \
if (!sizeof (x)) \
return; \
down (sizeof (x), (uint8_t *) & x + sizeof (x)); \
} while (0)

// to be called every 10ms
void job_timer_10ms()
{
DOWN (count.ms10);

if (count.ms10.timer_1s)
return;
count.ms10.timer_1s = 100;

DOWN (count.sec);

if (count.sec.timer_1m)
return;
count.sec.timer_1m = 60;

DOWN (count.min);

if (count.min.timer_1h)
return;
count.min.timer_1h = 60;

DOWN (count.hour);
}

#if !defined (TCNT1H)
#error Cannot use Timer1 this way!
#endif // TCNT1H

void init_timer1()
{
// Timer1 is counter, no PWM
TCCR1A = 0;

// Clear Timer on Compare Match (CTC, Mode #4)
// Full F_CPU (Prescale = 1)
#if defined (CTC1) && !defined (WGM12)
TCCR1B = (1 << CTC1) | (1 << CS10);
#elif !defined (CTC1) && defined (WGM12)
TCCR1B = (1 << WGM12) | (1 << CS10);
#else
#error Cannot initialize Timer1 this way!
#endif

// set OutputCompare to get desired Timer1 frequency
OCR1A = (uint16_t) ((uint32_t) F_CPU / IRQS_PER_SECOND -1);

// enable OutputCompareA Interrupt for Timer1
#if defined (TIMSK1)
TIMSK1 |= (1 << OCIE1A);
#elif defined (TIMSK)
TIMSK |= (1 << OCIE1A);
#else
#error Cannot initialize Timer1 IRQs this way!
#endif
}

toetzel
19.11.2006, 19:31
Danke für eure Infos, ich habe mich hier im Forum und unter mirkrocontroller.net zum Thema Interruptgesteuertes Programm auch einiges gefunden, bin aber nicht in der Lage das für mich umzusetzen.

Ich habe verstanden das eine Main Funktion existiert in der eine Endlosschleife läuft und ich habe Interruptroutinen in welchen bistimmte Dinge getan werden wie z.B. ein Timer laufen lassen. Wenn ich auf irgendetwas warte gehe ich wieder ( automatisch?) in die main Funktion. Aber wie setze ich das codingmäßig um? Ich habe mir SprintersSB Beispiel angesehen aber ich kapier es nicht. Könnt Ihr mir eventuell ein "Minigerüst" Posten in der Art.
#include <avr/io.h>
int main(void)
{

for( ;; )//Endlosschleife
{
irgendetwas tun

}

}
Wie ihr seht bin ich noch absoluter Anfänger.

Danke und Gruß
Tötzel

SprinterSB
20.11.2006, 10:02
Sorry, hatte die Hälfte des Code vergessen :oops:

Anmerkungen stehen im Code

main.c

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

#include "timer.h"

// ISR für Timer1-OutCompare1A-IRQ
// Wird IRQS_PER_SECOND mal pro Sekunde aufgerufen
SIGNAL (SIG_OUTPUT_COMPARE1A)
{
// count the number of IRQs, starting with 0.
static uint8_t irq_num_10ms;

// 10 Milli-Sekunden sind voll.
if (++irq_num_10ms == IRQS_PER_10MS)
{
irq_num_10ms = 0;

// Countdown-Timer erniedrigen
job_timer_10ms ();
}
}

// our entry point after RESET and initialization of globals
int main (void)
{
// init Timer1 to make IRQs
init_timer1();

// enable IRQs globally
sei();

// main loop
// Die main-Schleife realisiert einen Blinker:
// Am Anfang jeder Stunde wird 1 Minute lang mit 1/2 Hz geblinkt.
// main ist frei von Warteschleife(n)! :-)
// LED_AN; und LED_AUS; sind NICHT definiert und nur zur Verdeutlichung
while (1)
{
// in countdown_t (time.h) folgende Komponenten hinzufügen:
// .min.stundenzaehler // macht Stunden
// .sek.blinken // macht die gesamte blinkdauer
// .ms10.blink_led // macht die Blinkfrequenz

if (0 == count.min.stundenzaehler)
{
// Stundenzähler ist abgelaufen:
// neu aufziehen
// min.* wird im Minutentakt erniedrigt
// und eine Stunde hat 60 Minuten
// (Auflösung 1 Sekunde)
count.min.stundenzaehler = 60;

// Mach was...

// blinken auf 1 Minute aufziehen
// (Auflösung 10ms)
count.sek.blinken = 60;
}

// Am Anfang jeder Stunde wird 1 Minute lang im Sekundentakt
// (also mit 1/2 Hz) geblinkt
if (count.sek.blinken)
{
// Es wird geblinkt
// Falls blink_led abgelaufen ist:
// wieder aufziehen auf 2 Sekunden (200*10ms)
if (0 == count.ms10.blink_led)
count.ms10.blink_led = 200;

// Das eigentliche Blinken
// 1. Sekunde --> LED ist an
// 2. Sekunde --> LED ist aus
if (count.ms10.blink_led <= 100)
LED_AUS;
else
LED_AN;
}
else
{
// Falls die LED noch an ist
LED_AUS;
}
} // main loop

// we will never come here. No return needed (would be dead anyway).
}

toetzel
20.11.2006, 17:58
jezt wird es etwas lichter. Ich werde das gleich mal ausprobieren.....