commit 48bfdb909445c6708cd0e05666cd47551ef68a35
parent dca78b9a1c7d936f40aa82d2c088328c07800329
Author: Samdal <samdal@protonmail.com>
Date: Sun, 4 Jul 2021 16:24:28 +0200
attach sine and square wave to pins
Diffstat:
M | ArduinoNative.hpp | | | 98 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- |
M | README.org | | | 75 | ++++++++++++++++++++++++++++++++++++++++----------------------------------- |
2 files changed, 135 insertions(+), 38 deletions(-)
diff --git a/ArduinoNative.hpp b/ArduinoNative.hpp
@@ -108,6 +108,12 @@ float an_pin_voltage[AN_MAX_PINS] = {0};
// non-arduino functions
void an_set_voltage(const uint8_t pin, const float voltage);
+void an_request_voltage(const uint8_t pin);
+inline void an_print_timestamp();
+void an_attach_sine(const uint8_t pin, const unsigned hz = 1, const float amp = 2.5, const float dc = 2.5, const bool abs = false);
+void an_remove_sine(const uint8_t pin);
+void an_attach_square(const uint8_t pin, const unsigned hz = 1, const float duty = 0.5);
+void an_remove_square(const uint8_t pin);
// Digital I/O
bool digitalRead(const uint8_t pin);
@@ -139,6 +145,7 @@ unsigned long millis(void);
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
#define sq(x) ((x)*(x))
+#define PI 3.14159265
// Characthers
#define isAlpha(thisChar) (isalpha(thisChar))
@@ -292,13 +299,16 @@ typedef struct an_int {
an_int_mode_t mode;
} an_int_t;
std::unordered_map<uint8_t, an_int_t> an_ints;
+std::unordered_map<uint8_t, std::thread> an_sines;
+std::unordered_map<uint8_t, bool> an_sines_terminate;
+std::unordered_map<uint8_t, std::thread> an_squares;
+std::unordered_map<uint8_t, bool> an_squares_terminate;
bool an_interrupts_enabled = true;
float an_reference_v = 5.0;
void setup(void);
void loop(void);
void an_is_pin_defined(const uint8_t pin, const an_pin_types_t = an_digital);
-inline void an_print_timestamp();
#ifndef _WIN32
void serialEvent() __attribute__((weak));
#endif
@@ -607,11 +617,12 @@ void randomSeed(long seed) {srand(seed);}
// External Interrupts
void attachInterrupt(uint8_t pin, void (*intpointer)(), an_int_mode_t mode)
{
- an_is_pin_defined(pin, an_int_pin);
+ detachInterrupt(pin);
an_ints[pin] = {intpointer, mode};
}
void detachInterrupt(const uint8_t pin)
{
+ an_is_pin_defined(pin, an_int_pin);
auto int_pos = an_ints.find(pin);
if (int_pos != an_ints.end())
an_ints.erase(int_pos);
@@ -622,12 +633,14 @@ void noInterrupts() {an_interrupts_enabled = false;}
// Advanced I/O
inline void noTone(const uint8_t pin)
{
+ an_is_pin_defined(pin);
#ifndef _WIN32
system("killall \"ffplay\" -q");
#endif
}
unsigned long pulseIn(const uint8_t pin, const bool val, const unsigned long timeout)
{
+ an_is_pin_defined(pin);
while (digitalRead(pin) != val);
unsigned long before = micros();
while (digitalRead(pin) == val && (!timeout && micros() - before >= timeout));
@@ -640,6 +653,9 @@ inline unsigned long pulseInLong(const uint8_t pin, const bool val, const unsign
}
uint8_t shiftIn(const uint8_t data_pin, const uint8_t clock_pin, const uint8_t bit_order)
{
+ an_is_pin_defined(data_pin);
+ an_is_pin_defined(clock_pin);
+
uint8_t value = 0;
uint8_t i;
@@ -655,6 +671,9 @@ uint8_t shiftIn(const uint8_t data_pin, const uint8_t clock_pin, const uint8_t b
}
void shiftOut(const uint8_t data_pin, const uint8_t clock_pin, const bool bit_order, byte val)
{
+ an_is_pin_defined(data_pin);
+ an_is_pin_defined(clock_pin);
+
uint8_t i;
for (i = 0; i < 8; i++) {
@@ -672,15 +691,88 @@ void shiftOut(const uint8_t data_pin, const uint8_t clock_pin, const bool bit_or
}
void tone(const uint8_t pin, unsigned hz, unsigned long dur)
{
-#ifndef _WIN32
noTone(pin);
+#ifndef _WIN32
hz = constrain(hz, 0, 20000);
char ffplay[70];
snprintf(ffplay, sizeof(ffplay), "ffplay -f lavfi -i \"sine=frequency=%d\" -nodisp -loglevel quiet &", hz);
system(ffplay);
#endif
}
+void an_play_sine(const uint8_t pin, const unsigned hz, const float amp, const float dc)
+{
+ for (;;) {
+ if (an_sines_terminate[pin])
+ return;
+ an_set_voltage(pin, sin(((float)millis() / (1000.0f / (2.0f * PI))) * hz) * amp + dc);
+ }
+}
+void an_play_sine_abs(const uint8_t pin, const unsigned hz, const float amp, const float dc)
+{
+ for (;;) {
+ if (an_sines_terminate[pin])
+ return;
+ an_set_voltage(pin, fabs(sin(((float)millis() / (1000.0f / (2.0f * PI))) * hz) * amp + dc));
+ }
+}
+void an_attach_sine(const uint8_t pin, const unsigned hz, const float amp, const float dc, const bool is_abs)
+{
+ an_remove_sine(pin);
+ an_sines_terminate[pin] = false;
+ if (is_abs) {
+ std::thread sine(an_play_sine_abs, pin, hz, amp, dc);
+ an_sines[pin] = move(sine);
+ } else {
+ std::thread sine(an_play_sine, pin, hz, amp, dc);
+ an_sines[pin] = move(sine);
+ }
+}
+void an_remove_sine(const uint8_t pin)
+{
+ an_is_pin_defined(pin);
+ auto sine_pos = an_sines.find(pin);
+ if (sine_pos != an_sines.end()) {
+ an_sines_terminate[pin] = true;
+ an_sines[pin].join();
+ an_sines.erase(sine_pos);
+ }
+}
+
+void an_play_square(const uint8_t pin, const unsigned hz, const float duty)
+{
+ bool top = true;
+ for (;;) {
+ if (an_sines_terminate[pin])
+ return;
+ float sine = sin((millis() / (1000.0f / (2.0f * PI))) * hz);
+ float triangle = 1.0f-acos(sine)/PI;
+
+ float new_top = triangle <= duty;
+ if (new_top != top) {
+ an_set_voltage(pin, new_top * 5.0f);
+ top = new_top;
+ }
+ }
+}
+
+void an_attach_square(const uint8_t pin, const unsigned hz, const float duty)
+{
+ an_remove_square(pin);
+ an_squares_terminate[pin] = false;
+ std::thread square(an_play_square, pin, hz, duty);
+ an_squares[pin] = move(square);
+}
+void an_remove_square(const uint8_t pin)
+{
+ an_is_pin_defined(pin);
+ auto square_pos = an_squares.find(pin);
+ if (square_pos != an_squares.end()) {
+ an_squares_terminate[pin] = true;
+ an_squares[pin].join();
+ an_squares.erase(square_pos);
+ }
+}
#undef AN_IMPL
#endif // AN_IMPL
diff --git a/README.org b/README.org
@@ -41,8 +41,7 @@ Choose board by defining a macro
If no board is defined it will default to Arduino Uno
* Features
** Implemented from Arduino library
-[[https://www.arduino.cc/reference/en/][Arduino Library Reference]].
-Note that less used functions haven't been tested that much.
+[[https://www.arduino.cc/reference/en/][Arduino Library Reference]]. Note that less used functions haven't been tested that much.
*** Exceptions
- HIGH and LOW interrupt modes don’t work, only CHANGE, RISING and FALLING
- serialEvent() is only supported on GCC and Clang, as it uses a GCC extension.
@@ -55,18 +54,38 @@ This prevents you from having to remove them when actually compile for an Arduin
// this will only be compiled if ArduinoNative is used
#endif
#+END_SRC
-*** Change voltage of pin
+- Set pin voltage
#+BEGIN_SRC C++
an_set_voltage(pin, voltage)
#+END_SRC
-*** Change voltage of pin from console input
+- Set pin voltage from console input
#+BEGIN_SRC C++
an_request_voltage(pin)
#+END_SRC
-*** Take input from console and put it in Serial buffer
+- Take input from console and put it in Serial buffer
#+BEGIN_SRC C++
Serial.an_take_input()
#+END_SRC
+- Print timestamp in ms
+#+BEGIN_SRC C++
+an_print_timestamp(); // example "1530ms | "
+#+END_SRC
+- Attach sine wave to pin
+#+BEGIN_SRC C++
+an_attach_sine(pin, hz = 1, amplitude = 2.5, dc_offset = 2.5, abs = false)
+#+END_SRC
+- Remove sine wave on pin
+#+BEGIN_SRC C++
+an_remove_sine(pin)
+#+END_SRC
+- Attach square wave to pin
+#+BEGIN_SRC C++
+an_attach_square(pin, hz = 1, duty_cycle = 0.5);
+#+END_SRC
+- Remove square wave on pin
+#+BEGIN_SRC C++
+an_remove_square(pin)
+#+END_SRC
** Extra debug features
Debug features can be enabled by defining the following macros
- *AN_DEBUG_TIMESTAMP*: Prints a timestamp in milliseconds in front of all debug messages
@@ -76,15 +95,9 @@ Debug features can be enabled by defining the following macros
- *AN_DEBUG_ANALOGREAD*: Prints a message to console when analogRead is called
- *AN_DEBUG_ANALOGWRITE*: Prints a message to console when analogWrite is called
* Roadmap
-- [X] Basic functionality
-- [X] Debug options
-- [X] more complete functionality
-- [X] Windows support
-- [X] Serial full functionality
-- [X] String object
-- [X] Complete rest of Arduino Library
-- [ ] Support for attaching simulated hardware on pins
-- [ ] Attach sine and square(with duty cycle) waves to pins
+- [ ] Check for pin type
+- [ ] Attach simulated hardware on pins
+- [ ] Move examples to their own folder
- [ ] Debug viewer to show pin status instead of Serial
- [ ] Support more boards
- [ ] Implement extra libraries (Servo.h, FastLED, etc)
@@ -204,7 +217,7 @@ Output:
4000ms | Pin: 6 is now LOW
...
#+END_SRC
-** Interrupts
+** Interrupts and an_attach_square
#+BEGIN_SRC C++
#define AN_DEBUG_TIMESTAMP
#define AN_IMPL
@@ -219,36 +232,28 @@ void interrupt()
an_print_timestamp();
#endif
Serial.print("INTERRUPT");
- Serial.println(count);
+ Serial.println(++count);
+ if (count >= 5)
+ detachInterrupt(2);
}
void setup() {
+#ifdef ArduinoNative
+ an_attach_square(2);
+#endif
Serial.begin(9600);
attachInterrupt(digitalPinToInterrupt(2), interrupt, CHANGE);
}
-// count 5 times, each time toggling pin 2
-// after 5 times detach interrupt
-void loop() {
- unsigned long t = millis();
- if (t - switchdelay >= 1000) {
-#ifdef ArduinoNative
- an_set_voltage(2, !digitalRead(2) * 5.0);
-#endif
- switchdelay = t;
- count++;
- if (count == 5)
- detachInterrupt(digitalPinToInterrupt(2));
- }
-}
+void loop() {}
#+END_SRC
Output:
#+BEGIN_SRC
-1000ms | INTERRUPT0
-2000ms | INTERRUPT1
-3000ms | INTERRUPT2
-4000ms | INTERRUPT3
-5000ms | INTERRUPT4
+500ms | INTERRUPT1
+1001ms | INTERRUPT2
+1500ms | INTERRUPT3
+2001ms | INTERRUPT4
+2500ms | INTERRUPT5
#+END_SRC
** AnalogReference()
#+BEGIN_SRC C++