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".
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
Code:
#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
Code:
#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
}
Lesezeichen