1
+ /*
2
+ * Interrupt and PWM utilities for 16 bit Timer1 on ATmega168/328
3
+ * Original code by Jesse Tane for http://labs.ideo.com August 2008
4
+ * Modified March 2009 by Jérôme Despatis and Jesse Tane for ATmega328 support
5
+ * Modified June 2009 by Michael Polli and Jesse Tane to fix a bug in setPeriod() which caused the timer to stop
6
+ * Modified June 2011 by Lex Talionis to add a function to read the timer
7
+ *
8
+ * This is free software. You can redistribute it and/or modify it under
9
+ * the terms of Creative Commons Attribution 3.0 United States License.
10
+ * To view a copy of this license, visit http://creativecommons.org/licenses/by/3.0/us/
11
+ * or send a letter to Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA.
12
+ *
13
+ * See Google Code project http://code.google.com/p/arduino-timerone/ for latest
14
+ */
15
+ #ifndef TIMERONE_cpp
16
+ #define TIMERONE_cpp
17
+
18
+ #include " TimerOne.h"
19
+
20
+ TimerOne Timer1; // preinstatiate
21
+
22
+ ISR (TIMER1_OVF_vect) // interrupt service routine that wraps a user defined function supplied by attachInterrupt
23
+ {
24
+ Timer1.isrCallback ();
25
+ }
26
+
27
+ void TimerOne::initialize (long microseconds)
28
+ {
29
+ TCCR1A = 0 ; // clear control register A
30
+ TCCR1B = _BV (WGM13); // set mode 8: phase and frequency correct pwm, stop the timer
31
+ setPeriod (microseconds);
32
+ }
33
+
34
+ void TimerOne::setPeriod (long microseconds)
35
+ {
36
+ long cycles = (F_CPU / 2000000 ) * microseconds; // the counter runs backwards after TOP, interrupt is at BOTTOM so divide microseconds by 2
37
+ if (cycles < RESOLUTION) clockSelectBits = _BV (CS10); // no prescale, full xtal
38
+ else if ((cycles >>= 3 ) < RESOLUTION) clockSelectBits = _BV (CS11); // prescale by /8
39
+ else if ((cycles >>= 3 ) < RESOLUTION) clockSelectBits = _BV (CS11) | _BV (CS10); // prescale by /64
40
+ else if ((cycles >>= 2 ) < RESOLUTION) clockSelectBits = _BV (CS12); // prescale by /256
41
+ else if ((cycles >>= 2 ) < RESOLUTION) clockSelectBits = _BV (CS12) | _BV (CS10); // prescale by /1024
42
+ else cycles = RESOLUTION - 1 , clockSelectBits = _BV (CS12) | _BV (CS10); // request was out of bounds, set as maximum
43
+ ICR1 = pwmPeriod = cycles; // ICR1 is TOP in p & f correct pwm mode
44
+ TCCR1B &= ~(_BV (CS10) | _BV (CS11) | _BV (CS12));
45
+ TCCR1B |= clockSelectBits; // reset clock select register
46
+ }
47
+
48
+ void TimerOne::setPwmDuty (char pin, int duty)
49
+ {
50
+ unsigned long dutyCycle = pwmPeriod;
51
+ dutyCycle *= duty;
52
+ dutyCycle >>= 10 ;
53
+ if (pin == 1 || pin == 9 ) OCR1A = dutyCycle;
54
+ else if (pin == 2 || pin == 10 ) OCR1B = dutyCycle;
55
+ }
56
+
57
+ void TimerOne::pwm (char pin, int duty, long microseconds) // expects duty cycle to be 10 bit (1024)
58
+ {
59
+ if (microseconds > 0 ) setPeriod (microseconds);
60
+ if (pin == 1 || pin == 9 ) {
61
+ DDRB |= _BV (PORTB1); // sets data direction register for pwm output pin
62
+ TCCR1A |= _BV (COM1A1); // activates the output pin
63
+ }
64
+ else if (pin == 2 || pin == 10 ) {
65
+ DDRB |= _BV (PORTB2);
66
+ TCCR1A |= _BV (COM1B1);
67
+ }
68
+ setPwmDuty (pin, duty);
69
+ start ();
70
+ }
71
+
72
+ void TimerOne::disablePwm (char pin)
73
+ {
74
+ if (pin == 1 || pin == 9 ) TCCR1A &= ~_BV (COM1A1); // clear the bit that enables pwm on PB1
75
+ else if (pin == 2 || pin == 10 ) TCCR1A &= ~_BV (COM1B1); // clear the bit that enables pwm on PB2
76
+ }
77
+
78
+ void TimerOne::attachInterrupt (void (*isr)(), long microseconds)
79
+ {
80
+ if (microseconds > 0 ) setPeriod (microseconds);
81
+ isrCallback = isr; // register the user's callback with the real ISR
82
+ TIMSK1 = _BV (TOIE1); // sets the timer overflow interrupt enable bit
83
+ sei (); // ensures that interrupts are globally enabled
84
+ start ();
85
+ }
86
+
87
+ void TimerOne::detachInterrupt ()
88
+ {
89
+ TIMSK1 &= ~_BV (TOIE1); // clears the timer overflow interrupt enable bit
90
+ }
91
+
92
+ void TimerOne::start ()
93
+ {
94
+ TCCR1B |= clockSelectBits;
95
+ }
96
+
97
+ void TimerOne::stop ()
98
+ {
99
+ TCCR1B &= ~(_BV (CS10) | _BV (CS11) | _BV (CS12)); // clears all clock selects bits
100
+ }
101
+
102
+ void TimerOne::restart ()
103
+ {
104
+ TCNT1 = 0 ;
105
+ }
106
+
107
+ unsigned long TimerOne::read () // returns the value of the timer in microseconds
108
+ { // rember! phase and freq correct mode counts up to then down again
109
+ unsigned int tmp=TCNT1;
110
+ char scale=0 ;
111
+ switch (clockSelectBits)
112
+ {
113
+ case 1 :// no prescalse
114
+ scale=0 ;
115
+ break ;
116
+ case 2 :// x8 prescale
117
+ scale=3 ;
118
+ break ;
119
+ case 3 :// x64
120
+ scale=6 ;
121
+ break ;
122
+ case 4 :// x256
123
+ scale=8 ;
124
+ break ;
125
+ case 5 :// x1024
126
+ scale=10 ;
127
+ break ;
128
+ }
129
+ while (TCNT1==tmp) // if the timer has not ticked yet
130
+ {
131
+ // do nothing -- max delay here is ~1023 cycles
132
+ }
133
+ tmp = ( (TCNT1>tmp) ? (tmp) : (ICR1-TCNT1)+ICR1 );// if we are counting down add the top value to how far we have counted down
134
+ return ((tmp*1000L )/(F_CPU /1000L ))<<scale;
135
+ }
136
+
137
+ #endif
0 commit comments