-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathT003_LaserTankPulseSimulation.ino
219 lines (194 loc) · 7.66 KB
/
T003_LaserTankPulseSimulation.ino
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
// Laser Constants
#ifndef LASERDIGITALPWM
// D5 - PWM Out to TTL of Laser
#define LASERDIGITALPWM 5
#endif
// ISR Constants
// call ISR - TC4_Handler 20000 times per second
// an interrupt is called every 50 microseconds so to get:
// count 1 interrupts = 50us
// count 20 interrupts = 1ms
// count 100 interrupts = 5ms
// count 200 interrupts = 10ms
// count 20000 interrupts = 1s
// count 60000 interrupts = 3s
// count 100000 interrupts = 5s
#ifndef ISR_1MSECS
// number of 50usecs we need to get 1msec for the laser fire length,of the user defined time in msecs
#define ISR_1MSECS 20
#endif
#ifndef ISR_5MSECS
// pulse the laser every 5 milliseconds
#define ISR_5MSECS 100
#endif
// ISR vars
volatile boolean ISR_LaserOn = false; // tells the Arduino to turn on the laser to start the targeting process
volatile int ISR_LaserTargetCount = 0; // counts 50 usec pulses to trigger events related to targeting as defined in the code
volatile boolean ISR_LaserFire = false; // flag used to indicate when it's time to fire the laser
volatile int ISR_LaserFireLength = 0; // var used to hold the users input as to how long you want to laser on
volatile int ISR_LaserFireCount = 0; // counts 50 usec pulses to trigger events related to targeting as defined in the code
// Background Vars
boolean BackgroundHearBeat = false; // used to let us know the background is running
// Start MKR1010 software interrupt functions **********
uint16_t next_pow2(uint16_t v_)
{
// the next power-of-2 of the value (if v_ is pow-of-2 returns v_)
--v_;
v_|=v_>>1;
v_|=v_>>2;
v_|=v_>>4;
v_|=v_>>8;
return v_+1;
}
uint16_t get_clk_div(uint32_t freq_)
{
float ideal_clk_div=48000000.0f/(256.0f*float(freq_));
uint16_t clk_div=next_pow2(uint16_t(ceil(ideal_clk_div)));
switch(clk_div)
{
case 32: clk_div=64; break;
case 128: clk_div=256; break;
case 512: clk_div=1024; break;
}
return clk_div;
}
void setup_timer4(uint32_t freq_)
{
uint16_t clk_div=get_clk_div(freq_);
uint8_t clk_cnt=(48000000/clk_div)/freq_;
setup_timer4(clk_div, clk_cnt);
}
void setup_timer4(uint16_t clk_div_, uint8_t count_)
{
// Set up the generic clock (GCLK4) used to clock timers
REG_GCLK_GENDIV = GCLK_GENDIV_DIV(1) | // Divide the 48MHz clock source by divisor 1: 48MHz/1=48MHz
GCLK_GENDIV_ID(4); // Select Generic Clock (GCLK) 4
while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization
REG_GCLK_GENCTRL = GCLK_GENCTRL_IDC | // Set the duty cycle to 50/50 HIGH/LOW
GCLK_GENCTRL_GENEN | // Enable GCLK4
GCLK_GENCTRL_SRC_DFLL48M | // Set the 48MHz clock source
GCLK_GENCTRL_ID(4); // Select GCLK4
while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization
// Feed GCLK4 to TC4 and TC5
REG_GCLK_CLKCTRL = GCLK_CLKCTRL_CLKEN | // Enable GCLK4 to TC4 and TC5
GCLK_CLKCTRL_GEN_GCLK4 | // Select GCLK4
GCLK_CLKCTRL_ID_TC4_TC5; // Feed the GCLK4 to TC4 and TC5
while (GCLK->STATUS.bit.SYNCBUSY); // Wait for synchronization
REG_TC4_CTRLA |= TC_CTRLA_MODE_COUNT8; // Set the counter to 8-bit mode
while (TC4->COUNT8.STATUS.bit.SYNCBUSY); // Wait for synchronization
REG_TC4_COUNT8_CC0 = count_; // Set the TC4 CC0 register to some arbitary value
while (TC4->COUNT8.STATUS.bit.SYNCBUSY); // Wait for synchronization
NVIC_SetPriority(TC4_IRQn, 0); // Set the Nested Vector Interrupt Controller (NVIC) priority for TC4 to 0 (highest)
NVIC_EnableIRQ(TC4_IRQn); // Connect TC4 to Nested Vector Interrupt Controller (NVIC)
REG_TC4_INTFLAG |= TC_INTFLAG_OVF; // Clear the interrupt flags
REG_TC4_INTENSET = TC_INTENSET_OVF; // Enable TC4 interrupts
uint16_t prescale=0;
switch(clk_div_)
{
case 1: prescale=TC_CTRLA_PRESCALER(0); break;
case 2: prescale=TC_CTRLA_PRESCALER(1); break;
case 4: prescale=TC_CTRLA_PRESCALER(2); break;
case 8: prescale=TC_CTRLA_PRESCALER(3); break;
case 16: prescale=TC_CTRLA_PRESCALER(4); break;
case 64: prescale=TC_CTRLA_PRESCALER(5); break;
case 256: prescale=TC_CTRLA_PRESCALER(6); break;
case 1024: prescale=TC_CTRLA_PRESCALER(7); break;
}
REG_TC4_CTRLA |= prescale | TC_CTRLA_WAVEGEN_MFRQ | TC_CTRLA_ENABLE; // Enable TC4
while (TC4->COUNT8.STATUS.bit.SYNCBUSY); // Wait for synchronization
}
// End MKR1010 software interrupt functions **********
// Interrupt Service Routine (ISR)
void TC4_Handler()
{
if (TC4->COUNT16.INTFLAG.bit.OVF && TC4->COUNT16.INTENSET.bit.OVF)
{
// see if Targeting is active and/or we were asked to Fire the Laser
if(ISR_LaserFire) {
// Fire
// the length of the pulse is determined by the value of ISR_LaserFireLength (as milliseconds)
if(ISR_LaserFireCount == 0) {
digitalWrite(LASERDIGITALPWM, HIGH);
ISR_LaserFireCount++;
} else {
ISR_LaserFireCount++;
if(ISR_LaserFireCount == ((ISR_LaserFireLength * ISR_1MSECS))) {
digitalWrite(LASERDIGITALPWM, LOW);
ISR_LaserFireCount = 0;
ISR_LaserFire = false;
}
}
} else if (ISR_LaserOn) {
// Targeting
// generate a 50 microsecond digital pulse every 5 milliseconds
ISR_LaserTargetCount++;
if(ISR_LaserTargetCount == 1) {
digitalWrite(LASERDIGITALPWM, HIGH);
}
// 50 microseconds each interrupt
if(ISR_LaserTargetCount == 2) {
digitalWrite(LASERDIGITALPWM, LOW);
}
// do this every 5 milliseconds
if(ISR_LaserTargetCount == ISR_5MSECS) {
ISR_LaserTargetCount = 0;
}
}
// keep - clear interrupt
REG_TC4_INTFLAG = TC_INTFLAG_OVF;
}
}
void setup()
{
Serial.begin(9600); // opens serial port, sets data rate to 9600 bps
// we use this led to show the background is running
// flased on and off every time we go through the background loop
pinMode(LED_BUILTIN, OUTPUT);
// Digital PWM Pin
pinMode(LASERDIGITALPWM, OUTPUT);
digitalWrite(LASERDIGITALPWM, LOW); // No PWM
// done initilization so start the interrupts
// call ISR - TC4_Handler 20000 times per second
// an interrupt is called every 50 microseconds
setup_timer4(20000);
}
void loop()
{
String S_input;
while(Serial.available())
{
S_input = Serial.readString();// read the incoming data as string
S_input.trim();
Serial.println(S_input);
}
// Targeting on/off
if(S_input == "on") {
ISR_LaserOn = true;
S_input = "";
} else if (S_input == "off") {
ISR_LaserOn = false;
delay(10);
digitalWrite(LASERDIGITALPWM, LOW);
S_input = "";
}
// Fire Laser for user defined time
if(S_input.length() > 0) {
// remove the L
S_input.remove(0, 1);
// set LASERDIGITALPWM
Serial.println("LASERDIGITALPWM: " + S_input + " msec");
ISR_LaserFireLength = S_input.toInt();
ISR_LaserFire = true;
ISR_LaserFireCount = 0;
}
// Background Process 5
// show the background heart
BackgroundHearBeat = !BackgroundHearBeat;
if(BackgroundHearBeat) {
digitalWrite(LED_BUILTIN, LOW);
delay(500);
} else {
digitalWrite(LED_BUILTIN, HIGH);
delay(500);
}
}