commit a4b88564a430e39a323b809f40a329346d722654 Author: lumijiez <59575049+lumijiez@users.noreply.github.com> Date: Mon Apr 28 18:30:29 2025 +0300 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..89cc49c --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.pio +.vscode/.browse.c_cpp.db* +.vscode/c_cpp_properties.json +.vscode/launch.json +.vscode/ipch diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..080e70d --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,10 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 + // for the documentation about the extensions.json format + "recommendations": [ + "platformio.platformio-ide" + ], + "unwantedRecommendations": [ + "ms-vscode.cpptools-extension-pack" + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..03ba48b --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "files.associations": { + "new": "cpp" + } +} \ No newline at end of file diff --git a/include/drivers/AccelerometerController.h b/include/drivers/AccelerometerController.h new file mode 100644 index 0000000..eb30bec --- /dev/null +++ b/include/drivers/AccelerometerController.h @@ -0,0 +1,72 @@ +#ifndef ADXL345_CONTROLLER_H +#define ADXL345_CONTROLLER_H + +#include +#include + +#define ADXL345_DEVID 0x00 +#define ADXL345_THRESH_TAP 0x1D +#define ADXL345_OFSX 0x1E +#define ADXL345_OFSY 0x1F +#define ADXL345_OFSZ 0x20 +#define ADXL345_DUR 0x21 +#define ADXL345_LATENT 0x22 +#define ADXL345_WINDOW 0x23 +#define ADXL345_THRESH_ACT 0x24 +#define ADXL345_THRESH_INACT 0x25 +#define ADXL345_TIME_INACT 0x26 +#define ADXL345_ACT_INACT_CTL 0x27 +#define ADXL345_THRESH_FF 0x28 +#define ADXL345_TIME_FF 0x29 +#define ADXL345_TAP_AXES 0x2A +#define ADXL345_ACT_TAP_STATUS 0x2B +#define ADXL345_BW_RATE 0x2C +#define ADXL345_POWER_CTL 0x2D +#define ADXL345_INT_ENABLE 0x2E +#define ADXL345_INT_MAP 0x2F +#define ADXL345_INT_SOURCE 0x30 +#define ADXL345_DATA_FORMAT 0x31 +#define ADXL345_DATAX0 0x32 +#define ADXL345_DATAX1 0x33 +#define ADXL345_DATAY0 0x34 +#define ADXL345_DATAY1 0x35 +#define ADXL345_DATAZ0 0x36 +#define ADXL345_DATAZ1 0x37 +#define ADXL345_FIFO_CTL 0x38 +#define ADXL345_FIFO_STATUS 0x39 + +#define DEFAULT_MIN_READ_INTERVAL 50 + +class ADXL345Controller { +private: + uint8_t _deviceAddress; + unsigned long _lastReadTime; + unsigned long _minReadInterval; + double _lastX; + double _lastY; + double _lastZ; + bool _lastReadSuccess; + + void setRegister(uint8_t reg, uint8_t value); + uint8_t readRegister(uint8_t reg); + void readRegisters(uint8_t reg, uint8_t count, uint8_t *buffer); + +public: + ADXL345Controller(uint8_t deviceAddress = 0x53); + + void begin(); + + bool read(); + + double getX(); + double getY(); + double getZ(); + + bool isLastReadSuccessful() const; + void setMinReadInterval(unsigned long interval); + void setRange(uint8_t range); + void setDataRate(uint8_t rate); + void setOffsets(int8_t xOffset, int8_t yOffset, int8_t zOffset); +}; + +#endif \ No newline at end of file diff --git a/include/drivers/ButtonController.h b/include/drivers/ButtonController.h new file mode 100644 index 0000000..b3d9b3d --- /dev/null +++ b/include/drivers/ButtonController.h @@ -0,0 +1,21 @@ +#ifndef BUTTON_CONTROLLER_H +#define BUTTON_CONTROLLER_H + +#include + +class ButtonController { +private: + const int _buttonPin; + unsigned long _lastDebounceTime; + unsigned long _debounceDelay; + bool _lastButtonState; + bool _buttonState; + +public: + ButtonController(int buttonPin, unsigned long debounceDelay = 50); + bool wasOn(); + void tick(); + bool getState() const; +}; + +#endif \ No newline at end of file diff --git a/include/drivers/DHTController.h b/include/drivers/DHTController.h new file mode 100644 index 0000000..2844f00 --- /dev/null +++ b/include/drivers/DHTController.h @@ -0,0 +1,27 @@ +#ifndef DHT_CONTROLLER_H +#define DHT_CONTROLLER_H + +#include +#include + +class DHTController { +private: + DHT _dht; + unsigned long _lastReadTime; + unsigned long _minReadInterval; + float _lastTemperature; + float _lastHumidity; + bool _lastReadSuccess; + +public: + DHTController(uint8_t pin, uint8_t type = DHT11); + + void begin(); + bool read(); + float getTemperature(); + float getHumidity(); + bool isLastReadSuccessful() const; + void setMinReadInterval(unsigned long interval); +}; + +#endif \ No newline at end of file diff --git a/include/drivers/DistanceSensorController.h b/include/drivers/DistanceSensorController.h new file mode 100644 index 0000000..6d35888 --- /dev/null +++ b/include/drivers/DistanceSensorController.h @@ -0,0 +1,37 @@ +#ifndef DISTANCE_SENSOR_CONTROLLER_H +#define DISTANCE_SENSOR_CONTROLLER_H + +#include + +#define DEFAULT_MIN_READ_INTERVAL_DIST 100 +#define DEFAULT_SAMPLES 3 +#define MAX_DISTANCE 400 + +class DistanceSensorController { +private: + uint8_t _trigPin; + uint8_t _echoPin; + unsigned long _lastReadTime; + unsigned long _minReadInterval; + long _lastDistanceCm; + bool _lastReadSuccess; + uint8_t _numSamples; + unsigned long _timeout; + + long microsecondsToCentimeters(long microseconds); + + long takeMeasurement(); + +public: + DistanceSensorController(uint8_t trigPin, uint8_t echoPin); + void begin(); + bool read(); + long getDistanceCm(); + long getDistanceInch(); + bool isLastReadSuccessful() const; + void setMinReadInterval(unsigned long interval); + void setNumSamples(uint8_t samples); + void setTimeout(unsigned long timeout); +}; + +#endif \ No newline at end of file diff --git a/include/drivers/JoystickController.h b/include/drivers/JoystickController.h new file mode 100644 index 0000000..e068404 --- /dev/null +++ b/include/drivers/JoystickController.h @@ -0,0 +1,68 @@ +#ifndef JOYSTICK_H +#define JOYSTICK_H + +#include + +enum JoystickDirection { + CENTER, + UP, + UP_RIGHT, + RIGHT, + DOWN_RIGHT, + DOWN, + DOWN_LEFT, + LEFT, + UP_LEFT +}; + +class JoystickController { + private: + uint8_t pinX; + uint8_t pinY; + uint8_t pinButton; + + int centerX; + int centerY; + + int rawX; + int rawY; + bool buttonState; + + int deadzone; + int debounceDelay; + unsigned long lastDebounceTime; + + int lastX; + int lastY; + bool lastButtonState; + + void readRawValues(); + + static JoystickController* _instance; + + public: + JoystickController(uint8_t xPin, uint8_t yPin, uint8_t buttonPin = 255); + ~JoystickController(); + + void begin(); + void calibrate(); + void setDeadzone(int value); + void setDebounceDelay(int delayMs); + void tick(); + + int getRawX(); + int getRawY(); + int getX(); + int getY(); + int getOffsetX(); + int getOffsetY(); + + bool isPressed(); + bool isCentered(); + + JoystickDirection getDirection(); + String getDirectionString(); + int getDistancePercent(); +}; + +#endif \ No newline at end of file diff --git a/include/drivers/LCDController.h b/include/drivers/LCDController.h new file mode 100644 index 0000000..d06e044 --- /dev/null +++ b/include/drivers/LCDController.h @@ -0,0 +1,34 @@ +#ifndef LCD_CONTROLLER_H +#define LCD_CONTROLLER_H + +#include +#include +#include +#include "LEDController.h" + +class LCDController { +private: + FILE* _lcdOutput; + LiquidCrystal* _lcd; + int _lcdCols; + int _lcdRows; + int _cursorRow; + int _cursorCol; + + static int lcdPutchar(char c, FILE* stream); + static LCDController* _instance; + +public: + LCDController(uint8_t rs, uint8_t enable, uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7, + int cols = 16, int rows = 2); + ~LCDController(); + void begin(); + FILE* stream(); + void clear(); + void setCursor(int col, int row); + void print(const char* text); + + static LCDController* getInstance() { return _instance; } +}; + +#endif \ No newline at end of file diff --git a/include/drivers/LEDController.h b/include/drivers/LEDController.h new file mode 100644 index 0000000..3317d7c --- /dev/null +++ b/include/drivers/LEDController.h @@ -0,0 +1,31 @@ +#ifndef LED_CONTROLLER_H +#define LED_CONTROLLER_H + +#include + +class LEDController { +private: + const int _ledPin; + bool _state; + bool _isBlinking; + unsigned long _previousMillis; + unsigned long _blinkInterval; + unsigned long _blinkCount; + +public: + LEDController(int ledPin); + LEDController(int ledPin, bool state); + void turnOn(); + void turnOff(); + void toggle(); + bool getState() const; + void blink(bool enable); + bool isBlinkingEnabled() const; + void interval(unsigned long interval); + unsigned long getBlinkInterval() const; + unsigned long getBlinkCount() const; + void tick(); + void set(bool value); +}; + +#endif \ No newline at end of file diff --git a/include/drivers/MotorController.h b/include/drivers/MotorController.h new file mode 100644 index 0000000..42de9a1 --- /dev/null +++ b/include/drivers/MotorController.h @@ -0,0 +1,24 @@ +#ifndef DC_MOTOR_DRIVER_H +#define DC_MOTOR_DRIVER_H + +#include + +class MotorController { +private: + const int _pinIA; + const int _pinIB; + int _currentPower; + + void applyPower(); + +public: + MotorController(int pinIA, int pinIB); + void set(int power); + void stop(); + void maximum(); + void inc(); + void dec(); + int getPower() const; +}; + +#endif \ No newline at end of file diff --git a/include/drivers/PassiveBuzzerController.h b/include/drivers/PassiveBuzzerController.h new file mode 100644 index 0000000..e69de29 diff --git a/include/drivers/PhotoresistorController.h b/include/drivers/PhotoresistorController.h new file mode 100644 index 0000000..72fc36f --- /dev/null +++ b/include/drivers/PhotoresistorController.h @@ -0,0 +1,35 @@ +#ifndef PHOTORESISTOR_CONTROLLER_H +#define PHOTORESISTOR_CONTROLLER_H + +#include + +#define DEFAULT_MIN_READ_INTERVAL 50 +#define DEFAULT_SAMPLES 3 + +class PhotoresistorController { +private: + uint8_t _pin; + unsigned long _lastReadTime; + unsigned long _minReadInterval; + int _lastRawValue; + int _lastPercentValue; + bool _lastReadSuccess; + uint8_t _numSamples; + int _maxValue; + int _minValue; + +public: + PhotoresistorController(uint8_t pin, int minValue = 0, int maxValue = 1023); + void begin(); + bool read(); + int getRawValue(); + int getPercentValue(); + void calibrate(int minValue, int maxValue); + void autoCalibrateDark(); + void autoCalibrateBright(); + bool isLastReadSuccessful() const; + void setMinReadInterval(unsigned long interval); + void setNumSamples(uint8_t samples); +}; + +#endif \ No newline at end of file diff --git a/include/drivers/RGBLEDController.h b/include/drivers/RGBLEDController.h new file mode 100644 index 0000000..e69de29 diff --git a/include/drivers/RelayController.h b/include/drivers/RelayController.h new file mode 100644 index 0000000..65abead --- /dev/null +++ b/include/drivers/RelayController.h @@ -0,0 +1,38 @@ +#ifndef RELAY_CONTROLLER_H +#define RELAY_CONTROLLER_H + +#include + +class RelayController { +private: + const int _relayPin; + bool _isConnected; + +public: + RelayController(int relayPin) : + _relayPin(relayPin), + _isConnected(false) { + pinMode(_relayPin, OUTPUT); + disconnect(); + } + + void connect() { + digitalWrite(_relayPin, LOW); + _isConnected = true; + } + + void disconnect() { + digitalWrite(_relayPin, HIGH); + _isConnected = false; + } + + bool isConnected() const { + return _isConnected; + } + + int getPin() const { + return _relayPin; + } +}; + +#endif \ No newline at end of file diff --git a/include/drivers/ThermistorController.h b/include/drivers/ThermistorController.h new file mode 100644 index 0000000..ded2665 --- /dev/null +++ b/include/drivers/ThermistorController.h @@ -0,0 +1,54 @@ +#ifndef THERMISTOR_CONTROLLER_H +#define THERMISTOR_CONTROLLER_H + +#include + +class ThermistorController { +private: + const int _thermistorPin; + const float _seriesResistor; + const float _bParameter; + const float _nominalTemp; + + static const int _bufferSize = 10; + float _rawReadings[_bufferSize]; + int _bufferIndex; + bool _bufferFilled; + + float _filteredRaw; + float _smoothedRaw; + float _resistance; + float _temperatureC; + + const float _weights[_bufferSize] = {0.05, 0.05, 0.05, 0.05, 0.1, 0.1, 0.1, 0.15, 0.15, 0.2}; + + const float _minTemp; + const float _maxTemp; + + float applySaltPepperFilter(); + float applyWeightedMovingAverage(); + float calculateResistance(float adcValue); + float calculateTemperature(float resistance); + float applySaturation(float value, float min, float max); + +public: + ThermistorController( + int thermistorPin, + float seriesResistor = 10000.0, + float bParameter = 3435.0, + float nominalTemp = 25.0, + float minTemp = -55.0, + float maxTemp = 125.0 + ); + + void update(); + + float getRawValue() const; + float getFilteredRaw() const; + float getSmoothedRaw() const; + float getResistance() const; + float getTemperatureC() const; + float getTemperatureF() const; +}; + +#endif \ No newline at end of file diff --git a/include/labs/Lab2_1.h b/include/labs/Lab2_1.h new file mode 100644 index 0000000..e0311b4 --- /dev/null +++ b/include/labs/Lab2_1.h @@ -0,0 +1,24 @@ +#ifndef LAB2_1_H +#define LAB2_1_H + +#include +#include +#include "drivers/LEDController.h" +#include "drivers/ButtonController.h" +#include "drivers/LCDController.h" + +#define BUTTON_TOGGLE_PIN 13 +#define BUTTON_INCREMENT_PIN 11 +#define BUTTON_DECREMENT_PIN 12 +#define LED_PIN 22 +#define LED_BLINK_PIN 24 +#define RS 31 +#define EN 33 +#define D4 35 +#define D5 37 +#define D6 39 +#define D7 41 + +void Lab2_1Task(void* pv); + +#endif \ No newline at end of file diff --git a/include/labs/Lab2_2.h b/include/labs/Lab2_2.h new file mode 100644 index 0000000..9c21afd --- /dev/null +++ b/include/labs/Lab2_2.h @@ -0,0 +1,33 @@ +#ifndef LAB2_2_H +#define LAB2_2_H + +#include +#include +#include +#include +#include "drivers/LEDController.h" +#include "drivers/ButtonController.h" +#include "drivers/LCDController.h" + +#define LED_BUTTON_PIN 28 +#define LED_BLINK_PIN 24 +#define BUTTON_PIN 13 +#define RS 31 +#define EN 33 +#define D4 35 +#define D5 37 +#define D6 39 +#define D7 41 + +typedef struct { + ButtonController* button; + LEDController* led; + LEDController* blinkLed; + LCDController* lcd; + SemaphoreHandle_t buttonSemaphore; + QueueHandle_t dataQueue; +} TaskParameters; + +void Lab2_2Task(void* pv); + +#endif \ No newline at end of file diff --git a/include/labs/Lab3_1.h b/include/labs/Lab3_1.h new file mode 100644 index 0000000..5395c95 --- /dev/null +++ b/include/labs/Lab3_1.h @@ -0,0 +1,33 @@ +#ifndef LAB3_1_H +#define LAB3_1_H + +#include +#include +#include "drivers/LCDController.h" +#include "drivers/JoystickController.h" +#include "drivers/DHTController.h" +#include "drivers/AccelerometerController.h" +#include "drivers/PhotoresistorController.h" +#include "drivers/DistanceSensorController.h" + +#define VRX A0 +#define VRY A1 +#define SW 15 +#define RS 31 +#define EN 33 +#define D4 35 +#define D5 37 +#define D6 39 +#define D7 41 +#define DHT_PIN 4 +#define PHOTORESISTOR_PIN A3 +#define TRIG_PIN 5 +#define ECHO_PIN 6 + +void Lab3_1Task(void* pv); +void DHTTask(void* pv); +void AccelerometerTask(void* pv); +void PhotoresistorTask(void*pv); +void DistanceTask(void* pv); + +#endif \ No newline at end of file diff --git a/include/labs/Lab3_2.h b/include/labs/Lab3_2.h new file mode 100644 index 0000000..afd557f --- /dev/null +++ b/include/labs/Lab3_2.h @@ -0,0 +1,19 @@ +#ifndef LAB3_2_H +#define LAB3_2_H + +#include +#include +#include "drivers/LCDController.h" +#include "drivers/ThermistorController.h" + +#define THERMISTOR_PIN A2 +#define RS 31 +#define EN 33 +#define D4 35 +#define D5 37 +#define D6 39 +#define D7 41 + +void Lab3_2Task(void* pv); + +#endif \ No newline at end of file diff --git a/include/labs/Lab4_1.h b/include/labs/Lab4_1.h new file mode 100644 index 0000000..23205e1 --- /dev/null +++ b/include/labs/Lab4_1.h @@ -0,0 +1,23 @@ +#ifndef LAB4_1_H +#define LAB4_1_H + +#include +#include +#include "drivers/LCDController.h" +#include "drivers/JoystickController.h" +#include "drivers/RelayController.h" + +#define VRX A0 +#define VRY A1 +#define SW 15 +#define RS 31 +#define EN 33 +#define D4 35 +#define D5 37 +#define D6 39 +#define D7 41 +#define RELAY_PIN 14 + +void Lab4_1Task(void* pv); + +#endif \ No newline at end of file diff --git a/include/labs/Lab4_2.h b/include/labs/Lab4_2.h new file mode 100644 index 0000000..9ab1598 --- /dev/null +++ b/include/labs/Lab4_2.h @@ -0,0 +1,26 @@ +#ifndef LAB4_2_H +#define LAB4_2_H + +#include +#include +#include "drivers/LCDController.h" +#include "drivers/JoystickController.h" +#include "drivers/RelayController.h" +#include "drivers/MotorController.h" + +#define MOTOR_PIN_IA 2 +#define MOTOR_PIN_IB 3 +#define RELAY_PIN 14 +#define VRX A0 +#define VRY A1 +#define SW 15 +#define RS 31 +#define EN 33 +#define D4 35 +#define D5 37 +#define D6 39 +#define D7 41 + +void Lab4_2Task(void* pv); + +#endif \ No newline at end of file diff --git a/include/labs/LabSelector.h b/include/labs/LabSelector.h new file mode 100644 index 0000000..94c55e3 --- /dev/null +++ b/include/labs/LabSelector.h @@ -0,0 +1,21 @@ +#ifndef LABSELECTOR_H +#define LABSELECTOR_H + +#include +#include +#include "drivers/LCDController.h" +#include "drivers/JoystickController.h" +#include "Lab2_1.h" +#include "Lab2_2.h" +#include "Lab3_1.h" +#include "Lab3_2.h" +#include "Lab4_1.h" +#include "Lab4_2.h" + +#define VRX A0 +#define VRY A1 +#define SW 15 + +void LabSelectorTask(void* pv); + +#endif \ No newline at end of file diff --git a/platformio.ini b/platformio.ini new file mode 100644 index 0000000..773cc71 --- /dev/null +++ b/platformio.ini @@ -0,0 +1,19 @@ + +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[env:megaatmega2560] +platform = atmelavr +board = megaatmega2560 +framework = arduino +lib_deps = + adafruit/DHT sensor library@^1.4.6 + feilipu/FreeRTOS@^10.5.1-0 + arduino-libraries/LiquidCrystal@^1.0.7 diff --git a/src/drivers/AccelerometerController.cpp b/src/drivers/AccelerometerController.cpp new file mode 100644 index 0000000..1736d43 --- /dev/null +++ b/src/drivers/AccelerometerController.cpp @@ -0,0 +1,130 @@ +#include "drivers/AccelerometerController.h" + +ADXL345Controller::ADXL345Controller(uint8_t deviceAddress) : + _deviceAddress(deviceAddress), + _lastReadTime(0), + _minReadInterval(DEFAULT_MIN_READ_INTERVAL), + _lastX(0.0), + _lastY(0.0), + _lastZ(0.0), + _lastReadSuccess(false) { +} + +void ADXL345Controller::begin() { + Wire.begin(); + + uint8_t deviceID = readRegister(ADXL345_DEVID); + if (deviceID != 0xE5) { + _lastReadSuccess = false; + return; + } + + setRegister(ADXL345_POWER_CTL, 0x08); + + setRegister(ADXL345_DATA_FORMAT, 0x0B); + + setRegister(ADXL345_BW_RATE, 0x0A); + + setRegister(ADXL345_OFSX, 0x00); + setRegister(ADXL345_OFSY, 0x00); + setRegister(ADXL345_OFSZ, 0x00); + + _lastReadSuccess = true; +} + +bool ADXL345Controller::read() { + unsigned long currentTime = millis(); + + if (currentTime - _lastReadTime >= _minReadInterval) { + _lastReadTime = currentTime; + + uint8_t buffer[6]; + readRegisters(ADXL345_DATAX0, 6, buffer); + + int16_t x = ((int16_t)buffer[1] << 8) | buffer[0]; + int16_t y = ((int16_t)buffer[3] << 8) | buffer[2]; + int16_t z = ((int16_t)buffer[5] << 8) | buffer[4]; + + _lastX = x / 256.0; + _lastY = y / 256.0; + _lastZ = z / 256.0; + + _lastReadSuccess = true; + return true; + } + + return _lastReadSuccess; +} + +double ADXL345Controller::getX() { + if (millis() - _lastReadTime >= _minReadInterval) read(); + return _lastX; +} + +double ADXL345Controller::getY() { + if (millis() - _lastReadTime >= _minReadInterval) read(); + return _lastY; +} + +double ADXL345Controller::getZ() { + if (millis() - _lastReadTime >= _minReadInterval) read(); + return _lastZ; +} + +bool ADXL345Controller::isLastReadSuccessful() const { + return _lastReadSuccess; +} + +void ADXL345Controller::setMinReadInterval(unsigned long interval) { + _minReadInterval = interval; +} + +void ADXL345Controller::setRange(uint8_t range) { + uint8_t format = readRegister(ADXL345_DATA_FORMAT); + + format &= ~0x03; + + if (range > 3) range = 3; + format |= range; + + setRegister(ADXL345_DATA_FORMAT, format); +} + +void ADXL345Controller::setDataRate(uint8_t rate) { + if (rate > 15) rate = 15; + + setRegister(ADXL345_BW_RATE, rate); +} + +void ADXL345Controller::setOffsets(int8_t xOffset, int8_t yOffset, int8_t zOffset) { + setRegister(ADXL345_OFSX, xOffset); + setRegister(ADXL345_OFSY, yOffset); + setRegister(ADXL345_OFSZ, zOffset); +} + +void ADXL345Controller::setRegister(uint8_t reg, uint8_t value) { + Wire.beginTransmission(_deviceAddress); + Wire.write(reg); + Wire.write(value); + Wire.endTransmission(); +} + +uint8_t ADXL345Controller::readRegister(uint8_t reg) { + Wire.beginTransmission(_deviceAddress); + Wire.write(reg); + Wire.endTransmission(); + + Wire.requestFrom(_deviceAddress, (uint8_t)1); + return Wire.read(); +} + +void ADXL345Controller::readRegisters(uint8_t reg, uint8_t count, uint8_t *buffer) { + Wire.beginTransmission(_deviceAddress); + Wire.write(reg); + Wire.endTransmission(); + + Wire.requestFrom(_deviceAddress, count); + for (uint8_t i = 0; i < count && Wire.available(); i++) { + buffer[i] = Wire.read(); + } +} \ No newline at end of file diff --git a/src/drivers/ButtonController.cpp b/src/drivers/ButtonController.cpp new file mode 100644 index 0000000..34bd2be --- /dev/null +++ b/src/drivers/ButtonController.cpp @@ -0,0 +1,44 @@ +#include "drivers/ButtonController.h" + +ButtonController::ButtonController(int buttonPin, unsigned long debounceDelay) : + _buttonPin(buttonPin), + _lastDebounceTime(0), + _debounceDelay(debounceDelay), + _lastButtonState(HIGH), + _buttonState(HIGH) { + + pinMode(_buttonPin, INPUT_PULLUP); +} + +bool ButtonController::wasOn() { + bool result = false; + int reading = digitalRead(_buttonPin); + + if (reading != _lastButtonState) _lastDebounceTime = millis(); + + if ((millis() - _lastDebounceTime) > _debounceDelay) { + if (reading != _buttonState) { + _buttonState = reading; + if (_buttonState == LOW) result = true; + } + } + + _lastButtonState = reading; + + return result; +} + +void ButtonController::tick() { + int reading = digitalRead(_buttonPin); + + if (reading != _lastButtonState) _lastDebounceTime = millis(); + + if ((millis() - _lastDebounceTime) > _debounceDelay) + if (reading != _buttonState) _buttonState = reading; + + _lastButtonState = reading; +} + +bool ButtonController::getState() const { + return _buttonState; +} \ No newline at end of file diff --git a/src/drivers/DHTController.cpp b/src/drivers/DHTController.cpp new file mode 100644 index 0000000..b9b2721 --- /dev/null +++ b/src/drivers/DHTController.cpp @@ -0,0 +1,58 @@ +#include "drivers/DHTController.h" + +#define DEFAULT_MIN_READ_INTERVAL 2000 + +DHTController::DHTController(uint8_t pin, uint8_t type) : + _dht(pin, type), + _lastReadTime(0), + _minReadInterval(DEFAULT_MIN_READ_INTERVAL), + _lastTemperature(0.0f), + _lastHumidity(0.0f), + _lastReadSuccess(false) { +} + +void DHTController::begin() { + _dht.begin(); +} + +bool DHTController::read() { + unsigned long currentTime = millis(); + + if (currentTime - _lastReadTime >= _minReadInterval) { + _lastReadTime = currentTime; + + float humidity = _dht.readHumidity(); + + float temperature = _dht.readTemperature(); + + if (isnan(humidity) || isnan(temperature)) { + _lastReadSuccess = false; + return false; + } + + _lastHumidity = humidity; + _lastTemperature = temperature; + _lastReadSuccess = true; + return true; + } + + return _lastReadSuccess; +} + +float DHTController::getTemperature() { + if (millis() - _lastReadTime >= _minReadInterval) read(); + return _lastTemperature; +} + +float DHTController::getHumidity() { + if (millis() - _lastReadTime >= _minReadInterval) read(); + return _lastHumidity; +} + +bool DHTController::isLastReadSuccessful() const { + return _lastReadSuccess; +} + +void DHTController::setMinReadInterval(unsigned long interval) { + _minReadInterval = interval; +} \ No newline at end of file diff --git a/src/drivers/DistanceSensorController.cpp b/src/drivers/DistanceSensorController.cpp new file mode 100644 index 0000000..ab95e1c --- /dev/null +++ b/src/drivers/DistanceSensorController.cpp @@ -0,0 +1,99 @@ +#include "drivers/DistanceSensorController.h" + +DistanceSensorController::DistanceSensorController(uint8_t trigPin, uint8_t echoPin) : + _trigPin(trigPin), + _echoPin(echoPin), + _lastReadTime(0), + _minReadInterval(DEFAULT_MIN_READ_INTERVAL_DIST), + _lastDistanceCm(0), + _lastReadSuccess(false), + _numSamples(DEFAULT_SAMPLES), + _timeout(30000) { +} + +void DistanceSensorController::begin() { + pinMode(_trigPin, OUTPUT); + pinMode(_echoPin, INPUT); + _lastReadSuccess = true; +} + +bool DistanceSensorController::read() { + unsigned long currentTime = millis(); + + if (currentTime - _lastReadTime >= _minReadInterval) { + _lastReadTime = currentTime; + + long sum = 0; + int validSamples = 0; + + for (uint8_t i = 0; i < _numSamples; i++) { + long measurement = takeMeasurement(); + + if (measurement > 0 && measurement < MAX_DISTANCE) { + sum += measurement; + validSamples++; + } + + if (_numSamples > 1) { + delay(10); + } + } + + if (validSamples > 0) { + _lastDistanceCm = sum / validSamples; + _lastReadSuccess = true; + } else { + _lastReadSuccess = false; + } + + return _lastReadSuccess; + } + + return _lastReadSuccess; +} + +long DistanceSensorController::takeMeasurement() { + digitalWrite(_trigPin, LOW); + delayMicroseconds(2); + + digitalWrite(_trigPin, HIGH); + delayMicroseconds(10); + digitalWrite(_trigPin, LOW); + + long duration = pulseIn(_echoPin, HIGH, _timeout); + + return microsecondsToCentimeters(duration); +} + +long DistanceSensorController::microsecondsToCentimeters(long microseconds) { + if (microseconds == 0) return 0; + return microseconds / 29 / 2; +} + +long DistanceSensorController::getDistanceCm() { + if (millis() - _lastReadTime >= _minReadInterval) read(); + return _lastDistanceCm; +} + +long DistanceSensorController::getDistanceInch() { + if (millis() - _lastReadTime >= _minReadInterval) read(); + return _lastDistanceCm / 2.54; +} + +bool DistanceSensorController::isLastReadSuccessful() const { + return _lastReadSuccess; +} + +void DistanceSensorController::setMinReadInterval(unsigned long interval) { + _minReadInterval = interval; +} + +void DistanceSensorController::setNumSamples(uint8_t samples) { + if (samples > 0) { + _numSamples = samples; + } +} + +void DistanceSensorController::setTimeout(unsigned long timeout) { + _timeout = timeout; +} \ No newline at end of file diff --git a/src/drivers/JoystickController.cpp b/src/drivers/JoystickController.cpp new file mode 100644 index 0000000..fcb59d9 --- /dev/null +++ b/src/drivers/JoystickController.cpp @@ -0,0 +1,177 @@ +#include "drivers/JoystickController.h" + +JoystickController* JoystickController::_instance = nullptr; + +JoystickController::JoystickController(uint8_t xPin, uint8_t yPin, uint8_t buttonPin) { + pinX = xPin; + pinY = yPin; + pinButton = buttonPin; + + centerX = 512; + centerY = 512; + deadzone = 100; + debounceDelay = 10; + lastDebounceTime = 0; + + lastX = centerX; + lastY = centerY; + lastButtonState = false; + + pinMode(pinX, INPUT); + pinMode(pinY, INPUT); + + if (pinButton != 255) { + pinMode(pinButton, INPUT_PULLUP); + } + + _instance = this; + + calibrate(); +} + +JoystickController::~JoystickController() { + if (_instance == this) _instance = nullptr; +} + +void JoystickController::readRawValues() { + rawX = analogRead(pinX); + rawY = analogRead(pinY); + + if (pinButton != 255) { + buttonState = !digitalRead(pinButton); + } +} + +void JoystickController::begin() { + for (int i = 0; i < 10; i++) { + readRawValues(); + delay(5); + } + + calibrate(); +} + +void JoystickController::calibrate() { + int sumX = 0; + int sumY = 0; + const int samples = 20; + + for (int i = 0; i < samples; i++) { + readRawValues(); + sumX += rawX; + sumY += rawY; + delay(5); + } + + centerX = sumX / samples; + centerY = sumY / samples; + + lastX = centerX; + lastY = centerY; +} + +void JoystickController::setDeadzone(int value) { + deadzone = constrain(value, 0, 512); +} + +void JoystickController::setDebounceDelay(int delayMs) { + debounceDelay = delayMs; +} + +void JoystickController::tick() { + readRawValues(); + + if ((millis() - lastDebounceTime) > debounceDelay) { + if (abs(rawX - lastX) > deadzone || abs(rawY - lastY) > deadzone || buttonState != lastButtonState) { + lastX = rawX; + lastY = rawY; + lastButtonState = buttonState; + lastDebounceTime = millis(); + } + } +} + +int JoystickController::getRawX() { + return rawX; +} + +int JoystickController::getRawY() { + return rawY; +} + +int JoystickController::getX() { + return lastX; +} + +int JoystickController::getY() { + return lastY; +} + +int JoystickController::getOffsetX() { + return lastX - centerX; +} + +int JoystickController::getOffsetY() { + return lastY - centerY; +} + +bool JoystickController::isPressed() { + return lastButtonState; +} + +bool JoystickController::isCentered() { + return (abs(lastX - centerX) <= deadzone && abs(lastY - centerY) <= deadzone); +} + +JoystickDirection JoystickController::getDirection() { + int dx = lastX - centerX; + int dy = lastY - centerY; + + if (abs(dx) <= deadzone && abs(dy) <= deadzone) { + return CENTER; + } + + float angle = atan2(-dy, dx) * 180 / PI; + + float adjusted = angle + 22.5; + if (adjusted < 0) adjusted += 360; + + int sector = int(adjusted / 45) % 8; + + switch (sector) { + case 0: return RIGHT; + case 1: return UP_RIGHT; + case 2: return UP; + case 3: return UP_LEFT; + case 4: return LEFT; + case 5: return DOWN_LEFT; + case 6: return DOWN; + case 7: return DOWN_RIGHT; + default: return CENTER; + } +} + +String JoystickController::getDirectionString() { + JoystickDirection dir = getDirection(); + + switch (dir) { + case CENTER: return "CENTER"; + case UP: return "UP"; + case UP_RIGHT: return "UP_RIGHT"; + case RIGHT: return "RIGHT"; + case DOWN_RIGHT:return "DOWN_RIGHT"; + case DOWN: return "DOWN"; + case DOWN_LEFT: return "DOWN_LEFT"; + case LEFT: return "LEFT"; + case UP_LEFT: return "UP_LEFT"; + default: return "UNKNOWN"; + } +} + +int JoystickController::getDistancePercent() { + int dx = lastX - centerX; + int dy = lastY - centerY; + float distance = sqrt(dx*dx + dy*dy); + + return constrain(map(distance, deadzone, 512, 0, 100), 0, 100); +} \ No newline at end of file diff --git a/src/drivers/LCDController.cpp b/src/drivers/LCDController.cpp new file mode 100644 index 0000000..9fbb368 --- /dev/null +++ b/src/drivers/LCDController.cpp @@ -0,0 +1,89 @@ +#include "drivers/LCDController.h" + +LCDController* LCDController::_instance = nullptr; + +int LCDController::lcdPutchar(char c, FILE* stream) { + if (_instance && _instance->_lcd) { + if (c == '\n') { + _instance->_cursorRow = (_instance->_cursorRow + 1) % _instance->_lcdRows; + _instance->_cursorCol = 0; + _instance->_lcd->setCursor(_instance->_cursorCol, _instance->_cursorRow); + } + else if (c == '\r') { + _instance->_cursorCol = 0; + _instance->_lcd->setCursor(_instance->_cursorCol, _instance->_cursorRow); + } + else { + _instance->_lcd->write(c); + _instance->_cursorCol++; + + if (_instance->_cursorCol >= _instance->_lcdCols) { + _instance->_cursorRow = (_instance->_cursorRow + 1) % _instance->_lcdRows; + _instance->_cursorCol = 0; + _instance->_lcd->setCursor(_instance->_cursorCol, _instance->_cursorRow); + } + } + } + return 0; +} + +LCDController::LCDController(uint8_t rs, uint8_t enable, uint8_t d4, uint8_t d5, uint8_t d6, uint8_t d7, + int cols, int rows) : + _lcdOutput(nullptr), + _lcdCols(cols), + _lcdRows(rows), + _cursorRow(0), + _cursorCol(0) { + + _lcd = new LiquidCrystal(rs, enable, d4, d5, d6, d7); + _instance = this; + + begin(); +} + +LCDController::~LCDController() { + if (_lcdOutput) fclose(_lcdOutput); + if (_lcd) delete _lcd; + _instance = nullptr; +} + +void LCDController::begin() { + _lcd->begin(_lcdCols, _lcdRows); + _lcd->clear(); + + _lcdOutput = fdevopen(lcdPutchar, NULL); +} + +FILE* LCDController::stream() { + return _lcdOutput; +} + +void LCDController::clear() { + if (_lcd) { + _lcd->clear(); + _cursorRow = 0; + _cursorCol = 0; + } +} + +void LCDController::setCursor(int col, int row) { + if (_lcd) { + _cursorCol = col; + _cursorRow = row; + _lcd->setCursor(col, row); + } +} + +void LCDController::print(const char* text) { + if (_lcd) { + _lcd->print(text); + + int len = strlen(text); + _cursorCol += len; + + while (_cursorCol >= _lcdCols) { + _cursorCol -= _lcdCols; + _cursorRow = (_cursorRow + 1) % _lcdRows; + } + } +} \ No newline at end of file diff --git a/src/drivers/LEDController.cpp b/src/drivers/LEDController.cpp new file mode 100644 index 0000000..2c3f4d4 --- /dev/null +++ b/src/drivers/LEDController.cpp @@ -0,0 +1,88 @@ +#include "drivers/LEDController.h" + +#define BLINK_INTERVAL 500 + +LEDController::LEDController(int ledPin) : + _ledPin(ledPin), + _state(false), + _isBlinking(false), + _previousMillis(0), + _blinkInterval(BLINK_INTERVAL), + _blinkCount(0) { + + pinMode(_ledPin, OUTPUT); + digitalWrite(_ledPin, LOW); +} + +LEDController::LEDController(int ledPin, bool state) : + _ledPin(ledPin), + _state(state), + _isBlinking(false), + _previousMillis(0), + _blinkInterval(BLINK_INTERVAL), + _blinkCount(0) { + + pinMode(_ledPin, OUTPUT); + + if (state) digitalWrite(_ledPin, HIGH); + else digitalWrite(_ledPin, LOW); +} + +void LEDController::turnOn() { + _state = true; + digitalWrite(_ledPin, HIGH); +} + +void LEDController::turnOff() { + _state = false; + digitalWrite(_ledPin, LOW); +} + +void LEDController::toggle() { + _state = !_state; + digitalWrite(_ledPin, _state); +} + +bool LEDController::getState() const { + return _state; +} + +void LEDController::blink(bool enable) { + _isBlinking = enable; + if (!enable) { + turnOff(); + } +} + +bool LEDController::isBlinkingEnabled() const { + return _isBlinking; +} + +void LEDController::interval(unsigned long interval) { + _blinkInterval = interval; +} + +unsigned long LEDController::getBlinkInterval() const { + return _blinkInterval; +} + +unsigned long LEDController::getBlinkCount() const { + return _blinkCount; +} + +void LEDController::tick() { + if (_isBlinking) { + unsigned long currentMillis = millis(); + + if (currentMillis - _previousMillis >= _blinkInterval) { + _previousMillis = currentMillis; + toggle(); + if (_state)_blinkCount++; + } + } +} + +void LEDController::set(bool value) { + if (value) turnOn(); + else turnOff(); +} \ No newline at end of file diff --git a/src/drivers/MotorController.cpp b/src/drivers/MotorController.cpp new file mode 100644 index 0000000..c8e3dc0 --- /dev/null +++ b/src/drivers/MotorController.cpp @@ -0,0 +1,71 @@ +#include "drivers/MotorController.h" + +MotorController::MotorController(int pinIA, int pinIB) : + _pinIA(pinIA), + _pinIB(pinIB), + _currentPower(0) { + + pinMode(_pinIA, OUTPUT); + pinMode(_pinIB, OUTPUT); + stop(); +} + +void MotorController::applyPower() { + if (_currentPower == 0) { + analogWrite(_pinIA, 0); + analogWrite(_pinIB, 0); + } else if (_currentPower > 0) { + int pwmValue = map(abs(_currentPower), 0, 100, 0, 255); + analogWrite(_pinIA, pwmValue); + analogWrite(_pinIB, 0); + } else { + int pwmValue = map(abs(_currentPower), 0, 100, 0, 255); + analogWrite(_pinIA, 0); + analogWrite(_pinIB, pwmValue); + } +} + +void MotorController::set(int power) { + _currentPower = constrain(power, -100, 100); + applyPower(); +} + +void MotorController::stop() { + _currentPower = 0; + applyPower(); +} + +void MotorController::maximum() { + if (_currentPower >= 0) { + _currentPower = 100; + } else { + _currentPower = -100; + } + applyPower(); +} + +void MotorController::inc() { + if (_currentPower == 0) { + _currentPower = 10; + } else { + if (_currentPower > 0) { + _currentPower = min(100, _currentPower + 10); + } else { + _currentPower = max(-100, _currentPower - 10); + } + } + applyPower(); +} + +void MotorController::dec() { + if (_currentPower > 0) { + _currentPower = max(0, _currentPower - 10); + } else if (_currentPower < 0) { + _currentPower = min(0, _currentPower + 10); + } + applyPower(); +} + +int MotorController::getPower() const { + return _currentPower; +} \ No newline at end of file diff --git a/src/drivers/PassiveBuzzerController.cpp b/src/drivers/PassiveBuzzerController.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/drivers/PhotoresistorController.cpp b/src/drivers/PhotoresistorController.cpp new file mode 100644 index 0000000..ccf143c --- /dev/null +++ b/src/drivers/PhotoresistorController.cpp @@ -0,0 +1,90 @@ +#include "drivers/PhotoresistorController.h" + +PhotoresistorController::PhotoresistorController(uint8_t pin, int minValue, int maxValue) : + _pin(pin), + _lastReadTime(0), + _minReadInterval(DEFAULT_MIN_READ_INTERVAL), + _lastRawValue(0), + _lastPercentValue(0), + _lastReadSuccess(false), + _numSamples(DEFAULT_SAMPLES), + _maxValue(maxValue), + _minValue(minValue) { +} + +void PhotoresistorController::begin() { + pinMode(_pin, INPUT); + _lastReadSuccess = true; +} + +bool PhotoresistorController::read() { + unsigned long currentTime = millis(); + + if (currentTime - _lastReadTime >= _minReadInterval) { + _lastReadTime = currentTime; + + long sum = 0; + for (uint8_t i = 0; i < _numSamples; i++) { + sum += analogRead(_pin); + if (_numSamples > 1) { + delay(2); + } + } + + _lastRawValue = sum / _numSamples; + + long range = _maxValue - _minValue; + if (range <= 0) { + _lastPercentValue = 50; + } else { + int constrainedValue = constrain(_lastRawValue, _minValue, _maxValue); + _lastPercentValue = map(constrainedValue, _minValue, _maxValue, 0, 100); + } + + _lastReadSuccess = true; + return true; + } + + return _lastReadSuccess; +} + +int PhotoresistorController::getRawValue() { + if (millis() - _lastReadTime >= _minReadInterval) read(); + return _lastRawValue; +} + +int PhotoresistorController::getPercentValue() { + if (millis() - _lastReadTime >= _minReadInterval) read(); + return _lastPercentValue; +} + +void PhotoresistorController::calibrate(int minValue, int maxValue) { + if (minValue < maxValue) { + _minValue = minValue; + _maxValue = maxValue; + } +} + +void PhotoresistorController::autoCalibrateDark() { + read(); + _minValue = _lastRawValue; +} + +void PhotoresistorController::autoCalibrateBright() { + read(); + _maxValue = _lastRawValue; +} + +bool PhotoresistorController::isLastReadSuccessful() const { + return _lastReadSuccess; +} + +void PhotoresistorController::setMinReadInterval(unsigned long interval) { + _minReadInterval = interval; +} + +void PhotoresistorController::setNumSamples(uint8_t samples) { + if (samples > 0) { + _numSamples = samples; + } +} \ No newline at end of file diff --git a/src/drivers/RGBLEDController.cpp b/src/drivers/RGBLEDController.cpp new file mode 100644 index 0000000..e69de29 diff --git a/src/drivers/ThermistorController.cpp b/src/drivers/ThermistorController.cpp new file mode 100644 index 0000000..2a86630 --- /dev/null +++ b/src/drivers/ThermistorController.cpp @@ -0,0 +1,121 @@ +#include "drivers/ThermistorController.h" +#include + +ThermistorController::ThermistorController( + int thermistorPin, + float seriesResistor, + float bParameter, + float nominalTemp, + float minTemp, + float maxTemp +) : + _thermistorPin(thermistorPin), + _seriesResistor(seriesResistor), + _bParameter(bParameter), + _nominalTemp(nominalTemp), + _minTemp(minTemp), + _maxTemp(maxTemp), + _bufferIndex(0), + _bufferFilled(false), + _filteredRaw(0), + _smoothedRaw(0), + _resistance(0), + _temperatureC(0) +{ + pinMode(_thermistorPin, INPUT); + + for (int i = 0; i < _bufferSize; i++) { + _rawReadings[i] = 0; + } +} + +void ThermistorController::update() { + float rawValue = analogRead(_thermistorPin); + + _rawReadings[_bufferIndex] = rawValue; + + _bufferIndex = (_bufferIndex + 1) % _bufferSize; + if (_bufferIndex == 0) _bufferFilled = true; + + _filteredRaw = applySaltPepperFilter(); + _smoothedRaw = applyWeightedMovingAverage(); + _resistance = calculateResistance(_smoothedRaw); + _temperatureC = calculateTemperature(_resistance); + _temperatureC = applySaturation(_temperatureC, _minTemp, _maxTemp); +} + +int compare(const void* a, const void* b) { + return (*(int*)a - *(int*)b); +} + +float ThermistorController::applySaltPepperFilter() { + if (!_bufferFilled) { + return _rawReadings[(_bufferIndex - 1 + _bufferSize) % _bufferSize]; + } + + float sortedValues[_bufferSize]; + for (int i = 0; i < _bufferSize; i++) { + sortedValues[i] = _rawReadings[i]; + } + + qsort(sortedValues, _bufferSize, sizeof(int), compare); + + return sortedValues[_bufferSize / 2]; +} + +float ThermistorController::applyWeightedMovingAverage() { + if (!_bufferFilled) { + return _filteredRaw; + } + + float weightedSum = 0; + float sumOfWeights = 0; + + for (int i = 0; i < _bufferSize; i++) { + int index = (_bufferIndex - i - 1 + _bufferSize) % _bufferSize; + weightedSum += _rawReadings[index] * _weights[i]; + sumOfWeights += _weights[i]; + } + + return weightedSum / sumOfWeights; +} + +float ThermistorController::calculateResistance(float adcValue) { + return (1023.0 * _seriesResistor) / adcValue - _seriesResistor; +} + +float ThermistorController::calculateTemperature(float resistance) { + float logR = log(resistance / 10000.0); + float temp = (_bParameter / (logR + (_bParameter / (273.15 + _nominalTemp)))) - 273.15; + return temp; +} + +float ThermistorController::applySaturation(float value, float min, float max) { + if (value < min) return min; + if (value > max) return max; + return value; +} + +float ThermistorController::getRawValue() const { + return _rawReadings[(_bufferIndex - 1 + _bufferSize) % _bufferSize]; +} + +float ThermistorController::getFilteredRaw() const { + return _filteredRaw; +} + +float ThermistorController::getSmoothedRaw() const { + return _smoothedRaw; +} + +float ThermistorController::getResistance() const { + return _resistance; +} + +float ThermistorController::getTemperatureC() const { + return _temperatureC; +} + +float ThermistorController::getTemperatureF() const { + return _temperatureC * 9.0 / 5.0 + 32.0; +} \ No newline at end of file diff --git a/src/labs/Lab2_1.cpp b/src/labs/Lab2_1.cpp new file mode 100644 index 0000000..9c66ba8 --- /dev/null +++ b/src/labs/Lab2_1.cpp @@ -0,0 +1,45 @@ +#include "labs/Lab2_1.h" + +void TaskOne(bool* state, ButtonController* toggle, LEDController* led) { + if (toggle->wasOn()) *state = !*state; + led->set(*state); +} + +void TaskTwo(bool* toggleState, LEDController* led) { + led->tick(); + led->blink(!*toggleState); +} + +void TaskThree(int* delayMs, ButtonController* dec, ButtonController* inc, LEDController* led) { + *delayMs = dec->wasOn() ? max(200, *delayMs - 200) : inc->wasOn() ? min(4000, *delayMs + 200) : *delayMs; + led->interval(*delayMs); +} + +void TaskIdle(int* lastReportTime, bool* toggleState, int* delayState, LCDController* lcd) { + if (millis() - *lastReportTime < 300) return; + + *lastReportTime = millis(); + lcd->clear(); + printf("Toggle: %s\nDelay: %d ms", *toggleState ? "ON" : "OFF", *delayState); +} + +void Lab2_1Task(void* pv) { + LEDController ledToggle(LED_PIN), ledBlink(LED_BLINK_PIN); + LCDController lcd = LCDController(RS, EN, D4, D5, D6, D7); + ButtonController tog(BUTTON_TOGGLE_PIN), dec(BUTTON_DECREMENT_PIN), inc(BUTTON_INCREMENT_PIN); + + stdout = lcd.stream(); + + bool toggleState = false; + int delayMs = 1000; + int lastReportTime = 0; + + while(true) { + TaskOne(&toggleState, &tog, &ledToggle); + TaskTwo(&toggleState, &ledBlink); + TaskThree(&delayMs, &dec, &inc, &ledBlink); + TaskIdle(&lastReportTime, &toggleState, &delayMs, &lcd); + + vTaskDelay(pdMS_TO_TICKS(50)); + } +} diff --git a/src/labs/Lab2_2.cpp b/src/labs/Lab2_2.cpp new file mode 100644 index 0000000..7353bcd --- /dev/null +++ b/src/labs/Lab2_2.cpp @@ -0,0 +1,110 @@ +#include "labs/Lab2_2.h" + +void ButtonLedTask(void* parameters) { + TaskParameters* params = (TaskParameters*)parameters; + TickType_t xLastWakeTime = xTaskGetTickCount(); + + while(true) { + if (params->button->wasOn()) { + params->lcd->clear(); + params->led->set(true); + vTaskDelay(pdMS_TO_TICKS(1000)); + xSemaphoreGive(params->buttonSemaphore); + params->led->set(false); + } + + vTaskDelayUntil(&xLastWakeTime, pdMS_TO_TICKS(10)); + } +} + +void SyncTask(void* parameters) { + TaskParameters* params = (TaskParameters*)parameters; + int N = 0; + + while(true) { + if (xSemaphoreTake(params->buttonSemaphore, portMAX_DELAY) == pdTRUE) { + N = N + 1; + + for (int i = 1; i <= N; i++) { + xQueueSendToFront(params->dataQueue, &i, portMAX_DELAY); + vTaskDelay(pdMS_TO_TICKS(50)); + } + + // uint8_t endMarker = 0; + // xQueueSendToFront(params->dataQueue, &endMarker, portMAX_DELAY); + + for (int i = 0; i < N; i++) { + params->blinkLed->set(true); + vTaskDelay(pdMS_TO_TICKS(300)); + params->blinkLed->set(false); + vTaskDelay(pdMS_TO_TICKS(500)); + } + } + } +} + +void AsyncTask(void* parameters) { + TaskParameters* params = (TaskParameters*)parameters; + TickType_t xLastWakeTime = xTaskGetTickCount(); + uint8_t receivedByte; + + while(true) { + while (xQueueReceive(params->dataQueue, &receivedByte, 0) == pdTRUE) { + if (receivedByte == 0) { + printf("\n"); + } else { + printf("%d", receivedByte); + } + } + + vTaskDelayUntil(&xLastWakeTime, pdMS_TO_TICKS(200)); + } +} +void Lab2_2Task(void* pv) { + LEDController ledButton(LED_BUTTON_PIN), ledBlink(LED_BLINK_PIN); + LCDController lcd = LCDController(RS, EN, D4, D5, D6, D7); + ButtonController button(BUTTON_PIN); + + stdout = lcd.stream(); + + SemaphoreHandle_t buttonSemaphore = xSemaphoreCreateBinary(); + + QueueHandle_t dataQueue = xQueueCreate(100, sizeof(uint8_t)); + + TaskParameters taskParams; + taskParams.button = &button; + taskParams.led = &ledButton; + taskParams.blinkLed = &ledBlink; + taskParams.lcd = &lcd; + taskParams.buttonSemaphore = buttonSemaphore; + taskParams.dataQueue = dataQueue; + + xTaskCreate( + ButtonLedTask, + "ButtonLed", + configMINIMAL_STACK_SIZE, + &taskParams, + 1, + NULL + ); + + xTaskCreate( + SyncTask, + "Sync", + configMINIMAL_STACK_SIZE, + &taskParams, + 1, + NULL + ); + + xTaskCreate( + AsyncTask, + "Async", + configMINIMAL_STACK_SIZE, + &taskParams, + 1, + NULL + ); + + vTaskSuspend(NULL); +} \ No newline at end of file diff --git a/src/labs/Lab3_1.cpp b/src/labs/Lab3_1.cpp new file mode 100644 index 0000000..d2b1494 --- /dev/null +++ b/src/labs/Lab3_1.cpp @@ -0,0 +1,176 @@ +#include "labs/Lab3_1.h" +#include + +void Lab3_1Task(void* pv) { + LCDController lcd(RS, EN, D4, D5, D6, D7); + JoystickController joystick(VRX, VRY, SW); + stdout = lcd.stream(); + + const char* sensors[] = { + " DHT ", " Accltr ", " Light ", " Distance " + }; + const int totalSensors = 4; + int currentSensor = 0; + + auto printSelection = [&]() { + lcd.clear(); + printf("Picked:\n<-%s->", sensors[currentSensor]); + }; + + printf("Choose sensor <>"); + vTaskDelay(pdMS_TO_TICKS(2000)); + printSelection(); + + while (true) { + joystick.tick(); + JoystickDirection dir = joystick.getDirection(); + + if (dir == LEFT || dir == RIGHT) { + currentSensor = (dir == LEFT) ? (currentSensor + totalSensors - 1) % totalSensors : (currentSensor + 1) % totalSensors; + printSelection(); + vTaskDelay(pdMS_TO_TICKS(300)); + } + + if (joystick.isPressed()) { + lcd.clear(); + switch (currentSensor) { + case 0: xTaskCreate(DHTTask, "DHT", 512, NULL, 1, NULL); break; + case 1: xTaskCreate(AccelerometerTask, "Accelerometer", 512, NULL, 1, NULL); break; + case 2: xTaskCreate(PhotoresistorTask, "Photoresistor", 512, NULL, 1, NULL); break; + case 3: xTaskCreate(DistanceTask, "Distance", 512, NULL, 1, NULL); break; + } + vTaskDelete(NULL); + } + + vTaskDelay(pdMS_TO_TICKS(50)); + } +} + +void DHTTask(void* pv) { + LCDController lcd(RS, EN, D4, D5, D6, D7); + JoystickController joystick(VRX, VRY, SW); + DHTController dht = DHTController(DHT_PIN); + stdout = lcd.stream(); + + while (true) { + joystick.tick(); + + if(joystick.isPressed()) { + xTaskCreate(Lab3_1Task, "Lab3_1", 512, NULL, 1, NULL); + vTaskDelete(NULL); + } + + lcd.clear(); + bool success = dht.read(); + + float temp = dht.getTemperature(); + float hum = dht.getHumidity(); + + if(success && !isnan(temp) && !isnan(hum)) printf("Temp: %d.%d C\nHumi: %d.%d %%", (int)temp, (int)((temp - (int)temp) * 10), (int)hum, (int)((hum - (int)hum) * 10)); + else printf("Sensor read\nfailed!"); + + vTaskDelay(pdMS_TO_TICKS(200)); + } +} + +void AccelerometerTask(void* pv) { + LCDController lcd(RS, EN, D4, D5, D6, D7); + JoystickController joystick(VRX, VRY, SW); + ADXL345Controller accel; + stdout = lcd.stream(); + + accel.begin(); + accel.setRange(3); + + while (true) { + joystick.tick(); + + if(joystick.isPressed()) { + xTaskCreate(Lab3_1Task, "Lab3_1", 512, NULL, 1, NULL); + vTaskDelete(NULL); + } + + lcd.clear(); + bool success = accel.read(); + + double x = accel.getX(); + double y = accel.getY(); + double z = accel.getZ(); + + if(success) { + int x_whole = (int)x; + int x_dec = abs((int)((x - x_whole) * 100)); + + int y_whole = (int)y; + int y_dec = abs((int)((y - y_whole) * 100)); + + int z_whole = (int)z; + int z_dec = abs((int)((z - z_whole) * 100)); + + printf("Accelr XYZ:\n%d.%02d %d.%02d %d.%02d", x_whole, x_dec, y_whole, y_dec, z_whole, z_dec); + } else printf("Accel read\nfailed!"); + + vTaskDelay(pdMS_TO_TICKS(200)); + } +} + +void PhotoresistorTask(void* pv) { + LCDController lcd(RS, EN, D4, D5, D6, D7); + JoystickController joystick(VRX, VRY, SW); + PhotoresistorController photoresistor(PHOTORESISTOR_PIN); + stdout = lcd.stream(); + + photoresistor.begin(); + photoresistor.setNumSamples(5); + photoresistor.calibrate(100, 900); + + while (true) { + joystick.tick(); + + if(joystick.isPressed()) { + xTaskCreate(Lab3_1Task, "Lab3_1", 512, NULL, 1, NULL); + vTaskDelete(NULL); + } + + lcd.clear(); + bool success = photoresistor.read(); + + int rawValue = photoresistor.getRawValue(); + int percentValue = photoresistor.getPercentValue(); + + if(success) printf("Light Level:\nVal:%4d (%3d%%)", rawValue, percentValue); + else printf("Sensor read\nfailed!"); + + vTaskDelay(pdMS_TO_TICKS(200)); + } +} + +void DistanceTask(void* pv) { + LCDController lcd(RS, EN, D4, D5, D6, D7); + JoystickController joystick(VRX, VRY, SW); + DistanceSensorController distance(TRIG_PIN, ECHO_PIN); + stdout = lcd.stream(); + + distance.begin(); + + distance.setNumSamples(3); + + while (true) { + joystick.tick(); + + if(joystick.isPressed()) { + xTaskCreate(Lab3_1Task, "Lab3_1", 512, NULL, 1, NULL); + vTaskDelete(NULL); + } + + lcd.clear(); + bool success = distance.read(); + + long distanceCm = distance.getDistanceCm(); + + if(success) printf("Distance:\n%ld cm", distanceCm); + else printf("Sensor read\nfailed!"); + + vTaskDelay(pdMS_TO_TICKS(200)); + } +} \ No newline at end of file diff --git a/src/labs/Lab3_2.cpp b/src/labs/Lab3_2.cpp new file mode 100644 index 0000000..efb90a2 --- /dev/null +++ b/src/labs/Lab3_2.cpp @@ -0,0 +1,36 @@ +#include "labs/Lab3_2.h" + +void Lab3_2Task(void* pv) { + LCDController lcd(RS, EN, D4, D5, D6, D7); + + ThermistorController thermistor(THERMISTOR_PIN, 10000.0, 3435.0, 25.0, -55.0, 125.0); + + stdout = lcd.stream(); + + const TickType_t xFrequency = pdMS_TO_TICKS(200); + TickType_t xLastWakeTime = xTaskGetTickCount(); + + while (true) { + thermistor.update(); + + float tempC = thermistor.getTemperatureC(); + float tempF = thermistor.getTemperatureF(); + float resistance = thermistor.getResistance(); + + int tempCInt = (int)tempC; + int tempCDec = (int)((tempC - tempCInt) * 10); + + int tempFInt = (int)tempF; + int tempFDec = (int)((tempF - tempFInt) * 10); + + int resInt = (int)(resistance / 1000); + int resDec = (int)((resistance / 1000.0 - resInt) * 10); + + lcd.clear(); + printf("Temp: %d.%d C", tempCInt, tempCDec); + lcd.setCursor(0, 1); + printf("%d.%d F %d.%dk", tempFInt, tempFDec, resInt, resDec); + + vTaskDelayUntil(&xLastWakeTime, xFrequency); + } +} \ No newline at end of file diff --git a/src/labs/Lab4_1.cpp b/src/labs/Lab4_1.cpp new file mode 100644 index 0000000..e7e2575 --- /dev/null +++ b/src/labs/Lab4_1.cpp @@ -0,0 +1,47 @@ +#include "labs/Lab4_1.h" +#include + +void Lab4_1Task(void* pv) { + LCDController lcd(RS, EN, D4, D5, D6, D7); + JoystickController joystick(VRX, VRY, SW); + RelayController relay(RELAY_PIN); + stdout = lcd.stream(); + + const char* commands[] = { + "Turn ON", "Turn OFF" + }; + + const int totalCommands = 2; + int currentCommand = 0; + + auto printSelection = [&]() { + lcd.clear(); + printf("Relay is %s\n%s ->", relay.isConnected() ? "ON" : "OFF", commands[currentCommand]); + }; + + printf("Pick command <>"); + while(joystick.isCentered()) joystick.tick(); + printSelection(); + + while (true) { + joystick.tick(); + JoystickDirection dir = joystick.getDirection(); + + if (dir == LEFT || dir == RIGHT) { + currentCommand = (dir == LEFT) ? (currentCommand + totalCommands - 1) % totalCommands : (currentCommand + 1) % totalCommands; + printSelection(); + vTaskDelay(pdMS_TO_TICKS(300)); + } + + if (joystick.isPressed()) { + lcd.clear(); + switch (currentCommand) { + case 0: relay.connect(); break; + case 1: relay.disconnect(); break; + } + printSelection(); + } + + vTaskDelay(pdMS_TO_TICKS(50)); + } +} diff --git a/src/labs/Lab4_2.cpp b/src/labs/Lab4_2.cpp new file mode 100644 index 0000000..47ecead --- /dev/null +++ b/src/labs/Lab4_2.cpp @@ -0,0 +1,74 @@ +#include "labs/Lab4_2.h" + +void Lab4_2Task(void* pv) { + LCDController lcd(RS, EN, D4, D5, D6, D7); + JoystickController joystick(VRX, VRY, SW); + MotorController motor(MOTOR_PIN_IA, MOTOR_PIN_IB); + RelayController relay(RELAY_PIN); + relay.connect(); + + stdout = lcd.stream(); + + const char* commands[] = { + " set ", " stop ", " max ", " inc ", " dec " + }; + + const int totalCommands = 5; + int currentCommand = 0; + + auto printSelection = [&]() { + lcd.clear(); + printf("Power: %d%% \n%s ->", motor.getPower(), commands[currentCommand]); + }; + + printf("Motor Control\nUse joystick"); + vTaskDelay(pdMS_TO_TICKS(2000)); + printSelection(); + + while (true) { + joystick.tick(); + JoystickDirection dir = joystick.getDirection(); + + if (dir == LEFT || dir == RIGHT) { + currentCommand = (dir == LEFT) ? + (currentCommand + totalCommands - 1) % totalCommands : + (currentCommand + 1) % totalCommands; + printSelection(); + vTaskDelay(pdMS_TO_TICKS(300)); + } + + if (currentCommand == 0 && (dir == UP || dir == DOWN)) { + int power = motor.getPower(); + power = (dir == UP) ? min(100, power + 1) : max(-100, power - 1); + motor.set(power); + printSelection(); + vTaskDelay(pdMS_TO_TICKS(50)); + } + + if (joystick.isPressed()) { + lcd.clear(); + switch (currentCommand) { + case 1: + motor.stop(); + printf("Motor stopped"); + break; + case 2: + motor.maximum(); + printf("Max power: %d%%", motor.getPower()); + break; + case 3: + motor.inc(); + printf("Power inc: %d%%", motor.getPower()); + break; + case 4: + motor.dec(); + printf("Power dec: %d%%", motor.getPower()); + break; + } + vTaskDelay(pdMS_TO_TICKS(1000)); + printSelection(); + } + + vTaskDelay(pdMS_TO_TICKS(20)); + } +} diff --git a/src/labs/LabSelector.cpp b/src/labs/LabSelector.cpp new file mode 100644 index 0000000..77e9c05 --- /dev/null +++ b/src/labs/LabSelector.cpp @@ -0,0 +1,49 @@ +#include "labs/LabSelector.h" + +void LabSelectorTask(void* pv) { + LCDController lcd(RS, EN, D4, D5, D6, D7); + JoystickController joystick(VRX, VRY, SW); + stdout = lcd.stream(); + + const char* labNames[] = { + "Lab2.1", "Lab2.2", "Lab3.1", + "Lab3.2", "Lab4.1", "Lab4.2" + }; + const int totalLabs = 6; + int currentLab = 0; + + auto printSelection = [&]() { + lcd.clear(); + printf("Selected:\n<- %s ->", labNames[currentLab]); + }; + + printf("Lab Picker\nUse joystick <>"); + vTaskDelay(pdMS_TO_TICKS(2000)); + printSelection(); + + while (true) { + joystick.tick(); + JoystickDirection dir = joystick.getDirection(); + + if (dir == LEFT || dir == RIGHT) { + currentLab = (dir == LEFT) ? (currentLab + totalLabs - 1) % totalLabs : (currentLab + 1) % totalLabs; + printSelection(); + vTaskDelay(pdMS_TO_TICKS(300)); + } + + if (joystick.isPressed()) { + lcd.clear(); + switch (currentLab) { + case 0: xTaskCreate(Lab2_1Task, "Lab2_1", 512, NULL, 1, NULL); break; + case 1: xTaskCreate(Lab2_2Task, "Lab2_2", 512, NULL, 1, NULL); break; + case 2: xTaskCreate(Lab3_1Task, "Lab3_1", 512, NULL, 1, NULL); break; + case 3: xTaskCreate(Lab3_2Task, "Lab3_2", 512, NULL, 1, NULL); break; + case 4: xTaskCreate(Lab4_1Task, "Lab4_1", 512, NULL, 1, NULL); break; + case 5: xTaskCreate(Lab4_2Task, "Lab4_2", 512, NULL, 1, NULL); break; + } + vTaskDelete(NULL); + } + + vTaskDelay(pdMS_TO_TICKS(50)); + } +} diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..5abc52a --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,14 @@ +#include "labs/LabSelector.h" + +void setup() { + xTaskCreate( + LabSelectorTask, + "LabPicker", + 512, + NULL, + 1, + NULL + ); +} + +void loop() {} \ No newline at end of file diff --git a/test/README b/test/README new file mode 100644 index 0000000..9b1e87b --- /dev/null +++ b/test/README @@ -0,0 +1,11 @@ + +This directory is intended for PlatformIO Test Runner and project tests. + +Unit Testing is a software testing method by which individual units of +source code, sets of one or more MCU program modules together with associated +control data, usage procedures, and operating procedures, are tested to +determine whether they are fit for use. Unit testing finds problems early +in the development cycle. + +More information about PlatformIO Unit Testing: +- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html