root / arduino-1.0 / hardware / arduino / cores / arduino / Tone.cpp @ 58d82c77
History | View | Annotate | Download (14 KB)
1 |
/* Tone.cpp
|
---|---|
2 |
|
3 |
A Tone Generator Library
|
4 |
|
5 |
Written by Brett Hagman
|
6 |
|
7 |
This library is free software; you can redistribute it and/or
|
8 |
modify it under the terms of the GNU Lesser General Public
|
9 |
License as published by the Free Software Foundation; either
|
10 |
version 2.1 of the License, or (at your option) any later version.
|
11 |
|
12 |
This library is distributed in the hope that it will be useful,
|
13 |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
15 |
Lesser General Public License for more details.
|
16 |
|
17 |
You should have received a copy of the GNU Lesser General Public
|
18 |
License along with this library; if not, write to the Free Software
|
19 |
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
20 |
|
21 |
Version Modified By Date Comments
|
22 |
------- ----------- -------- --------
|
23 |
0001 B Hagman 09/08/02 Initial coding
|
24 |
0002 B Hagman 09/08/18 Multiple pins
|
25 |
0003 B Hagman 09/08/18 Moved initialization from constructor to begin()
|
26 |
0004 B Hagman 09/09/26 Fixed problems with ATmega8
|
27 |
0005 B Hagman 09/11/23 Scanned prescalars for best fit on 8 bit timers
|
28 |
09/11/25 Changed pin toggle method to XOR
|
29 |
09/11/25 Fixed timer0 from being excluded
|
30 |
0006 D Mellis 09/12/29 Replaced objects with functions
|
31 |
0007 M Sproul 10/08/29 Changed #ifdefs from cpu to register
|
32 |
*************************************************/
|
33 |
|
34 |
#include <avr/interrupt.h> |
35 |
#include <avr/pgmspace.h> |
36 |
#include "Arduino.h" |
37 |
#include "pins_arduino.h" |
38 |
|
39 |
#if defined(__AVR_ATmega8__) || defined(__AVR_ATmega128__)
|
40 |
#define TCCR2A TCCR2
|
41 |
#define TCCR2B TCCR2
|
42 |
#define COM2A1 COM21
|
43 |
#define COM2A0 COM20
|
44 |
#define OCR2A OCR2
|
45 |
#define TIMSK2 TIMSK
|
46 |
#define OCIE2A OCIE2
|
47 |
#define TIMER2_COMPA_vect TIMER2_COMP_vect
|
48 |
#define TIMSK1 TIMSK
|
49 |
#endif
|
50 |
|
51 |
// timerx_toggle_count:
|
52 |
// > 0 - duration specified
|
53 |
// = 0 - stopped
|
54 |
// < 0 - infinitely (until stop() method called, or new play() called)
|
55 |
|
56 |
#if !defined(__AVR_ATmega8__)
|
57 |
volatile long timer0_toggle_count; |
58 |
volatile uint8_t *timer0_pin_port;
|
59 |
volatile uint8_t timer0_pin_mask;
|
60 |
#endif
|
61 |
|
62 |
volatile long timer1_toggle_count; |
63 |
volatile uint8_t *timer1_pin_port;
|
64 |
volatile uint8_t timer1_pin_mask;
|
65 |
volatile long timer2_toggle_count; |
66 |
volatile uint8_t *timer2_pin_port;
|
67 |
volatile uint8_t timer2_pin_mask;
|
68 |
|
69 |
#if defined(TIMSK3)
|
70 |
volatile long timer3_toggle_count; |
71 |
volatile uint8_t *timer3_pin_port;
|
72 |
volatile uint8_t timer3_pin_mask;
|
73 |
#endif
|
74 |
|
75 |
#if defined(TIMSK4)
|
76 |
volatile long timer4_toggle_count; |
77 |
volatile uint8_t *timer4_pin_port;
|
78 |
volatile uint8_t timer4_pin_mask;
|
79 |
#endif
|
80 |
|
81 |
#if defined(TIMSK5)
|
82 |
volatile long timer5_toggle_count; |
83 |
volatile uint8_t *timer5_pin_port;
|
84 |
volatile uint8_t timer5_pin_mask;
|
85 |
#endif
|
86 |
|
87 |
|
88 |
// MLS: This does not make sense, the 3 options are the same
|
89 |
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
90 |
|
91 |
#define AVAILABLE_TONE_PINS 1 |
92 |
|
93 |
const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 2 /*, 3, 4, 5, 1, 0 */ }; |
94 |
static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { 255 /*, 255, 255, 255, 255, 255 */ }; |
95 |
|
96 |
#elif defined(__AVR_ATmega8__)
|
97 |
|
98 |
#define AVAILABLE_TONE_PINS 1 |
99 |
|
100 |
const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 2 /*, 1 */ }; |
101 |
static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { 255 /*, 255 */ }; |
102 |
|
103 |
#else
|
104 |
|
105 |
#define AVAILABLE_TONE_PINS 1 |
106 |
|
107 |
// Leave timer 0 to last.
|
108 |
const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 2 /*, 1, 0 */ }; |
109 |
static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { 255 /*, 255, 255 */ }; |
110 |
|
111 |
#endif
|
112 |
|
113 |
|
114 |
|
115 |
static int8_t toneBegin(uint8_t _pin)
|
116 |
{ |
117 |
int8_t _timer = -1;
|
118 |
|
119 |
// if we're already using the pin, the timer should be configured.
|
120 |
for (int i = 0; i < AVAILABLE_TONE_PINS; i++) { |
121 |
if (tone_pins[i] == _pin) {
|
122 |
return pgm_read_byte(tone_pin_to_timer_PGM + i);
|
123 |
} |
124 |
} |
125 |
|
126 |
// search for an unused timer.
|
127 |
for (int i = 0; i < AVAILABLE_TONE_PINS; i++) { |
128 |
if (tone_pins[i] == 255) { |
129 |
tone_pins[i] = _pin; |
130 |
_timer = pgm_read_byte(tone_pin_to_timer_PGM + i); |
131 |
break;
|
132 |
} |
133 |
} |
134 |
|
135 |
if (_timer != -1) |
136 |
{ |
137 |
// Set timer specific stuff
|
138 |
// All timers in CTC mode
|
139 |
// 8 bit timers will require changing prescalar values,
|
140 |
// whereas 16 bit timers are set to either ck/1 or ck/64 prescalar
|
141 |
switch (_timer)
|
142 |
{ |
143 |
#if defined(TCCR0A) && defined(TCCR0B)
|
144 |
case 0: |
145 |
// 8 bit timer
|
146 |
TCCR0A = 0;
|
147 |
TCCR0B = 0;
|
148 |
bitWrite(TCCR0A, WGM01, 1);
|
149 |
bitWrite(TCCR0B, CS00, 1);
|
150 |
timer0_pin_port = portOutputRegister(digitalPinToPort(_pin)); |
151 |
timer0_pin_mask = digitalPinToBitMask(_pin); |
152 |
break;
|
153 |
#endif
|
154 |
|
155 |
#if defined(TCCR1A) && defined(TCCR1B) && defined(WGM12)
|
156 |
case 1: |
157 |
// 16 bit timer
|
158 |
TCCR1A = 0;
|
159 |
TCCR1B = 0;
|
160 |
bitWrite(TCCR1B, WGM12, 1);
|
161 |
bitWrite(TCCR1B, CS10, 1);
|
162 |
timer1_pin_port = portOutputRegister(digitalPinToPort(_pin)); |
163 |
timer1_pin_mask = digitalPinToBitMask(_pin); |
164 |
break;
|
165 |
#endif
|
166 |
|
167 |
#if defined(TCCR2A) && defined(TCCR2B)
|
168 |
case 2: |
169 |
// 8 bit timer
|
170 |
TCCR2A = 0;
|
171 |
TCCR2B = 0;
|
172 |
bitWrite(TCCR2A, WGM21, 1);
|
173 |
bitWrite(TCCR2B, CS20, 1);
|
174 |
timer2_pin_port = portOutputRegister(digitalPinToPort(_pin)); |
175 |
timer2_pin_mask = digitalPinToBitMask(_pin); |
176 |
break;
|
177 |
#endif
|
178 |
|
179 |
#if defined(TCCR3A) && defined(TCCR3B) && defined(TIMSK3)
|
180 |
case 3: |
181 |
// 16 bit timer
|
182 |
TCCR3A = 0;
|
183 |
TCCR3B = 0;
|
184 |
bitWrite(TCCR3B, WGM32, 1);
|
185 |
bitWrite(TCCR3B, CS30, 1);
|
186 |
timer3_pin_port = portOutputRegister(digitalPinToPort(_pin)); |
187 |
timer3_pin_mask = digitalPinToBitMask(_pin); |
188 |
break;
|
189 |
#endif
|
190 |
|
191 |
#if defined(TCCR4A) && defined(TCCR4B) && defined(TIMSK4)
|
192 |
case 4: |
193 |
// 16 bit timer
|
194 |
TCCR4A = 0;
|
195 |
TCCR4B = 0;
|
196 |
#if defined(WGM42)
|
197 |
bitWrite(TCCR4B, WGM42, 1);
|
198 |
#elif defined(CS43)
|
199 |
#warning this may not be correct |
200 |
// atmega32u4
|
201 |
bitWrite(TCCR4B, CS43, 1);
|
202 |
#endif
|
203 |
bitWrite(TCCR4B, CS40, 1);
|
204 |
timer4_pin_port = portOutputRegister(digitalPinToPort(_pin)); |
205 |
timer4_pin_mask = digitalPinToBitMask(_pin); |
206 |
break;
|
207 |
#endif
|
208 |
|
209 |
#if defined(TCCR5A) && defined(TCCR5B) && defined(TIMSK5)
|
210 |
case 5: |
211 |
// 16 bit timer
|
212 |
TCCR5A = 0;
|
213 |
TCCR5B = 0;
|
214 |
bitWrite(TCCR5B, WGM52, 1);
|
215 |
bitWrite(TCCR5B, CS50, 1);
|
216 |
timer5_pin_port = portOutputRegister(digitalPinToPort(_pin)); |
217 |
timer5_pin_mask = digitalPinToBitMask(_pin); |
218 |
break;
|
219 |
#endif
|
220 |
} |
221 |
} |
222 |
|
223 |
return _timer;
|
224 |
} |
225 |
|
226 |
|
227 |
|
228 |
// frequency (in hertz) and duration (in milliseconds).
|
229 |
|
230 |
void tone(uint8_t _pin, unsigned int frequency, unsigned long duration) |
231 |
{ |
232 |
uint8_t prescalarbits = 0b001;
|
233 |
long toggle_count = 0; |
234 |
uint32_t ocr = 0;
|
235 |
int8_t _timer; |
236 |
|
237 |
_timer = toneBegin(_pin); |
238 |
|
239 |
if (_timer >= 0) |
240 |
{ |
241 |
// Set the pinMode as OUTPUT
|
242 |
pinMode(_pin, OUTPUT); |
243 |
|
244 |
// if we are using an 8 bit timer, scan through prescalars to find the best fit
|
245 |
if (_timer == 0 || _timer == 2) |
246 |
{ |
247 |
ocr = F_CPU / frequency / 2 - 1; |
248 |
prescalarbits = 0b001; // ck/1: same for both timers |
249 |
if (ocr > 255) |
250 |
{ |
251 |
ocr = F_CPU / frequency / 2 / 8 - 1; |
252 |
prescalarbits = 0b010; // ck/8: same for both timers |
253 |
|
254 |
if (_timer == 2 && ocr > 255) |
255 |
{ |
256 |
ocr = F_CPU / frequency / 2 / 32 - 1; |
257 |
prescalarbits = 0b011;
|
258 |
} |
259 |
|
260 |
if (ocr > 255) |
261 |
{ |
262 |
ocr = F_CPU / frequency / 2 / 64 - 1; |
263 |
prescalarbits = _timer == 0 ? 0b011 : 0b100; |
264 |
|
265 |
if (_timer == 2 && ocr > 255) |
266 |
{ |
267 |
ocr = F_CPU / frequency / 2 / 128 - 1; |
268 |
prescalarbits = 0b101;
|
269 |
} |
270 |
|
271 |
if (ocr > 255) |
272 |
{ |
273 |
ocr = F_CPU / frequency / 2 / 256 - 1; |
274 |
prescalarbits = _timer == 0 ? 0b100 : 0b110; |
275 |
if (ocr > 255) |
276 |
{ |
277 |
// can't do any better than /1024
|
278 |
ocr = F_CPU / frequency / 2 / 1024 - 1; |
279 |
prescalarbits = _timer == 0 ? 0b101 : 0b111; |
280 |
} |
281 |
} |
282 |
} |
283 |
} |
284 |
|
285 |
#if defined(TCCR0B)
|
286 |
if (_timer == 0) |
287 |
{ |
288 |
TCCR0B = prescalarbits; |
289 |
} |
290 |
else
|
291 |
#endif
|
292 |
#if defined(TCCR2B)
|
293 |
{ |
294 |
TCCR2B = prescalarbits; |
295 |
} |
296 |
#else
|
297 |
{ |
298 |
// dummy place holder to make the above ifdefs work
|
299 |
} |
300 |
#endif
|
301 |
} |
302 |
else
|
303 |
{ |
304 |
// two choices for the 16 bit timers: ck/1 or ck/64
|
305 |
ocr = F_CPU / frequency / 2 - 1; |
306 |
|
307 |
prescalarbits = 0b001;
|
308 |
if (ocr > 0xffff) |
309 |
{ |
310 |
ocr = F_CPU / frequency / 2 / 64 - 1; |
311 |
prescalarbits = 0b011;
|
312 |
} |
313 |
|
314 |
if (_timer == 1) |
315 |
{ |
316 |
#if defined(TCCR1B)
|
317 |
TCCR1B = (TCCR1B & 0b11111000) | prescalarbits;
|
318 |
#endif
|
319 |
} |
320 |
#if defined(TCCR3B)
|
321 |
else if (_timer == 3) |
322 |
TCCR3B = (TCCR3B & 0b11111000) | prescalarbits;
|
323 |
#endif
|
324 |
#if defined(TCCR4B)
|
325 |
else if (_timer == 4) |
326 |
TCCR4B = (TCCR4B & 0b11111000) | prescalarbits;
|
327 |
#endif
|
328 |
#if defined(TCCR5B)
|
329 |
else if (_timer == 5) |
330 |
TCCR5B = (TCCR5B & 0b11111000) | prescalarbits;
|
331 |
#endif
|
332 |
|
333 |
} |
334 |
|
335 |
|
336 |
// Calculate the toggle count
|
337 |
if (duration > 0) |
338 |
{ |
339 |
toggle_count = 2 * frequency * duration / 1000; |
340 |
} |
341 |
else
|
342 |
{ |
343 |
toggle_count = -1;
|
344 |
} |
345 |
|
346 |
// Set the OCR for the given timer,
|
347 |
// set the toggle count,
|
348 |
// then turn on the interrupts
|
349 |
switch (_timer)
|
350 |
{ |
351 |
|
352 |
#if defined(OCR0A) && defined(TIMSK0) && defined(OCIE0A)
|
353 |
case 0: |
354 |
OCR0A = ocr; |
355 |
timer0_toggle_count = toggle_count; |
356 |
bitWrite(TIMSK0, OCIE0A, 1);
|
357 |
break;
|
358 |
#endif
|
359 |
|
360 |
case 1: |
361 |
#if defined(OCR1A) && defined(TIMSK1) && defined(OCIE1A)
|
362 |
OCR1A = ocr; |
363 |
timer1_toggle_count = toggle_count; |
364 |
bitWrite(TIMSK1, OCIE1A, 1);
|
365 |
#elif defined(OCR1A) && defined(TIMSK) && defined(OCIE1A)
|
366 |
// this combination is for at least the ATmega32
|
367 |
OCR1A = ocr; |
368 |
timer1_toggle_count = toggle_count; |
369 |
bitWrite(TIMSK, OCIE1A, 1);
|
370 |
#endif
|
371 |
break;
|
372 |
|
373 |
#if defined(OCR2A) && defined(TIMSK2) && defined(OCIE2A)
|
374 |
case 2: |
375 |
OCR2A = ocr; |
376 |
timer2_toggle_count = toggle_count; |
377 |
bitWrite(TIMSK2, OCIE2A, 1);
|
378 |
break;
|
379 |
#endif
|
380 |
|
381 |
#if defined(TIMSK3)
|
382 |
case 3: |
383 |
OCR3A = ocr; |
384 |
timer3_toggle_count = toggle_count; |
385 |
bitWrite(TIMSK3, OCIE3A, 1);
|
386 |
break;
|
387 |
#endif
|
388 |
|
389 |
#if defined(TIMSK4)
|
390 |
case 4: |
391 |
OCR4A = ocr; |
392 |
timer4_toggle_count = toggle_count; |
393 |
bitWrite(TIMSK4, OCIE4A, 1);
|
394 |
break;
|
395 |
#endif
|
396 |
|
397 |
#if defined(OCR5A) && defined(TIMSK5) && defined(OCIE5A)
|
398 |
case 5: |
399 |
OCR5A = ocr; |
400 |
timer5_toggle_count = toggle_count; |
401 |
bitWrite(TIMSK5, OCIE5A, 1);
|
402 |
break;
|
403 |
#endif
|
404 |
|
405 |
} |
406 |
} |
407 |
} |
408 |
|
409 |
|
410 |
// XXX: this function only works properly for timer 2 (the only one we use
|
411 |
// currently). for the others, it should end the tone, but won't restore
|
412 |
// proper PWM functionality for the timer.
|
413 |
void disableTimer(uint8_t _timer)
|
414 |
{ |
415 |
switch (_timer)
|
416 |
{ |
417 |
case 0: |
418 |
#if defined(TIMSK0)
|
419 |
TIMSK0 = 0;
|
420 |
#elif defined(TIMSK)
|
421 |
TIMSK = 0; // atmega32 |
422 |
#endif
|
423 |
break;
|
424 |
|
425 |
#if defined(TIMSK1) && defined(OCIE1A)
|
426 |
case 1: |
427 |
bitWrite(TIMSK1, OCIE1A, 0);
|
428 |
break;
|
429 |
#endif
|
430 |
|
431 |
case 2: |
432 |
#if defined(TIMSK2) && defined(OCIE2A)
|
433 |
bitWrite(TIMSK2, OCIE2A, 0); // disable interrupt |
434 |
#endif
|
435 |
#if defined(TCCR2A) && defined(WGM20)
|
436 |
TCCR2A = (1 << WGM20);
|
437 |
#endif
|
438 |
#if defined(TCCR2B) && defined(CS22)
|
439 |
TCCR2B = (TCCR2B & 0b11111000) | (1 << CS22); |
440 |
#endif
|
441 |
#if defined(OCR2A)
|
442 |
OCR2A = 0;
|
443 |
#endif
|
444 |
break;
|
445 |
|
446 |
#if defined(TIMSK3)
|
447 |
case 3: |
448 |
TIMSK3 = 0;
|
449 |
break;
|
450 |
#endif
|
451 |
|
452 |
#if defined(TIMSK4)
|
453 |
case 4: |
454 |
TIMSK4 = 0;
|
455 |
break;
|
456 |
#endif
|
457 |
|
458 |
#if defined(TIMSK5)
|
459 |
case 5: |
460 |
TIMSK5 = 0;
|
461 |
break;
|
462 |
#endif
|
463 |
} |
464 |
} |
465 |
|
466 |
|
467 |
void noTone(uint8_t _pin)
|
468 |
{ |
469 |
int8_t _timer = -1;
|
470 |
|
471 |
for (int i = 0; i < AVAILABLE_TONE_PINS; i++) { |
472 |
if (tone_pins[i] == _pin) {
|
473 |
_timer = pgm_read_byte(tone_pin_to_timer_PGM + i); |
474 |
tone_pins[i] = 255;
|
475 |
} |
476 |
} |
477 |
|
478 |
disableTimer(_timer); |
479 |
|
480 |
digitalWrite(_pin, 0);
|
481 |
} |
482 |
|
483 |
#if 0
|
484 |
#if !defined(__AVR_ATmega8__)
|
485 |
ISR(TIMER0_COMPA_vect)
|
486 |
{
|
487 |
if (timer0_toggle_count != 0)
|
488 |
{
|
489 |
// toggle the pin
|
490 |
*timer0_pin_port ^= timer0_pin_mask;
|
491 |
|
492 |
if (timer0_toggle_count > 0)
|
493 |
timer0_toggle_count--;
|
494 |
}
|
495 |
else
|
496 |
{
|
497 |
disableTimer(0);
|
498 |
*timer0_pin_port &= ~(timer0_pin_mask); // keep pin low after stop
|
499 |
}
|
500 |
}
|
501 |
#endif
|
502 |
|
503 |
|
504 |
ISR(TIMER1_COMPA_vect) |
505 |
{ |
506 |
if (timer1_toggle_count != 0) |
507 |
{ |
508 |
// toggle the pin
|
509 |
*timer1_pin_port ^= timer1_pin_mask; |
510 |
|
511 |
if (timer1_toggle_count > 0) |
512 |
timer1_toggle_count--; |
513 |
} |
514 |
else
|
515 |
{ |
516 |
disableTimer(1);
|
517 |
*timer1_pin_port &= ~(timer1_pin_mask); // keep pin low after stop
|
518 |
} |
519 |
} |
520 |
#endif
|
521 |
|
522 |
|
523 |
ISR(TIMER2_COMPA_vect) |
524 |
{ |
525 |
|
526 |
if (timer2_toggle_count != 0) |
527 |
{ |
528 |
// toggle the pin
|
529 |
*timer2_pin_port ^= timer2_pin_mask; |
530 |
|
531 |
if (timer2_toggle_count > 0) |
532 |
timer2_toggle_count--; |
533 |
} |
534 |
else
|
535 |
{ |
536 |
// need to call noTone() so that the tone_pins[] entry is reset, so the
|
537 |
// timer gets initialized next time we call tone().
|
538 |
// XXX: this assumes timer 2 is always the first one used.
|
539 |
noTone(tone_pins[0]);
|
540 |
// disableTimer(2);
|
541 |
// *timer2_pin_port &= ~(timer2_pin_mask); // keep pin low after stop
|
542 |
} |
543 |
} |
544 |
|
545 |
|
546 |
|
547 |
//#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
548 |
#if 0
|
549 |
|
550 |
ISR(TIMER3_COMPA_vect)
|
551 |
{
|
552 |
if (timer3_toggle_count != 0)
|
553 |
{
|
554 |
// toggle the pin
|
555 |
*timer3_pin_port ^= timer3_pin_mask;
|
556 |
|
557 |
if (timer3_toggle_count > 0)
|
558 |
timer3_toggle_count--;
|
559 |
}
|
560 |
else
|
561 |
{
|
562 |
disableTimer(3);
|
563 |
*timer3_pin_port &= ~(timer3_pin_mask); // keep pin low after stop
|
564 |
}
|
565 |
}
|
566 |
|
567 |
ISR(TIMER4_COMPA_vect)
|
568 |
{
|
569 |
if (timer4_toggle_count != 0)
|
570 |
{
|
571 |
// toggle the pin
|
572 |
*timer4_pin_port ^= timer4_pin_mask;
|
573 |
|
574 |
if (timer4_toggle_count > 0)
|
575 |
timer4_toggle_count--;
|
576 |
}
|
577 |
else
|
578 |
{
|
579 |
disableTimer(4);
|
580 |
*timer4_pin_port &= ~(timer4_pin_mask); // keep pin low after stop
|
581 |
}
|
582 |
}
|
583 |
|
584 |
ISR(TIMER5_COMPA_vect)
|
585 |
{
|
586 |
if (timer5_toggle_count != 0)
|
587 |
{
|
588 |
// toggle the pin
|
589 |
*timer5_pin_port ^= timer5_pin_mask;
|
590 |
|
591 |
if (timer5_toggle_count > 0)
|
592 |
timer5_toggle_count--;
|
593 |
}
|
594 |
else
|
595 |
{
|
596 |
disableTimer(5);
|
597 |
*timer5_pin_port &= ~(timer5_pin_mask); // keep pin low after stop
|
598 |
}
|
599 |
}
|
600 |
|
601 |
#endif
|