Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <Wire.h>
- #include <SPI.h>
- #include <SD.h>
- #include <Adafruit_GFX.h>
- #include <Adafruit_SSD1306.h>
- #include <Adafruit_NeoPixel.h>
- #include <Adafruit_LPS2X.h>
- #include <Adafruit_LSM6DS3TRC.h>
- #include <freertos/FreeRTOS.h>
- #include <freertos/task.h>
- #include <freertos/semphr.h>
- // Define I2C pins for ESP32
- #define SDA_PIN 21
- #define SCL_PIN 22
- #define SCREEN_WIDTH 128
- #define SCREEN_HEIGHT 64
- #define OLED_RESET -1
- #define SCREEN_ADDRESS 0x3C
- #define HDC1000_ADDRESS 0x40 // I2C address for HDC1000 sensor
- #define SD_CS_PIN 5 // SD card CS pin on GPIO 5
- Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
- Adafruit_LPS22 lps22;
- Adafruit_LSM6DS3TRC lsm6ds3trc;
- const int button1Pin = 32; // SW1
- const int button2Pin = 33; // SW2
- const int irPin = 36;
- const int potPin = 34;
- const int ldrPin = 35;
- const int redLEDPin = 15; // Swapped with blue LED
- const int blueLEDPin = 2; // Swapped with red LED
- const int rgbLEDPin = 4;
- const int buzzerPin = 27;
- Adafruit_NeoPixel rgbLED(1, rgbLEDPin, NEO_GRB + NEO_KHZ800);
- int currentScreen = 0;
- unsigned long pulseLow, pulseHigh;
- unsigned long irHexValue;
- int potValue, ldrValue;
- bool buzzerActive = false;
- float temp = 0;
- float humidity = 0;
- float pressure = 0;
- float altitude = 0;
- // Adjustable logging interval (1 second default)
- unsigned long loggingInterval = 1000;
- unsigned long previousMillis = 0;
- // SD Card status variable
- bool sdCardAvailable = false;
- String sdCardErrorMessage = "";
- // Known sea level pressure for Centurion, South Africa in hPa
- const float knownSeaLevelPressure = 1026.0;
- // IMU sensor data
- sensors_event_t accelEvent;
- sensors_event_t gyroEvent;
- sensors_event_t tempEvent; // Added to hold temperature data from IMU
- // Mutexes for shared resources
- SemaphoreHandle_t xSensorDataMutex;
- SemaphoreHandle_t xDataMutex;
- // Button debouncing variables
- int button1State = HIGH; // the current stable state of button1
- int lastButton1Reading = HIGH; // the previous reading from the button1 pin
- unsigned long button1LastDebounceTime = 0; // the last time the button1 input pin was toggled
- int button2State = HIGH; // the current stable state of button2
- int lastButton2Reading = HIGH; // the previous reading from the button2 pin
- unsigned long button2LastDebounceTime = 0; // the last time the button2 input pin was toggled
- const unsigned long debounceDelay = 50; // the debounce time in milliseconds
- void setup() {
- Serial.begin(115200);
- while (!Serial)
- delay(10); // Wait for serial port to be available
- pinMode(button1Pin, INPUT_PULLUP);
- pinMode(button2Pin, INPUT_PULLUP);
- pinMode(irPin, INPUT);
- pinMode(potPin, INPUT);
- pinMode(ldrPin, INPUT);
- pinMode(redLEDPin, OUTPUT);
- pinMode(blueLEDPin, OUTPUT);
- pinMode(buzzerPin, OUTPUT);
- // Initialize I2C communication
- Wire.begin(SDA_PIN, SCL_PIN);
- // Initialize display
- Serial.println("Initializing display...");
- if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
- Serial.println(F("SSD1306 allocation failed"));
- for (;;);
- }
- display.clearDisplay();
- display.display();
- // Show splash screen
- displaySplashScreen();
- // Wait for user to press SW1 for IMU calibration
- waitForIMUCalibration();
- // Initialize the LSM6DS3TR-C IMU
- Serial.println("Initializing LSM6DS3TR-C IMU...");
- if (!lsm6ds3trc.begin_I2C()) {
- Serial.println("Failed to find LSM6DS3TR-C chip");
- while (1) {
- vTaskDelay(pdMS_TO_TICKS(10));
- }
- }
- Serial.println("LSM6DS3TR-C Found!");
- // Initialize the LPS22HB pressure sensor
- Serial.println("Initializing LPS22HB sensor...");
- if (!lps22.begin_I2C(0x5C)) { // Explicitly use address 0x5C
- Serial.println("Failed to find LPS22HB sensor at 0x5C");
- while (1) {
- vTaskDelay(pdMS_TO_TICKS(10));
- }
- }
- Serial.println("LPS22HB sensor initialized.");
- // Initialize RGB LED
- rgbLED.begin();
- rgbLED.show();
- // Print free heap memory
- Serial.print("Free heap memory before mutex creation: ");
- Serial.println(ESP.getFreeHeap());
- // Create mutex for sensor data
- xSensorDataMutex = xSemaphoreCreateMutex();
- if (xSensorDataMutex == NULL) {
- Serial.println("Failed to create sensor data mutex");
- while (1) {
- vTaskDelay(pdMS_TO_TICKS(1000));
- }
- }
- // Create mutex for shared data
- xDataMutex = xSemaphoreCreateMutex();
- if (xDataMutex == NULL) {
- Serial.println("Failed to create data mutex");
- while (1) {
- vTaskDelay(pdMS_TO_TICKS(1000));
- }
- }
- Serial.print("Free heap memory after mutex creation: ");
- Serial.println(ESP.getFreeHeap());
- // Initialize SD card (Optional: Comment out if not using SD card)
- /*
- Serial.println("Initializing SD card...");
- if (!SD.begin(SD_CS_PIN)) {
- Serial.println("SD card initialization failed!");
- sdCardAvailable = false;
- sdCardErrorMessage = "SD Init Failed";
- } else {
- Serial.println("SD card initialized.");
- sdCardAvailable = true;
- sdCardErrorMessage = "";
- }
- */
- // Create FreeRTOS tasks with sufficient stack sizes
- xTaskCreate(sensorTask, "Sensor Task", 4096, NULL, 1, NULL);
- xTaskCreate(displayTask, "Display Task", 4096, NULL, 1, NULL);
- // Only create logTask if SD card is available (Optional)
- /*
- if (sdCardAvailable) {
- xTaskCreate(logTask, "Log Task", 4096, NULL, 1, NULL);
- }
- */
- }
- void loop() {
- // Main loop is not used in this FreeRTOS implementation
- }
- void displaySplashScreen() {
- display.clearDisplay();
- display.setTextSize(1);
- display.setTextColor(SSD1306_WHITE);
- display.setCursor(10, 0);
- display.setTextWrap(false);
- display.println("Welcome!");
- display.println("");
- display.println("Place the board on a");
- display.println("stable, stationary,");
- display.println("and level surface.");
- display.println("");
- display.println("Press SW1 to calibrate");
- display.println("the IMU.");
- display.display();
- }
- void waitForIMUCalibration() {
- // Wait for SW1 to be pressed
- while (digitalRead(button1Pin) == HIGH) {
- vTaskDelay(pdMS_TO_TICKS(100)); // Small debounce delay
- }
- vTaskDelay(pdMS_TO_TICKS(200)); // Additional delay to ensure button release
- // Start IMU calibration once the button is pressed
- display.clearDisplay();
- display.setCursor(0, 0);
- display.setTextWrap(false);
- display.println("Calibrating IMU...");
- display.display();
- calibrateIMU();
- }
- void calibrateIMU() {
- // Calibration code can be added here if necessary
- vTaskDelay(pdMS_TO_TICKS(2000)); // Simulate calibration delay
- display.clearDisplay();
- display.setCursor(0, 0);
- display.setTextWrap(false);
- display.println("Calibration complete!");
- display.display();
- vTaskDelay(pdMS_TO_TICKS(1000));
- }
- void sensorTask(void *pvParameters) {
- (void)pvParameters;
- for (;;) {
- unsigned long currentMillis = millis();
- // Read the current state of button1
- int reading1 = digitalRead(button1Pin);
- // If the switch changed, due to noise or pressing:
- if (reading1 != lastButton1Reading) {
- // reset the debouncing timer
- button1LastDebounceTime = currentMillis;
- }
- if ((currentMillis - button1LastDebounceTime) > debounceDelay) {
- // whatever the reading is at, it's been there for longer than the debounce delay
- // so take it as the actual current state
- // if the button state has changed:
- if (reading1 != button1State) {
- button1State = reading1;
- // only increment screen if the new button state is LOW (button pressed)
- if (button1State == LOW) {
- currentScreen++;
- if (currentScreen > 11) currentScreen = 0;
- }
- }
- }
- lastButton1Reading = reading1;
- // Similar code for button2
- int reading2 = digitalRead(button2Pin);
- if (reading2 != lastButton2Reading) {
- button2LastDebounceTime = currentMillis;
- }
- if ((currentMillis - button2LastDebounceTime) > debounceDelay) {
- if (reading2 != button2State) {
- button2State = reading2;
- if (button2State == LOW) {
- currentScreen--;
- if (currentScreen < 0) currentScreen = 11;
- }
- }
- }
- lastButton2Reading = reading2;
- // Read IMU data
- if (xSemaphoreTake(xSensorDataMutex, pdMS_TO_TICKS(100)) == pdTRUE) {
- if (!lsm6ds3trc.getEvent(&accelEvent, &gyroEvent, &tempEvent)) {
- Serial.println("Failed to read IMU data");
- }
- xSemaphoreGive(xSensorDataMutex);
- } else {
- Serial.println("Failed to take sensor data mutex in sensorTask");
- }
- // Read other sensors based on the current screen
- switch (currentScreen) {
- case 0:
- readIRSensor();
- break;
- case 3:
- readTempHumidity();
- break;
- case 4:
- readPressureSensor();
- break;
- case 5:
- potValue = averageAnalogRead(potPin, 20);
- break;
- case 6:
- ldrValue = analogRead(ldrPin);
- break;
- case 9:
- // Read potentiometer value for RGB LED control
- potValue = averageAnalogRead(potPin, 5);
- break;
- // Cases 7-11 are for LED, buzzer, and SD card status
- }
- vTaskDelay(pdMS_TO_TICKS(10)); // Adjust the delay as needed
- }
- }
- void readIRSensor() {
- if (digitalRead(irPin) == LOW) {
- pulseLow = pulseIn(irPin, LOW, 100000); // Timeout of 100 ms
- pulseHigh = pulseIn(irPin, HIGH, 100000); // Timeout of 100 ms
- irHexValue = (pulseHigh << 16) | pulseLow;
- }
- }
- void readTempHumidity() {
- if (xSemaphoreTake(xDataMutex, pdMS_TO_TICKS(100)) == pdTRUE) {
- temp = readTemperature();
- humidity = readHumidity();
- xSemaphoreGive(xDataMutex);
- } else {
- Serial.println("Failed to take data mutex in readTempHumidity");
- }
- }
- void readPressureSensor() {
- if (xSemaphoreTake(xDataMutex, pdMS_TO_TICKS(100)) == pdTRUE) {
- sensors_event_t pressure_event;
- lps22.getPressureSensor()->getEvent(&pressure_event);
- pressure = pressure_event.pressure;
- altitude = calculateAltitude(pressure, knownSeaLevelPressure);
- xSemaphoreGive(xDataMutex);
- } else {
- Serial.println("Failed to take data mutex in readPressureSensor");
- }
- }
- void displayTask(void *pvParameters) {
- (void)pvParameters;
- for (;;) {
- display.clearDisplay();
- display.setTextSize(1);
- display.setTextColor(SSD1306_WHITE);
- display.setCursor(0, 0);
- display.setTextWrap(false);
- // Turn off RGB LED before switching screens unless on screen 9
- if (currentScreen != 9) {
- rgbLED.setPixelColor(0, rgbLED.Color(0, 0, 0));
- rgbLED.show();
- }
- // Turn off LEDs before switching screens
- digitalWrite(redLEDPin, LOW);
- digitalWrite(blueLEDPin, LOW);
- // Turn off buzzer before switching screens
- controlBuzzer(false);
- switch (currentScreen) {
- case 0:
- displayIRData();
- break;
- case 1:
- displayAccelData();
- break;
- case 2:
- displayGyroData();
- break;
- case 3:
- displayTempHumidity();
- break;
- case 4:
- displayPressureData();
- break;
- case 5:
- displayPotData();
- break;
- case 6:
- displayLDRData();
- break;
- case 7:
- display.println("Red LED ON");
- digitalWrite(redLEDPin, HIGH);
- break;
- case 8:
- display.println("Blue LED ON");
- digitalWrite(blueLEDPin, HIGH);
- break;
- case 9:
- displayRGBControl();
- break;
- case 10:
- display.println("Buzzer ON");
- controlBuzzer(true);
- break;
- case 11:
- displaySDCardStatus();
- break;
- }
- display.display();
- vTaskDelay(pdMS_TO_TICKS(100)); // Delay for task
- }
- }
- void displayIRData() {
- display.setCursor(0, 0);
- display.println("IR Receiver Data");
- display.println("");
- display.print("Pulse Low: ");
- display.println(pulseLow);
- display.print("Pulse High: ");
- display.println(pulseHigh);
- display.print("Hex Value: 0x");
- display.println(irHexValue, HEX);
- }
- void displayAccelData() {
- if (xSemaphoreTake(xSensorDataMutex, pdMS_TO_TICKS(100)) == pdTRUE) {
- display.setCursor(0, 0);
- display.println("Accelerometer Data");
- display.println("");
- display.print("X: ");
- display.print(accelEvent.acceleration.x / 9.81, 2); // Convert m/s² to g
- display.print(" g");
- display.println("");
- display.print("Y: ");
- display.print(accelEvent.acceleration.y / 9.81, 2); // Convert m/s² to g
- display.print(" g");
- display.println("");
- display.print("Z: ");
- display.print(accelEvent.acceleration.z / 9.81, 2); // Convert m/s² to g
- display.print(" g");
- xSemaphoreGive(xSensorDataMutex);
- } else {
- display.println("Accelerometer Data");
- display.println("Unavailable");
- }
- }
- void displayGyroData() {
- if (xSemaphoreTake(xSensorDataMutex, pdMS_TO_TICKS(100)) == pdTRUE) {
- display.setCursor(0, 0);
- display.println("Gyroscope Data");
- display.println("");
- display.print("X: ");
- display.print(gyroEvent.gyro.x, 2);
- display.print(" rad/s");
- display.println("");
- display.print("Y: ");
- display.print(gyroEvent.gyro.y, 2);
- display.print(" rad/s");
- display.println("");
- display.print("Z: ");
- display.print(gyroEvent.gyro.z, 2);
- display.print(" rad/s");
- xSemaphoreGive(xSensorDataMutex);
- } else {
- display.println("Gyroscope Data");
- display.println("Unavailable");
- }
- }
- void displayTempHumidity() {
- if (xSemaphoreTake(xDataMutex, pdMS_TO_TICKS(100)) == pdTRUE) {
- display.setCursor(0, 0);
- display.println("Temperature & Humidity");
- display.println("");
- display.print("Temp: ");
- display.print(temp, 1);
- display.println(" C");
- display.print("Humidity: ");
- display.print(humidity, 1);
- display.println(" %");
- xSemaphoreGive(xDataMutex);
- } else {
- display.println("Temperature & Humidity");
- display.println("Unavailable");
- }
- }
- void displayPressureData() {
- if (xSemaphoreTake(xDataMutex, pdMS_TO_TICKS(100)) == pdTRUE) {
- display.setCursor(0, 0);
- display.println("Pressure & Altitude");
- display.println("");
- display.print("Pressure: ");
- display.print(pressure, 1);
- display.println(" hPa");
- display.print("Altitude: ");
- display.print(altitude, 1);
- display.println(" m");
- xSemaphoreGive(xDataMutex);
- } else {
- display.println("Pressure & Altitude");
- display.println("Unavailable");
- }
- }
- void displayPotData() {
- display.setCursor(0, 0);
- display.println("Potentiometer");
- display.println("");
- display.print("Value: ");
- display.println(potValue);
- }
- void displayLDRData() {
- display.setCursor(0, 0);
- display.println("LDR Data");
- display.println("");
- display.print("Value: ");
- display.println(ldrValue);
- }
- void displayRGBControl() {
- display.setCursor(0, 0);
- display.println("RGB LED Control");
- display.println("");
- display.println("Turn pot to change");
- display.println("RGB LED color");
- // Map potentiometer value to RGB color
- uint16_t potValue = averageAnalogRead(potPin, 5);
- uint16_t hue = map(potValue, 0, 4095, 0, 65535);
- uint32_t color = rgbLED.gamma32(rgbLED.ColorHSV(hue));
- // Update RGB LED color
- rgbLED.setPixelColor(0, color);
- rgbLED.show();
- }
- void displaySDCardStatus() {
- display.setCursor(0, 0);
- display.println("SD Card Status:");
- display.println("");
- if (sdCardAvailable) {
- display.println("SD Card OK");
- } else {
- display.println("SD Card Error:");
- display.println(sdCardErrorMessage);
- }
- }
- void controlBuzzer(bool state) {
- if (state && !buzzerActive) {
- tone(buzzerPin, 1000); // Play a 1000 Hz tone
- buzzerActive = true;
- } else if (!state && buzzerActive) {
- noTone(buzzerPin); // Stop the tone
- buzzerActive = false;
- }
- }
- float readTemperature() {
- Wire.beginTransmission(HDC1000_ADDRESS);
- Wire.write(0x00); // Temperature register
- Wire.endTransmission();
- vTaskDelay(pdMS_TO_TICKS(15)); // Wait for conversion
- Wire.requestFrom(HDC1000_ADDRESS, 2);
- if (Wire.available() == 2) {
- uint16_t rawTemp = (Wire.read() << 8) | Wire.read();
- return ((rawTemp / 65536.0) * 165.0) - 40.0;
- }
- return NAN; // Return NaN if no data is available
- }
- float readHumidity() {
- Wire.beginTransmission(HDC1000_ADDRESS);
- Wire.write(0x01); // Humidity register
- Wire.endTransmission();
- vTaskDelay(pdMS_TO_TICKS(15)); // Wait for conversion
- Wire.requestFrom(HDC1000_ADDRESS, 2);
- if (Wire.available() == 2) {
- uint16_t rawHum = (Wire.read() << 8) | Wire.read();
- return (rawHum / 65536.0) * 100.0;
- }
- return NAN; // Return NaN if no data is available
- }
- float calculateAltitude(float pressure, float seaLevelPressure) {
- return 44330.0 * (1.0 - pow(pressure / seaLevelPressure, 0.1903));
- }
- int averageAnalogRead(int pin, int samples) {
- int sum = 0;
- for (int i = 0; i < samples; i++) {
- sum += analogRead(pin);
- vTaskDelay(pdMS_TO_TICKS(5)); // Small delay between readings
- }
- return sum / samples;
- }
- // Optional: Implement logTask if using SD card
- /*
- void logTask(void *pvParameters) {
- (void)pvParameters;
- for (;;) {
- if (sdCardAvailable) {
- unsigned long currentMillis = millis();
- if (currentMillis - previousMillis >= loggingInterval) {
- previousMillis = currentMillis;
- // Open the file for appending
- File dataFile = SD.open("/data.txt", FILE_APPEND);
- if (dataFile) {
- // Prepare data to log
- String dataString = "";
- dataString += "Time: ";
- dataString += currentMillis / 1000;
- dataString += " s, ";
- // Add sensor data
- dataString += "Temp: ";
- dataString += temp;
- dataString += " C, Humidity: ";
- dataString += humidity;
- dataString += " %, Pressure: ";
- dataString += pressure;
- dataString += " hPa, Altitude: ";
- dataString += altitude;
- dataString += " m";
- // Write data to file
- if (dataFile.println(dataString)) {
- dataFile.close();
- } else {
- // Write failed, possibly SD card full
- Serial.println("Failed to write to SD card");
- sdCardAvailable = false;
- sdCardErrorMessage = "SD Write Failed";
- dataFile.close();
- }
- } else {
- // Failed to open file
- Serial.println("Failed to open file on SD card");
- sdCardAvailable = false;
- sdCardErrorMessage = "SD Open Failed";
- }
- }
- }
- vTaskDelay(pdMS_TO_TICKS(100)); // Small delay
- }
- }
- */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement