2014-03-01 03:50:09 +01:00
|
|
|
/*
|
|
|
|
* "THE BEER-WARE LICENSE" (Revision 42):
|
|
|
|
* Martin Wenger <martin.wenger@arcormail.de> and Stefan Rupp <struppi@struppi.name>
|
|
|
|
* wrote this file. As long as you retain this notice you can do whatever you want
|
|
|
|
* with this stuff. If we meet some day, and you think this stuff is worth it,
|
|
|
|
* you can buy me/us a beer in return.
|
|
|
|
* (c) 2005-2010 Martin Wenger, Stefan Rupp
|
|
|
|
* (c) 2013,2014 Stefan Rupp
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <avr/io.h>
|
|
|
|
#include "timer.h"
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <avr/interrupt.h>
|
|
|
|
|
|
|
|
|
|
|
|
/* timer_time gets increased on every interrupt
|
|
|
|
* those interrupts happen every 1ms
|
|
|
|
*/
|
2014-03-12 21:54:28 +01:00
|
|
|
static volatile uint32_t _timer_time;
|
2014-03-01 03:50:09 +01:00
|
|
|
|
2014-03-01 18:03:19 +01:00
|
|
|
ISR(TIMER0_COMPA_vect) {
|
2014-03-12 21:54:28 +01:00
|
|
|
++_timer_time;
|
2014-03-01 03:50:09 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initialize the timer
|
|
|
|
* This function has to be called first, before calling timer_wait and/or timer_get,
|
|
|
|
* else timer_get will always return 0, and timer_wait will wait forever!
|
|
|
|
*/
|
|
|
|
|
|
|
|
void timer_init(void)
|
|
|
|
{
|
2014-03-12 17:07:18 +01:00
|
|
|
|
2014-03-09 00:36:20 +01:00
|
|
|
uint8_t sreg = SREG;
|
2014-03-01 03:50:09 +01:00
|
|
|
// Stop all interrupts
|
|
|
|
cli();
|
|
|
|
|
|
|
|
// Reset timer to zero
|
2014-03-12 21:54:28 +01:00
|
|
|
_timer_time = 0;
|
2014-03-01 03:50:09 +01:00
|
|
|
|
|
|
|
// - Time accuracy: 1 millisecond (corresponding frequency: 1kHz)
|
2014-03-09 00:25:02 +01:00
|
|
|
// ==> F_CPU = 20Mhz
|
|
|
|
// ==> 20Mhz / 256 = 78.125 kHz
|
2014-03-12 17:07:18 +01:00
|
|
|
// ==> let timer count to 77 to get (almost) 1kHz frequency
|
2014-03-01 03:50:09 +01:00
|
|
|
// therefore:
|
2014-03-09 00:25:02 +01:00
|
|
|
// - Set Timer/Counter0 prescaler to 256 ==> (1<<CS02)
|
2015-01-09 03:12:11 +01:00
|
|
|
// - Set OCR0 to 77
|
2014-03-01 03:50:09 +01:00
|
|
|
// - CTC ( i.e. clear counter, when COUNTER == OCR0A) ==> (1<<WGM01)
|
2014-03-09 00:25:02 +01:00
|
|
|
// unfortunately, due to the 20MHz and the coarse prescaler dividers
|
|
|
|
// provided, we can't get any closer to the desired frequency of
|
|
|
|
// 1kHz :(
|
2014-03-12 17:07:18 +01:00
|
|
|
OCR0A = 77;
|
2014-03-12 21:54:28 +01:00
|
|
|
TCCR0A = (1<<WGM01);
|
|
|
|
TCCR0B = (1<<CS02);
|
2014-03-01 18:03:19 +01:00
|
|
|
|
2014-03-01 03:50:09 +01:00
|
|
|
// Interrupts setzen
|
2014-03-01 18:03:19 +01:00
|
|
|
TIMSK0 |= (1<<OCIE0A);
|
2014-03-09 00:36:20 +01:00
|
|
|
SREG = sreg;
|
2014-03-01 03:50:09 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the current time
|
|
|
|
* \return the current time (in ms)
|
|
|
|
*/
|
|
|
|
inline uint32_t timer_get(void)
|
|
|
|
{
|
|
|
|
uint32_t t;
|
|
|
|
uint8_t sreg;
|
|
|
|
|
|
|
|
sreg = SREG;
|
|
|
|
cli();
|
2014-03-12 21:54:28 +01:00
|
|
|
t = _timer_time;
|
2014-03-01 03:50:09 +01:00
|
|
|
SREG = sreg;
|
|
|
|
return t;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Wait for (at least) the specified amount of time
|
|
|
|
* \param delay The time to wait (in ms)
|
|
|
|
*/
|
|
|
|
|
|
|
|
void timer_wait(uint32_t delay)
|
|
|
|
{
|
|
|
|
uint32_t end = timer_get() + delay +1;
|
|
|
|
while ( end > timer_get() );
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Decode a integer timestamp (in microseconds)
|
|
|
|
* into hours, minutes, seconds, microseconds
|
|
|
|
* \param time the time in microseconds
|
|
|
|
* \param hours will be filled in to contain the hours after return
|
|
|
|
* \param minutes will be filled in to contain the minutes after return
|
|
|
|
* \param seconds will be filled in to contain the seconds after return
|
|
|
|
* \param ms be filled in to contain the microseconds after return
|
|
|
|
*/
|
|
|
|
void timer_decode(uint32_t time, uint8_t *hours, uint8_t *minutes, uint8_t *seconds, uint16_t *ms)
|
|
|
|
{
|
|
|
|
if (ms != NULL) {
|
|
|
|
*ms = time % 1000;
|
|
|
|
}
|
|
|
|
time /= 1000;
|
|
|
|
if (seconds != NULL) {
|
|
|
|
*seconds = time % 60;
|
|
|
|
}
|
|
|
|
time /= 60;
|
|
|
|
if (minutes != NULL) {
|
|
|
|
*minutes = time % 60;
|
|
|
|
}
|
|
|
|
time /= 60;
|
|
|
|
if (hours != NULL) {
|
|
|
|
*hours = time;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Encode a time given as hours, minutes, seconds and microsecods into a integer storing micorseconds
|
|
|
|
* \param time the variable to store the time into
|
|
|
|
* \param hour the hours to store
|
|
|
|
* \param hour the minutes to store
|
|
|
|
* \param hour the seconds to store
|
|
|
|
* \param hour the microseconds to store
|
|
|
|
*/
|
|
|
|
void timer_encode(uint32_t *time, uint8_t hours, uint8_t minutes, uint8_t seconds, uint16_t ms)
|
|
|
|
{
|
|
|
|
|
|
|
|
*time = hours;
|
|
|
|
*time *= 60;
|
|
|
|
|
|
|
|
*time += minutes;
|
|
|
|
*time *= 60;
|
|
|
|
|
|
|
|
*time += seconds;
|
|
|
|
*time *= 1000U;
|
|
|
|
|
|
|
|
*time += ms;
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
void timer_validate(uint8_t *hours, uint8_t *minutes, uint8_t *seconds, uint16_t *ms)
|
|
|
|
{
|
|
|
|
|
|
|
|
while (*ms >= 1000) {
|
|
|
|
*ms -= 1000;
|
|
|
|
(*seconds)++;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (*seconds >= 60) {
|
|
|
|
*ms -= 60;
|
|
|
|
(*minutes)++;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (*minutes >= 60) {
|
|
|
|
*minutes -= 60;
|
|
|
|
(*hours)++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
*/
|