-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathMillisecondTimer.h
105 lines (72 loc) · 2.27 KB
/
MillisecondTimer.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
/*
* Andy's Workshop NXA66 controller ATMega328p firmware
* Copyright (c) 2017 Andy Brown. http://www.andybrown.me.uk
* Please see website for licensing terms.
*/
#pragma once
namespace nxa66 {
/*
* Use Timer0 to count in milliseconds
*/
class MillisecondTimer {
public:
static volatile uint32_t _counter;
static volatile uint8_t _subCounter;
public:
static void setup();
static uint32_t millis();
static void delay(uint32_t waitfor);
static uint32_t difference(uint32_t start);
static bool hasTimedOut(uint32_t start,uint32_t timeout);
};
/*
* Setup timer 0. It will tick at 1MHz (CLK/8) and count 0-255 then generate an overflow
* interrupt. So interrupt frequency = (CLK/8)*256 = 256uS. We will increment the millisecond
* timer every 4 ticks = 1.024ms. Each interrupt we add 6 to the counter register which has the
* effect of changing the interrupt frequency to (CLK/8)*250 and that gives us an accurate 1ms counter.
*/
inline void MillisecondTimer::setup() {
// set up timer 0
TCCR0A = 0; // normal mode
TCCR0B = (1 << CS01); // CLK/8
TIMSK0 = (1 << TOIE0); // timer0 overflow interrupt
}
/*
* Return the timer
*/
inline uint32_t MillisecondTimer::millis() {
uint32_t ms;
// an 8-bit MCU cannot atomically read/write a 32-bit value so we must
// disable interrupts while retrieving the value to avoid getting a half-written
// value if an interrupt gets in while we're reading it
cli();
ms=_counter;
sei();
return ms;
}
/*
* Simple delay method
*/
inline void MillisecondTimer::delay(uint32_t waitfor) {
uint32_t target;
target=millis()+waitfor;
while(_counter<target);
}
/*
* Return the difference between a starting time and now, taking into account
* wrap around
*/
inline uint32_t MillisecondTimer::difference(uint32_t start) {
uint32_t now=millis();
if(now>start)
return now-start;
else
return now+(0xffffffff-start+1);
}
/*
* Check if a timeout has been exceeded. This is designed to cope with wrap around
*/
inline bool MillisecondTimer::hasTimedOut(uint32_t start,uint32_t timeout) {
return difference(start)>timeout;
}
}