forked from RobTillaart/Arduino
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPulsePattern.cpp
More file actions
132 lines (117 loc) · 3.07 KB
/
Copy pathPulsePattern.cpp
File metadata and controls
132 lines (117 loc) · 3.07 KB
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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
//
// FILE: PulsePattern.cpp
// AUTHOR: Rob dot Tillaart at gmail dot com
// VERSION: see PULSEPATTERN_LIB_VERSION in .h
// PURPOSE: PulsePattern library for Arduino
//
// HISTORY:
// 0.0.1 - 2012-11-23 initial version
// 0.0.2 - 2012-11-23 adapted a static PPO
// 0.0.3 - 2012-12-27 renamed to PulsePattern
// 0.0.4 - 2012-12-27 code stable(?) enough to publish
// 0.0.5 - 2012-12-27 code cleanup+comment
// 0.0.6 - 2015-04-18 completed the state machine
// 0.0.7 - 2017-07-16 refactor & review
//
// Released to the public domain
//
// TODO
// - fast function iso array to return the next period?
// more adaptive to e.g. sensor values. (investigate)
// - test PRE 1.0 backwards compatibility
// - move code to .h file so compiler can inline?
// - optimize timer code
// - adjust timing to more accurate values -> setTimer()
// - worker should be private - how???
// - test invalid array periods
// - start en stop index ipv size?
// - pulsepattern recorder
//
#include "PulsePattern.h"
#if defined(ARDUINO) && ARDUINO >= 100
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
// Predefined generator (singleton)
PulsePattern PPGenerator;
ISR(TIMER1_COMPA_vect)
{
PPGenerator.worker();
}
PulsePattern::PulsePattern()
{
_size = 0;
_state = NOTINIT;
_ar = NULL;
_cnt = 0;
_level = LOW;
_prescaler = 0;
_pin = 0;
}
void PulsePattern::init(uint8_t pin, uint16_t * ar, uint8_t size,
uint8_t level, uint8_t prescaler)
{
_pin = pin;
pinMode(_pin, OUTPUT);
stop();
_ar = ar;
_size = size;
// TODO: run over the array to test invalid values?
// constrain them 10-4095?
_level = constrain(level, LOW, HIGH);
_prescaler = constrain(prescaler, PRESCALE_1, PRESCALE_1024);
_cnt = 0;
digitalWrite(_pin, _level);
_state = STOPPED;
}
void PulsePattern::start()
{
if (_size == 0) return; // no pattern
if (_state == RUNNING) return; // no restart
setTimer(1); // start asap
_state = RUNNING;
}
void PulsePattern::stop()
{
stopTimer();
_state = STOPPED;
_level = LOW;
digitalWrite(_pin, _level);
}
void PulsePattern::worker()
{
if (_state != RUNNING) return;
// set next period & flip signal
_level = !_level;
// direct port faster
digitalWrite(_pin, _level);
// TODO: adjustment needed for code overhead when micros?;
// + 5.2 usec for digitalWrite
// + 3 usec for settimer call
OCR1A = (_ar[_cnt]) * (F_CPU/1000000L);
_cnt++;
if (_cnt >= _size) _cnt = 0; // repeat
}
// TIMER code based upon - http://www.gammon.com.au/forum/?id=11504
void PulsePattern::stopTimer()
{
TCCR1A = 0; // reset timer 1
TCCR1B = 0;
}
// TODO: can be optimized?
void PulsePattern::setTimer(const uint16_t cc) const
{
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0; // reset counter
OCR1A = cc * 16; // compare A register value;
// * 16 makes max period 4095
// min period 12?
// 4: CTC mode, top = OCR1A
TCCR1A = _BV (COM1A1); // clear on compare
TCCR1B = _BV (WGM12) | _prescaler;
TIFR1 |= _BV (OCF1A); // clear interrupt flag
TIMSK1 = _BV (OCIE1A); // interrupt on Compare A Match
}
// END OF FILE