From c5f2e7b142c2c105963fa15db622aa3c60aecff7 Mon Sep 17 00:00:00 2001 From: KemoNine Date: Sat, 1 Jun 2019 21:47:10 -0400 Subject: [PATCH] Initial bring up, screens, config --- .../calibration_jig/calibration_jig.ino | 264 ++++++++++++++++++ 1 file changed, 264 insertions(+) create mode 100644 hardware/arduino/calibration_jig/calibration_jig.ino diff --git a/hardware/arduino/calibration_jig/calibration_jig.ino b/hardware/arduino/calibration_jig/calibration_jig.ino new file mode 100644 index 0000000..efa66aa --- /dev/null +++ b/hardware/arduino/calibration_jig/calibration_jig.ino @@ -0,0 +1,264 @@ +#include +#include +#include +#include "SPI.h" +#include "Adafruit_GFX.h" +#include "Adafruit_ILI9341.h" +#include +#include +#include +//FreeMono18pt7b.h +//FreeMono24pt7b.h +//FreeMono9pt7b.h +//FreeMonoBold12pt7b.h +//FreeMonoBold18pt7b.h +//FreeMonoBold24pt7b.h +//FreeMonoBold9pt7b.h + +// Various tunables +#define ERROR_LED_PIN 13 +#define ERROR_LED_LIGHTUP_STATE HIGH +#define PIXEL_PIN 40 // pin of pixel +#define PIXEL_MAX_BRIGHTNESS 48 // 255 max +#define PIXEL_MIN_BRIGHTNESS 4 // 0 min +#define BREATHE_DELAY 5 // milliseconds +#define BUTTON_UP 6 // MUST be an interrupt pin +#define BUTTON_DOWN 5 // MUST be an interrupt pin +#define BUTTON_OK 7 // MUST be an interrupt pin +// TFT pins +#define TFT_DC 9 +#define TFT_CS 10 +#define TFT_MOSI 13 +#define TFT_CLK 12 +#define TFT_RST 8 +#define TFT_MISO 11 + +// Init hardware used in tasks +Adafruit_NeoPixel pixel(1, PIXEL_PIN, NEO_GRB + NEO_KHZ800); + +// Adafruit 2.2 TFT -- 320x240 resolution, up to 18-bit (262,144) color +// Use hardware SPI (on Uno, #13, #12, #11) and the above for CS/DC +//Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC); +// If using the breakout, change pins as desired +Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_MOSI, TFT_CLK, TFT_RST, TFT_MISO); + +// Button Semaphores +SemaphoreHandle_t sem_btn_up; +SemaphoreHandle_t sem_btn_down; +SemaphoreHandle_t sem_btn_ok; + +// define two tasks for Blink & AnalogRead +void TaskBlink( void *pvParameters ); +void InterruptHandlerButtonUp(); +void InterruptHandlerButtonDown(); +void InterruptHandlerButtonOk(); +void TaskLCD(void *pvParameters); + +// UI screens +void screenClear(); +void screenSoilStemma(); +void screenSoilCatnip(); +void screenWaterLevelETape(); + +// Color conversion (RGB888 -> RGB565 used by Adafruit GFX) +uint16_t RGB565(uint8_t r, uint8_t g, uint8_t b) { + return ((r & 0b11111000) << 8) | ((g & 0b11111100) << 3) | (b >> 3); +} + +// the setup function runs once when you press reset or power the board +void setup() { + + vNopDelayMS(1000); // prevents usb driver crash on startup, do not omit this + + // Set the led the rtos will blink when we have a fatal rtos error + // RTOS also Needs to know if high/low is the state that turns on the led. + // Error Blink Codes: + // 3 blinks - Fatal Rtos Error, something bad happened. Think really hard about what you just changed. + // 2 blinks - Malloc Failed, Happens when you couldnt create a rtos object. + // Probably ran out of heap. + // 1 blink - Stack overflow, Task needs more bytes defined for its stack! + // Use the taskMonitor thread to help gauge how much more you need + vSetErrorLed(ERROR_LED_PIN, ERROR_LED_LIGHTUP_STATE); + + // initialize serial communication at 9600 bits per second: + //Serial.begin(9600); + + //while (!Serial) { + // ; // wait for serial port to connect. Needed for native USB, on LEONARDO, MICRO, YUN, and other 32u4 based boards. + //} + + pixel.begin(); + pixel.clear(); + pixel.setBrightness(PIXEL_MAX_BRIGHTNESS); + pixel.setPixelColor(0, pixel.Color(0, 0, 255)); + pixel.show(); + + tft.begin(); + tft.setRotation(3); + screenClear(); + tft.setFont(&FreeMonoBold18pt7b); + tft.setCursor(tft.width() / 2 - 138, tft.height() / 2 + 10); + tft.println("Press Up/Down"); + + pinMode(BUTTON_UP, INPUT_PULLUP); + pinMode(BUTTON_DOWN, INPUT_PULLUP); + pinMode(BUTTON_OK, INPUT_PULLUP); + attachInterrupt(digitalPinToInterrupt(BUTTON_UP), InterruptHandlerButtonUp, RISING); + attachInterrupt(digitalPinToInterrupt(BUTTON_DOWN), InterruptHandlerButtonDown, RISING); + attachInterrupt(digitalPinToInterrupt(BUTTON_OK), InterruptHandlerButtonOk, RISING); + + sem_btn_up = xSemaphoreCreateBinary(); + sem_btn_down = xSemaphoreCreateBinary(); + sem_btn_ok = xSemaphoreCreateBinary(); + + // Now set up two tasks to run independently. + xTaskCreate( + TaskBlink + , (const portCHAR *)"Blink" // A name just for humans + , 128 // This stack size can be checked & adjusted by reading the Stack Highwater + , NULL + , 0 // Priority, with 3 (configMAX_PRIORITIES - 1) being the highest, and 0 being the lowest. + , NULL ); + + xTaskCreate( + TaskLCD + , (const portCHAR *)"LCD" // A name just for humans + , 128 // This stack size can be checked & adjusted by reading the Stack Highwater + , NULL + , 2 // Priority, with 3 (configMAX_PRIORITIES - 1) being the highest, and 0 being the lowest. + , NULL ); + + // Now the task scheduler, which takes over control of scheduling individual tasks, is automatically started. + vTaskStartScheduler(); +} + +void loop() { + // Empty. Things are done in Tasks. +} + +/*--------------------------------------------------*/ +/*---------------------- Tasks ---------------------*/ +/*--------------------------------------------------*/ + +void TaskBlink(void *pvParameters) { + (void) pvParameters; + + while (1) { + pixel.setPixelColor(0, pixel.Color(0, 255, 0)); // Pulse heartbeat green -- reset in case another task interrupts w/ a different color + for (int i = PIXEL_MIN_BRIGHTNESS ; i < PIXEL_MAX_BRIGHTNESS ; i++) { + pixel.setBrightness(i); + pixel.show(); + vTaskDelay( 50 / portTICK_PERIOD_MS ); + } + for (int i = PIXEL_MAX_BRIGHTNESS ; i > PIXEL_MIN_BRIGHTNESS ; i--) { + pixel.setBrightness(i); + pixel.show(); + vTaskDelay( 50 / portTICK_PERIOD_MS ); + } + } +} + + +void TaskLCD(void *pvParameters) { + (void) pvParameters; + + void (*screens[3])() = {screenSoilStemma, screenSoilCatnip, screenWaterLevelETape}; + int current = 0; + + while (1) { + if (xSemaphoreTake(sem_btn_up, 50 / portTICK_PERIOD_MS) == pdPASS) { + screenClear(); + tft.fillRect(tft.width() - 50, 0, 50, 20, RGB565(0, 0, 0)); + tft.setFont(&FreeMonoBold9pt7b); + tft.setCursor(tft.width() - 50, 15); + tft.print("Up"); + current++; + if (current >= sizeof(screens) / sizeof(screens[0])) { + current = 0; + } + screens[current](); + } + if (xSemaphoreTake(sem_btn_down, 50 / portTICK_PERIOD_MS) == pdPASS) { + screenClear(); + tft.fillRect(tft.width() - 50, 0, 50, 20, RGB565(0, 0, 0)); + tft.setFont(&FreeMonoBold9pt7b); + tft.setCursor(tft.width() - 50, 15); + tft.print("Down"); + current--; + if (current < 0) { + current = sizeof(screens) / sizeof(screens[0]) - 1; + } + screens[current](); + } + if (xSemaphoreTake(sem_btn_ok, 50 / portTICK_PERIOD_MS) == pdPASS) { + tft.fillRect(tft.width() - 50, 0, 50, 20, RGB565(0, 0, 0)); + tft.setFont(&FreeMonoBold9pt7b); + tft.setCursor(tft.width() - 50, 15); + tft.print("OK"); + } + } +} + +void InterruptHandlerButtonUp() { + xSemaphoreGiveFromISR(sem_btn_up, NULL); +} + +void InterruptHandlerButtonDown() { + xSemaphoreGiveFromISR(sem_btn_down, NULL); +} + +void InterruptHandlerButtonOk() { + xSemaphoreGiveFromISR(sem_btn_ok, NULL); +} + +void screenClear() { + tft.setCursor(0, 0); + tft.fillScreen(RGB565(0, 0, 0)); +} + +void screenSoilStemma() { + tft.setFont(&FreeMonoBold18pt7b); + tft.setCursor(0, 25); + tft.println("Soil"); + tft.setFont(&FreeMono12pt7b); + tft.println("Adafruit STEMMA"); + tft.println("Soil Sensor"); + tft.println("i2c address: 0x36"); + tft.println("seesaw address: 0x36"); + tft.println(""); + tft.setFont(&FreeMonoBold9pt7b); + tft.println("--Press OK To Read Value--"); + tft.println(""); + tft.println("Value: [value]"); +} + + +void screenSoilCatnip() { + tft.setFont(&FreeMonoBold18pt7b); + tft.setCursor(0, 25); + tft.println("Soil"); + tft.setFont(&FreeMono12pt7b); + tft.println("Catnip Soil Sensor"); + tft.println("i2c address: 0x20"); + tft.println(""); + tft.setFont(&FreeMonoBold9pt7b); + tft.println("--Press OK To Read Value--"); + tft.println(""); + tft.println("Capacitance: [value]"); + tft.println("Temperature: [value]"); + tft.println("Light: [value]"); +} + +void screenWaterLevelETape() { + tft.setFont(&FreeMonoBold18pt7b); + tft.setCursor(0, 25); + tft.println("Water Level"); + tft.setFont(&FreeMono12pt7b); + tft.println("Milone eTape"); + tft.println("Analog Pin #0"); + tft.println(""); + tft.setFont(&FreeMonoBold9pt7b); + tft.println("--Press OK To Read Value--"); + tft.println(""); + tft.println("Value: [value]"); +}