commit bc348e535b5ad89e70920e487d59da0742038a39
Author: Petar Yotsev <petar@yotsev.xyz>
Date: Mon, 12 Jul 2021 02:35:45 +0100
Initial commit
Diffstat:
A | Makefile | | | 22 | ++++++++++++++++++++++ |
A | README.md | | | 50 | ++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | inverter.ino | | | 119 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
3 files changed, 191 insertions(+), 0 deletions(-)
diff --git a/Makefile b/Makefile
@@ -0,0 +1,22 @@
+BOARDS_TXT = /usr/share/arduino/hardware/archlinux-arduino/avr/boards.txt
+ARDUINO_DIR = /usr/share/arduino
+ARDMK_DIR = /usr/share/arduino
+
+# ARDUINO_LIBS =
+# USER_LIB_PATH = ./lib
+
+ARDMK_VENDOR = arduino
+BOARD_TAG = nano
+BOARD_SUB = atmega328
+ARCHITECTURE = avr
+AVRDUDE_ARD_BAUDRATE = 57600
+MONITOR_PORT = /dev/ttyUSB*
+
+AVR_TOOLS_DIR = /usr
+AVRDUDE_CONF = /etc/avrdude.conf
+ARDUINO_CORE_PATH = /usr/share/arduino/hardware/archlinux-arduino/avr/cores/arduino
+ARDUINO_PLATFORM_LIB_PATH = /usr/share/arduino/hardware/archlinux-arduino/avr/libraries
+ARDUINO_VAR_PATH = /usr/share/arduino/hardware/archlinux-arduino/avr/variants
+BOOTLOADER_PARENT = /usr/share/arduino/hardware/archlinux-arduino/avr/bootloaders
+
+include /usr/share/arduino/Arduino.mk
diff --git a/README.md b/README.md
@@ -0,0 +1,50 @@
+## About
+
+This is a program for the Arduino Nano that generates control signals
+with power width modulation (pwm) for a simple inverter circuit.
+
+## Installation
+
+Connect an Arduino nano with a USB cable and run
+
+ make upload
+
+from the project directory.
+
+The project was created on Arch Linux with `Arduino.mk`. If you run it
+under a different operating system, you should change the paths in the
+Makefile. It uses half the baude rate because the nano I'm using has an
+older bootloader.
+
+## Usage
+
+The builtin LED will flash while the board is calculating the time
+intervals of the pwm for the specified frequency.
+
+Here's a diagram of the circuit:
+
+ ____________
+ | | |
+ | p1 n1
+ + | |
+ bat |--load--|
+ - | |
+ | p2 n2
+ |___|________|
+
+I didn't have four transistors of the same type.
+
+## Specifics
+
+The code uses floats because on ATMEGA based boards doubles are the
+same as floats. I wanted to make that explicit. If your board supports
+doubles, you can change the base case in Converge() to get more
+accuracy. The limited accuracy of floats also restricts the resolution
+or how many distinct intervals can be calculated in a cycle. The higher
+the resolution, the smoother the modulation becomes. The default
+resolution is 220 roots in a cycles (219 intervals) and the maximum
+resolution that doesn't brake everything (on my nano) is 227.
+
+## License
+
+GPLv2
diff --git a/inverter.ino b/inverter.ino
@@ -0,0 +1,119 @@
+#include <math.h>
+
+#define p1 7
+#define p2 6
+#define n1 5
+#define n2 4
+
+/* specify the frequency of AC */
+/* =========================== */
+constexpr float freq = 10.0f;
+/* =========================== */
+
+// resolution / number of roots
+constexpr int res = 220;
+
+// temporary pointer for the top of an array
+unsigned int index = 0;
+float roots[res];
+int time_intervals[res - 1]; // in microseconds
+
+constexpr float pi = 3.141592653589793;
+
+float Wave(const float& x)
+{
+ return (2.1f / pi) * asin(sin(float(res) * pi * x))
+ + sin(2.0f * pi * x - pi / 2.0f);
+}
+
+bool led_is_on = false;
+
+void Converge(
+ const float& lower,
+ const float& upper,
+ const int& exponent)
+{
+ // base case, maximum float precision reached for root
+ if (exponent < -7) {
+ roots[index] = (lower + upper) / 2;
+ index++;
+ // flash builtin LED
+ digitalWrite(LED_BUILTIN, (led_is_on) ? LOW : HIGH);
+ led_is_on = !led_is_on;
+ return;
+ }
+
+ // record if the wave function is positive or negative before it
+ // crosses the x-axis
+ bool is_positive = (Wave(lower) > 0) ? true : false;
+ // define the incremental step
+ float step = 1.0f * pow(10, exponent);
+
+ // scan for a change of sign in Wave() between upper and lower bound
+ for (float func, x = lower; x < upper + step; x += step) {
+ // record output of Wave() to avoid multiple calls for same x
+ func = Wave(x);
+ // sign of the output has changed / root is found
+ if ((func > 0 && !is_positive) || (func < 0 && is_positive)) {
+ // go one magnitude lower for more precision
+ Converge(x - step, x, exponent - 1);
+ is_positive = !is_positive;
+ }
+ }
+}
+
+void setup()
+{
+ pinMode(p1, OUTPUT);
+ pinMode(p2, OUTPUT);
+ pinMode(n1, OUTPUT);
+ pinMode(n2, OUTPUT);
+
+ pinMode(LED_BUILTIN, OUTPUT);
+
+ // find roots
+ Converge(0, 1, -4);
+
+ digitalWrite(LED_BUILTIN, LOW);
+
+ // calculate intervals between roots
+ index = 0;
+ for (int i = 1; i < res; ++i) {
+ time_intervals[index]
+ = int(1000000.0f * (roots[i] - roots[i - 1]) / (freq * 2.0f));
+ index++;
+ }
+}
+
+void loop()
+{
+ // set other set of transistors off to avoid feedback
+ digitalWrite(p2, LOW);
+ digitalWrite(n1, HIGH);
+ // set first transistor (from +) on
+ digitalWrite(p1, HIGH);
+
+ for (int i = 0; i < res - 1; i += 2) {
+ // set second transistor (from +) on
+ digitalWrite(n2, LOW);
+ delayMicroseconds(time_intervals[i]);
+ // set second transistor (from +) off
+ digitalWrite(n2, HIGH);
+ delayMicroseconds(time_intervals[i + 1]);
+ }
+
+ // set other set of transistors off to avoid feedback
+ digitalWrite(p1, LOW);
+ digitalWrite(n2, HIGH);
+ // set first transistor (from +) on
+ digitalWrite(p2, HIGH);
+
+ for (int i = 0; i < res - 1; i += 2) {
+ // set second transistor (from +) on
+ digitalWrite(n1, LOW);
+ delayMicroseconds(time_intervals[i]);
+ // set second transistor (from +) off
+ digitalWrite(n1, HIGH);
+ delayMicroseconds(time_intervals[i + 1]);
+ }
+}