diff --git a/.github/workflows/LibraryBuild.yml b/.github/workflows/LibraryBuild.yml
index 51f7d35..757ed4b 100644
--- a/.github/workflows/LibraryBuild.yml
+++ b/.github/workflows/LibraryBuild.yml
@@ -65,22 +65,22 @@ jobs:
- arduino-boards-fqbn: digistump:avr:digispark-tiny:clock=clock1 # ATtiny85 board @1 MHz
platform-url: https://raw.githubusercontent.com/ArminJo/DigistumpArduino/master/package_digistump_index.json
- sketches-exclude: LightToTone PlayChristmasMelodyUSDistance RandomMelody # Only OneMelody example
+ sketches-exclude: LightToTone PlayChristmasMelodyUSDistance RandomMelody ReactionTimeTestGame # Only OneMelody example
build-properties: # the flags were put in compiler.cpp.extra_flags
OneMelody:
-DDEBUG
- arduino-boards-fqbn: esp8266:esp8266:huzzah:eesz=4M3M,xtal=80
platform-url: https://arduino.esp8266.com/stable/package_esp8266com_index.json
- sketches-exclude: LightToTone PlayChristmasMelodyUSDistance # EasyButton and Talkie library not available
+ sketches-exclude: LightToTone PlayChristmasMelodyUSDistance ReactionTimeTestGame # EasyButton and Talkie library not available
- arduino-boards-fqbn: esp32:esp32:featheresp32:FlashFreq=80
platform-url: https://dl.espressif.com/dl/package_esp32_index.json
- sketches-exclude: LightToTone PlayChristmasMelodyUSDistance # EasyButton and Talkie library not available
+ sketches-exclude: LightToTone PlayChristmasMelodyUSDistance ReactionTimeTestGame # EasyButton and Talkie library not available
- arduino-boards-fqbn: STM32:stm32:GenF1:pnum=BLUEPILL_F103C8
platform-url: https://github.com/stm32duino/BoardManagerFiles/raw/master/STM32/package_stm_index.json
- sketches-exclude: LightToTone PlayChristmasMelodyUSDistance # EasyButton and Talkie library not available
+ sketches-exclude: LightToTone PlayChristmasMelodyUSDistance ReactionTimeTestGame # EasyButton and Talkie library not available
# Do not cancel all jobs / architectures if one job fails
fail-fast: false
diff --git a/README.md b/README.md
index 891d82e..8609244 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
# [PlayRtttl](https://github.com/ArminJo/PlayRtttl)
Available as Arduino library "PlayRtttl"
-### [Version 1.4.1](https://github.com/ArminJo/PlayRtttl/releases)
+### [Version 1.4.2](https://github.com/ArminJo/PlayRtttl/releases)
[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0)
[![Installation instructions](https://www.ardu-badge.com/badge/PlayRtttl.svg?)](https://www.ardu-badge.com/PlayRtttl)
@@ -48,7 +48,7 @@ const int TONE_PIN = 11;
# Compile options / macros for this library
To customize the library to different requirements, there are some compile options / makros available.
-Modify it by commenting them out or in, or change the values if applicable. Or define the macro with the -D compiler option for gobal compile (the latter is not possible with the Arduino IDE, so consider to use [sloeber](https://eclipse.baeyens.it).
+Modify it by commenting them out or in, or change the values if applicable. Or define the macro with the -D compiler option for gobal compile (the latter is not possible with the Arduino IDE, so consider to use [Sloeber](https://eclipse.baeyens.it).
Some options which are enabed by default can be disabled also by defining a *inhibit* macro like `USE_NO_RTX_EXTENSIONS`.
| Macro | Default | File | Disable macro | Description |
|-|-|-|-|-|
@@ -56,6 +56,16 @@ Some options which are enabed by default can be disabled also by defining a *inh
| `SUPPORT_RTX_FORMAT` | enabled | PlayRtttl.h | `USE_NO_RTX_EXTENSIONS` | Enables evaluating RTX format definitions `'s'` and `'l'`. |
| `RTX_STYLE_DEFAULT` | 'N' | PlayRtttl.h | | (Natural) Tone length = note length - 1/16. |
+### Modifying compile options with Arduino IDE
+First use *Sketch > Show Sketch Folder (Ctrl+K)*.
+If you did not yet stored the example as your own sketch, then you are instantly in the right library folder.
+Otherwise you have to navigate to the parallel `libraries` folder and select the library you want to access.
+In both cases the library files itself are located in the `src` directory.
+
+### Modifying compile options with Sloeber IDE
+If you are using Sloeber as your IDE, you can easily define global symbols with *Properties > Arduino > CompileOptions*.
+![Sloeber settings](https://github.com/ArminJo/ServoEasing/blob/master/pictures/SloeberDefineSymbols.png)
+
# Running with 1 MHz
If running with 1 MHz, e.g on an ATtiny, the millis() interrupt needs so much time, that it disturbes the tone() generation by interrupt. You can avoid this by using a tone pin, which is directly supported by hardware. Look at the appropriate *pins_arduino.h*, find `digital_pin_to_timer_PGM[]` and choose pins with TIMER1x entries.
@@ -64,6 +74,8 @@ More RTTTL songs can be found under http://www.picaxe.com/RTTTL-Ringtones-for-Tu
[C array of songs on GitHub](https://github.com/granadaxronos/120-SONG_NOKIA_RTTTL_RINGTONE_PLAYER_FOR_ARDUINO_UNO/blob/master/RTTTL_PLAYER/songs.h)
# Revision History
+### Version 1.4.2
+- New example ReactionTimeTestGame.
### Version 1.4.1
- Removed blocking wait for ATmega32U4 Serial in examples.
@@ -91,7 +103,7 @@ More RTTTL songs can be found under http://www.picaxe.com/RTTTL-Ringtones-for-Tu
### Version 1.2.0
- No Serial.print statements in this library anymore, to avoid problems with different Serial implementations.
- Function `playRandomRtttlBlocking()` + `startPlayRandomRtttlFromArrayPGM()` do not print name now. If needed, use new functions `playRandomRtttlSampleBlockingAndPrintName()` + `startPlayRandomRtttlFromArrayPGMAndPrintName()`.
-- Printing functions have parameter (..., Stream * aSerial) to print to any serial. Call it (..., &Serial) to use standard Serial;
+- Printing functions have parameter (..., Stream *aSerial) to print to any serial. Call it (..., &Serial) to use standard Serial;
- `playRandomRtttlBlocking()` renamed to `playRandomRtttlSampleBlocking()` and bug fixing.
### Version 1.1.0
diff --git a/examples/LightToTone/EasyButtonAtInt01.cpp.h b/examples/LightToTone/EasyButtonAtInt01.cpp.h
index e81f480..33ae590 100644
--- a/examples/LightToTone/EasyButtonAtInt01.cpp.h
+++ b/examples/LightToTone/EasyButtonAtInt01.cpp.h
@@ -53,15 +53,15 @@
// For external measurement of code timing
//#define MEASURE_EASY_BUTTON_INTERRUPT_TIMING
-#if defined(MEASURE_EASY_BUTTON_INTERRUPT_TIMING) || defined (LED_FEEDBACK_TEST)
+#if defined(MEASURE_EASY_BUTTON_INTERRUPT_TIMING) || defined(LED_FEEDBACK_TEST)
#include "digitalWriteFast.h"
#endif
#if defined(USE_BUTTON_0)
-EasyButton * EasyButton::sPointerToButton0ForISR;
+EasyButton *EasyButton::sPointerToButton0ForISR;
#endif
#if defined(USE_BUTTON_1)
-EasyButton * EasyButton::sPointerToButton1ForISR;
+EasyButton *EasyButton::sPointerToButton1ForISR;
#endif
// @formatter:off // the eclipse formatter has problems with // comments in undefined code blocks
diff --git a/examples/LightToTone/EasyButtonAtInt01.h b/examples/LightToTone/EasyButtonAtInt01.h
index 5142974..575b75a 100644
--- a/examples/LightToTone/EasyButtonAtInt01.h
+++ b/examples/LightToTone/EasyButtonAtInt01.h
@@ -37,29 +37,7 @@
#define VERSION_EASY_BUTTON "3.1.0"
#define VERSION_EASY_BUTTON_MAJOR 3
#define VERSION_EASY_BUTTON_MINOR 1
-
-/*
- * Version 3.1.0 - 6/2020
- * - 2 sets of constructors, one for only one button used and one for the second button if two buttons used.
- * - Map pin numbers for Digispark pro boards, for use with with digispark library.
- *
- * Version 3.0.0 - 5/2020
- * - Added button release handler and adapted examples.
- * - Revoke change for "only one true result per press for checkForLongPressBlocking()". It is superseded by button release handler.
- * - Support buttons which are active high by defining BUTTON_IS_ACTIVE_HIGH.
- * - Improved detection of maximum bouncing period used in DebounceTest.
- *
- * Version 2.1.0 - 5/2020
- * - Avoid 1 ms delay for checkForLongPressBlocking() if button is not pressed.
- * - Only one true result per press for checkForLongPressBlocking().
- *
- * Version 2.0.0 - 1/2020
- * - Ported to ATtinyX5 and ATiny167.
- * - Support also PinChangeInterrupt for button 1 on Pin PA0 to PA7 for ATtiniy87/167.
- * - Long press detection support.
- * - Double press detection support.
- * - Renamed to EasyButtonAtInt01.cpp.h
- */
+// The change log is at the bottom of the file
#if defined(__AVR__)
#include
@@ -83,7 +61,7 @@
//#define BUTTON_IS_ACTIVE_HIGH
/*
* Define USE_ATTACH_INTERRUPT to force use of the arduino function attachInterrupt().
- * Needed if you get the error " multiple definition of `__vector_1'" (or `__vector_2'), because another library uses the attachInterrupt() function.
+ * Required if you get the error " multiple definition of `__vector_1'" (or `__vector_2'), because another library uses the attachInterrupt() function.
* For one button it needs additional 160 bytes FLASH, for 2 buttons it needs additional 88 bytes.
*/
//#define USE_ATTACH_INTERRUPT
@@ -124,9 +102,9 @@
* Activate LED_BUILTIN as long as button is pressed
*/
//#define LED_FEEDBACK_TEST
-#if defined (LED_FEEDBACK_TEST)
+#if defined(LED_FEEDBACK_TEST)
# if ! defined(BUTTON_TEST_FEEDBACK_LED_PIN)
-# if defined (LED_BUILTIN)
+# if defined(LED_BUILTIN)
# define BUTTON_TEST_FEEDBACK_LED_PIN LED_BUILTIN // if not specified, use built in led - pin 13 on Uno board
# else
# error "LED_FEEDBACK_TEST defined but no BUTTON_TEST_FEEDBACK_LED_PIN or LED_BUILTIN defined"
@@ -146,7 +124,7 @@
//#define TRACE
#ifdef TRACE
-#warning "If using TRACE, the timing of the interrupt service routine changes, e.g. you will see more spikes, than expected!"
+#warning If using TRACE, the timing of the interrupt service routine changes, e.g. you will see more spikes, than expected!
#endif
/*
@@ -171,7 +149,7 @@
# if ! defined(INT1_PIN)
#define INT1_PIN 3
# elif (INT1_PIN != 2) && (INT1_PIN > 5)
-#error "INT1_PIN (for PCINT0 interrupt) can only be 0,1,3,4,5"
+#error INT1_PIN (for PCINT0 interrupt) can only be 0,1,3,4,5
# endif
#define INT1_DDR_PORT (DDRB)
#define INT1_IN_PORT (PINB)
@@ -218,11 +196,11 @@
#undef INT1_PIN
#define INT1_PIN 6 // PA6
# else
-#error "INT1_PIN (for PCINT0 interrupt) can only be 5 to 12"
+#error INT1_PIN (for PCINT0 interrupt) can only be 5 to 12
# endif
# else // defined(ARDUINO_AVR_DIGISPARKPRO)
# if (INT1_PIN > 7)
-#error "INT1_PIN (for PCINT0 interrupt) can only be 0 to 7"
+#error INT1_PIN (for PCINT0 interrupt) can only be 0 to 7
# endif
# endif // defined(ARDUINO_AVR_DIGISPARKPRO)
#define INT1_DDR_PORT (DDRA)
@@ -241,7 +219,7 @@
# if ! defined(INT1_PIN)
#define INT1_PIN 3
# elif (INT1_PIN > 7)
-#error "INT1_PIN (for PCINT2 interrupt) can only be Arduino pins 0 to 7 (PD0 to PD7)"
+#error INT1_PIN (for PCINT2 interrupt) can only be Arduino pins 0 to 7 (PD0 to PD7)
# endif
#define INT1_DDR_PORT (DDRD)
#define INT1_IN_PORT (PIND)
@@ -255,7 +233,7 @@
#if defined(USE_BUTTON_1) && ((! defined(ISC10)) || ((defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__)) && INT1_PIN != 3)) \
&& ! defined(INTENTIONALLY_USE_PCI0_FOR_BUTTON1) && !(defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__))
-#warning "Using PCINT0 interrupt for button 1"
+#warning Using PCINT0 interrupt for button 1
#endif
#if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
@@ -357,10 +335,10 @@ class EasyButton {
#endif
#if defined(USE_BUTTON_0)
- static EasyButton * sPointerToButton0ForISR;
+ static EasyButton *sPointerToButton0ForISR;
#endif
#if defined(USE_BUTTON_1)
- static EasyButton * sPointerToButton1ForISR;
+ static EasyButton *sPointerToButton1ForISR;
#endif
};
// end of class definition
@@ -380,6 +358,30 @@ void __attribute__ ((weak)) handleINT1Interrupt();
#endif
#endif // defined(__AVR__)
+
+/*
+ * Version 3.1.0 - 6/2020
+ * - 2 sets of constructors, one for only one button used and one for the second button if two buttons used.
+ * - Map pin numbers for Digispark pro boards, for use with with digispark library.
+ *
+ * Version 3.0.0 - 5/2020
+ * - Added button release handler and adapted examples.
+ * - Revoke change for "only one true result per press for checkForLongPressBlocking()". It is superseded by button release handler.
+ * - Support buttons which are active high by defining BUTTON_IS_ACTIVE_HIGH.
+ * - Improved detection of maximum bouncing period used in DebounceTest.
+ *
+ * Version 2.1.0 - 5/2020
+ * - Avoid 1 ms delay for checkForLongPressBlocking() if button is not pressed.
+ * - Only one true result per press for checkForLongPressBlocking().
+ *
+ * Version 2.0.0 - 1/2020
+ * - Ported to ATtinyX5 and ATiny167.
+ * - Support also PinChangeInterrupt for button 1 on Pin PA0 to PA7 for ATtiniy87/167.
+ * - Long press detection support.
+ * - Double press detection support.
+ * - Renamed to EasyButtonAtInt01.cpp.h
+ */
+
#endif /* EASY_BUTTON_AT_INT01_H_ */
#pragma once
diff --git a/examples/LightToTone/LightToTone.ino b/examples/LightToTone/LightToTone.ino
index 7310323..b0b3900 100644
--- a/examples/LightToTone/LightToTone.ino
+++ b/examples/LightToTone/LightToTone.ino
@@ -11,7 +11,7 @@
* Copyright (C) 2018 Armin Joachimsmeyer
* armin.joachimsmeyer@gmail.com
*
- * This file is part of PlayRttl https://github.com/ArminJo/PlayRttl.
+ * This file is part of PlayRttl https://github.com/ArminJo/PlayRtttl.
*
* PlayRttl is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -152,7 +152,7 @@ void loop() {
if (tThresholdCount > 10) {
// stop playing melody
stopPlayRtttl();
- break; // not really needed here, since the while condition will also change because of stopPlayRtttl.
+ break; // not really required here, since the while condition will also change because of stopPlayRtttl.
}
} else {
tThresholdCount = 0;
diff --git a/examples/OneMelody/ATtinySerialOut.cpp b/examples/OneMelody/ATtinySerialOut.cpp
index d312931..f33b830 100644
--- a/examples/OneMelody/ATtinySerialOut.cpp
+++ b/examples/OneMelody/ATtinySerialOut.cpp
@@ -32,7 +32,9 @@
*
*/
-#if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__)
+#if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) \
+ || defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) \
+ || defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__)
#include "ATtinySerialOut.h"
#include // for eeprom_read_byte() in writeString_E()
@@ -62,10 +64,6 @@
#define TX_DDR DDRB
#endif // defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__)
-#if defined(Serial)
-#undef Serial
-#endif
-
void write1Start8Data1StopNoParity(uint8_t aValue);
bool sUseCliSeiForWrite = true;
@@ -98,7 +96,7 @@ void useCliSeiForStrings(bool aUseCliSeiForWrite) {
/*
* Write String residing in RAM
*/
-void writeString(const char * aStringPtr) {
+void writeString(const char *aStringPtr) {
#ifndef USE_ALWAYS_CLI_SEI_GUARD_FOR_OUTPUT
if (sUseCliSeiForWrite) {
#endif
@@ -117,7 +115,7 @@ void writeString(const char * aStringPtr) {
/*
* Write string residing in program space (FLASH)
*/
-void writeString_P(const char * aStringPtr) {
+void writeString_P(const char *aStringPtr) {
uint8_t tChar = pgm_read_byte((const uint8_t * ) aStringPtr);
// Comparing with 0xFF is safety net for wrong string pointer
while (tChar != 0 && tChar != 0xFF) {
@@ -137,7 +135,7 @@ void writeString_P(const char * aStringPtr) {
/*
* Write string residing in program space (FLASH)
*/
-void writeString(const __FlashStringHelper * aStringPtr) {
+void writeString(const __FlashStringHelper *aStringPtr) {
PGM_P tPGMStringPtr = reinterpret_cast(aStringPtr);
uint8_t tChar = pgm_read_byte((const uint8_t * ) aStringPtr);
// Comparing with 0xFF is safety net for wrong string pointer
@@ -158,7 +156,7 @@ void writeString(const __FlashStringHelper * aStringPtr) {
/*
* Write string residing in EEPROM space
*/
-void writeString_E(const char * aStringPtr) {
+void writeString_E(const char *aStringPtr) {
uint8_t tChar = eeprom_read_byte((const uint8_t *) aStringPtr);
// Comparing with 0xFF is safety net for wrong string pointer
while (tChar != 0 && tChar != 0xFF) {
@@ -175,19 +173,19 @@ void writeString_E(const char * aStringPtr) {
}
}
-void writeStringWithoutCliSei(const char * aStringPtr) {
+void writeStringWithoutCliSei(const char *aStringPtr) {
while (*aStringPtr != 0) {
write1Start8Data1StopNoParity(*aStringPtr++);
}
}
-void writeStringWithCliSei(const char * aStringPtr) {
+void writeStringWithCliSei(const char *aStringPtr) {
while (*aStringPtr != 0) {
write1Start8Data1StopNoParityWithCliSei(*aStringPtr++);
}
}
-void writeStringSkipLeadingSpaces(const char * aStringPtr) {
+void writeStringSkipLeadingSpaces(const char *aStringPtr) {
// skip leading spaces
while (*aStringPtr == ' ' && *aStringPtr != 0) {
aStringPtr++;
@@ -373,11 +371,11 @@ size_t TinySerialOut::write(uint8_t aByte) {
return 1;
}
-void TinySerialOut::print(const char* aStringPtr) {
+void TinySerialOut::print(const char *aStringPtr) {
writeString(aStringPtr);
}
-void TinySerialOut::print(const __FlashStringHelper * aStringPtr) {
+void TinySerialOut::print(const __FlashStringHelper *aStringPtr) {
writeString(aStringPtr);
}
@@ -433,12 +431,12 @@ void TinySerialOut::println(char aChar) {
println();
}
-void TinySerialOut::println(const char* aStringPtr) {
+void TinySerialOut::println(const char *aStringPtr) {
print(aStringPtr);
println();
}
-void TinySerialOut::println(const __FlashStringHelper * aStringPtr) {
+void TinySerialOut::println(const __FlashStringHelper *aStringPtr) {
print(aStringPtr);
println();
}
diff --git a/examples/OneMelody/ATtinySerialOut.h b/examples/OneMelody/ATtinySerialOut.h
index da5bd66..eefe970 100644
--- a/examples/OneMelody/ATtinySerialOut.h
+++ b/examples/OneMelody/ATtinySerialOut.h
@@ -52,15 +52,17 @@
#ifndef ATTINY_SERIAL_OUT_H_
#define ATTINY_SERIAL_OUT_H_
-#if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__)
+#if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) \
+ || defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) \
+ || defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__)
#include
-#define VERSION_ATTINY_SERIAL_OUT "1.2.0"
+#define VERSION_ATTINY_SERIAL_OUT "1.2.1"
#define VERSION_ATTINY_SERIAL_OUT_MAJOR 1
#define VERSION_ATTINY_SERIAL_OUT_MINOR 2
#if (F_CPU != 1000000) && (F_CPU != 8000000) && (F_CPU != 16000000)
-#error "F_CPU value must be 1000000, 8000000 or 16000000."
+#error F_CPU value must be 1000000, 8000000 or 16000000.
#endif
#if defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__)
@@ -102,13 +104,13 @@ void write1Start8Data1StopNoParity(uint8_t aValue);
void write1Start8Data1StopNoParityWithCliSei(uint8_t aValue);
void writeValue(uint8_t aValue);
-void writeString(const char * aStringPtr);
-void writeString(const __FlashStringHelper * aStringPtr);
-void writeString_P(const char * aStringPtr);
-void writeString_E(const char * aStringPtr);
-void writeStringWithCliSei(const char * aStringPtr);
-void writeStringWithoutCliSei(const char * aStringPtr);
-void writeStringSkipLeadingSpaces(const char * aStringPtr);
+void writeString(const char *aStringPtr);
+void writeString(const __FlashStringHelper *aStringPtr);
+void writeString_P(const char *aStringPtr);
+void writeString_E(const char *aStringPtr);
+void writeStringWithCliSei(const char *aStringPtr);
+void writeStringWithoutCliSei(const char *aStringPtr);
+void writeStringSkipLeadingSpaces(const char *aStringPtr);
void writeBinary(uint8_t aByte); // write direct without decoding
void writeChar(uint8_t aChar); // Synonym for writeBinary
@@ -141,10 +143,10 @@ class TinySerialOut
// virtual functions of Print class
size_t write(uint8_t aByte);
- operator bool(); // To support "while (!Serial); // wait for serial port to connect. Needed for Leonardo only
+ operator bool(); // To support "while (!Serial); // wait for serial port to connect. Required for Leonardo only
- void print(const __FlashStringHelper * aStringPtr);
- void print(const char* aStringPtr);
+ void print(const __FlashStringHelper *aStringPtr);
+ void print(const char *aStringPtr);
void print(char aChar);
void print(uint8_t aByte, uint8_t aBase = 10);
void print(int16_t aInteger, uint8_t aBase = 10);
@@ -153,8 +155,8 @@ class TinySerialOut
void print(uint32_t aLong, uint8_t aBase = 10);
void print(double aFloat, uint8_t aDigits = 2);
- void println(const char* aStringPtr);
- void println(const __FlashStringHelper * aStringPtr);
+ void println(const char *aStringPtr);
+ void println(const __FlashStringHelper *aStringPtr);
void println(char aChar);
void println(uint8_t aByte, uint8_t aBase = 10);
void println(int16_t aInteger, uint8_t aBase = 10);
@@ -176,6 +178,9 @@ class TinySerialOut
extern TinySerialOut SerialOut;
#define Serial SerialOut
#else
+# if defined(Serial)
+#undef Serial
+# endif
extern TinySerialOut Serial;
#endif
#define Print TinySerialOut
diff --git a/examples/OneMelody/OneMelody.ino b/examples/OneMelody/OneMelody.ino
index b862c66..7dc455e 100644
--- a/examples/OneMelody/OneMelody.ino
+++ b/examples/OneMelody/OneMelody.ino
@@ -8,7 +8,7 @@
* Copyright (C) 2019 Armin Joachimsmeyer
* armin.joachimsmeyer@gmail.com
*
- * This file is part of PlayRttl https://github.com/ArminJo/PlayRttl.
+ * This file is part of PlayRttl https://github.com/ArminJo/PlayRtttl.
*
* PlayRttl is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/examples/PlayChristmasMelodyUSDistance/BlinkLed.cpp b/examples/PlayChristmasMelodyUSDistance/BlinkLed.cpp
index edd7f4a..8f6deff 100644
--- a/examples/PlayChristmasMelodyUSDistance/BlinkLed.cpp
+++ b/examples/PlayChristmasMelodyUSDistance/BlinkLed.cpp
@@ -29,12 +29,12 @@
/*
* The simple blocking variant
*/
-void blinkLEDBlocking(uint8_t aLedPin, uint16_t aDelay, uint8_t aRepetitions) {
- for (int i = 0; i < aRepetitions; ++i) {
+void blinkLEDBlocking(uint8_t aLedPin, uint8_t aBlinkCount, uint16_t aDelayMillis) {
+ for (int i = 0; i < aBlinkCount; ++i) {
digitalWrite(aLedPin, HIGH);
- delay(aDelay);
+ delay(aDelayMillis);
digitalWrite(aLedPin, LOW);
- delay(aDelay);
+ delay(aDelayMillis);
}
}
@@ -44,9 +44,9 @@ BlinkLed::BlinkLed(uint8_t aLedPin) {
setOnOffTime(1000, 1000);
}
-BlinkLed::BlinkLed(uint8_t aLedPin, bool aInitState, unsigned int aOnTime, unsigned int aOffTime) {
+BlinkLed::BlinkLed(uint8_t aLedPin, bool aInitState, unsigned int aOnTimeMillis, unsigned int aOffTimeMillis) {
init(aLedPin, aInitState);
- setOnOffTime(aOnTime, aOffTime);
+ setOnOffTime(aOnTimeMillis, aOffTimeMillis);
}
void BlinkLed::init(uint8_t aLedPin, bool aInitState) {
@@ -59,9 +59,9 @@ void BlinkLed::init(uint8_t aLedPin, bool aInitState) {
/*
* No count specified here, so set to BLINK_LED_FOREVER
*/
-void BlinkLed::setOnOffTime(unsigned int aOnTime, unsigned int aOffTime) {
- onDelay = aOnTime;
- offDelay = aOffTime;
+void BlinkLed::setOnOffTime(unsigned int aOnTimeMillis, unsigned int aOffTimeMillis) {
+ onDelayMillis = aOnTimeMillis;
+ offDelayMillis = aOffTimeMillis;
}
// must be called continuously in loop()
@@ -73,7 +73,7 @@ void BlinkLed::update() {
if (state) {
// check for on time gone to change state
- if ((millis() - lastUpdate >= onDelay)) {
+ if ((millis() - lastUpdateMillis >= onDelayMillis)) {
toggle();
// count blinks
if (numberOfBlinks > 0) {
@@ -84,14 +84,14 @@ void BlinkLed::update() {
}
}
}
- } else if ((millis() - lastUpdate >= offDelay)) {
+ } else if ((millis() - lastUpdateMillis >= offDelayMillis)) {
toggle();
}
}
-void BlinkLed::start(signed int aBlinkCount, unsigned int aOnTime, unsigned int aOffTime) {
- onDelay = aOnTime;
- offDelay = aOffTime;
+void BlinkLed::start(signed int aBlinkCount, unsigned int aOnTimeMillis, unsigned int aOffTimeMillis) {
+ onDelayMillis = aOnTimeMillis;
+ offDelayMillis = aOffTimeMillis;
start(aBlinkCount);
}
@@ -99,7 +99,7 @@ void BlinkLed::start(signed int aBlinkCount, unsigned int aOnTime, unsigned int
* set to 50% duty cycle
*/
void BlinkLed::start(signed int aBlinkCount, unsigned int aPeriod) {
- onDelay = offDelay = aPeriod / 2;
+ onDelayMillis = offDelayMillis = aPeriod / 2;
start(aBlinkCount);
}
@@ -116,7 +116,7 @@ void BlinkLed::start() {
digitalWrite(pin, HIGH);
state = true;
enabled = true;
- lastUpdate = millis();
+ lastUpdateMillis = millis();
}
/*
@@ -133,8 +133,8 @@ void BlinkLed::blink(signed int aBlinkCount, unsigned int aPeriod) {
/*
* No count specified here, so set to BLINK_LED_FOREVER
*/
-void BlinkLed::startWithOnOffTime(unsigned int aOnTime, unsigned int aOffTime) {
- start(BLINK_LED_FOREVER, aOnTime, aOffTime);
+void BlinkLed::startWithOnOffTime(unsigned int aOnTimeMillis, unsigned int aOffTimeMillis) {
+ start(BLINK_LED_FOREVER, aOnTimeMillis, aOffTimeMillis);
}
/*
@@ -148,17 +148,17 @@ void BlinkLed::startWithPeriod(unsigned int aPeriod) {
* set to 50% duty cycle
*/
void BlinkLed::startWithFrequency(float aFrequency) {
- offDelay = onDelay = 500.0 / aFrequency;
+ offDelayMillis = onDelayMillis = 500.0 / aFrequency;
start(BLINK_LED_FOREVER);
}
-void BlinkLed::startWithOnTime(unsigned int aOnTime) {
- onDelay = aOnTime;
+void BlinkLed::startWithOnTime(unsigned int aOnTimeMillis) {
+ onDelayMillis = aOnTimeMillis;
start();
}
-void BlinkLed::startWithOffTime(unsigned int aOffTime) {
- offDelay = aOffTime;
+void BlinkLed::startWithOffTime(unsigned int aOffTimeMillis) {
+ offDelayMillis = aOffTimeMillis;
start();
}
@@ -166,7 +166,7 @@ void BlinkLed::startWithOffTime(unsigned int aOffTime) {
void BlinkLed::toggle() {
state = !state;
digitalWrite(pin, state);
- lastUpdate = millis();
+ lastUpdateMillis = millis();
}
// Force ON and disable blink
diff --git a/examples/PlayChristmasMelodyUSDistance/BlinkLed.h b/examples/PlayChristmasMelodyUSDistance/BlinkLed.h
index 133cb61..6eba2b4 100644
--- a/examples/PlayChristmasMelodyUSDistance/BlinkLed.h
+++ b/examples/PlayChristmasMelodyUSDistance/BlinkLed.h
@@ -27,7 +27,7 @@
#define BLINK_LED_H_
// The simple blocking variant
-void blinkLEDBlocking(uint8_t aLedPin, uint16_t aDelay, uint8_t aRepetitions);
+void blinkLEDBlocking(uint8_t aLedPin, uint8_t aBlinkCount, uint16_t aDelayMillis);
#define BLINK_LED_FOREVER -1
class BlinkLed {
@@ -35,24 +35,24 @@ class BlinkLed {
// constructors and initialization
BlinkLed();
BlinkLed(uint8_t aLedPin);
- BlinkLed(uint8_t aLedPin, bool aInitState, unsigned int aOnTime, unsigned int aOffTime);
+ BlinkLed(uint8_t aLedPin, bool aInitState, unsigned int aOnTimeMillis, unsigned int aOffTime);
void init(uint8_t aLedPin, bool aInitState);
- void setOnOffTime(unsigned int aOnTime, unsigned int aOffTime);
+ void setOnOffTime(unsigned int aOnTimeMillis, unsigned int aOffTime);
void blink(signed int aBlinkCount, unsigned int aPeriod); // blocking version
void update(); // must be called continuously in loop()
// Blinking ends after aBlinkCount
- void start(signed int aBlinkCount, unsigned int aOnTime, unsigned int aOffTime); // start
+ void start(signed int aBlinkCount, unsigned int aOnTimeMillis, unsigned int aOffTime); // start
void start(signed int aBlinkCount, unsigned int aPeriod); // start
void start(signed int aBlinkCount); // use old values for on and off time
void start();
// Blinking goes forever until off()
- void startWithOnOffTime(unsigned int aOnTime, unsigned int aOffTime);
+ void startWithOnOffTime(unsigned int aOnTimeMillis, unsigned int aOffTime);
void startWithPeriod(unsigned int aPeriod);
- void startWithOnTime(unsigned int aOnTime);
+ void startWithOnTime(unsigned int aOnTimeMillis);
void startWithOffTime(unsigned int aOffTime);
void startWithFrequency(float aFrequency); // set to 50% duty cycle
@@ -66,9 +66,9 @@ class BlinkLed {
uint8_t pin; // Pin number connected to LED anode
volatile bool state; // LED state (volatile so that the compiler doesn't optimize this variable into some constant)
signed int numberOfBlinks; // Negative values mean forever
- unsigned int onDelay; // On time in milliseconds
- unsigned int offDelay; // Off time in milliseconds
- unsigned long lastUpdate; // The last time (millis) LED was updated
+ unsigned int onDelayMillis; // On time in milliseconds
+ unsigned int offDelayMillis; // Off time in milliseconds
+ unsigned long lastUpdateMillis; // The last time (millis) LED was updated
bool enabled = true; // LED enabled/disabled state
};
diff --git a/examples/PlayChristmasMelodyUSDistance/HCSR04.cpp b/examples/PlayChristmasMelodyUSDistance/HCSR04.cpp
index c3badb5..2e9d3d9 100644
--- a/examples/PlayChristmasMelodyUSDistance/HCSR04.cpp
+++ b/examples/PlayChristmasMelodyUSDistance/HCSR04.cpp
@@ -4,6 +4,8 @@
* US Sensor (HC-SR04) functions.
* The non blocking functions are using pin change interrupts and need the PinChangeInterrupt library to be installed.
*
+ * 58,23 us per centimeter and 17,17 cm/ms (forth and back).
+ *
* Supports 1 Pin mode as you get on the HY-SRF05 if you connect OUT to ground.
* You can modify the HC-SR04 modules to 1 Pin mode by:
* Old module with 3 16 pin chips: Connect Trigger and Echo direct or use a resistor < 4.7 kOhm.
@@ -85,6 +87,7 @@ void initUSDistancePin(uint8_t aTriggerOutEchoInPin) {
/*
* Start of standard blocking implementation using pulseInLong() since PulseIn gives wrong (too small) results :-(
+ * @return 0 if uninitialized or timeout happened
*/
unsigned int getUSDistance(unsigned int aTimeoutMicros) {
if (sHCSR04Mode == HCSR04_MODE_UNITITIALIZED) {
@@ -93,7 +96,6 @@ unsigned int getUSDistance(unsigned int aTimeoutMicros) {
// need minimum 10 usec Trigger Pulse
digitalWrite(sTriggerOutPin, HIGH);
- // If in
if (sHCSR04Mode == HCSR04_MODE_USE_1_PIN) {
// do it AFTER digitalWrite to avoid spurious triggering by just switching pin to output
@@ -126,6 +128,7 @@ unsigned int getUSDistance(unsigned int aTimeoutMicros) {
*
* Use pulseInLong, this uses micros() as counter, relying on interrupts being enabled, which is not disturbed by (e.g. the 1 ms timer) interrupts.
* Only thing is that the pulse ends when we are in an interrupt routine, thus prolonging the measured pulse duration.
+ * I measured 6 us for the millis() and 14 to 20 us for the Servo signal generating interrupt. This is equivalent to around 1 to 3 mm distance.
* Alternatively we can use pulseIn() in a noInterrupts() context, but this will effectively stop the millis() timer for duration of pulse / or timeout.
*/
#if ! defined(__AVR__) || defined(TEENSYDUINO) || defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__)
@@ -135,10 +138,6 @@ unsigned int getUSDistance(unsigned int aTimeoutMicros) {
#else
unsigned long tUSPulseMicros = pulseInLong(tEchoInPin, HIGH, aTimeoutMicros);
#endif
- if (tUSPulseMicros == 0) {
-// timeout happened -> change value to timeout value. This eases comparison with different distances.
- tUSPulseMicros = aTimeoutMicros;
- }
return tUSPulseMicros;
}
@@ -149,18 +148,13 @@ unsigned int getCentimeterFromUSMicroSeconds(unsigned int aDistanceMicros) {
/*
* @return Distance in centimeter @20 degree (time in us/58.25)
- * aTimeoutMicros/58.25 if timeout happens
- * 0 if pins are not initialized
+ * 0 if timeout or pins are not initialized
+ *
* timeout of 5825 micros is equivalent to 1 meter
* Default timeout of 20000 micro seconds is 3.43 meter
*/
unsigned int getUSDistanceAsCentiMeter(unsigned int aTimeoutMicros) {
- unsigned int tDistanceMicros = getUSDistance(aTimeoutMicros);
- if (tDistanceMicros == 0) {
-// timeout happened
- tDistanceMicros = aTimeoutMicros;
- }
- return (getCentimeterFromUSMicroSeconds(tDistanceMicros));
+ return (getCentimeterFromUSMicroSeconds(getUSDistance(aTimeoutMicros)));
}
// 58,23 us per centimeter (forth and back)
@@ -170,6 +164,10 @@ unsigned int getUSDistanceAsCentiMeterWithCentimeterTimeout(unsigned int aTimeou
return getUSDistanceAsCentiMeter(tTimeoutMicros);
}
+/*
+ * Trigger US sensor as fast as sensible if called in a loop to test US devices.
+ * trigger pulse is equivalent to 10 cm and then we wait for 20 ms / 3.43 meter
+ */
void testUSSensor(uint16_t aSecondsToTest) {
for (long i = 0; i < aSecondsToTest * 50; ++i) {
digitalWrite(sTriggerOutPin, HIGH);
diff --git a/examples/PlayChristmasMelodyUSDistance/HCSR04.h b/examples/PlayChristmasMelodyUSDistance/HCSR04.h
index 8dcdb05..ebb359d 100644
--- a/examples/PlayChristmasMelodyUSDistance/HCSR04.h
+++ b/examples/PlayChristmasMelodyUSDistance/HCSR04.h
@@ -35,10 +35,11 @@
#include
#define US_DISTANCE_DEFAULT_TIMEOUT_MICROS 20000
+#define US_DISTANCE_DEFAULT_TIMEOUT_CENTIMETER 343 // Timeout of 20000L is 3.43 meter
+
#define US_DISTANCE_TIMEOUT_MICROS_FOR_1_METER 5825 // Timeout of 5825 is 1 meter
#define US_DISTANCE_TIMEOUT_MICROS_FOR_2_METER 11650 // Timeout of 11650 is 2 meter
#define US_DISTANCE_TIMEOUT_MICROS_FOR_3_METER 17475 // Timeout of 17475 is 3 meter
-#define US_DISTANCE_DEFAULT_TIMEOUT_CENTIMETER 343 // Timeout of 20000L is 3.43 meter
void initUSDistancePins(uint8_t aTriggerOutPin, uint8_t aEchoInPin = 0);
void initUSDistancePin(uint8_t aTriggerOutEchoInPin); // Using this determines one pin mode
diff --git a/examples/PlayChristmasMelodyUSDistance/PlayChristmasMelodyUSDistance.ino b/examples/PlayChristmasMelodyUSDistance/PlayChristmasMelodyUSDistance.ino
index 8b76952..c3867cd 100644
--- a/examples/PlayChristmasMelodyUSDistance/PlayChristmasMelodyUSDistance.ino
+++ b/examples/PlayChristmasMelodyUSDistance/PlayChristmasMelodyUSDistance.ino
@@ -6,7 +6,7 @@
* Copyright (C) 2019 Armin Joachimsmeyer
* armin.joachimsmeyer@gmail.com
*
- * This file is part of PlayRttl https://github.com/ArminJo/PlayRttl.
+ * This file is part of PlayRttl https://github.com/ArminJo/PlayRtttl.
*
* PlayRttl is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -54,7 +54,7 @@ EasyButton Button0AtPB6;
#define NUMBER_OF_CONSECUTIVE_OUT_RANGE_READINGS 5
#define DELAY_MILLIS_FOR_OUT_RANGE_READING 1000
-#define PIN_SPEAKER 3
+#define PIN_BUZZER 3
#define PIN_ECHO_IN 4
#define PIN_TRIGGER_OUT 5
@@ -107,11 +107,11 @@ void loop() {
/*
* Output distance with talkie
*/
- if (tCentimeter < 300) {
- sayQNumber(&Voice, tCentimeter);
- } else {
+ if (tCentimeter == 0) {
Voice.sayQ(sp2_TIME);
Voice.sayQ(sp2_OUT);
+ } else {
+ sayQNumber(&Voice, tCentimeter);
}
Voice.wait();
}
@@ -119,7 +119,7 @@ void loop() {
if (tCentimeter > MINIMUM_DISTANCE_CENTIMETER && tCentimeter < MAXIMUM_DISTANCE_CENTIMETER) {
sInRangeCounter++;
- tRandomSeed +=tCentimeter;
+ tRandomSeed += tCentimeter;
if (sInRangeCounter >= NUMBER_OF_CONSECUTIVE_IN_RANGE_READINGS) {
/*
* Now an object is for a longer time in the right range.
@@ -143,7 +143,12 @@ void loop() {
/*
* Output distance with talkie
*/
- sayQNumber(&Voice, tCentimeter);
+ if (tCentimeter > 0) {
+ sayQNumber(&Voice, tCentimeter);
+ } else {
+ Voice.sayQ(sp2_TIME);
+ Voice.sayQ(sp2_OUT);
+ }
Voice.wait();
}
#endif
@@ -179,7 +184,7 @@ void playRandomSongAndBlink() {
char StringBuffer[16];
Serial.println();
Serial.print("Now playing: ");
- startPlayRandomRtttlFromArrayPGM(PIN_SPEAKER, RTTTLChristmasMelodies, ARRAY_SIZE_CHRISTMAS_MELODIES, StringBuffer,
+ startPlayRandomRtttlFromArrayPGM(PIN_BUZZER, RTTTLChristmasMelodies, ARRAY_SIZE_CHRISTMAS_MELODIES, StringBuffer,
sizeof(StringBuffer));
Serial.println(StringBuffer);
diff --git a/examples/RandomMelody/ATtinySerialOut.cpp b/examples/RandomMelody/ATtinySerialOut.cpp
index d312931..f33b830 100644
--- a/examples/RandomMelody/ATtinySerialOut.cpp
+++ b/examples/RandomMelody/ATtinySerialOut.cpp
@@ -32,7 +32,9 @@
*
*/
-#if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__)
+#if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) \
+ || defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) \
+ || defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__)
#include "ATtinySerialOut.h"
#include // for eeprom_read_byte() in writeString_E()
@@ -62,10 +64,6 @@
#define TX_DDR DDRB
#endif // defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__)
-#if defined(Serial)
-#undef Serial
-#endif
-
void write1Start8Data1StopNoParity(uint8_t aValue);
bool sUseCliSeiForWrite = true;
@@ -98,7 +96,7 @@ void useCliSeiForStrings(bool aUseCliSeiForWrite) {
/*
* Write String residing in RAM
*/
-void writeString(const char * aStringPtr) {
+void writeString(const char *aStringPtr) {
#ifndef USE_ALWAYS_CLI_SEI_GUARD_FOR_OUTPUT
if (sUseCliSeiForWrite) {
#endif
@@ -117,7 +115,7 @@ void writeString(const char * aStringPtr) {
/*
* Write string residing in program space (FLASH)
*/
-void writeString_P(const char * aStringPtr) {
+void writeString_P(const char *aStringPtr) {
uint8_t tChar = pgm_read_byte((const uint8_t * ) aStringPtr);
// Comparing with 0xFF is safety net for wrong string pointer
while (tChar != 0 && tChar != 0xFF) {
@@ -137,7 +135,7 @@ void writeString_P(const char * aStringPtr) {
/*
* Write string residing in program space (FLASH)
*/
-void writeString(const __FlashStringHelper * aStringPtr) {
+void writeString(const __FlashStringHelper *aStringPtr) {
PGM_P tPGMStringPtr = reinterpret_cast(aStringPtr);
uint8_t tChar = pgm_read_byte((const uint8_t * ) aStringPtr);
// Comparing with 0xFF is safety net for wrong string pointer
@@ -158,7 +156,7 @@ void writeString(const __FlashStringHelper * aStringPtr) {
/*
* Write string residing in EEPROM space
*/
-void writeString_E(const char * aStringPtr) {
+void writeString_E(const char *aStringPtr) {
uint8_t tChar = eeprom_read_byte((const uint8_t *) aStringPtr);
// Comparing with 0xFF is safety net for wrong string pointer
while (tChar != 0 && tChar != 0xFF) {
@@ -175,19 +173,19 @@ void writeString_E(const char * aStringPtr) {
}
}
-void writeStringWithoutCliSei(const char * aStringPtr) {
+void writeStringWithoutCliSei(const char *aStringPtr) {
while (*aStringPtr != 0) {
write1Start8Data1StopNoParity(*aStringPtr++);
}
}
-void writeStringWithCliSei(const char * aStringPtr) {
+void writeStringWithCliSei(const char *aStringPtr) {
while (*aStringPtr != 0) {
write1Start8Data1StopNoParityWithCliSei(*aStringPtr++);
}
}
-void writeStringSkipLeadingSpaces(const char * aStringPtr) {
+void writeStringSkipLeadingSpaces(const char *aStringPtr) {
// skip leading spaces
while (*aStringPtr == ' ' && *aStringPtr != 0) {
aStringPtr++;
@@ -373,11 +371,11 @@ size_t TinySerialOut::write(uint8_t aByte) {
return 1;
}
-void TinySerialOut::print(const char* aStringPtr) {
+void TinySerialOut::print(const char *aStringPtr) {
writeString(aStringPtr);
}
-void TinySerialOut::print(const __FlashStringHelper * aStringPtr) {
+void TinySerialOut::print(const __FlashStringHelper *aStringPtr) {
writeString(aStringPtr);
}
@@ -433,12 +431,12 @@ void TinySerialOut::println(char aChar) {
println();
}
-void TinySerialOut::println(const char* aStringPtr) {
+void TinySerialOut::println(const char *aStringPtr) {
print(aStringPtr);
println();
}
-void TinySerialOut::println(const __FlashStringHelper * aStringPtr) {
+void TinySerialOut::println(const __FlashStringHelper *aStringPtr) {
print(aStringPtr);
println();
}
diff --git a/examples/RandomMelody/ATtinySerialOut.h b/examples/RandomMelody/ATtinySerialOut.h
index da5bd66..eefe970 100644
--- a/examples/RandomMelody/ATtinySerialOut.h
+++ b/examples/RandomMelody/ATtinySerialOut.h
@@ -52,15 +52,17 @@
#ifndef ATTINY_SERIAL_OUT_H_
#define ATTINY_SERIAL_OUT_H_
-#if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) || defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__)
+#if defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) \
+ || defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) \
+ || defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__)
#include
-#define VERSION_ATTINY_SERIAL_OUT "1.2.0"
+#define VERSION_ATTINY_SERIAL_OUT "1.2.1"
#define VERSION_ATTINY_SERIAL_OUT_MAJOR 1
#define VERSION_ATTINY_SERIAL_OUT_MINOR 2
#if (F_CPU != 1000000) && (F_CPU != 8000000) && (F_CPU != 16000000)
-#error "F_CPU value must be 1000000, 8000000 or 16000000."
+#error F_CPU value must be 1000000, 8000000 or 16000000.
#endif
#if defined(__AVR_ATtiny87__) || defined(__AVR_ATtiny167__)
@@ -102,13 +104,13 @@ void write1Start8Data1StopNoParity(uint8_t aValue);
void write1Start8Data1StopNoParityWithCliSei(uint8_t aValue);
void writeValue(uint8_t aValue);
-void writeString(const char * aStringPtr);
-void writeString(const __FlashStringHelper * aStringPtr);
-void writeString_P(const char * aStringPtr);
-void writeString_E(const char * aStringPtr);
-void writeStringWithCliSei(const char * aStringPtr);
-void writeStringWithoutCliSei(const char * aStringPtr);
-void writeStringSkipLeadingSpaces(const char * aStringPtr);
+void writeString(const char *aStringPtr);
+void writeString(const __FlashStringHelper *aStringPtr);
+void writeString_P(const char *aStringPtr);
+void writeString_E(const char *aStringPtr);
+void writeStringWithCliSei(const char *aStringPtr);
+void writeStringWithoutCliSei(const char *aStringPtr);
+void writeStringSkipLeadingSpaces(const char *aStringPtr);
void writeBinary(uint8_t aByte); // write direct without decoding
void writeChar(uint8_t aChar); // Synonym for writeBinary
@@ -141,10 +143,10 @@ class TinySerialOut
// virtual functions of Print class
size_t write(uint8_t aByte);
- operator bool(); // To support "while (!Serial); // wait for serial port to connect. Needed for Leonardo only
+ operator bool(); // To support "while (!Serial); // wait for serial port to connect. Required for Leonardo only
- void print(const __FlashStringHelper * aStringPtr);
- void print(const char* aStringPtr);
+ void print(const __FlashStringHelper *aStringPtr);
+ void print(const char *aStringPtr);
void print(char aChar);
void print(uint8_t aByte, uint8_t aBase = 10);
void print(int16_t aInteger, uint8_t aBase = 10);
@@ -153,8 +155,8 @@ class TinySerialOut
void print(uint32_t aLong, uint8_t aBase = 10);
void print(double aFloat, uint8_t aDigits = 2);
- void println(const char* aStringPtr);
- void println(const __FlashStringHelper * aStringPtr);
+ void println(const char *aStringPtr);
+ void println(const __FlashStringHelper *aStringPtr);
void println(char aChar);
void println(uint8_t aByte, uint8_t aBase = 10);
void println(int16_t aInteger, uint8_t aBase = 10);
@@ -176,6 +178,9 @@ class TinySerialOut
extern TinySerialOut SerialOut;
#define Serial SerialOut
#else
+# if defined(Serial)
+#undef Serial
+# endif
extern TinySerialOut Serial;
#endif
#define Print TinySerialOut
diff --git a/examples/RandomMelody/RandomMelody.ino b/examples/RandomMelody/RandomMelody.ino
index 52c20fd..281c975 100644
--- a/examples/RandomMelody/RandomMelody.ino
+++ b/examples/RandomMelody/RandomMelody.ino
@@ -8,7 +8,7 @@
* Copyright (C) 2019 Armin Joachimsmeyer
* armin.joachimsmeyer@gmail.com
*
- * This file is part of PlayRttl https://github.com/ArminJo/PlayRttl.
+ * This file is part of PlayRttl https://github.com/ArminJo/PlayRtttl.
*
* PlayRttl is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/examples/ReactionTimeTestGame/Breadboard.h b/examples/ReactionTimeTestGame/Breadboard.h
new file mode 100644
index 0000000..b225b08
--- /dev/null
+++ b/examples/ReactionTimeTestGame/Breadboard.h
@@ -0,0 +1,65 @@
+/*
+ * Breadboard.h
+ *
+ * Pin mappings for the example breadboard
+ *
+ * Copyright 2019 Armin Joachimsmeyer
+ * This code is released under GPLv3 license.
+ *
+ * This file is part of Arduino-Lessons-for-School https://github.com/ArminJo/Arduino-Lessons-for-School.
+ *
+ * ServoEasing is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef BREADBOARD_H_
+#define BREADBOARD_H_
+
+#define PIN_GREEN_LED 2
+#define PIN_YELLOW_LED 3
+#define PIN_RED_LED 4
+
+#define PIN_RIGHT_LED PIN_GREEN_LED
+#define PIN_MIDDLE_LED PIN_YELLOW_LED
+#define PIN_LEFT_LED PIN_RED_LED
+
+#define PIN_RIGHT_BUTTON A1
+#define PIN_LEFT_BUTTON A4
+
+#define PIN_LASER 5
+#define PIN_SERVO_HORIZONTAL 6
+#define PIN_SERVO_VERTICAL 7
+#define PIN_NEOPIXEL 8
+#define PIN_TRIGGER_OUT 9
+#define PIN_ECHO_IN 10
+#define PIN_BUZZER 11
+#define PIN_INTERNAL_LED 13 // aka LED_BUILTIN
+
+#define PIN_POTENTIOMETER A0
+#define PIN_LDR A5
+
+/*
+ * Set output pins to OUTPUT and button pins to INPUT_PULLUP
+ */
+void initBreadboardPins() {
+
+ // Enable output on the LED pins
+ pinMode(PIN_RED_LED, OUTPUT);
+ pinMode(PIN_YELLOW_LED, OUTPUT);
+ pinMode(PIN_GREEN_LED, OUTPUT);
+
+ // Prepare for buttons at the pins
+ pinMode(PIN_RIGHT_BUTTON, INPUT_PULLUP);
+ pinMode(PIN_LEFT_BUTTON, INPUT_PULLUP);
+
+ pinMode(PIN_LASER, OUTPUT);
+ pinMode(PIN_TRIGGER_OUT, OUTPUT);
+// Is done by tone()
+// pinMode(PIN_BUZZER, OUTPUT);
+ pinMode(LED_BUILTIN, OUTPUT);
+
+}
+
+#endif /* BREADBOARD_H_ */
diff --git a/examples/ReactionTimeTestGame/MultiFuncShield.cpp b/examples/ReactionTimeTestGame/MultiFuncShield.cpp
new file mode 100644
index 0000000..a4d7fae
--- /dev/null
+++ b/examples/ReactionTimeTestGame/MultiFuncShield.cpp
@@ -0,0 +1,1341 @@
+#include "MultiFuncShield.h"
+
+#define BUTTON_SAMPLE_INTERVAL_SCALE 20
+#define BUTTON_SAMPLE_INTERVAL (1000 / BUTTON_SAMPLE_INTERVAL_SCALE)
+
+
+MultiFuncShield MFS;
+
+// Display specific variables
+
+const byte LED[] = {LED_1_PIN, LED_2_PIN, LED_3_PIN, LED_4_PIN};
+
+/* Segment byte maps for numbers 0 to 9 */
+const byte SEGMENT_MAP_DIGIT[] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0X80,0X90};
+/* Segment byte maps for alpha a-z */
+const byte SEGMENT_MAP_ALPHA[] = {136, 131, 167, 161, 134, 142, 144, 139 ,207, 241, 182, 199, 182, 171, 163, 140, 152, 175, 146, 135, 227, 182, 182, 182, 145, 182};
+
+/* Byte maps to select digit 1 to 4 */
+const byte SEGMENT_SELECT[] = {0xF1,0xF2,0xF4,0xF8};
+const char DISPLAY_OVERFLOW_ERROR = 'E';
+
+const byte BLINK_ON_COUNT = 65;
+const byte BLINK_OFF_COUNT = 20;
+
+volatile byte displayMemory[4] = {255,255,255,255};
+byte displayTimerScaler = 4;
+
+
+// Sonar ranger specific variables
+
+int sonarData[9];
+byte sonarDataIndex = 0;
+
+// LM35 specific variables
+
+int lm35Data[8];
+byte lm35DataIndex = 0;
+
+// Misc methods and functions.
+void isrWrapper ();
+void WriteValueToSegment(byte Segment, byte Value);
+byte AsciiToSegmentValue (byte ascii);
+void writeBeeper (byte value);
+byte readButton (byte btnIndex);
+void writeLed(byte ledIdx, byte value);
+
+int MedianOf9(int s0, int s1, int s2, int s3, int s4, int s5, int s6, int s7, int s8);
+int MedianOf5(int s0, int s1, int s2, int s3, int s4);
+
+// Pulse in counter port specifics.
+uint8_t pulseInBit;
+uint8_t pulseInPort;
+
+
+void initShield()
+{
+ /* Set each LED pin to outputs */
+ pinMode(LED[0], OUTPUT);
+ pinMode(LED[1], OUTPUT);
+ pinMode(LED[2], OUTPUT);
+ pinMode(LED[3], OUTPUT);
+
+ /* Turn all the LED's off */
+ digitalWrite(LED[0], HIGH);
+ digitalWrite(LED[1], HIGH);
+ digitalWrite(LED[2], HIGH);
+ digitalWrite(LED[3], HIGH);
+
+ /* Set Segment display DIO pins to outputs */
+ pinMode(LATCH_PIN,OUTPUT);
+ pinMode(CLK_PIN,OUTPUT);
+ pinMode(DATA_PIN,OUTPUT);
+
+ WriteValueToSegment(0,255);
+
+ /* Set the buzzer pin to an output and turn the buzzer off */
+ pinMode(BEEPER_PIN, OUTPUT);
+ digitalWrite(BEEPER_PIN, HIGH);
+}
+
+// ----------------------------------------------------------------------------------------------------
+void MultiFuncShield::initialize(TimerOne *timer1Instance)
+{
+ initShield();
+
+ timer1 = timer1Instance;
+ timer1->attachInterrupt(isrWrapper, 1000); // effectively, 1000 times per second
+}
+
+
+void MultiFuncShield::initialize()
+{
+ initShield();
+}
+
+// ----------------------------------------------------------------------------------------------------
+void MultiFuncShield::initSonar(byte level)
+{
+ sonarSmoothingLevel = level;
+ sonarDataIndex = 0;
+
+ for (int i=0; i < 9; i++)
+ {
+ sonarData[i] = 0;
+ }
+}
+
+
+// ----------------------------------------------------------------------------------------------------
+unsigned int MultiFuncShield::getSonarDataCm(byte triggerPin, byte echoPin)
+{
+ uint8_t bit = digitalPinToBitMask(echoPin);
+ uint8_t port = digitalPinToPort(echoPin);
+ uint8_t stateMask = (HIGH ? bit : 0);
+
+ noInterrupts();
+ digitalWrite(triggerPin, LOW); //Low, high and low level take a short time to TrigPin pulse
+ delayMicroseconds(2);
+ digitalWrite(triggerPin, HIGH);
+ delayMicroseconds(10);
+ digitalWrite(triggerPin, LOW);
+ interrupts();
+
+ // wait for any previous pulse to end
+ while ((*portInputRegister(port) & bit) == stateMask) ;
+
+ // wait for the pulse to start
+ while ((*portInputRegister(port) & bit) != stateMask) ;
+
+ unsigned long timeStart = micros();
+ // wait for the pulse to stop
+ while ((*portInputRegister(port) & bit) == stateMask) ;
+
+ sonarData [sonarDataIndex] = ((micros() - timeStart) * 141) >> 13; // (value * 1.00) / 58
+
+ int medianReading;
+
+ if (sonarSmoothingLevel == SMOOTHING_NONE)
+ {
+ medianReading = sonarData [sonarDataIndex];
+ }
+ else if (sonarSmoothingLevel == SMOOTHING_MODERATE)
+ {
+ sonarDataIndex++;
+ if (sonarDataIndex >= 5)
+ {
+ sonarDataIndex = 0;
+ }
+ medianReading = MedianOf5(sonarData[0], sonarData[1], sonarData[2], sonarData[3], sonarData[4]);
+ }
+ else
+ {
+ sonarDataIndex++;
+ if (sonarDataIndex >= 9)
+ {
+ sonarDataIndex = 0;
+ }
+ medianReading = MedianOf9(sonarData[0], sonarData[1], sonarData[2], sonarData[3], sonarData[4], sonarData[5], sonarData[6], sonarData[7], sonarData[8]);
+ }
+
+ return medianReading;
+}
+
+
+// ----------------------------------------------------------------------------------------------------
+void MultiFuncShield::initLM35(byte level)
+{
+ lm35SmoothingLevel = level;
+ lm35DataIndex = 0;
+
+ for (int i=0; i < 8; i++)
+ {
+ lm35Data[i] = 0;
+ }
+}
+
+
+// ----------------------------------------------------------------------------------------------------
+int MultiFuncShield::getLM35Data()
+{
+
+ lm35Data [lm35DataIndex] = analogRead(LM35_PIN);
+
+ int reading =0;
+
+ if (lm35SmoothingLevel == SMOOTHING_NONE)
+ {
+ reading = lm35Data [lm35DataIndex];
+ }
+ else if (lm35SmoothingLevel == SMOOTHING_MODERATE)
+ {
+ lm35DataIndex++;
+ if (lm35DataIndex >= 4)
+ {
+ lm35DataIndex = 0;
+ }
+
+ for (int i=0; i<4; i++)
+ {
+ reading = reading + lm35Data[i];
+ }
+ }
+ else
+ {
+ lm35DataIndex++;
+ if (lm35DataIndex >= 8)
+ {
+ lm35DataIndex = 0;
+ }
+
+ for (int i=0; i<8; i++)
+ {
+ reading = reading + lm35Data[i];
+ }
+ }
+
+ if (lm35SmoothingLevel == SMOOTHING_NONE)
+ {
+ return ((unsigned long)1250 * reading) >> 8;;
+ }
+ else if (lm35SmoothingLevel == SMOOTHING_MODERATE)
+ {
+ return ((unsigned long)1250 * reading) >> 10;
+ }
+ else
+ {
+ return ((unsigned long)1250 * reading) >> 11;
+ }
+}
+
+
+// ----------------------------------------------------------------------------------------------------
+void MultiFuncShield::initPulseInCounter(byte pin, unsigned int timeOut, byte trigger)
+{
+ pulseInWriteInProgress = 1;
+
+ pulseInBit = digitalPinToBitMask(pin);
+ pulseInPort = digitalPinToPort(pin);
+
+ pulseInTimeOut = timeOut;
+ pulseInPin = pin;
+ pulseInPeriodCounter =timeOut;
+ pulseInPeriod_volatile =0;
+ pulseInPeriod_safe =0;
+ pulseInState =0;
+ pulseInTrigger = trigger;
+ pulseInTotalCount_volatile = 0;
+ pulseInTotalCount_safe = 0;
+
+ pulseInWriteInProgress = 0;
+ pulseInEnabled = true;
+}
+
+void MultiFuncShield::disablePulseInCounter ()
+{
+ pulseInEnabled = false;
+}
+
+// ----------------------------------------------------------------------------------------------------
+unsigned int MultiFuncShield::getPulseInPeriod()
+{
+ unsigned int period;
+
+ pulseInReadInProgress = 1;
+ period = pulseInPeriod_safe;
+ pulseInReadInProgress =0;
+
+ return period;
+}
+
+
+// ----------------------------------------------------------------------------------------------------
+unsigned long MultiFuncShield::getPulseInTotalCount()
+{
+ unsigned long count;
+
+ pulseInReadInProgress = 1;
+ count = pulseInTotalCount_safe;
+ pulseInReadInProgress =0;
+
+ return count;
+}
+
+
+// ----------------------------------------------------------------------------------------------------
+void MultiFuncShield::resetPulseInTotalCount()
+{
+ pulseInWriteInProgress = 1;
+ pulseInTotalCount_volatile = 0;
+ pulseInTotalCount_safe = 0;
+ pulseInWriteInProgress = 0;
+}
+
+
+// ----------------------------------------------------------------------------------------------------
+void MultiFuncShield::setPulseInTimeOut(unsigned int timeOut)
+{
+ pulseInWriteInProgress = 1;
+ pulseInTimeOut = timeOut;
+ pulseInWriteInProgress = 0;
+}
+
+
+// ----------------------------------------------------------------------------------------------------
+void MultiFuncShield::queueButton (byte button)
+{
+ if (buttonBufferCount <= sizeof (buttonBuffer))
+ {
+ buttonBuffer [button_write_pos] = button;
+ buttonBufferCount++;
+ button_write_pos++;
+
+ if (button_write_pos >= sizeof (buttonBuffer))
+ {
+ button_write_pos = 0;
+ }
+ }
+}
+
+
+// ----------------------------------------------------------------------------------------------------
+byte MultiFuncShield::getButton ()
+{
+ byte button = 0;
+
+ if (buttonBufferCount > 0)
+ {
+ button = buttonBuffer [button_read_pos];
+ buttonBufferCount--;
+ button_read_pos++;
+
+ if (button_read_pos >= sizeof (buttonBuffer))
+ {
+ button_read_pos = 0;
+ }
+ }
+
+ return button;
+}
+
+
+// ----------------------------------------------------------------------------------------------------
+void MultiFuncShield::beep(unsigned int onPeriod, unsigned int offPeriod, byte cycles, unsigned int loopCycles, unsigned int loopDelayPeriod)
+{
+ cycles = cycles == 0 ? 1 : cycles;
+
+ beeperModifyInProgress = 1; // must do this first before changing volatile fields.
+
+ if (onPeriod == 0)
+ {
+ digitalWrite(BEEPER_PIN, 1); // turn off beeper immediately
+ }
+
+ beeperState = 0;
+ beeperOnPeriodReloadValue = onPeriod * 10;
+ beeperOffPeriodReloadValue = offPeriod * 10;
+ beeperPeriodCounter = onPeriod * 10;
+
+ beeperCycleReloadValue = cycles;
+ beeperCycleCounter = cycles;
+
+ beeperLoopCycleCounter = loopCycles;
+ beeperLoopDelayPeriodReloadValue = loopDelayPeriod * 10;
+
+ beeperModifyInProgress = 0; // must do this last.
+}
+
+
+// ----------------------------------------------------------------------------------------------------
+void MultiFuncShield::setBeepOffPeriod(unsigned int offPeriod)
+{
+ beeperModifyInProgress = 1; // must do this first before changing volatile fields.
+
+ if (beeperState == 1)
+ {
+ if (offPeriod * 10 < beeperPeriodCounter)
+ {
+ beeperPeriodCounter = offPeriod * 10;
+ }
+ }
+
+ beeperOffPeriodReloadValue = offPeriod * 10;
+ beeperModifyInProgress = 0; // must do this last.
+}
+
+
+// ----------------------------------------------------------------------------------------------------
+//void MultiFuncShield::setLedControlMask(byte controlMask)
+//{
+// ledControlMask = controlMask;
+//}
+
+
+// ----------------------------------------------------------------------------------------------------
+void MultiFuncShield::writeLeds(byte leds, byte lit)
+{
+ if (lit)
+ {
+ ledState = ledState | leds;
+ //ledControlMask = ledControlMask | leds;
+ }
+ else
+ {
+ ledState = ledState & (255 - leds);
+ //ledControlMask = ledControlMask & (255 - leds);
+ }
+}
+
+
+// ----------------------------------------------------------------------------------------------------
+void MultiFuncShield::blinkLeds(byte leds, byte enabled)
+{
+ if (enabled)
+ {
+ ledBlinkEnabled = ledBlinkEnabled | leds;
+ }
+ else
+ {
+ ledBlinkEnabled = ledBlinkEnabled & (255 - leds);
+ }
+}
+
+
+// ----------------------------------------------------------------------------------------------------
+void MultiFuncShield::write(int integer)
+{
+ char displayText[5] = {' ',' ',' ',' ',0};
+
+ if (integer > 9999 || integer < -999)
+ {
+ displayText[3] = DISPLAY_OVERFLOW_ERROR;
+ write(displayText);
+ }
+ else if (integer == 0)
+ {
+ displayText[3] = '0';
+ write (displayText);
+ }
+ else
+ {
+ byte sign = 0;
+ if (integer < 0)
+ {
+ sign = 1;
+ integer = integer * -1;
+ }
+
+ byte idx = 3;
+ for (; idx >=0 && integer !=0; integer /= 10, idx--)
+ {
+ displayText[idx]=(integer % 10) + '0';
+ }
+
+ if (sign)
+ {
+ displayText[idx] = '-';
+ }
+
+ write (displayText);
+ }
+}
+
+
+// ----------------------------------------------------------------------------------------------------
+void MultiFuncShield::write(float number, byte decimalPlaces)
+{
+ char outstr[7];
+ dtostrf(number, 4, decimalPlaces, outstr);
+
+ if (strlen(outstr) > 5)
+ {
+ outstr[0] = DISPLAY_OVERFLOW_ERROR;
+ outstr[1] = 0;
+ }
+ write(outstr,1);
+}
+
+
+// ----------------------------------------------------------------------------------------------------
+void MultiFuncShield::write(const char *text, byte rightJustify)
+{
+ byte displayBuf[] = {0,0,0,0}, *pBuf = displayBuf;
+
+ byte idx =0;
+
+ for (; *text != 0 && idx < sizeof(displayBuf); text++)
+ {
+ byte offset = 0;
+
+ if (*text == '.')
+ {
+ if (idx > 0)
+ {
+ displayBuf[idx-1] = displayBuf[idx-1] & 127;
+ }
+ else
+ {
+ displayBuf[idx] = AsciiToSegmentValue(*text);
+ idx++;
+ }
+ }
+ else
+ {
+ displayBuf[idx] = AsciiToSegmentValue(*text);
+ idx++;
+ }
+ }
+
+ for (; idx < sizeof(displayBuf); idx++)
+ {
+ displayBuf[idx] = 255;
+ }
+
+ // Copy display buffer to display memory
+
+ if (rightJustify)
+ {
+ // right justify
+ int i_src = sizeof(displayBuf)-1;
+ int i_dst = sizeof(displayMemory)-1;
+
+ for (; i_src >= 0 && displayBuf[i_src] == 255; i_src--) ;
+
+ for (; i_src >= 0 && i_dst >= 0; i_src--, i_dst--)
+ {
+ displayMemory[i_dst] = displayBuf[i_src];
+ }
+
+ for (; i_dst >= 0; i_dst--)
+ {
+ displayMemory[i_dst] = 255;
+ }
+ }
+ // left justify
+ else
+ {
+ for (int i =0; i < sizeof(displayBuf); i++)
+ {
+ displayMemory[i] = displayBuf[i];
+ }
+ }
+}
+
+
+// ----------------------------------------------------------------------------------------------------
+void MultiFuncShield::blinkDisplay(byte digits, byte enabled)
+{
+ if (enabled)
+ {
+ blinkEnabled = blinkEnabled | digits;
+ }
+ else
+ {
+ blinkEnabled = blinkEnabled & (255 - digits);
+ }
+}
+
+
+// ----------------------------------------------------------------------------------------------------
+void MultiFuncShield::setTimer(unsigned long thousandths)
+{
+ timerWriteInProgress = 1;
+ timer_volatile = thousandths;
+ timerWriteInProgress = 0;
+
+ timerReadInProgress = 1;
+ timer_safe = thousandths;
+ timerReadInProgress = 0;
+}
+
+
+// ----------------------------------------------------------------------------------------------------
+unsigned long MultiFuncShield::getTimer()
+{
+ unsigned long timer;
+ timerReadInProgress = 1;
+ timer = timer_safe;
+ timerReadInProgress = 0;
+
+ return timer;
+}
+
+
+// ----------------------------------------------------------------------------------------------------
+void MultiFuncShield::wait(unsigned long thousandths)
+{
+ setTimer(thousandths);
+ while (getTimer()) __asm__("nop\n\t""nop\n\t""nop\n\t""nop\n\t");
+}
+
+
+// ----------------------------------------------------------------------------------------------------
+void MultiFuncShield::isrCallBack()
+{
+ byte displayEnabled = 1;
+
+ displayTimerScaler--;
+
+ if (displayTimerScaler == 0)
+ {
+ displayTimerScaler = 4;
+
+ // Global bink control
+ if (blinkEnabled || ledBlinkEnabled)
+ {
+ blinkCounter++;
+ if (blinkState)
+ {
+ displayEnabled = 1;
+ if (blinkCounter > BLINK_ON_COUNT)
+ {
+ blinkState = 0;
+ blinkCounter = 0;
+ displayEnabled = 0;
+ }
+ }
+ else
+ {
+ displayEnabled = 0;
+ if (blinkCounter > BLINK_OFF_COUNT)
+ {
+ blinkState = 1;
+ blinkCounter = 0;
+ displayEnabled = 1;
+ }
+ }
+ }
+
+ // Digit display blink control
+ if (blinkEnabled & (1 << displayIdx))
+ {
+ if (displayEnabled)
+ {
+ WriteValueToSegment(displayIdx, displayMemory[displayIdx]);
+ }
+ else
+ {
+ WriteValueToSegment(displayIdx, 255);
+ }
+ }
+ else
+ {
+ WriteValueToSegment(displayIdx, displayMemory[displayIdx]);
+ }
+
+ displayIdx++;
+ if (displayIdx > sizeof(displayMemory)-1)
+ {
+ displayIdx = 0;
+ }
+
+
+ // LED output and blink control.
+
+ byte ledOutputNew = (ledState & (displayEnabled ? 255 : 0) & ledBlinkEnabled) | (ledState & ~ledBlinkEnabled);
+
+ if (ledOutputNew != ledOutput)
+ {
+ for (byte ledIdx = 0; ledIdx < 4; ledIdx++)
+ {
+ if ((ledOutputNew ^ ledOutput) & (1 << ledIdx)) // only set LED if its state has changed
+ {
+ if (ledBlinkEnabled & (1 << ledIdx))
+ {
+ //digitalWrite(LED[ledIdx], !(displayEnabled && ledState & (1 << ledIdx)));
+ writeLed(ledIdx, !(displayEnabled && ledState & (1 << ledIdx)));
+ }
+ else
+ {
+ //digitalWrite(LED[ledIdx], !(ledState & (1 << ledIdx)));
+ writeLed(ledIdx, !(ledState & (1 << ledIdx)));
+ }
+ }
+ }
+ ledOutput = ledOutputNew;
+ }
+ }
+
+
+ // Beeper control.
+
+ if (!beeperModifyInProgress && beeperOnPeriodReloadValue)
+ {
+ if (beeperPeriodCounter == 0)
+ {
+ switch (beeperState)
+ {
+ case 0: // on period
+ if (beeperOffPeriodReloadValue)
+ {
+ beeperPeriodCounter = beeperOffPeriodReloadValue;
+ beeperState = 1;
+ break;
+ }
+ // Fall thru to next state immediately.
+ case 1: // off period
+ beeperCycleCounter--;
+ if (beeperCycleCounter)
+ {
+ beeperPeriodCounter = beeperOnPeriodReloadValue;
+ beeperState = 0;
+ break;
+ }
+ else
+ {
+ beeperCycleCounter = beeperCycleReloadValue;
+ beeperPeriodCounter = beeperLoopDelayPeriodReloadValue;
+ beeperState = 2;
+
+ if (beeperLoopDelayPeriodReloadValue)
+ {
+ break;
+ }
+ }
+ // Fall thru to next state immediately.
+ case 2: // loop cycle delay period
+ if (beeperLoopCycleCounter == 0) // loop beeper indefinitely
+ {
+ beeperPeriodCounter = beeperOnPeriodReloadValue;
+ beeperState = 0;
+ }
+ else
+ {
+ beeperLoopCycleCounter--;
+ if (beeperLoopCycleCounter == 0)
+ {
+ beeperOnPeriodReloadValue = 0; // beeper activity has now ended.
+ //digitalWrite(BEEPER_PIN, 1);
+ writeBeeper(1);
+ }
+ else
+ {
+ beeperPeriodCounter = beeperOnPeriodReloadValue;
+ beeperState = 0;
+ }
+ }
+ break;
+ }
+ }
+
+ if (beeperPeriodCounter)
+ {
+ beeperPeriodCounter--;
+ }
+
+ if (beeperState == 0)
+ {
+ // beep on
+ //digitalWrite(BEEPER_PIN, 0);
+ writeBeeper(0);
+ }
+ else
+ {
+ // beep off
+ //digitalWrite(BEEPER_PIN, 1);
+ writeBeeper(1);
+ }
+ }
+
+
+ // Bump button sample interval counter
+
+ if (buttonSampleIntervalCounter++ >= BUTTON_SAMPLE_INTERVAL)
+ {
+ buttonSampleIntervalCounter =0;
+
+ byte btnStateNow;
+
+ for (int i=0; i < sizeof(buttonPins); i++)
+ {
+ //btnStateNow = !digitalRead(buttonPins[i]);
+ btnStateNow = !readButton(i);
+
+ // If button state has changed, action the change.
+ if (buttonState[i] != btnStateNow)
+ {
+ // if button state changes to pressed, queue SHORT PRESS to buffer.
+ if (btnStateNow)
+ {
+ queueButton((i+1) | BUTTON_PRESSED_IND);
+ }
+ else
+ {
+ // otherwise button state has changed to up, queue SHORT or LONG RELEASE state to buffer, and reset pressed time counter.
+ if (buttonPressTime[i] > (1000 / BUTTON_SAMPLE_INTERVAL))
+ {
+ queueButton((i+1) | BUTTON_LONG_RELEASE_IND);
+ }
+ else
+ {
+ queueButton((i+1) | BUTTON_SHORT_RELEASE_IND);
+ }
+ buttonPressTime[i] = 0;
+ }
+ buttonState[i] = btnStateNow;
+ }
+
+ // if button state pressed, increment pressed time counter. Queue LONG PRESS to buffer, if button is held long.
+ if (btnStateNow)
+ {
+ if (buttonPressTime[i] > (1000 / BUTTON_SAMPLE_INTERVAL) && (buttonPressTime[i] & 3) == 0)
+ {
+ queueButton((i+1) | BUTTON_LONG_PRESSED_IND);
+ }
+
+ if (buttonPressTime[i] < 65535)
+ {
+ buttonPressTime[i]++;
+ }
+ }
+ }
+ }
+
+ // Pulse in processing
+
+ if (pulseInEnabled && !pulseInWriteInProgress)
+ {
+ //byte pulseInStateNow = digitalRead(pulseInPin);
+ byte pulseInStateNow = (*portInputRegister(pulseInPort) & pulseInBit ? 1 : 0);
+
+ // Has the state of the pulse changed?
+ if ((pulseInState != pulseInStateNow) && (pulseInStateNow == pulseInTrigger))
+ {
+ pulseInTotalCount_volatile++;
+
+ pulseInPeriod_volatile = (pulseInPeriodCounter >= pulseInTimeOut ? 0 : pulseInPeriodCounter);
+ pulseInPeriodCounter = 0;
+ }
+ else
+ {
+ if (pulseInPeriodCounter < pulseInTimeOut)
+ {
+ pulseInPeriodCounter++;
+ }
+ else
+ {
+ pulseInPeriod_volatile = 0;
+ }
+ }
+
+ if (!pulseInReadInProgress)
+ {
+ pulseInPeriod_safe = pulseInPeriod_volatile;
+ pulseInTotalCount_safe = pulseInTotalCount_volatile;
+ }
+
+ if (pulseInState != pulseInStateNow)
+ {
+ pulseInState = pulseInStateNow;
+ }
+ }
+
+ // Bump the count down timer.
+ if (timer_volatile && !timerWriteInProgress)
+ {
+ timer_volatile--;
+ }
+
+ if (!timerReadInProgress)
+ {
+ timer_safe = timer_volatile;
+ }
+
+ if (userInterrupt)
+ {
+ userInterrupt();
+ }
+}
+
+
+// ----------------------------------------------------------------------------------------------------
+void MultiFuncShield::manualDisplayRefresh()
+{
+ WriteValueToSegment(displayIdx, displayMemory[displayIdx]);
+
+ displayIdx++;
+ if (displayIdx > sizeof(displayMemory)-1)
+ {
+ displayIdx = 0;
+ }
+}
+
+
+// ----------------------------------------------------------------------------------------------------
+void MultiFuncShield::manualButtonHandler()
+{
+ byte btnStateNow;
+
+ for (int i=0; i < sizeof(buttonPins); i++)
+ {
+ btnStateNow = !digitalRead(buttonPins[i]);
+
+ // If button state has changed, action the change.
+
+ if (buttonState[i] != btnStateNow)
+ {
+ // if button state changes to pressed, queue SHORT PRESS to buffer.
+ if (btnStateNow)
+ {
+ queueButton((i+1) | BUTTON_PRESSED_IND);
+ }
+ else
+ {
+ // otherwise button state has changed to up, queue SHORT RELEASE state to buffer.
+ queueButton((i+1) | BUTTON_SHORT_RELEASE_IND);
+ }
+ buttonState[i] = btnStateNow;
+ }
+ }
+}
+
+
+// ----------------------------------------------------------------------------------------------------
+void isrWrapper ()
+{
+ MFS.isrCallBack();
+}
+
+
+// ----------------------------------------------------------------------------------------------------
+byte AsciiToSegmentValue (byte ascii)
+{
+ byte segmentValue = 182;
+
+ if (ascii >= '0' && ascii <= '9')
+ {
+ segmentValue = SEGMENT_MAP_DIGIT[ascii - '0'];
+ }
+ else if (ascii >= 'a' && ascii <='z')
+ {
+ segmentValue = SEGMENT_MAP_ALPHA[ascii - 'a'];
+ }
+ else if (ascii >= 'A' && ascii <='Z')
+ {
+ segmentValue = SEGMENT_MAP_ALPHA[ascii - 'A'];
+ }
+ else
+ {
+ switch (ascii)
+ {
+ case '-':
+ segmentValue = 191;
+ break;
+ case '.':
+ segmentValue = 127;
+ break;
+ case '_':
+ segmentValue = 247;
+ break;
+ case ' ':
+ segmentValue = 255;
+ break;
+ }
+ }
+
+ return segmentValue;
+}
+
+// ----------------------------------------------------------------------------------------------------
+int MedianOf5(int s0, int s1, int s2, int s3, int s4)
+{
+ int tmp;
+
+ if (s1 > s2)
+ {
+ tmp = s1;
+ s1 = s2;
+ s2 = tmp;
+ }
+
+ if (s0 > s1)
+ {
+ tmp = s0;
+ s0 = s1;
+ s1 = tmp;
+ }
+ if (s3 > s4)
+ {
+ tmp = s3;
+ s3 = s4;
+ s4 = tmp;
+ }
+
+ if (s1 > s2)
+ {
+ tmp = s1;
+ s1 = s2;
+ s2 = tmp;
+ }
+
+ if (s0 > s3)
+ {
+ s3 = s0;
+ }
+
+ if (s1 > s4)
+ {
+ s1 = s4;
+ }
+
+ if (s1 > s3)
+ {
+ s3 = s1;
+ }
+
+ if (s2 > s3)
+ {
+ s2 = s3;
+ }
+
+ return s2;
+}
+
+
+// ----------------------------------------------------------------------------------------------------
+// Find the median value, given nine data samples.
+int MedianOf9(int s0, int s1, int s2, int s3, int s4, int s5, int s6, int s7, int s8)
+{
+ int tmp;
+
+ if (s1 > s2)
+ {
+ tmp = s1;
+ s1 = s2;
+ s2 = tmp;
+ }
+ if (s4 > s5)
+ {
+ tmp = s4;
+ s4 = s5;
+ s5 = tmp;
+ }
+ if (s7 > s8)
+ {
+ tmp = s7;
+ s7 = s8;
+ s8 = tmp;
+ }
+
+ if (s0 > s1)
+ {
+ tmp = s0;
+ s0 = s1;
+ s1 = tmp;
+ }
+ if (s3 > s4)
+ {
+ tmp = s3;
+ s3 = s4;
+ s4 = tmp;
+ }
+ if (s6 > s7)
+ {
+ tmp = s6;
+ s6 = s7;
+ s7 = tmp;
+ }
+
+ if (s1 > s2)
+ {
+ tmp = s1;
+ s1 = s2;
+ s2 = tmp;
+ }
+ if (s4 > s5)
+ {
+ tmp = s4;
+ s4 = s5;
+ s5 = tmp;
+ }
+ if (s7 > s8)
+ {
+ tmp = s7;
+ s7 = s8;
+ s8 = tmp;
+ }
+
+ if (s3 > s6)
+ {
+ tmp = s3;
+ s3 = s6;
+ s6 = tmp;
+ }
+ if (s4 > s7)
+ {
+ tmp = s4;
+ s4 = s7;
+ s7 = tmp;
+ }
+ if (s5 > s8)
+ {
+ s5 = s8;
+ }
+ if (s0 > s3)
+ {
+ tmp = s0;
+ s3 = tmp;
+ }
+
+ if (s1 > s4)
+ {
+ tmp = s1;
+ s1 = s4;
+ s4 = tmp;
+ }
+ if (s2 > s5)
+ {
+ s2 = s5;
+ }
+ if (s3 > s6)
+ {
+ tmp = s3;
+ s3 = s6;
+ s6 = tmp;
+ }
+
+ if (s4 > s7)
+ {
+ s4 = s7;
+ }
+ if (s1 > s3)
+ {
+ s3 = s1;
+ }
+
+ if (s2 > s6)
+ {
+ tmp = s2;
+ s2 = s6;
+ s6 = tmp;
+ }
+
+ if (s2 > s3)
+ {
+ s3 = s2;
+ }
+ if (s4 > s6)
+ {
+ s4 = s6;
+ }
+
+ if (s3 > s4)
+ {
+ s4 = s3;
+ }
+ return s4;
+}
+
+/* ---------------------------------------------------------------------- */
+
+#if defined(__AVR_ATmega328P__) // Uno
+
+ /* Write a value to one of the 4 digits of the display */
+ void WriteValueToSegment(byte Segment, byte Value)
+ {
+ bitClear(PORTD, 4);
+
+ for (uint8_t i = 0; i < 8; i++) {
+ bitWrite(PORTB, 0, !!(Value & (1 << (7 - i))));
+ bitSet(PORTD, 7);
+ bitClear(PORTD, 7);
+ }
+
+ for (uint8_t i = 0; i < 8; i++) {
+ bitWrite(PORTB, 0, !!(SEGMENT_SELECT[Segment] & (1 << (7 - i))));
+ bitSet(PORTD, 7);
+ bitClear(PORTD, 7);
+ }
+
+ bitSet(PORTD, 4);
+ }
+
+
+ byte readButton (byte btnIndex)
+ {
+ switch (btnIndex)
+ {
+ case 0:
+ return bitRead(PINC, 1);
+ case 1:
+ return bitRead(PINC, 2);
+ case 2:
+ return bitRead(PINC, 3);
+ }
+ }
+
+ void writeBeeper (byte value)
+ {
+ bitWrite(PORTD, 3, value);
+ }
+
+ void writeLed(byte ledIdx, byte value)
+ {
+ switch (ledIdx)
+ {
+ case 0:
+ bitWrite(PORTB, 5, value);
+ break;
+ case 1:
+ bitWrite(PORTB, 4, value);
+ break;
+ case 2:
+ bitWrite(PORTB, 3, value);
+ break;
+ case 3:
+ bitWrite(PORTB, 2, value);
+ break;
+ }
+ }
+
+#elif defined(__AVR_ATmega32U4__) // Leonardo
+
+ /* Write a value to one of the 4 digits of the display */
+ void WriteValueToSegment(byte Segment, byte Value)
+ {
+ bitClear(PORTD, 4);
+
+ for (uint8_t i = 0; i < 8; i++) {
+ bitWrite(PORTB, 4, !!(Value & (1 << (7 - i))));
+ bitSet(PORTE, 6);
+ bitClear(PORTE, 6);
+ }
+
+ for (uint8_t i = 0; i < 8; i++) {
+ bitWrite(PORTB, 4, !!(SEGMENT_SELECT[Segment] & (1 << (7 - i))));
+ bitSet(PORTE, 6);
+ bitClear(PORTE, 6);
+ }
+
+ bitSet(PORTD, 4);
+ }
+
+
+ byte readButton (byte btnIndex)
+ {
+ switch (btnIndex)
+ {
+ case 0:
+ return bitRead(PINF, 6);
+ case 1:
+ return bitRead(PINF, 5);
+ case 2:
+ return bitRead(PINF, 4);
+ }
+ }
+
+ void writeBeeper (byte value)
+ {
+ bitWrite(PORTD, 0, value);
+ }
+
+ void writeLed(byte ledIdx, byte value)
+ {
+ switch (ledIdx)
+ {
+ case 0:
+ bitWrite(PORTC, 7, value);
+ break;
+ case 1:
+ bitWrite(PORTD, 6, value);
+ break;
+ case 2:
+ bitWrite(PORTB, 7, value);
+ break;
+ case 3:
+ bitWrite(PORTB, 6, value);
+ break;
+ }
+ }
+
+#elif defined(__AVR_ATmega2560__) // Mega 2560
+
+/* Write a value to one of the 4 digits of the display */
+/*
+void WriteValueToSegment(byte Segment, byte Value)
+{
+ digitalWrite(LATCH_PIN,LOW);
+ shiftOut(DATA_PIN, CLK_PIN, MSBFIRST, Value);
+ shiftOut(DATA_PIN, CLK_PIN, MSBFIRST, SEGMENT_SELECT[Segment] );
+ digitalWrite(LATCH_PIN,HIGH);
+}
+*/
+
+ /* Write a value to one of the 4 digits of the display */
+ void WriteValueToSegment(byte Segment, byte Value)
+ {
+ bitClear(PORTG, 5);
+
+ for (uint8_t i = 0; i < 8; i++) {
+ bitWrite(PORTH, 5, !!(Value & (1 << (7 - i))));
+ bitSet(PORTH, 4);
+ bitClear(PORTH, 4);
+ }
+
+ for (uint8_t i = 0; i < 8; i++) {
+ bitWrite(PORTH, 5, !!(SEGMENT_SELECT[Segment] & (1 << (7 - i))));
+ bitSet(PORTH, 4);
+ bitClear(PORTH, 4);
+ }
+
+ bitSet(PORTG, 5);
+ }
+
+
+ byte readButton (byte btnIndex)
+ {
+ switch (btnIndex)
+ {
+ case 0:
+ return bitRead(PINF, 1);
+ case 1:
+ return bitRead(PINF, 2);
+ case 2:
+ return bitRead(PINF, 3);
+ }
+ }
+
+ void writeBeeper (byte value)
+ {
+ bitWrite(PORTE, 5, value);
+ }
+
+ void writeLed(byte ledIdx, byte value)
+ {
+ switch (ledIdx)
+ {
+ case 0:
+ bitWrite(PORTB, 7, value);
+ break;
+ case 1:
+ bitWrite(PORTB, 6, value);
+ break;
+ case 2:
+ bitWrite(PORTB, 5, value);
+ break;
+ case 3:
+ bitWrite(PORTB, 4, value);
+ break;
+ }
+ }
+#endif
diff --git a/examples/ReactionTimeTestGame/MultiFuncShield.h b/examples/ReactionTimeTestGame/MultiFuncShield.h
new file mode 100644
index 0000000..5aa6b99
--- /dev/null
+++ b/examples/ReactionTimeTestGame/MultiFuncShield.h
@@ -0,0 +1,226 @@
+#include "TimerOne.h"
+
+#ifndef MultiFuncShield_h_
+#define MultiFuncShield_h_
+
+#include "Arduino.h"
+
+#define ON 1
+#define OFF 0
+
+#define LED_1_PIN 13
+#define LED_2_PIN 12
+#define LED_3_PIN 11
+#define LED_4_PIN 10
+#define POT_PIN 0
+#define BEEPER_PIN 3
+#define BUTTON_1_PIN A1
+#define BUTTON_2_PIN A2
+#define BUTTON_3_PIN A3
+#define LATCH_PIN 4
+#define CLK_PIN 7
+#define DATA_PIN 8
+#define LM35_PIN A4
+
+#define DIGIT_1 1
+#define DIGIT_2 2
+#define DIGIT_3 4
+#define DIGIT_4 8
+#define DIGIT_ALL 15
+
+#define LED_1 1
+#define LED_2 2
+#define LED_3 4
+#define LED_4 8
+#define LED_ALL 15
+
+// button state indicators
+#define BUTTON_PRESSED_IND (0 << 6)
+#define BUTTON_SHORT_RELEASE_IND (1 << 6)
+#define BUTTON_LONG_PRESSED_IND (2 << 6)
+#define BUTTON_LONG_RELEASE_IND (3 << 6)
+
+#define BUTTON_1_PRESSED (1 | BUTTON_PRESSED_IND)
+#define BUTTON_1_SHORT_RELEASE (1 | BUTTON_SHORT_RELEASE_IND)
+#define BUTTON_1_LONG_PRESSED (1 | BUTTON_LONG_PRESSED_IND)
+#define BUTTON_1_LONG_RELEASE (1 | BUTTON_LONG_RELEASE_IND)
+
+#define BUTTON_2_PRESSED (2 | BUTTON_PRESSED_IND)
+#define BUTTON_2_SHORT_RELEASE (2 | BUTTON_SHORT_RELEASE_IND)
+#define BUTTON_2_LONG_PRESSED (2 | BUTTON_LONG_PRESSED_IND)
+#define BUTTON_2_LONG_RELEASE (2 | BUTTON_LONG_RELEASE_IND)
+
+#define BUTTON_3_PRESSED (3 | BUTTON_PRESSED_IND)
+#define BUTTON_3_SHORT_RELEASE (3 | BUTTON_SHORT_RELEASE_IND)
+#define BUTTON_3_LONG_PRESSED (3 | BUTTON_LONG_PRESSED_IND)
+#define BUTTON_3_LONG_RELEASE (3 | BUTTON_LONG_RELEASE_IND)
+
+#define SMOOTHING_NONE 0
+#define SMOOTHING_MODERATE 1
+#define SMOOTHING_STRONG 2
+
+
+class MultiFuncShield
+{
+
+ public:
+ // Pointer to user interrupt with frequency of 1khz.
+ void (*userInterrupt)() = NULL;
+
+ // Initializes this instance using a TimerOne instance. A 1khz interrupt is attached.
+ void initialize(TimerOne *timer1);
+
+ // Initializes this instance, but interrupt based features are not available.
+ void initialize();
+
+ // For internal use only.
+ void isrCallBack();
+
+ // Initiates a millisecond countdown timer.
+ void setTimer (unsigned long thousandths);
+
+ // Gets the current value of the countdown timer.
+ unsigned long getTimer();
+
+ // Initiates and waits for millisecond countdown timer to reach 0.
+ void wait(unsigned long thousandths);
+
+ // Writes to the LED digit display.
+ void write(const char *textstring, byte rightJustify =0);
+ void write(int integer);
+ void write(float number, byte decimalPlaces = 1);
+
+ // Manually refreshes the Led digit display.
+ // Not to be used whilst interrupt based features are available.
+ void manualDisplayRefresh();
+
+ // Blinks the digits on the LED digit display.
+ void blinkDisplay(byte digits, // use bitwise or, e.g. DIGIT_1 | DIGIT_2
+ byte enabled = ON // turns on/off the blinking
+ );
+
+ // Turns LEDs on or off.
+ void writeLeds(byte leds, // use bitwise or, e.g. LED_1 | LED_2
+ byte lit // ON or OFF
+ );
+
+ // Blinks the LEDs.
+ void blinkLeds(byte leds, // use bitwise or, e.g. LED_1 | LED_2
+ byte enabled = ON // ON or OFF
+ );
+
+ // Engage the beeper, which is managed in the background. Period timing is in 100th of second
+ void beep(unsigned int onPeriod = 20, unsigned int offPeriod = 0, byte cycles = 1, unsigned int loopCycles = 1 /* 0=indefinitely */, unsigned int loopDelayPeriod =0);
+
+ // Use this to set the off period whilst the beeper is engaged,
+ void setBeepOffPeriod(unsigned int offPeriod);
+
+ // Queues a button action to the button queue, e.g BUTTON_1_PRESSED
+ void queueButton (byte button);
+
+ // Pulls a button action from the button queue.
+ byte getButton();
+
+ // Queues button short press and release actions. Long button presses are not supported, and long releases are reported as short releases.
+ // Should not be used whilst interrupt based features are available.
+ void manualButtonHandler();
+
+ // Initializes the pulse counter. Used for counting pulses applied to an input pin. Max pulse frequency 500hz.
+ void initPulseInCounter(byte pin = BUTTON_1_PIN, // input pin
+ unsigned int timeOut = 3000, // the number of milliseconds to wait for a pulse, before resetting pulse in period to 0.
+ byte trigger = LOW // trigger counter on either rising or falling edge
+ );
+
+ void disablePulseInCounter();
+
+ // Gets the period of the most recent pulse (in milliseconds).
+ unsigned int getPulseInPeriod();
+
+ // Gets the total number pulses counted.
+ unsigned long getPulseInTotalCount();
+
+ // Resets the pulse counter to 0.
+ void resetPulseInTotalCount();
+
+ // Sets the pulse in timeout, which is the number of milliseconds to wait for a pulse, before resetting pulse in period to 0.
+ void setPulseInTimeOut(unsigned int timeOut);
+
+ // Initializes the sonar reading feature. Needs HC-SR04 sonar module.
+ void initSonar(byte level = SMOOTHING_MODERATE); // level 0=none, 1=moderate, 2=strong.
+
+ // Gets the distance measured in centimeters, using HC-SR04 sonar module.
+ unsigned int getSonarDataCm(byte triggerPin, byte echoPin);
+
+ // Initializes temperature reading feature. Needs LM35 sensor. Must remove jumper J1 from shield.
+ void initLM35(byte level = SMOOTHING_MODERATE); // level 0=none, 1=moderate, 2=strong
+
+ // Gets the temperature reading in 1 tenths of a centigrade.
+ int getLM35Data();
+
+ private:
+ TimerOne *timer1;
+ volatile byte timerReadInProgress = 0;
+ volatile byte timerWriteInProgress = 0;
+
+ const byte buttonPins[3] = {BUTTON_1_PIN, BUTTON_2_PIN, BUTTON_3_PIN}; // must correspond to button macros above
+
+ volatile byte buttonBuffer[sizeof(buttonPins) * 2];
+ volatile char buttonBufferCount = 0;
+ volatile byte button_write_pos = 0;
+ volatile byte button_read_pos = 0;
+
+ unsigned int buttonSampleIntervalCounter =0;
+ byte buttonState[sizeof(buttonPins)] = {0,0,0}; // current up or down state
+ unsigned int buttonPressTime[sizeof(buttonPins)] = {0,0,0};
+
+ volatile unsigned long timer_volatile = 0; // count down timer 1000th of a second resolution.
+ volatile unsigned long timer_safe = 0;
+
+ volatile byte beeperModifyInProgress = 0;
+ volatile byte beeperState =0; // 0=on period; 1=off period
+ volatile unsigned int beeperOnPeriodReloadValue =0;
+ volatile unsigned int beeperOffPeriodReloadValue =0;
+ volatile unsigned int beeperPeriodCounter = 0;
+ volatile byte beeperCycleReloadValue = 0;
+ volatile byte beeperCycleCounter =0;
+ volatile unsigned int beeperLoopCycleCounter =0;
+ volatile unsigned int beeperLoopDelayPeriodReloadValue =0;
+
+ byte displayIdx = 0;
+ byte blinkEnabled = 0; // least significant bits mapped to display digits.
+ byte blinkState = 0;
+ byte blinkCounter = 0;
+
+ //byte ledControlMask = 0; // soft enable / disable LED. Disable LEDs here if using PWM from TImerOne library.
+ byte ledState =0; // least significant bits mapped to LEDs
+ byte ledBlinkEnabled =0; // least significant bits mapped to LEDs
+ byte ledOutput=0; // current led outputs (taking into consideration blink)
+
+ volatile byte pulseInEnabled = false;
+ volatile byte pulseInReadInProgress =0;
+ volatile byte pulseInWriteInProgress =0;
+
+ volatile unsigned int pulseInTimeOut = 3000; // time frame for measuring pulse period.
+ volatile byte pulseInPin = BUTTON_1_PIN;
+ volatile unsigned int pulseInPeriodCounter = 3000;
+ volatile byte pulseInTrigger = LOW; // trigger on LOW or HIGH
+ volatile unsigned int pulseInPeriod_volatile =0;
+ volatile unsigned int pulseInPeriod_safe =0;
+ volatile byte pulseInState =0;
+ volatile unsigned long pulseInTotalCount_volatile = 0;
+ volatile unsigned long pulseInTotalCount_safe = 0;
+
+ byte sonarSmoothingLevel = SMOOTHING_MODERATE;
+ byte lm35SmoothingLevel = SMOOTHING_MODERATE;
+};
+
+extern MultiFuncShield MFS;
+
+// returns median of 5 data samples.
+extern int MedianOf5(int s0, int s1, int s2, int s3, int s4);
+
+// returns median of 9 data samples.
+extern int MedianOf9(int s0, int s1, int s2, int s3, int s4, int s5, int s6, int s7, int s8);
+
+#endif
+
diff --git a/examples/ReactionTimeTestGame/ReactionTimeTestGame.ino b/examples/ReactionTimeTestGame/ReactionTimeTestGame.ino
new file mode 100644
index 0000000..7c5f7c2
--- /dev/null
+++ b/examples/ReactionTimeTestGame/ReactionTimeTestGame.ino
@@ -0,0 +1,332 @@
+/*
+ * Game to measure reaction time with 2 buttons, 3 LEDs and a buzzer
+ *
+ * Aufgaben:
+ * 1. Warte bis ein Button gedrückt wird und gebe die Reaktionszeit aus. Schalte die LED des Spielers an und erhöhe die Punkte des Spielers.
+ * Benutze digitalRead() und z.B. "sRightPlayerScore++".
+ * 2. Wenn der Punktestand POINTS_FOR_WIN erreicht hat, lasse die LED blinken und spiele eine Melodie.
+ * Benutze blinkLed() und playRtttlBlockingPGM(PIN_BUZZER, StarWars). Selektiere "StarWars" und drücke Taste F3.
+ * 3. Bestrafe cheaten (der Button ist schon vor dem angehen der LED gedrückt) mit Punktabzug und signalisiere das mit einer blinkenden LED.
+ *
+ *
+ * Copyright (C) 2018-2020 Armin Joachimsmeyer
+ * armin.joachimsmeyer@gmail.com
+ *
+ * This file is part of PlayRttl https://github.com/ArminJo/PlayRtttl.
+ *
+ * PlayRttl is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include
+#include "PlayRtttl.h"
+
+#define VERSION_EXAMPLE "2.1"
+
+/*
+ * Comment the next line out if you want to run this program on an Arduino Multifunction Shield
+ * https://www.electroschematics.com/getting-started-with-the-arduino-multifunction-shield/
+ */
+//#define MULTI_FUNCTION_SHIELD
+/*
+ * Comment the next line out, if you use the breadboard layout for school lessons
+ * https://github.com/ArminJo/Arduino-Lessons-for-School#universal-breadboard-layout-for-all-lessons
+ */
+//#define BREADBOARD_LAYOUT
+#ifdef MULTI_FUNCTION_SHIELD
+#include "MultiFuncShield.h"
+// inverse logic for LEDS and buzzer: they are active at LOW
+#define PIN_BUZZER 3
+
+#define PIN_RED_LED 13
+#define PIN_RED_LED_2 12
+#define PIN_RED_LED_3 11
+#define PIN_RED_LED_4 10
+#define PIN_RIGHT_LED PIN_RED_LED_4
+#define PIN_LEFT_LED PIN_RED_LED
+#define PIN_START_LED PIN_RED_LED_2
+#define PIN_START_LED_2 PIN_RED_LED_3
+
+#define PIN_RIGHT_BUTTON A3
+#define PIN_LEFT_BUTTON A1
+
+#define PIN_SERVO_HORIZONTAL 6
+#define PIN_SERVO_VERTICAL 5
+
+#define TRIGGER_OUT_PIN 9
+#define ECHO_IN_PIN A5
+
+#define PIN_POTENTIOMETER A0
+
+#elif defined(BREADBOARD_LAYOUT)
+#include "Breadboard.h"
+
+#define PIN_START_LED PIN_MIDDLE_LED
+
+#else
+/*
+ * Layout for "Simon Says" layout
+ * https://learn.sparkfun.com/tutorials/sparkfun-inventors-kit-experiment-guide---v40/circuit-2c-simon-says-game
+ * https://dingfluence.dingfabrik.de/pages/viewpage.action?pageId=31653962
+ */
+#define PIN_BUZZER 10
+
+#define PIN_RIGHT_LED 7
+#define PIN_LEFT_LED 5
+#define PIN_START_LED 3
+#define PIN_START_LED_2 9
+
+#define PIN_RIGHT_BUTTON 6
+#define PIN_LEFT_BUTTON 4
+#endif
+
+const int POINTS_FOR_WIN = 3;
+
+int sLeftPlayerScore, sRightPlayerScore;
+int sLeftPlayerWins = 0, sRightPlayerWins = 0; // Count wins, to play a random song every second win.
+int tHighScore = 8000; // the minimum reaction time in millis
+
+void blinkLEDBlocking(uint8_t aLedPin, uint8_t aBlinkCount, uint16_t aDelay);
+
+// The setup function is called once at startup of the sketch
+void setup() {
+ pinMode(LED_BUILTIN, OUTPUT);
+ Serial.begin(115200);
+#if defined(__AVR_ATmega32U4__) || defined(SERIAL_USB) || defined(SERIAL_PORT_USBVIRTUAL)
+ delay(2000); // To be able to connect Serial monitor after reset and before first printout
+#endif
+ // Just to know which program is running on my Arduino
+ Serial.println(F("START " __FILE__ "\r\nVersion " VERSION_EXAMPLE " from " __DATE__));
+
+ // Enable output on the LED pins
+ pinMode(PIN_RIGHT_LED, OUTPUT);
+ pinMode(PIN_LEFT_LED, OUTPUT);
+ pinMode(PIN_START_LED, OUTPUT);
+#if defined(PIN_START_LED_2)
+ pinMode(PIN_START_LED_2, OUTPUT);
+#endif
+
+#ifdef MULTI_FUNCTION_SHIELD
+ // LEDS are active low on the MuFu shield so switch them off by writing a HIGH
+ digitalWrite(PIN_RIGHT_LED, HIGH);
+ digitalWrite(PIN_LEFT_LED, HIGH);
+ digitalWrite(PIN_START_LED, HIGH);
+ digitalWrite(PIN_START_LED_2, HIGH);
+
+ Timer1.initialize();
+ MFS.initialize(&Timer1);
+ setTonePinIsInverted(true);// configure PlayRtttl output polarity
+#endif
+
+ // Prepare for buttons reading
+ pinMode(PIN_RIGHT_BUTTON, INPUT_PULLUP);
+ pinMode(PIN_LEFT_BUTTON, INPUT_PULLUP);
+}
+
+/*
+ * Die mittlere Led nach einer zufälligen Zeit anschalten und dann warten, welche Taste zuerst gedrückt wird.
+ * Die Zeit bis zum Drücken der Taste ausgeben und die Led an der zuerst gedrückten Taste leuchten lassen.
+ * Wenn ein Spieler die Punktzahl erreicht hat eine Melodie spielen.
+ * Danach kurz warten und die Messung wieder von vorne beginnen.
+ */
+void loop() {
+ int tRightPlayerButton;
+ int tLeftPlayerButton;
+
+ delay(random(500, 4000)); // random delay before next lap
+
+ /*
+ * Task 3. Check for cheating just before switching led on and give feedback if detected
+ * Bestrafe cheaten (der Button ist schon vor dem angehen der LED gedrückt) mit Punktabzug und signalisiere das mit einer blinkenden LED.
+ */
+ tRightPlayerButton = digitalRead(PIN_RIGHT_BUTTON);
+ tLeftPlayerButton = digitalRead(PIN_LEFT_BUTTON);
+ if (tRightPlayerButton == LOW || tLeftPlayerButton == LOW) {
+ /*
+ * Cheating detected -> blink and decrement score
+ */
+ if (tRightPlayerButton == LOW) {
+ blinkLEDBlocking(PIN_RIGHT_LED, 5, 50);
+ sRightPlayerScore--;
+ } else {
+ blinkLEDBlocking(PIN_LEFT_LED, 5, 50);
+ sLeftPlayerScore--;
+ }
+ return; // start next lap
+ }
+
+ uint32_t tStartMillis = millis();
+ /*
+ * No cheating here -> switch on start LED(s) and wait for first button to be pressed
+ */
+#ifdef MULTI_FUNCTION_SHIELD
+ digitalWrite(PIN_START_LED, LOW);
+ digitalWrite(PIN_START_LED_2, LOW);
+ digitalWrite(PIN_BUZZER, LOW);
+ MFS.write("");
+ delay(20);
+ digitalWrite(PIN_BUZZER, HIGH);
+#else
+ tone(PIN_BUZZER, 2200, 40);
+ digitalWrite(PIN_START_LED, HIGH);
+# if defined(PIN_START_LED_2)
+ digitalWrite(PIN_START_LED_2, HIGH);
+# endif
+#endif
+
+ /*
+ * Task 1. Wait for press after LED switched on, give LED feedback and output reaction time
+ * Warte bis ein Button gedrückt wird und gebe die Reaktionszeit aus. Schalte die LED des Spielers an und erhöhe die Punkte des Spielers.
+ * Benutze digitalRead() und z.B. "sRightPlayerScore++".
+ */
+ do {
+ tRightPlayerButton = digitalRead(PIN_RIGHT_BUTTON);
+ tLeftPlayerButton = digitalRead(PIN_LEFT_BUTTON);
+ } while (tRightPlayerButton != LOW && tLeftPlayerButton != LOW);
+ int tReactionTimeMilliseconds = millis() - tStartMillis;
+
+ /*
+ * Manage high score
+ */
+#ifdef MULTI_FUNCTION_SHIELD
+ bool tIsHighScore = false;
+#endif
+ if (tReactionTimeMilliseconds < tHighScore) {
+ tHighScore = tReactionTimeMilliseconds;
+#ifdef MULTI_FUNCTION_SHIELD
+ tIsHighScore = true;
+#endif
+ }
+
+ /*
+ * One button is pressed here
+ * Output result to Serial
+ */
+ if (tRightPlayerButton == LOW) {
+ // Right button was pressed
+ sRightPlayerScore++;
+#ifdef MULTI_FUNCTION_SHIELD
+ digitalWrite(PIN_RIGHT_LED, LOW);
+#else
+ digitalWrite(PIN_RIGHT_LED, HIGH);
+#endif
+ Serial.print("Right player wins with ");
+ } else {
+ // Left button must be pressed here
+ sLeftPlayerScore++;
+#ifdef MULTI_FUNCTION_SHIELD
+ digitalWrite(PIN_LEFT_LED, LOW);
+#else
+ digitalWrite(PIN_LEFT_LED, HIGH);
+#endif
+ Serial.print("Left player wins with ");
+ }
+ Serial.print(tReactionTimeMilliseconds);
+ Serial.println(" ms");
+
+#ifdef MULTI_FUNCTION_SHIELD
+ // show time on 4 digit display
+ MFS.write(tReactionTimeMilliseconds);
+ MFS.blinkDisplay(DIGIT_ALL, tIsHighScore);
+#endif
+
+ /*
+ * Task 2. Check for score level, blink LED and play melody
+ * Wenn der Punktestand POINTS_FOR_WIN erreicht hat, lasse die LED blinken und spiele eine Melodie.
+ * Benutze blinkLed() und playRtttlBlockingPGM(PIN_BUZZER, StarWars). Selektiere "StarWars" und drücke Taste F3.
+ */
+ if (sRightPlayerScore >= POINTS_FOR_WIN) {
+ sLeftPlayerScore = 0;
+ sRightPlayerScore = 0;
+ /*
+ * Here we use the non blocking version of blink and tone, which enables them to act simultaneously.
+ * The simple one goes like this:
+ * RightLed.blink(5, 100);
+ * playRtttlBlockingPGM(PIN_BUZZER, StarWars);
+ */
+ sLeftPlayerWins++;
+ if (sLeftPlayerWins == 1) {
+ // Play StarWars the first win
+ startPlayRtttlPGM(PIN_BUZZER, StarWars);
+ } else {
+ startPlayRandomRtttlFromArrayPGMAndPrintName(PIN_BUZZER, RTTTLMelodies, ARRAY_SIZE_MELODIES, &Serial);
+ }
+ // update both libraries to let them act simultaneously
+ // break if button is pressed after 2000 milliseconds
+ uint32_t tLastLedChangeMillis = millis();
+ uint32_t tStartCheckButtonMillis = millis();
+ while (updatePlayRtttl() && (((millis() - tStartCheckButtonMillis) < 2000) || digitalRead(PIN_RIGHT_BUTTON))) {
+ if (millis() - tLastLedChangeMillis > 200) {
+ tLastLedChangeMillis = millis();
+ digitalWrite(PIN_RIGHT_LED, !digitalRead(PIN_RIGHT_LED)); // toggle LED
+ }
+ }
+ digitalWrite(PIN_RIGHT_LED, LOW);
+ stopPlayRtttl(); // in case we left by button press
+
+ } else if (sLeftPlayerScore >= POINTS_FOR_WIN) {
+ sLeftPlayerScore = 0;
+ sRightPlayerScore = 0;
+ //Here we use the non blocking version of blink and tone, which enables them to act simultaneously.
+ sRightPlayerWins++;
+ if (sRightPlayerWins == 1) {
+ // Play MissionImpossible the first win
+ startPlayRtttlPGM(PIN_BUZZER, MissionImp);
+ } else {
+ startPlayRandomRtttlFromArrayPGMAndPrintName(PIN_BUZZER, RTTTLMelodies, ARRAY_SIZE_MELODIES, &Serial);
+ }
+ uint32_t tLastLedChangeMillis = millis();
+ uint32_t tStartCheckButtonMillis = millis();
+ while (updatePlayRtttl() && (((millis() - tStartCheckButtonMillis) < 2000) || digitalRead(PIN_LEFT_BUTTON))) {
+ if (millis() - tLastLedChangeMillis > 200) {
+ tLastLedChangeMillis = millis();
+ digitalWrite(PIN_LEFT_LED, !digitalRead(PIN_LEFT_LED)); // toggle LED
+ }
+ }
+ digitalWrite(PIN_LEFT_LED, LOW);
+ stopPlayRtttl(); // in case we left by button press
+ }
+
+#ifdef MULTI_FUNCTION_SHIELD
+ // switch buzzer off
+ digitalWrite(PIN_BUZZER, HIGH);
+#endif
+
+ // Wait before switching off LEDs
+ delay(300);
+
+ // Switching off LEDs
+#ifdef MULTI_FUNCTION_SHIELD
+ digitalWrite(PIN_RIGHT_LED, HIGH);
+ digitalWrite(PIN_LEFT_LED, HIGH);
+ digitalWrite(PIN_START_LED, HIGH);
+ digitalWrite(PIN_START_LED_2, HIGH);
+#else
+ digitalWrite(PIN_RIGHT_LED, LOW);
+ digitalWrite(PIN_LEFT_LED, LOW);
+ digitalWrite(PIN_START_LED, LOW);
+# if defined(PIN_START_LED_2)
+ pinMode(PIN_START_LED_2, LOW);
+# endif
+#endif
+
+} // loop end
+
+void blinkLEDBlocking(uint8_t aLedPin, uint8_t aBlinkCount, uint16_t aDelay) {
+ for (int i = 0; i < aBlinkCount; ++i) {
+ digitalWrite(aLedPin, HIGH);
+ delay(aDelay);
+ digitalWrite(aLedPin, LOW);
+ delay(aDelay);
+ }
+}
diff --git a/examples/ReactionTimeTestGame/TimerOne.cpp b/examples/ReactionTimeTestGame/TimerOne.cpp
new file mode 100644
index 0000000..8a287fa
--- /dev/null
+++ b/examples/ReactionTimeTestGame/TimerOne.cpp
@@ -0,0 +1,59 @@
+/*
+ * Interrupt and PWM utilities for 16 bit Timer1 on ATmega168/328
+ * Original code by Jesse Tane for http://labs.ideo.com August 2008
+ * Modified March 2009 by Jérôme Despatis and Jesse Tane for ATmega328 support
+ * Modified June 2009 by Michael Polli and Jesse Tane to fix a bug in setPeriod() which caused the timer to stop
+ * Modified Oct 2009 by Dan Clemens to work with timer1 of the ATMega1280 or Arduino Mega
+ * Modified April 2012 by Paul Stoffregen
+ * Modified again, June 2014 by Paul Stoffregen
+ * Modified July 2017 by Stoyko Dimitrov - added support for ATTiny85 except for the PWM functionality
+ *
+ * This is free software. You can redistribute it and/or modify it under
+ * the terms of Creative Commons Attribution 3.0 United States License.
+ * To view a copy of this license, visit http://creativecommons.org/licenses/by/3.0/us/
+ * or send a letter to Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA.
+ *
+ */
+
+#include "TimerOne.h"
+
+TimerOne Timer1; // preinstatiate
+
+unsigned short TimerOne::pwmPeriod = 0;
+unsigned char TimerOne::clockSelectBits = 0;
+void (*TimerOne::isrCallback)() = TimerOne::isrDefaultUnused;
+
+// interrupt service routine that wraps a user defined function supplied by attachInterrupt
+#if defined (__AVR_ATtiny85__)
+ISR(TIMER1_COMPA_vect)
+{
+ Timer1.isrCallback();
+}
+#elif defined(__AVR__)
+ISR(TIMER1_OVF_vect)
+{
+ Timer1.isrCallback();
+}
+#elif defined(__arm__) && defined(TEENSYDUINO) && (defined(KINETISK) || defined(KINETISL))
+void ftm1_isr(void)
+{
+ uint32_t sc = FTM1_SC;
+ #ifdef KINETISL
+ if (sc & 0x80) FTM1_SC = sc;
+ #else
+ if (sc & 0x80) FTM1_SC = sc & 0x7F;
+ #endif
+ Timer1.isrCallback();
+}
+#elif defined(__arm__) && defined(TEENSYDUINO) && (defined(__IMXRT1052__) || defined(__IMXRT1062__))
+void TimerOne::isr(void)
+{
+ FLEXPWM1_SM3STS = FLEXPWM_SMSTS_RF;
+ Timer1.isrCallback();
+}
+
+#endif
+
+void TimerOne::isrDefaultUnused()
+{
+}
diff --git a/examples/ReactionTimeTestGame/TimerOne.h b/examples/ReactionTimeTestGame/TimerOne.h
new file mode 100644
index 0000000..383e76d
--- /dev/null
+++ b/examples/ReactionTimeTestGame/TimerOne.h
@@ -0,0 +1,619 @@
+/*
+ * Interrupt and PWM utilities for 16 bit Timer1 on ATmega168/328
+ * Original code by Jesse Tane for http://labs.ideo.com August 2008
+ * Modified March 2009 by Jérôme Despatis and Jesse Tane for ATmega328 support
+ * Modified June 2009 by Michael Polli and Jesse Tane to fix a bug in setPeriod() which caused the timer to stop
+ * Modified April 2012 by Paul Stoffregen - portable to other AVR chips, use inline functions
+ * Modified again, June 2014 by Paul Stoffregen - support Teensy 3.x & even more AVR chips
+ * Modified July 2017 by Stoyko Dimitrov - added support for ATTiny85 except for the PWM functionality
+ *
+ *
+ * This is free software. You can redistribute it and/or modify it under
+ * the terms of Creative Commons Attribution 3.0 United States License.
+ * To view a copy of this license, visit http://creativecommons.org/licenses/by/3.0/us/
+ * or send a letter to Creative Commons, 171 Second Street, Suite 300, San Francisco, California, 94105, USA.
+ *
+ */
+
+#ifndef TimerOne_h_
+#define TimerOne_h_
+
+#include "Arduino.h"
+
+#include "known_16bit_timers.h"
+#if defined (__AVR_ATtiny85__)
+#define TIMER1_RESOLUTION 256UL // Timer1 is 8 bit
+#elif defined(__AVR__)
+#define TIMER1_RESOLUTION 65536UL // Timer1 is 16 bit
+#else
+#define TIMER1_RESOLUTION 65536UL // assume 16 bits for non-AVR chips
+#endif
+
+// Placing nearly all the code in this .h file allows the functions to be
+// inlined by the compiler. In the very common case with constant values
+// the compiler will perform all calculations and simply write constants
+// to the hardware registers (for example, setPeriod).
+
+
+class TimerOne
+{
+
+#if defined (__AVR_ATtiny85__)
+ public:
+ //****************************
+ // Configuration
+ //****************************
+ void initialize(unsigned long microseconds=1000000) __attribute__((always_inline)) {
+ TCCR1 = _BV(CTC1); //clear timer1 when it matches the value in OCR1C
+ TIMSK |= _BV(OCIE1A); //enable interrupt when OCR1A matches the timer value
+ setPeriod(microseconds);
+ }
+ void setPeriod(unsigned long microseconds) __attribute__((always_inline)) {
+ const unsigned long cycles = microseconds * ratio;
+ if (cycles < TIMER1_RESOLUTION) {
+ clockSelectBits = _BV(CS10);
+ pwmPeriod = cycles;
+ } else
+ if (cycles < TIMER1_RESOLUTION * 2UL) {
+ clockSelectBits = _BV(CS11);
+ pwmPeriod = cycles / 2;
+ } else
+ if (cycles < TIMER1_RESOLUTION * 4UL) {
+ clockSelectBits = _BV(CS11) | _BV(CS10);
+ pwmPeriod = cycles / 4;
+ } else
+ if (cycles < TIMER1_RESOLUTION * 8UL) {
+ clockSelectBits = _BV(CS12);
+ pwmPeriod = cycles / 8;
+ } else
+ if (cycles < TIMER1_RESOLUTION * 16UL) {
+ clockSelectBits = _BV(CS12) | _BV(CS10);
+ pwmPeriod = cycles / 16;
+ } else
+ if (cycles < TIMER1_RESOLUTION * 32UL) {
+ clockSelectBits = _BV(CS12) | _BV(CS11);
+ pwmPeriod = cycles / 32;
+ } else
+ if (cycles < TIMER1_RESOLUTION * 64UL) {
+ clockSelectBits = _BV(CS12) | _BV(CS11) | _BV(CS10);
+ pwmPeriod = cycles / 64UL;
+ } else
+ if (cycles < TIMER1_RESOLUTION * 128UL) {
+ clockSelectBits = _BV(CS13);
+ pwmPeriod = cycles / 128;
+ } else
+ if (cycles < TIMER1_RESOLUTION * 256UL) {
+ clockSelectBits = _BV(CS13) | _BV(CS10);
+ pwmPeriod = cycles / 256;
+ } else
+ if (cycles < TIMER1_RESOLUTION * 512UL) {
+ clockSelectBits = _BV(CS13) | _BV(CS11);
+ pwmPeriod = cycles / 512;
+ } else
+ if (cycles < TIMER1_RESOLUTION * 1024UL) {
+ clockSelectBits = _BV(CS13) | _BV(CS11) | _BV(CS10);
+ pwmPeriod = cycles / 1024;
+ } else
+ if (cycles < TIMER1_RESOLUTION * 2048UL) {
+ clockSelectBits = _BV(CS13) | _BV(CS12);
+ pwmPeriod = cycles / 2048;
+ } else
+ if (cycles < TIMER1_RESOLUTION * 4096UL) {
+ clockSelectBits = _BV(CS13) | _BV(CS12) | _BV(CS10);
+ pwmPeriod = cycles / 4096;
+ } else
+ if (cycles < TIMER1_RESOLUTION * 8192UL) {
+ clockSelectBits = _BV(CS13) | _BV(CS12) | _BV(CS11);
+ pwmPeriod = cycles / 8192;
+ } else
+ if (cycles < TIMER1_RESOLUTION * 16384UL) {
+ clockSelectBits = _BV(CS13) | _BV(CS12) | _BV(CS11) | _BV(CS10);
+ pwmPeriod = cycles / 16384;
+ } else {
+ clockSelectBits = _BV(CS13) | _BV(CS12) | _BV(CS11) | _BV(CS10);
+ pwmPeriod = TIMER1_RESOLUTION - 1;
+ }
+ OCR1A = pwmPeriod;
+ OCR1C = pwmPeriod;
+ TCCR1 = _BV(CTC1) | clockSelectBits;
+ }
+
+ //****************************
+ // Run Control
+ //****************************
+ void start() __attribute__((always_inline)) {
+ TCCR1 = 0;
+ TCNT1 = 0;
+ resume();
+ }
+ void stop() __attribute__((always_inline)) {
+ TCCR1 = _BV(CTC1);
+ }
+ void restart() __attribute__((always_inline)) {
+ start();
+ }
+ void resume() __attribute__((always_inline)) {
+ TCCR1 = _BV(CTC1) | clockSelectBits;
+ }
+
+ //****************************
+ // PWM outputs
+ //****************************
+ //Not implemented yet for ATTiny85
+ //TO DO
+
+ //****************************
+ // Interrupt Function
+ //****************************
+ void attachInterrupt(void (*isr)()) __attribute__((always_inline)) {
+ isrCallback = isr;
+ TIMSK |= _BV(OCIE1A);
+ }
+ void attachInterrupt(void (*isr)(), unsigned long microseconds) __attribute__((always_inline)) {
+ if(microseconds > 0) setPeriod(microseconds);
+ attachInterrupt(isr);
+ }
+ void detachInterrupt() __attribute__((always_inline)) {
+ //TIMSK = 0; // Timer 0 and Timer 1 both use TIMSK register so setting it to 0 will override settings for Timer1 as well
+ TIMSK &= ~_BV(OCIE1A);
+ }
+ static void (*isrCallback)();
+ static void isrDefaultUnused();
+
+ private:
+ static unsigned short pwmPeriod;
+ static unsigned char clockSelectBits;
+ static const byte ratio = (F_CPU)/ ( 1000000 );
+
+#elif defined(__AVR__)
+
+#if defined (__AVR_ATmega8__)
+ //in some io definitions for older microcontrollers TIMSK is used instead of TIMSK1
+ #define TIMSK1 TIMSK
+#endif
+
+ public:
+ //****************************
+ // Configuration
+ //****************************
+ void initialize(unsigned long microseconds=1000000) __attribute__((always_inline)) {
+ TCCR1B = _BV(WGM13); // set mode as phase and frequency correct pwm, stop the timer
+ TCCR1A = 0; // clear control register A
+ setPeriod(microseconds);
+ }
+ void setPeriod(unsigned long microseconds) __attribute__((always_inline)) {
+ const unsigned long cycles = ((F_CPU/100000 * microseconds) / 20);
+ if (cycles < TIMER1_RESOLUTION) {
+ clockSelectBits = _BV(CS10);
+ pwmPeriod = cycles;
+ } else
+ if (cycles < TIMER1_RESOLUTION * 8) {
+ clockSelectBits = _BV(CS11);
+ pwmPeriod = cycles / 8;
+ } else
+ if (cycles < TIMER1_RESOLUTION * 64) {
+ clockSelectBits = _BV(CS11) | _BV(CS10);
+ pwmPeriod = cycles / 64;
+ } else
+ if (cycles < TIMER1_RESOLUTION * 256) {
+ clockSelectBits = _BV(CS12);
+ pwmPeriod = cycles / 256;
+ } else
+ if (cycles < TIMER1_RESOLUTION * 1024) {
+ clockSelectBits = _BV(CS12) | _BV(CS10);
+ pwmPeriod = cycles / 1024;
+ } else {
+ clockSelectBits = _BV(CS12) | _BV(CS10);
+ pwmPeriod = TIMER1_RESOLUTION - 1;
+ }
+ ICR1 = pwmPeriod;
+ TCCR1B = _BV(WGM13) | clockSelectBits;
+ }
+
+ //****************************
+ // Run Control
+ //****************************
+ void start() __attribute__((always_inline)) {
+ TCCR1B = 0;
+ TCNT1 = 0; // TODO: does this cause an undesired interrupt?
+ resume();
+ }
+ void stop() __attribute__((always_inline)) {
+ TCCR1B = _BV(WGM13);
+ }
+ void restart() __attribute__((always_inline)) {
+ start();
+ }
+ void resume() __attribute__((always_inline)) {
+ TCCR1B = _BV(WGM13) | clockSelectBits;
+ }
+
+ //****************************
+ // PWM outputs
+ //****************************
+ void setPwmDuty(char pin, unsigned int duty) __attribute__((always_inline)) {
+ unsigned long dutyCycle = pwmPeriod;
+ dutyCycle *= duty;
+ dutyCycle >>= 10;
+ if (pin == TIMER1_A_PIN) OCR1A = dutyCycle;
+ #ifdef TIMER1_B_PIN
+ else if (pin == TIMER1_B_PIN) OCR1B = dutyCycle;
+ #endif
+ #ifdef TIMER1_C_PIN
+ else if (pin == TIMER1_C_PIN) OCR1C = dutyCycle;
+ #endif
+ }
+ void pwm(char pin, unsigned int duty) __attribute__((always_inline)) {
+ if (pin == TIMER1_A_PIN) { pinMode(TIMER1_A_PIN, OUTPUT); TCCR1A |= _BV(COM1A1); }
+ #ifdef TIMER1_B_PIN
+ else if (pin == TIMER1_B_PIN) { pinMode(TIMER1_B_PIN, OUTPUT); TCCR1A |= _BV(COM1B1); }
+ #endif
+ #ifdef TIMER1_C_PIN
+ else if (pin == TIMER1_C_PIN) { pinMode(TIMER1_C_PIN, OUTPUT); TCCR1A |= _BV(COM1C1); }
+ #endif
+ setPwmDuty(pin, duty);
+ TCCR1B = _BV(WGM13) | clockSelectBits;
+ }
+ void pwm(char pin, unsigned int duty, unsigned long microseconds) __attribute__((always_inline)) {
+ if (microseconds > 0) setPeriod(microseconds);
+ pwm(pin, duty);
+ }
+ void disablePwm(char pin) __attribute__((always_inline)) {
+ if (pin == TIMER1_A_PIN) TCCR1A &= ~_BV(COM1A1);
+ #ifdef TIMER1_B_PIN
+ else if (pin == TIMER1_B_PIN) TCCR1A &= ~_BV(COM1B1);
+ #endif
+ #ifdef TIMER1_C_PIN
+ else if (pin == TIMER1_C_PIN) TCCR1A &= ~_BV(COM1C1);
+ #endif
+ }
+
+ //****************************
+ // Interrupt Function
+ //****************************
+
+ void attachInterrupt(void (*isr)()) __attribute__((always_inline)) {
+ isrCallback = isr;
+ TIMSK1 = _BV(TOIE1);
+ }
+ void attachInterrupt(void (*isr)(), unsigned long microseconds) __attribute__((always_inline)) {
+ if(microseconds > 0) setPeriod(microseconds);
+ attachInterrupt(isr);
+ }
+ void detachInterrupt() __attribute__((always_inline)) {
+ TIMSK1 = 0;
+ }
+ static void (*isrCallback)();
+ static void isrDefaultUnused();
+
+ private:
+ // properties
+ static unsigned short pwmPeriod;
+ static unsigned char clockSelectBits;
+
+
+
+
+
+
+#elif defined(__arm__) && defined(TEENSYDUINO) && (defined(KINETISK) || defined(KINETISL))
+
+#if defined(KINETISK)
+#define F_TIMER F_BUS
+#elif defined(KINETISL)
+#define F_TIMER (F_PLL/2)
+#endif
+
+// Use only 15 bit resolution. From K66 reference manual, 45.5.7 page 1200:
+// The CPWM pulse width (duty cycle) is determined by 2 x (CnV - CNTIN) and the
+// period is determined by 2 x (MOD - CNTIN). See the following figure. MOD must be
+// kept in the range of 0x0001 to 0x7FFF because values outside this range can produce
+// ambiguous results.
+#undef TIMER1_RESOLUTION
+#define TIMER1_RESOLUTION 32768
+
+ public:
+ //****************************
+ // Configuration
+ //****************************
+ void initialize(unsigned long microseconds=1000000) __attribute__((always_inline)) {
+ setPeriod(microseconds);
+ }
+ void setPeriod(unsigned long microseconds) __attribute__((always_inline)) {
+ const unsigned long cycles = (F_TIMER / 2000000) * microseconds;
+ // A much faster if-else
+ // This is like a binary serch tree and no more than 3 conditions are evaluated.
+ // I haven't checked if this becomes significantly longer ASM than the simple ladder.
+ // It looks very similar to the ladder tho: same # of if's and else's
+
+ /*
+ // This code does not work properly in all cases :(
+ // https://github.com/PaulStoffregen/TimerOne/issues/17
+ if (cycles < TIMER1_RESOLUTION * 16) {
+ if (cycles < TIMER1_RESOLUTION * 4) {
+ if (cycles < TIMER1_RESOLUTION) {
+ clockSelectBits = 0;
+ pwmPeriod = cycles;
+ }else{
+ clockSelectBits = 1;
+ pwmPeriod = cycles >> 1;
+ }
+ }else{
+ if (cycles < TIMER1_RESOLUTION * 8) {
+ clockSelectBits = 3;
+ pwmPeriod = cycles >> 3;
+ }else{
+ clockSelectBits = 4;
+ pwmPeriod = cycles >> 4;
+ }
+ }
+ }else{
+ if (cycles > TIMER1_RESOLUTION * 64) {
+ if (cycles > TIMER1_RESOLUTION * 128) {
+ clockSelectBits = 7;
+ pwmPeriod = TIMER1_RESOLUTION - 1;
+ }else{
+ clockSelectBits = 7;
+ pwmPeriod = cycles >> 7;
+ }
+ }
+ else{
+ if (cycles > TIMER1_RESOLUTION * 32) {
+ clockSelectBits = 6;
+ pwmPeriod = cycles >> 6;
+ }else{
+ clockSelectBits = 5;
+ pwmPeriod = cycles >> 5;
+ }
+ }
+ }
+ */
+ if (cycles < TIMER1_RESOLUTION) {
+ clockSelectBits = 0;
+ pwmPeriod = cycles;
+ } else
+ if (cycles < TIMER1_RESOLUTION * 2) {
+ clockSelectBits = 1;
+ pwmPeriod = cycles >> 1;
+ } else
+ if (cycles < TIMER1_RESOLUTION * 4) {
+ clockSelectBits = 2;
+ pwmPeriod = cycles >> 2;
+ } else
+ if (cycles < TIMER1_RESOLUTION * 8) {
+ clockSelectBits = 3;
+ pwmPeriod = cycles >> 3;
+ } else
+ if (cycles < TIMER1_RESOLUTION * 16) {
+ clockSelectBits = 4;
+ pwmPeriod = cycles >> 4;
+ } else
+ if (cycles < TIMER1_RESOLUTION * 32) {
+ clockSelectBits = 5;
+ pwmPeriod = cycles >> 5;
+ } else
+ if (cycles < TIMER1_RESOLUTION * 64) {
+ clockSelectBits = 6;
+ pwmPeriod = cycles >> 6;
+ } else
+ if (cycles < TIMER1_RESOLUTION * 128) {
+ clockSelectBits = 7;
+ pwmPeriod = cycles >> 7;
+ } else {
+ clockSelectBits = 7;
+ pwmPeriod = TIMER1_RESOLUTION - 1;
+ }
+
+ uint32_t sc = FTM1_SC;
+ FTM1_SC = 0;
+ FTM1_MOD = pwmPeriod;
+ FTM1_SC = FTM_SC_CLKS(1) | FTM_SC_CPWMS | clockSelectBits | (sc & FTM_SC_TOIE);
+ }
+
+ //****************************
+ // Run Control
+ //****************************
+ void start() __attribute__((always_inline)) {
+ stop();
+ FTM1_CNT = 0;
+ resume();
+ }
+ void stop() __attribute__((always_inline)) {
+ FTM1_SC = FTM1_SC & (FTM_SC_TOIE | FTM_SC_CPWMS | FTM_SC_PS(7));
+ }
+ void restart() __attribute__((always_inline)) {
+ start();
+ }
+ void resume() __attribute__((always_inline)) {
+ FTM1_SC = (FTM1_SC & (FTM_SC_TOIE | FTM_SC_PS(7))) | FTM_SC_CPWMS | FTM_SC_CLKS(1);
+ }
+
+ //****************************
+ // PWM outputs
+ //****************************
+ void setPwmDuty(char pin, unsigned int duty) __attribute__((always_inline)) {
+ unsigned long dutyCycle = pwmPeriod;
+ dutyCycle *= duty;
+ dutyCycle >>= 10;
+ if (pin == TIMER1_A_PIN) {
+ FTM1_C0V = dutyCycle;
+ } else if (pin == TIMER1_B_PIN) {
+ FTM1_C1V = dutyCycle;
+ }
+ }
+ void pwm(char pin, unsigned int duty) __attribute__((always_inline)) {
+ setPwmDuty(pin, duty);
+ if (pin == TIMER1_A_PIN) {
+ *portConfigRegister(TIMER1_A_PIN) = PORT_PCR_MUX(3) | PORT_PCR_DSE | PORT_PCR_SRE;
+ } else if (pin == TIMER1_B_PIN) {
+ *portConfigRegister(TIMER1_B_PIN) = PORT_PCR_MUX(3) | PORT_PCR_DSE | PORT_PCR_SRE;
+ }
+ }
+ void pwm(char pin, unsigned int duty, unsigned long microseconds) __attribute__((always_inline)) {
+ if (microseconds > 0) setPeriod(microseconds);
+ pwm(pin, duty);
+ }
+ void disablePwm(char pin) __attribute__((always_inline)) {
+ if (pin == TIMER1_A_PIN) {
+ *portConfigRegister(TIMER1_A_PIN) = 0;
+ } else if (pin == TIMER1_B_PIN) {
+ *portConfigRegister(TIMER1_B_PIN) = 0;
+ }
+ }
+
+ //****************************
+ // Interrupt Function
+ //****************************
+ void attachInterrupt(void (*isr)()) __attribute__((always_inline)) {
+ isrCallback = isr;
+ FTM1_SC |= FTM_SC_TOIE;
+ NVIC_ENABLE_IRQ(IRQ_FTM1);
+ }
+ void attachInterrupt(void (*isr)(), unsigned long microseconds) __attribute__((always_inline)) {
+ if(microseconds > 0) setPeriod(microseconds);
+ attachInterrupt(isr);
+ }
+ void detachInterrupt() __attribute__((always_inline)) {
+ FTM1_SC &= ~FTM_SC_TOIE;
+ NVIC_DISABLE_IRQ(IRQ_FTM1);
+ }
+ static void (*isrCallback)();
+ static void isrDefaultUnused();
+
+ private:
+ // properties
+ static unsigned short pwmPeriod;
+ static unsigned char clockSelectBits;
+
+#undef F_TIMER
+
+#elif defined(__arm__) && defined(TEENSYDUINO) && (defined(__IMXRT1052__) || defined(__IMXRT1062__))
+
+ public:
+ //****************************
+ // Configuration
+ //****************************
+ void initialize(unsigned long microseconds=1000000) __attribute__((always_inline)) {
+ setPeriod(microseconds);
+ }
+ void setPeriod(unsigned long microseconds) __attribute__((always_inline)) {
+ uint32_t period = (float)F_BUS_ACTUAL * (float)microseconds * 0.0000005f;
+ uint32_t prescale = 0;
+ while (period > 32767) {
+ period = period >> 1;
+ if (++prescale > 7) {
+ prescale = 7; // when F_BUS is 150 MHz, longest
+ period = 32767; // period is 55922 us (~17.9 Hz)
+ break;
+ }
+ }
+ //Serial.printf("setPeriod, period=%u, prescale=%u\n", period, prescale);
+ FLEXPWM1_FCTRL0 |= FLEXPWM_FCTRL0_FLVL(8); // logic high = fault
+ FLEXPWM1_FSTS0 = 0x0008; // clear fault status
+ FLEXPWM1_MCTRL |= FLEXPWM_MCTRL_CLDOK(8);
+ FLEXPWM1_SM3CTRL2 = FLEXPWM_SMCTRL2_INDEP;
+ FLEXPWM1_SM3CTRL = FLEXPWM_SMCTRL_HALF | FLEXPWM_SMCTRL_PRSC(prescale);
+ FLEXPWM1_SM3INIT = -period;
+ FLEXPWM1_SM3VAL0 = 0;
+ FLEXPWM1_SM3VAL1 = period;
+ FLEXPWM1_SM3VAL2 = 0;
+ FLEXPWM1_SM3VAL3 = 0;
+ FLEXPWM1_SM3VAL4 = 0;
+ FLEXPWM1_SM3VAL5 = 0;
+ FLEXPWM1_MCTRL |= FLEXPWM_MCTRL_LDOK(8) | FLEXPWM_MCTRL_RUN(8);
+ pwmPeriod = period;
+ }
+ //****************************
+ // Run Control
+ //****************************
+ void start() __attribute__((always_inline)) {
+ stop();
+ // TODO: how to force counter back to zero?
+ resume();
+ }
+ void stop() __attribute__((always_inline)) {
+ FLEXPWM1_MCTRL &= ~FLEXPWM_MCTRL_RUN(8);
+ }
+ void restart() __attribute__((always_inline)) {
+ start();
+ }
+ void resume() __attribute__((always_inline)) {
+ FLEXPWM1_MCTRL |= FLEXPWM_MCTRL_RUN(8);
+ }
+
+ //****************************
+ // PWM outputs
+ //****************************
+ void setPwmDuty(char pin, unsigned int duty) __attribute__((always_inline)) {
+ if (duty > 1023) duty = 1023;
+ int dutyCycle = (pwmPeriod * duty) >> 10;
+ //Serial.printf("setPwmDuty, period=%u\n", dutyCycle);
+ if (pin == TIMER1_A_PIN) {
+ FLEXPWM1_MCTRL |= FLEXPWM_MCTRL_CLDOK(8);
+ FLEXPWM1_SM3VAL5 = dutyCycle;
+ FLEXPWM1_SM3VAL4 = -dutyCycle;
+ FLEXPWM1_MCTRL |= FLEXPWM_MCTRL_LDOK(8);
+ } else if (pin == TIMER1_B_PIN) {
+ FLEXPWM1_MCTRL |= FLEXPWM_MCTRL_CLDOK(8);
+ FLEXPWM1_SM3VAL3 = dutyCycle;
+ FLEXPWM1_SM3VAL2 = -dutyCycle;
+ FLEXPWM1_MCTRL |= FLEXPWM_MCTRL_LDOK(8);
+ }
+ }
+ void pwm(char pin, unsigned int duty) __attribute__((always_inline)) {
+ setPwmDuty(pin, duty);
+ if (pin == TIMER1_A_PIN) {
+ FLEXPWM1_OUTEN |= FLEXPWM_OUTEN_PWMB_EN(8);
+ IOMUXC_SW_MUX_CTL_PAD_GPIO_B1_01 = 6; // pin 6 FLEXPWM1_PWM3_B
+ } else if (pin == TIMER1_B_PIN) {
+ FLEXPWM1_OUTEN |= FLEXPWM_OUTEN_PWMA_EN(8);
+ IOMUXC_SW_MUX_CTL_PAD_GPIO_B1_00 = 6; // pin 7 FLEXPWM1_PWM3_A
+ }
+ }
+ void pwm(char pin, unsigned int duty, unsigned long microseconds) __attribute__((always_inline)) {
+ if (microseconds > 0) setPeriod(microseconds);
+ pwm(pin, duty);
+ }
+ void disablePwm(char pin) __attribute__((always_inline)) {
+ if (pin == TIMER1_A_PIN) {
+ IOMUXC_SW_MUX_CTL_PAD_GPIO_B1_01 = 5; // pin 6 FLEXPWM1_PWM3_B
+ FLEXPWM1_OUTEN &= ~FLEXPWM_OUTEN_PWMB_EN(8);
+ } else if (pin == TIMER1_B_PIN) {
+ IOMUXC_SW_MUX_CTL_PAD_GPIO_B1_00 = 5; // pin 7 FLEXPWM1_PWM3_A
+ FLEXPWM1_OUTEN &= ~FLEXPWM_OUTEN_PWMA_EN(8);
+ }
+ }
+ //****************************
+ // Interrupt Function
+ //****************************
+ void attachInterrupt(void (*f)()) __attribute__((always_inline)) {
+ isrCallback = f;
+ attachInterruptVector(IRQ_FLEXPWM1_3, &isr);
+ FLEXPWM1_SM3STS = FLEXPWM_SMSTS_RF;
+ FLEXPWM1_SM3INTEN = FLEXPWM_SMINTEN_RIE;
+ NVIC_ENABLE_IRQ(IRQ_FLEXPWM1_3);
+ }
+ void attachInterrupt(void (*f)(), unsigned long microseconds) __attribute__((always_inline)) {
+ if(microseconds > 0) setPeriod(microseconds);
+ attachInterrupt(f);
+ }
+ void detachInterrupt() __attribute__((always_inline)) {
+ NVIC_DISABLE_IRQ(IRQ_FLEXPWM1_3);
+ FLEXPWM1_SM3INTEN = 0;
+ }
+ static void isr(void);
+ static void (*isrCallback)();
+ static void isrDefaultUnused();
+
+ private:
+ // properties
+ static unsigned short pwmPeriod;
+ static unsigned char clockSelectBits;
+
+#endif
+};
+
+extern TimerOne Timer1;
+
+#endif
+
diff --git a/examples/ReactionTimeTestGame/known_16bit_timers.h b/examples/ReactionTimeTestGame/known_16bit_timers.h
new file mode 100644
index 0000000..01cd4e9
--- /dev/null
+++ b/examples/ReactionTimeTestGame/known_16bit_timers.h
@@ -0,0 +1,169 @@
+#ifndef known_16bit_timers_header_
+#define known_16bit_timers_header_
+
+// Wiring-S
+//
+#if defined(__AVR_ATmega644P__) && defined(WIRING)
+ #define TIMER1_A_PIN 5
+ #define TIMER1_B_PIN 4
+ #define TIMER1_ICP_PIN 6
+
+// Teensy 2.0
+//
+#elif defined(__AVR_ATmega32U4__) && defined(CORE_TEENSY)
+ #define TIMER1_A_PIN 14
+ #define TIMER1_B_PIN 15
+ #define TIMER1_C_PIN 4
+ #define TIMER1_ICP_PIN 22
+ #define TIMER1_CLK_PIN 11
+ #define TIMER3_A_PIN 9
+ #define TIMER3_ICP_PIN 10
+
+// Teensy++ 2.0
+#elif defined(__AVR_AT90USB1286__) && defined(CORE_TEENSY)
+ #define TIMER1_A_PIN 25
+ #define TIMER1_B_PIN 26
+ #define TIMER1_C_PIN 27
+ #define TIMER1_ICP_PIN 4
+ #define TIMER1_CLK_PIN 6
+ #define TIMER3_A_PIN 16
+ #define TIMER3_B_PIN 15
+ #define TIMER3_C_PIN 14
+ #define TIMER3_ICP_PIN 17
+ #define TIMER3_CLK_PIN 13
+
+// Teensy 3.0
+//
+#elif defined(__MK20DX128__)
+ #define TIMER1_A_PIN 3
+ #define TIMER1_B_PIN 4
+ #define TIMER1_ICP_PIN 4
+
+// Teensy 3.1 / Teensy 3.2
+//
+#elif defined(__MK20DX256__)
+ #define TIMER1_A_PIN 3
+ #define TIMER1_B_PIN 4
+ #define TIMER1_ICP_PIN 4
+ #define TIMER3_A_PIN 32
+ #define TIMER3_B_PIN 25
+ #define TIMER3_ICP_PIN 32
+
+// Teensy 3.5 / Teensy 3.6
+//
+#elif defined(__MK64FX512__) || defined(__MK66FX1M0__)
+ #define TIMER1_A_PIN 3
+ #define TIMER1_B_PIN 4
+ #define TIMER1_ICP_PIN 4
+ #define TIMER3_A_PIN 29
+ #define TIMER3_B_PIN 30
+ #define TIMER3_ICP_PIN 29
+
+// Teensy-LC
+//
+#elif defined(__MKL26Z64__)
+ #define TIMER1_A_PIN 16
+ #define TIMER1_B_PIN 17
+ #define TIMER1_ICP_PIN 17
+ #define TIMER3_A_PIN 3
+ #define TIMER3_B_PIN 4
+ #define TIMER3_ICP_PIN 4
+
+// Teensy 4
+//
+#elif defined(__IMXRT1052__) || defined(__IMXRT1062__)
+ #define TIMER1_A_PIN 6
+ #define TIMER1_B_PIN 7
+ #define TIMER3_A_PIN 8
+ #define TIMER3_B_PIN 9
+
+// Arduino Mega
+//
+#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
+ #define TIMER1_A_PIN 11
+ #define TIMER1_B_PIN 12
+ #define TIMER1_C_PIN 13
+ #define TIMER3_A_PIN 5
+ #define TIMER3_B_PIN 2
+ #define TIMER3_C_PIN 3
+ #define TIMER4_A_PIN 6
+ #define TIMER4_B_PIN 7
+ #define TIMER4_C_PIN 8
+ #define TIMER4_ICP_PIN 49
+ #define TIMER5_A_PIN 46
+ #define TIMER5_B_PIN 45
+ #define TIMER5_C_PIN 44
+ #define TIMER3_ICP_PIN 48
+ #define TIMER3_CLK_PIN 47
+
+// Arduino Leonardo, Yun, etc
+//
+#elif defined(__AVR_ATmega32U4__)
+ #define TIMER1_A_PIN 9
+ #define TIMER1_B_PIN 10
+ #define TIMER1_C_PIN 11
+ #define TIMER1_ICP_PIN 4
+ #define TIMER1_CLK_PIN 12
+ #define TIMER3_A_PIN 5
+ #define TIMER3_ICP_PIN 13
+
+// Uno, Duemilanove, LilyPad, etc
+//
+#elif defined (__AVR_ATmega168__) || defined (__AVR_ATmega328P__) || defined (__AVR_ATmega328__) || defined (__AVR_ATmega8__)
+ #define TIMER1_A_PIN 9
+ #define TIMER1_B_PIN 10
+ #define TIMER1_ICP_PIN 8
+ #define TIMER1_CLK_PIN 5
+
+ // attiny167
+//
+#elif defined (__AVR_ATtiny167__)
+ #define TIMER1_A_PIN 14
+ #define TIMER1_B_PIN 11
+ //#define TIMER1_ICP_PIN 8
+ //#define TIMER1_CLK_PIN 5
+
+// Sanguino
+//
+#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__)
+ #define TIMER1_A_PIN 13
+ #define TIMER1_B_PIN 12
+ #define TIMER1_ICP_PIN 14
+ #define TIMER1_CLK_PIN 1
+
+// Wildfire - Wicked Devices
+//
+#elif defined(__AVR_ATmega1284P__) && defined(WILDFIRE_VERSION) && WILDFIRE_VERSION >= 3
+ #define TIMER1_A_PIN 5 // PD5
+ #define TIMER1_B_PIN 8 // PD4
+ #define TIMER1_ICP_PIN 6 // PD6
+ #define TIMER1_CLK_PIN 23 // PB1
+ #define TIMER3_A_PIN 12 // PB6
+ #define TIMER3_B_PIN 13 // PB7
+ #define TIMER3_ICP_PIN 9 // PB5
+ #define TIMER3_CLK_PIN 0 // PD0
+#elif defined(__AVR_ATmega1284P__) && defined(WILDFIRE_VERSION) && WILDFIRE_VERSION < 3
+ #define TIMER1_A_PIN 5 // PD5
+ #define TIMER1_B_PIN 4 // PD4
+ #define TIMER1_ICP_PIN 6 // PD6
+ #define TIMER1_CLK_PIN 15 // PB1
+ #define TIMER3_A_PIN 12 // PB6
+ #define TIMER3_B_PIN 13 // PB7
+ #define TIMER3_ICP_PIN 11 // PB5
+ #define TIMER3_CLK_PIN 0 // PD0
+
+// Mighty-1284 - Maniacbug
+//
+#elif defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega1284__)
+ #define TIMER1_A_PIN 12 // PD5
+ #define TIMER1_B_PIN 13 // PD4
+ #define TIMER1_ICP_PIN 14 // PD6
+ #define TIMER1_CLK_PIN 1 // PB1
+ #define TIMER3_A_PIN 6 // PB6
+ #define TIMER3_B_PIN 7 // PB7
+ #define TIMER3_ICP_PIN 5 // PB5
+ #define TIMER3_CLK_PIN 8 // PD0
+
+#endif
+
+#endif
diff --git a/library.json b/library.json
index 6f38c91..2feb470 100644
--- a/library.json
+++ b/library.json
@@ -6,7 +6,7 @@
"type": "git",
"url": "https://github.com/ArminJo/PlayRtttl"
},
- "version": "1.4.1",
+ "version": "1.4.2",
"exclude": "pictures",
"authors": {
"name": "Armin Joachimsmeyer",
diff --git a/library.properties b/library.properties
index 6d83460..3d642a6 100644
--- a/library.properties
+++ b/library.properties
@@ -1,9 +1,9 @@
name=PlayRtttl
-version=1.4.1
+version=1.4.2
author=Armin Joachimsmeyer
maintainer=Armin Joachimsmeyer
sentence=Plays RTTTL / RTX melodies/ringtones from FLASH or RAM.
-paragraph=Improved Arduino library version of the RTTTL.pde example code written by Brett Hagman.
Uses the Arduino tone() function.
Fatures:- Non blocking version.
- support all octaves below 8.
- Name output function.
- Sample melodies.
- Random play of melodies array.
- Supports inverted tone pin logic i.e. tone pin is HIGH at playing a pause.
- Accepts even invalid specified RTTTL files found in the wild.
- Support of RTX format.
- setNumberOfLoops() and setDefaultStyle() functions.
New: Removed blocking wait for ATmega32U4 Serial in examples.
+paragraph=Improved Arduino library version of the RTTTL.pde example code written by Brett Hagman.
Uses the Arduino tone() function.
Fatures:- Non blocking version.
- support all octaves below 8.
- Name output function.
- Sample melodies.
- Random play of melodies array.
- Supports inverted tone pin logic i.e. tone pin is HIGH at playing a pause.
- Accepts even invalid specified RTTTL files found in the wild.
- Support of RTX format.
- setNumberOfLoops() and setDefaultStyle() functions.
New: New example ReactionTimeTestGame.
category=Other
url=https://github.com/ArminJo/PlayRtttl
architectures=*
diff --git a/src/PlayRtttl.cpp b/src/PlayRtttl.cpp
index 99556f6..ee7d05a 100644
--- a/src/PlayRtttl.cpp
+++ b/src/PlayRtttl.cpp
@@ -12,7 +12,7 @@
*
* The example melodies may have copyrights you have to respect.
*
- * This file is part of PlayRttl https://github.com/ArminJo/PlayRttl.
+ * This file is part of PlayRttl https://github.com/ArminJo/PlayRtttl.
*
* PlayRttl is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -26,7 +26,6 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
- *
*/
#include
@@ -75,7 +74,7 @@ void playRtttlBlocking(uint8_t aTonePin, const char *aRTTTLArrayPtr) {
* Version for RTTTL Data in RAM. Ie. you must call updatePlayRtttl() in your loop.
* Since we do not need all the pgm_read_byte() calls this version is more simple and maybe better to understand.
*/
-void startPlayRtttl(uint8_t aTonePin, const char * aRTTTLArrayPtr, void (*aOnComplete)()) {
+void startPlayRtttl(uint8_t aTonePin, const char *aRTTTLArrayPtr, void (*aOnComplete)()) {
sPlayRtttlState.Flags.IsPGMMemory = false;
sPlayRtttlState.OnComplete = aOnComplete;
sPlayRtttlState.TonePin = aTonePin;
@@ -249,7 +248,7 @@ void stopPlayRtttl(void) {
sPlayRtttlState.Flags.IsRunning = false;
}
-char getNextCharFromRTTLArray(const char* aRTTTLArrayPtr) {
+char getNextCharFromRTTLArray(const char *aRTTTLArrayPtr) {
if (sPlayRtttlState.Flags.IsPGMMemory) {
return pgm_read_byte(aRTTTLArrayPtr);
}
@@ -272,7 +271,7 @@ bool updatePlayRtttl(void) {
long tMillis = millis();
if (tMillis >= sPlayRtttlState.MillisOfNextAction) {
- const char * tRTTTLArrayPtr = sPlayRtttlState.NextTonePointer;
+ const char *tRTTTLArrayPtr = sPlayRtttlState.NextTonePointer;
char tChar;
tChar = getNextCharFromRTTLArray(tRTTTLArrayPtr);
@@ -408,7 +407,7 @@ bool updatePlayRtttl(void) {
/*
* now play the note
*/
-# if defined (SUPPORT_RTX_EXTENSIONS)
+# if defined(SUPPORT_RTX_EXTENSIONS)
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
unsigned long tDurationOfTone;
#endif
@@ -422,7 +421,7 @@ bool updatePlayRtttl(void) {
#if defined(ESP32)
ledcWriteTone(0, tFrequency);
#else
-# if defined (SUPPORT_RTX_EXTENSIONS)
+# if defined(SUPPORT_RTX_EXTENSIONS)
if (sPlayRtttlState.StyleDivisorValue != 0) {
/*
* handle style parameter, compute duration of tone output for note and do rounding for integer division
@@ -440,7 +439,7 @@ bool updatePlayRtttl(void) {
# endif
# if defined(TCCR2A)
- if(sPlayRtttlState.TonePin == 11) {
+ if (sPlayRtttlState.TonePin == 11) {
// switch to direct hardware toggle output at OC2A / pin 11
TCCR2A |= _BV(COM2A0);
}
@@ -482,7 +481,7 @@ bool updatePlayRtttl(void) {
sPointerToSerial->print(Notes[tNote] >> (NOTES_OCTAVE - tOctave), 10);
# endif
sPointerToSerial->print(F(" Hz for "));
-# if defined (SUPPORT_RTX_EXTENSIONS)
+# if defined(SUPPORT_RTX_EXTENSIONS)
if (sPlayRtttlState.StyleDivisorValue != 0 && tNote <= 12) {
sPointerToSerial->print(tDurationOfTone, 10);
sPointerToSerial->print(F(" of "));
@@ -498,7 +497,7 @@ bool updatePlayRtttl(void) {
return true;
}
-void getRtttlName(const char *aRTTTLArrayPtr, char * aBuffer, uint8_t aBuffersize) {
+void getRtttlName(const char *aRTTTLArrayPtr, char *aBuffer, uint8_t aBuffersize) {
char tChar = *aRTTTLArrayPtr++;
while (tChar != ':' && aBuffersize > 1) {
*aBuffer++ = tChar;
@@ -512,7 +511,7 @@ void getRtttlName(const char *aRTTTLArrayPtr, char * aBuffer, uint8_t aBuffersiz
* Prints text "Now playing: Song xy"
* call it e.g. printNamePGM(RTTTLMelodies[tRandomIndex], &Serial);
*/
-void printName(const char *aRTTTLArrayPtr, Print * aSerial) {
+void printName(const char *aRTTTLArrayPtr, Print *aSerial) {
char StringBuffer[16];
aSerial->print(F("Now playing: "));
getRtttlName(aRTTTLArrayPtr, StringBuffer, sizeof(StringBuffer));
@@ -525,7 +524,7 @@ void printName(const char *aRTTTLArrayPtr, Print * aSerial) {
* char StringBuffer[16] is sufficient for most titles.
*/
void startPlayRandomRtttlFromArray(uint8_t aTonePin, const char * const aSongArray[], uint8_t aNumberOfEntriesInSongArray,
- char* aBufferPointer, uint8_t aBufferSize, void (*aOnComplete)()) {
+ char *aBufferPointer, uint8_t aBufferSize, void (*aOnComplete)()) {
uint8_t tRandomIndex = random(0, aNumberOfEntriesInSongArray - 1);
char* tSongPtr = (char*) aSongArray[tRandomIndex];
startPlayRtttl(aTonePin, tSongPtr, aOnComplete);
@@ -536,7 +535,7 @@ void startPlayRandomRtttlFromArray(uint8_t aTonePin, const char * const aSongArr
}
void startPlayRandomRtttlFromArrayAndPrintName(uint8_t aTonePin, const char * const aSongArray[],
- uint8_t aNumberOfEntriesInSongArray, Print * aSerial, void (*aOnComplete)()) {
+ uint8_t aNumberOfEntriesInSongArray, Print *aSerial, void (*aOnComplete)()) {
uint8_t tRandomIndex = random(0, aNumberOfEntriesInSongArray - 1);
char* tSongPtr = (char*) aSongArray[tRandomIndex];
startPlayRtttl(aTonePin, tSongPtr, aOnComplete);
@@ -548,12 +547,12 @@ void startPlayRandomRtttlFromArrayAndPrintName(uint8_t aTonePin, const char * co
* Plays one of the samples from RTTTLMelodies array
*/
void playRandomRtttlSampleBlocking(uint8_t aTonePin) {
- uint8_t tRandomIndex = random(0, sizeof(RTTTLMelodies) / sizeof(char *) - 1);
+ uint8_t tRandomIndex = random(0, sizeof(RTTTLMelodies) / sizeof(char*) - 1);
char* tSongPtr = (char*) RTTTLMelodies[tRandomIndex];
playRtttlBlocking(aTonePin, tSongPtr);
}
-void playRandomRtttlSampleBlockingAndPrintName(uint8_t aTonePin, Print * aSerial) {
+void playRandomRtttlSampleBlockingAndPrintName(uint8_t aTonePin, Print *aSerial) {
uint8_t tRandomIndex = random(0, sizeof(RTTTLMelodies) / sizeof(char *) - 1);
char* tSongPtr = (char*) RTTTLMelodies[tRandomIndex];
printName(tSongPtr, aSerial);
@@ -570,7 +569,7 @@ void playRtttlBlockingPGM(uint8_t aTonePin, const char *aRTTTLArrayPtrPGM) {
/*
* Non blocking version for RTTTL Data in FLASH. Ie. you must call updatePlayRtttl() in your loop.
*/
-void startPlayRtttlPGM(uint8_t aTonePin, const char * aRTTTLArrayPtrPGM, void (*aOnComplete)()) {
+void startPlayRtttlPGM(uint8_t aTonePin, const char *aRTTTLArrayPtrPGM, void (*aOnComplete)()) {
sPlayRtttlState.Flags.IsPGMMemory = true;
sPlayRtttlState.OnComplete = aOnComplete;
sPlayRtttlState.TonePin = aTonePin;
@@ -598,7 +597,7 @@ void startPlayRtttlPGM(uint8_t aTonePin, const char * aRTTTLArrayPtrPGM, void (*
sPlayRtttlState.DefaultDuration = DEFAULT_DURATION;
sPlayRtttlState.DefaultOctave = DEFAULT_OCTAVE;
sPlayRtttlState.TimeForWholeNoteMillis = (60 * 1000L / DEFAULT_BPM) * 4;
-#if defined (SUPPORT_RTX_EXTENSIONS)
+#if defined(SUPPORT_RTX_EXTENSIONS)
sPlayRtttlState.NumberOfLoops = 1;
sPlayRtttlState.StyleDivisorValue = sDefaultStyleDivisorValue;
#endif
@@ -740,7 +739,7 @@ void startPlayRtttlPGM(uint8_t aTonePin, const char * aRTTTLArrayPtrPGM, void (*
updatePlayRtttl();
}
-void getRtttlNamePGM(const char *aRTTTLArrayPtrPGM, char * aBuffer, uint8_t aBuffersize) {
+void getRtttlNamePGM(const char *aRTTTLArrayPtrPGM, char *aBuffer, uint8_t aBuffersize) {
#if !defined(__AVR__) // Let the function work for non AVR platforms
getRtttlName(aRTTTLArrayPtrPGM, aBuffer, aBuffersize);
#else
@@ -754,7 +753,7 @@ void getRtttlNamePGM(const char *aRTTTLArrayPtrPGM, char * aBuffer, uint8_t aBuf
#endif
}
-void printNamePGM(const char *aRTTTLArrayPtrPGM, Print * aSerial) {
+void printNamePGM(const char *aRTTTLArrayPtrPGM, Print *aSerial) {
#if !defined(__AVR__) // Let the function work for non AVR platforms
printName(aRTTTLArrayPtrPGM, aSerial);
#else
@@ -772,7 +771,7 @@ void printNamePGM(const char *aRTTTLArrayPtrPGM, Print * aSerial) {
* char StringBuffer[16] is sufficient for most titles.
*/
void startPlayRandomRtttlFromArrayPGM(uint8_t aTonePin, const char * const aSongArrayPGM[], uint8_t aNumberOfEntriesInSongArrayPGM,
- char* aBufferPointer, uint8_t aBufferSize, void (*aOnComplete)()) {
+ char *aBufferPointer, uint8_t aBufferSize, void (*aOnComplete)()) {
#if !defined(__AVR__) // Let the function work for non AVR platforms
startPlayRandomRtttlFromArray(aTonePin, aSongArrayPGM, aNumberOfEntriesInSongArrayPGM, aBufferPointer, aBufferSize, aOnComplete);
#else
@@ -790,7 +789,7 @@ void startPlayRandomRtttlFromArrayPGM(uint8_t aTonePin, const char * const aSong
* !!! Songs are in an array stored in FLASH containing pointers to song arrays also stored in FLASH, see PlayRtttl.h. !!!
*/
void startPlayRandomRtttlFromArrayPGMAndPrintName(uint8_t aTonePin, const char * const aSongArrayPGM[],
- uint8_t aNumberOfEntriesInSongArrayPGM, Print * aSerial, void (*aOnComplete)()) {
+ uint8_t aNumberOfEntriesInSongArrayPGM, Print *aSerial, void (*aOnComplete)()) {
#if !defined(__AVR__) // Let the function work for non AVR platforms
startPlayRandomRtttlFromArrayAndPrintName(aTonePin, aSongArrayPGM, aNumberOfEntriesInSongArrayPGM, aSerial, aOnComplete);
#else
@@ -815,7 +814,7 @@ void playRandomRtttlSampleBlockingPGM(uint8_t aTonePin) {
#endif
}
-void playRandomRtttlSampleBlockingPGMAndPrintName(uint8_t aTonePin, Print * aSerial) {
+void playRandomRtttlSampleBlockingPGMAndPrintName(uint8_t aTonePin, Print *aSerial) {
#if !defined(__AVR__) // Let the function work for non AVR platforms
playRandomRtttlSampleBlockingAndPrintName(aTonePin, aSerial);
#else
diff --git a/src/PlayRtttl.h b/src/PlayRtttl.h
index b61e514..2feb1c3 100644
--- a/src/PlayRtttl.h
+++ b/src/PlayRtttl.h
@@ -13,7 +13,7 @@
* bhagman@roguerobotics.com
*
*
- * This file is part of PlayRttl https://github.com/ArminJo/PlayRttl.
+ * This file is part of PlayRttl https://github.com/ArminJo/PlayRtttl.
*
* PlayRttl is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -34,49 +34,17 @@
#define SRC_PLAYRTTTL_H_
#if defined(__SAM3X8E__)
-#error "Sorry no tone library for Arduino Due"
+#error Sorry no tone library for Arduino Due
#endif
#if defined(__AVR__)
#include
#endif
#include "pitches.h"
-#define VERSION_PLAY_RTTTL "1.4.1"
+#define VERSION_PLAY_RTTTL "1.4.2"
#define VERSION_PLAY_RTTTL_MAJOR 1
#define VERSION_PLAY_RTTTL_MINOR 4
-
-/*
- * Version 1.4.1 - 9/2020
- * - Removed blocking wait for ATmega32U4 Serial in examples.
- *
- * Version 1.4.0 - 1/2020
- * - Supporting direct tone output at pin 11 for ATmega328. Can be used with interrupt blocking libraries for NeoPixel etc.
- * - Use Print * instead of Stream *.
- * - Improved non-AVR compatibility.
- * - New Christmas songs example.
- *
- * Version 1.3.0 - 10/2019
- * - Support all octaves below 8.
- * - New styles '1' to '9' in addition to RTX styles 'C', 'N', 'S'.
- *
- * Version 1.2.2 - 6/2019
- * - Porting to non AVR architectures.
- *
- * Version 1.2.1 - 5/2019
- * - Natural is the new default style.
- * - New RTTTLMelodiesSmall sample array with less entries.
- * - Parameter now order independent.
- * - Modified oneMelody example.
- *
- * Version 1.2.0 - 5/2019
- * - No Serial.print statements in this library anymore, to avoid problems with different Serial implementations.
- * - Function playRandomRtttlBlocking() + startPlayRandomRtttlFromArrayPGM() do not print name now. If needed, use new functions playRandomRtttlSampleBlockingAndPrintName() + startPlayRandomRtttlFromArrayPGMAndPrintName().
- * - Printing functions have parameter (..., Print * aSerial) to print to any serial. Call it (..., &Serial) to use standard Serial;
- * - playRandomRtttlBlocking() renamed to playRandomRtttlSampleBlocking() and bug fixing.
- *
- * Version 1.1 - 5/2019
- * - new setNumberOfLoops() and setDefaultStyle() functions.
- */
+// The change log is at the bottom of the file
#if ! defined(USE_NO_RTX_EXTENSIONS) // if defined it suppresses the next 2 defines / useful for ATtinies to shrink code up to 182 bytes
// Even without `SUPPORT_RTX_EXTENSIONS` the default style is natural (Tone length = note length - 1/16)
@@ -114,33 +82,33 @@ void setDefaultStyle(uint8_t aDefaultStyleDivisorValue);
uint8_t convertStyleCharacterToDivisorValue(char aStyleCharacter);
#endif
-void getRtttlName(const char *aRTTTLArrayPtr, char * aBuffer, uint8_t aBuffersize);
-void printName(const char *aRTTTLArrayPtr, Print * aSerial);
+void getRtttlName(const char *aRTTTLArrayPtr, char *aBuffer, uint8_t aBuffersize);
+void printName(const char *aRTTTLArrayPtr, Print *aSerial);
void startPlayRtttl(uint8_t aTonePin, const char *aRTTTLArrayPtr, void (*aOnComplete)()=NULL);
void playRtttlBlocking(uint8_t aTonePin, const char *aRTTTLArrayPtr);
void startPlayRandomRtttlFromArray(uint8_t aTonePin, const char* const aSongArray[], uint8_t aNumberOfEntriesInSongArray,
- char* aBufferPointer = NULL, uint8_t aBufferSize = 0, void (*aOnComplete)()=NULL);
+ char *aBufferPointer = NULL, uint8_t aBufferSize = 0, void (*aOnComplete)()=NULL);
void startPlayRandomRtttlFromArrayAndPrintName(uint8_t aTonePin, const char* const aSongArray[],
- uint8_t aNumberOfEntriesInSongArray, Print * aSerial, void (*aOnComplete)()=NULL);
+ uint8_t aNumberOfEntriesInSongArray, Print *aSerial, void (*aOnComplete)()=NULL);
void playRandomRtttlSampleBlocking(uint8_t aTonePin);
-void playRandomRtttlSampleBlockingAndPrintName(uint8_t aTonePin, Print * aSerial);
+void playRandomRtttlSampleBlockingAndPrintName(uint8_t aTonePin, Print *aSerial);
-void getRtttlNamePGM(const char *aRTTTLArrayPtrPGM, char * aBuffer, uint8_t aBuffersize);
-void printNamePGM(const char *aRTTTLArrayPtrPGM, Print * aSerial);
+void getRtttlNamePGM(const char *aRTTTLArrayPtrPGM, char *aBuffer, uint8_t aBuffersize);
+void printNamePGM(const char *aRTTTLArrayPtrPGM, Print *aSerial);
void startPlayRtttlPGM(uint8_t aTonePin, const char *aRTTTLArrayPtrPGM, void (*aOnComplete)()=NULL);
void playRtttlBlockingPGM(uint8_t aTonePin, const char *aRTTTLArrayPtrPGM);
void startPlayRandomRtttlFromArrayPGM(uint8_t aTonePin, const char* const aSongArrayPGM[], uint8_t aNumberOfEntriesInSongArrayPGM,
- char* aBufferPointer = NULL, uint8_t aBufferSize = 0, void (*aOnComplete)()=NULL);
+ char *aBufferPointer = NULL, uint8_t aBufferSize = 0, void (*aOnComplete)()=NULL);
void startPlayRandomRtttlFromArrayPGMAndPrintName(uint8_t aTonePin, const char* const aSongArrayPGM[],
- uint8_t aNumberOfEntriesInSongArrayPGM, Print * aSerial, void (*aOnComplete)()=NULL);
+ uint8_t aNumberOfEntriesInSongArrayPGM, Print *aSerial, void (*aOnComplete)()=NULL);
void playRandomRtttlSampleBlockingPGM(uint8_t aTonePin);
-void playRandomRtttlSampleBlockingPGMAndPrintName(uint8_t aTonePin, Print * aSerial);
+void playRandomRtttlSampleBlockingPGMAndPrintName(uint8_t aTonePin, Print *aSerial);
// To be called from loop. - Returns true if tone is playing, false if tone has ended or stopped
bool updatePlayRtttl(void);
@@ -149,7 +117,7 @@ void stopPlayRtttl(void);
struct playRtttlState {
long MillisOfNextAction;
- const char * NextTonePointer;
+ const char *NextTonePointer;
struct {
uint8_t IsRunning :1; // is false after boot
@@ -170,7 +138,7 @@ struct playRtttlState {
// The divisor for the formula: Tone length = note length - note length * (1 / divisor)
// If 0 then Tone length = note length;
uint8_t StyleDivisorValue;
- const char * LastTonePointer; // used for loops
+ const char *LastTonePointer; // used for loops
#endif
};
@@ -298,4 +266,40 @@ static const char * const RTTTLChristmasMelodies[] PROGMEM = { JingleBell, Rudol
WinterWonderland, LetItSnow, Frosty, LastChristmas, AllIWant, AmazingGrace };
#define ARRAY_SIZE_CHRISTMAS_MELODIES (sizeof(RTTTLChristmasMelodies)/sizeof(const char *)) // 11
+/*
+ * Version 1.4.2 11/2020
+ * - New example ReactionTimeTestGame.
+ *
+ * Version 1.4.1 - 9/2020
+ * - Removed blocking wait for ATmega32U4 Serial in examples.
+ *
+ * Version 1.4.0 - 1/2020
+ * - Supporting direct tone output at pin 11 for ATmega328. Can be used with interrupt blocking libraries for NeoPixel etc.
+ * - Use Print * instead of Stream *.
+ * - Improved non-AVR compatibility.
+ * - New Christmas songs example.
+ *
+ * Version 1.3.0 - 10/2019
+ * - Support all octaves below 8.
+ * - New styles '1' to '9' in addition to RTX styles 'C', 'N', 'S'.
+ *
+ * Version 1.2.2 - 6/2019
+ * - Porting to non AVR architectures.
+ *
+ * Version 1.2.1 - 5/2019
+ * - Natural is the new default style.
+ * - New RTTTLMelodiesSmall sample array with less entries.
+ * - Parameter now order independent.
+ * - Modified oneMelody example.
+ *
+ * Version 1.2.0 - 5/2019
+ * - No Serial.print statements in this library anymore, to avoid problems with different Serial implementations.
+ * - Function playRandomRtttlBlocking() + startPlayRandomRtttlFromArrayPGM() do not print name now. If needed, use new functions playRandomRtttlSampleBlockingAndPrintName() + startPlayRandomRtttlFromArrayPGMAndPrintName().
+ * - Printing functions have parameter (..., Print *aSerial) to print to any serial. Call it (..., &Serial) to use standard Serial;
+ * - playRandomRtttlBlocking() renamed to playRandomRtttlSampleBlocking() and bug fixing.
+ *
+ * Version 1.1 - 5/2019
+ * - new setNumberOfLoops() and setDefaultStyle() functions.
+ */
+
#endif /* SRC_PLAYRTTTL_H_ */