diff --git a/Arduino code/main.ino b/Arduino code/main.ino index a247532..8b7dbda 100644 --- a/Arduino code/main.ino +++ b/Arduino code/main.ino @@ -1,20 +1,30 @@ -#include #include #include #include -#include "LowPower.h" +#include "ArduinoLowPower.h" +#include "SD.h" +#include "src/graphics.h" // Pin definition -#define VBATPIN A9 +#define VBATPIN A7 #define CHTMEASUREPIN A1 -#define RPMPIN 0 -#define BUTTONPIN 1 +#define RPMPIN 1 +#define BUTTONPIN 0 #define RPMPOWER A2 #define CHTPOWER A3 +#define chipSelect 4 + // uncomment this for dev mode -#define DEVMODE 1 +// #define DEVMODE 1 +// #define FAKERPM 1 + +// SAMD serial port adaptation +#if defined(ARDUINO_SAMD_ZERO) && defined(SERIAL_PORT_USBVIRTUAL) +// Required for Serial on Zero based boards +#define Serial SERIAL_PORT_USBVIRTUAL +#endif // Battery monitoring const float minVoltage = 3.2; @@ -24,25 +34,26 @@ const float refVoltage = 3.3; // defines for tacho const float min_rpm = 2000; const float max_rpm = 8000; -const long updatet = 20; float rpm_filt = 0; -float ww = 2; // filter weight. larger numbers -> slower filters. 40 is ..s, 1 +float ww = 3; // filter weight. larger numbers -> slower filters. 40 is ..s, 1 // is no filtering // defines for tacho: Timer auxiliary variables unsigned long tt = millis(); unsigned long dt = micros(); -unsigned long oldtime = micros(); -float rev = 0; +volatile unsigned long t0 = micros(); +volatile unsigned long t1 = micros(); +// volatile unsigned long oldtime = micros(); +volatile float rev = 0; float rpm = 0; +unsigned long fakerpm_dt = 0; +unsigned long fakerpm_tt = 0; + unsigned long lastTrigger = 0; boolean startTimer = false; -// Defining the type of display used (128x32) -U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE); - // Defining variables for OLED display char displayBuffer[20]; String displayString; @@ -56,9 +67,12 @@ bool wasSleeping = true; bool awake = true; float sleepInput = 0; -// time variables +// Defining the type of display used (128x32) +U8G2_SSD1306_128X32_UNIVISION_F_HW_I2C u8g2(U8G2_R0, U8X8_PIN_NONE); + +// time keeping variables long tt_loop = 0; -long loopUpdateTime = 10; +long loopUpdateTime = 25; long tt_button = 0; long dt_button = 500; long tt_slowdraw = 0; @@ -68,47 +82,102 @@ unsigned long tt_running = 0; unsigned long current_runtime = 0; unsigned long total_runtime = 0; -long EEPROMReadlong(long address) { - long four = EEPROM.read(address); - long three = EEPROM.read(address + 1); - long two = EEPROM.read(address + 2); - long one = EEPROM.read(address + 3); - - return ((four << 0) & 0xFF) + ((three << 8) & 0xFFFF) + - ((two << 16) & 0xFFFFFF) + ((one << 24) & 0xFFFFFFFF); -} - -void EEPROMWritelong(int address, long value) { - byte four = (value & 0xFF); - byte three = ((value >> 8) & 0xFF); - byte two = ((value >> 16) & 0xFF); - byte one = ((value >> 24) & 0xFF); - - EEPROM.write(address, four); - EEPROM.write(address + 1, three); - EEPROM.write(address + 2, two); - EEPROM.write(address + 3, one); +// SD card stuff +File logfile; + +// blink out an error code +void error(uint8_t errno) { + while (1) { + uint8_t i; + for (i = 0; i < errno; i++) { + digitalWrite(LED_BUILTIN, HIGH); + delay(100); + digitalWrite(LED_BUILTIN, LOW); + delay(100); + } + for (i = errno; i < 10; i++) { + delay(200); + } + } } +// sleepy function void prepareSleep() { u8g2.setPowerSave(1); pinMode(RPMPOWER, INPUT); pinMode(CHTPOWER, INPUT); + pinMode(13, INPUT); digitalWrite(RPMPOWER, LOW); digitalWrite(CHTPOWER, LOW); wasSleeping = false; - EEPROMWritelong(0, total_runtime); - LowPower.powerDown(SLEEP_1S, ADC_OFF, BOD_OFF); + logfile.println(total_runtime); + logfile.flush(); + logfile.close(); + LowPower.deepSleep(1000); } +// wakeup function void wakeupProc() { u8g2.setPowerSave(0); - u8g2.begin(); + + u8g2.clearBuffer(); + u8g2.drawXBMP(0, 0, mouth1_width, mouth1_height, mouth1_bits); + u8g2.sendBuffer(); + delay(2000); + u8g2.clearBuffer(); + +#if defined(FAKERPM) + pinMode(RPMPOWER, INPUT); + digitalWrite(RPMPOWER, LOW); +#else pinMode(RPMPOWER, OUTPUT); - pinMode(CHTPOWER, OUTPUT); digitalWrite(RPMPOWER, HIGH); +#endif + pinMode(CHTPOWER, OUTPUT); + pinMode(LED_BUILTIN, OUTPUT); digitalWrite(CHTPOWER, HIGH); - total_runtime = EEPROMReadlong(0); + + char filename[17]; + strcpy(filename, "logger/HOURS.TXT"); + // for (uint8_t i = 0; i < 100; i++) { + // filename[10] = '0' + i / 10; + // filename[11] = '0' + i % 10; + // // create if does not exist, do not open existing, write, sync after + // write if (!SD.exists(filename)) { + // break; + // } + // } + logfile = SD.open(filename, FILE_READ); + if (!logfile) { +#if defined(DEVMODE) + Serial.print("Couldnt open "); + Serial.println(filename); +#endif + error(2); + } + + while (logfile.available()) { + unsigned long runtime_temp = logfile.parseInt(); + if (runtime_temp > 0) { + total_runtime = runtime_temp; + } + } +#if defined(DEVMODE) + Serial.println(total_runtime); +#endif + logfile.close(); + + logfile = SD.open(filename, FILE_WRITE); + logfile.seek(EOF); + if (!logfile) { +#if defined(DEVMODE) + Serial.print("Couldnt open for write "); + Serial.println(filename); +#endif + error(3); + } + + // total_runtime = EEPROMReadlong(0); } void setup() { @@ -120,10 +189,18 @@ void setup() { // initialize serial: #if defined(DEVMODE) Serial.begin(115200); - Serial.print("Devmode ON"); + while (!Serial) delay(10); // wait for native usb + Serial.println("Devmode ON"); #endif - Wire.setClock(400000); + u8g2.setBusClock(400000); + u8g2.begin(); + + if (!SD.begin(chipSelect)) { +#if defined(DEVMODE) + Serial.println("SD init failed"); +#endif + } wakeupProc(); } @@ -155,6 +232,9 @@ void loop() { while (Serial.available() > 0) { // look for the next valid integer in the incoming serial stream: rev = Serial.parseInt(); +#if defined(FAKERPM) + fakerpm_dt = 60000.0 / rev; +#endif if (Serial.read() == '\n') { Serial.println(rev); if (rev < 0) { @@ -164,15 +244,29 @@ void loop() { } } } + +#if defined(FAKERPM) + if (millis() - fakerpm_tt > fakerpm_dt) { + // pinmode input detaches internal pullup, so transistor in pcb takes pin + // to 0V however, it also detaches the interrupt for some reason + pinMode(RPMPIN, INPUT); + delayMicroseconds(20); + pinMode(RPMPIN, INPUT_PULLUP); + attachInterrupt(digitalPinToInterrupt(RPMPIN), rpm_isr, FALLING); + fakerpm_tt = millis(); + } +#endif + // Serial.println(rpm_filt); #endif if (millis() - tt_loop > loopUpdateTime) { updateRunningTime(); updateTacho(); - readCht(); +#if !defined(FAKERPM) readBatteryVoltage(); readCht(); updateMainDisplay(); +#endif tt_loop = millis(); } } else { @@ -279,22 +373,32 @@ void readBatteryVoltage() { #endif } -void rpm_isr() { rev++; } +void rpm_isr() { + t1 = micros(); + rev++; +} void updateTacho() { - dt = micros() - oldtime; - oldtime = micros(); - if (dt > 0) { - rpm = (rev / dt) * 60000000; + if (rev > 0) { + dt = t1 - t0; + if (dt > 0) { + rpm = (rev / dt) * 60000000; + t0 = t1; +#if defined(FAKERPM) + rev = 0; +#endif #if !defined(DEVMODE) - rev = 0; + rev = 0; #endif - } - rpm_filt = - constrain((1 / ww) * (rpm) + (1 - (1 / ww)) * rpm_filt, 0, max_rpm); + } + rpm_filt = + constrain((1 / ww) * (rpm) + (1 - (1 / ww)) * rpm_filt, 0, max_rpm); #if defined(DEVMODE) - Serial.print("rpm: "); - Serial.println(rpm_filt); + Serial.print("rpm: "); + Serial.print(rpm_filt); + Serial.print(" "); + Serial.println(dt); + } #endif } @@ -317,6 +421,8 @@ typedef struct barStruct { } barStruct; void updateMainDisplay() { + // u8g2.clearBuffer(); + barStruct rpmBar; rpmBar.value = rpm_filt / 1000; rpmBar.x = 0; @@ -535,7 +641,7 @@ void drawBar( u8g2.drawHLine(pp.x, pp.y + 10, 5); u8g2.drawHLine(pp.x + 52 - 4, pp.y + 10, 5); - int width = constrain(map(pp.value, pp.min, pp.max, 0, 49), 0, 49); + int width = constrain(map_float(pp.value, pp.min, pp.max, 0, 49), 0, 49); for (int i = 0; i < width; i++) { u8g2.drawVLine(pp.x + i + 2, pp.y + 2, 7); } @@ -562,3 +668,8 @@ void drawBar( // } // } } + +float map_float(float x, float in_min, float in_max, float out_min, + float out_max) { + return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; +} diff --git a/Arduino code/src/graphics.h b/Arduino code/src/graphics.h new file mode 100644 index 0000000..c330c77 --- /dev/null +++ b/Arduino code/src/graphics.h @@ -0,0 +1,46 @@ +#define mouth1_width 128 +#define mouth1_height 32 +static const unsigned char mouth1_bits[] = { + 0x00, 0xF0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0x07, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x00, 0x80, 0xFF, 0x3F, 0x00, + 0xC0, 0x0F, 0x00, 0xF0, 0x03, 0x00, 0xF8, 0x03, 0x00, 0xFC, 0xFF, 0x00, + 0xF0, 0x0F, 0x0E, 0x00, 0x00, 0x07, 0x00, 0xC0, 0x01, 0x00, 0xE0, 0x00, + 0x00, 0x38, 0xFC, 0x07, 0xFC, 0x0F, 0x0E, 0x00, 0x00, 0x07, 0x00, 0xC0, + 0x01, 0x00, 0xE0, 0x00, 0x00, 0x38, 0xF0, 0x1F, 0xFC, 0x01, 0x0E, 0x00, + 0x00, 0x07, 0x00, 0xC0, 0x01, 0x00, 0xE0, 0x00, 0x00, 0x38, 0xC0, 0x3F, + 0x7F, 0x00, 0x0E, 0x00, 0x00, 0x07, 0x00, 0xC0, 0x01, 0x00, 0xE0, 0x00, + 0x00, 0x38, 0x00, 0x7F, 0x7F, 0x00, 0x0E, 0x00, 0x00, 0x07, 0x00, 0xC0, + 0x01, 0x00, 0xE0, 0x00, 0x00, 0x38, 0x00, 0xFE, 0x3F, 0x00, 0x0E, 0x00, + 0x00, 0x07, 0x00, 0xC0, 0x01, 0x00, 0xE0, 0x00, 0x00, 0x38, 0x00, 0xFE, + 0x3F, 0x00, 0x0E, 0x00, 0x00, 0x07, 0x00, 0xE0, 0xFF, 0x00, 0xE0, 0x00, + 0x00, 0x38, 0x00, 0xFC, 0x3F, 0x00, 0x0E, 0x00, 0x00, 0x07, 0xF0, 0xFF, + 0xFF, 0x3F, 0xE0, 0x00, 0x00, 0x3C, 0x00, 0xFC, 0x3F, 0x00, 0x0E, 0x00, + 0x00, 0x07, 0xFE, 0xFF, 0x01, 0xFF, 0xE3, 0x00, 0x00, 0x1C, 0x00, 0xFC, + 0x3F, 0x00, 0x0E, 0x00, 0x00, 0xFF, 0x7F, 0xC0, 0x01, 0xC0, 0xFF, 0x01, + 0x00, 0x1C, 0x00, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0xC0, + 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0x07, 0x00, 0xC0, 0x01, 0x00, 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x3F, 0x00, 0x1E, 0x00, 0x00, 0x07, 0x00, 0xC0, 0x01, 0x00, 0xE0, 0x00, + 0x00, 0x1C, 0x00, 0xFC, 0x3F, 0x00, 0x1C, 0x00, 0x00, 0x07, 0x00, 0xC0, + 0x01, 0x00, 0xE0, 0x00, 0x00, 0x1C, 0x00, 0xFC, 0x3F, 0x00, 0x1C, 0x00, + 0x00, 0x07, 0x00, 0xC0, 0x01, 0x00, 0xE0, 0x00, 0x00, 0x1C, 0x00, 0xFC, + 0xFF, 0x0F, 0x1C, 0x00, 0x00, 0x07, 0x00, 0xC0, 0x01, 0x00, 0xE0, 0x00, + 0x00, 0x1C, 0x00, 0xFC, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x07, 0x00, 0xC0, + 0x01, 0x00, 0xE0, 0x00, 0x00, 0x1C, 0x00, 0xFC, 0x3F, 0xFC, 0xFF, 0x7F, + 0x00, 0x07, 0x00, 0xC0, 0x01, 0x00, 0xE0, 0x00, 0x00, 0xFC, 0xFF, 0xFF, + 0x3F, 0x00, 0xFC, 0xFF, 0x3F, 0x07, 0x00, 0xC0, 0x01, 0x00, 0xE0, 0xC0, + 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x38, 0xFE, 0xFF, 0xFF, 0x01, 0xC0, + 0x01, 0xFC, 0xFF, 0xFF, 0xFF, 0x1F, 0x00, 0xFC, 0x7F, 0x00, 0x38, 0x00, + 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x1C, 0x00, 0x7E, + 0x7E, 0x00, 0x38, 0x00, 0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0x07, 0x70, 0x00, + 0x00, 0x1C, 0x00, 0x7F, 0xFE, 0x00, 0x38, 0x00, 0x00, 0x07, 0x00, 0xC0, + 0x01, 0x00, 0x70, 0x00, 0x00, 0x1C, 0x00, 0x7F, 0xFC, 0x01, 0x38, 0x00, + 0x00, 0x07, 0x00, 0xC0, 0x01, 0x00, 0x70, 0x00, 0x00, 0x1C, 0xC0, 0x3F, + 0xF8, 0x07, 0x38, 0x00, 0x00, 0x07, 0x00, 0xC0, 0x01, 0x00, 0x70, 0x00, + 0x00, 0x1C, 0xE0, 0x1F, 0xF0, 0x1F, 0x38, 0x00, 0x00, 0x07, 0x00, 0xC0, + 0x01, 0x00, 0x70, 0x00, 0x00, 0x1C, 0xFC, 0x07, 0xC0, 0x7F, 0x38, 0x00, + 0x00, 0x07, 0x00, 0xC0, 0x01, 0x00, 0x70, 0x00, 0x00, 0x1C, 0xFC, 0x01, + 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, }; \ No newline at end of file