Advertisement
microrobotics

ESP32-EASY-PROTO-V2_COMBINED_REV2

Jan 15th, 2025
45
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Arduino 18.78 KB | None | 0 0
  1. #include <Wire.h>
  2. #include <SPI.h>
  3. #include <SD.h>
  4. #include <Adafruit_GFX.h>
  5. #include <Adafruit_SSD1306.h>
  6. #include <Adafruit_NeoPixel.h>
  7. #include <Adafruit_LPS2X.h>
  8. #include <Adafruit_LSM6DS3TRC.h>
  9. #include <freertos/FreeRTOS.h>
  10. #include <freertos/task.h>
  11. #include <freertos/semphr.h>
  12.  
  13. // Define I2C pins for ESP32
  14. #define SDA_PIN 21
  15. #define SCL_PIN 22
  16.  
  17. #define SCREEN_WIDTH 128
  18. #define SCREEN_HEIGHT 64
  19. #define OLED_RESET    -1
  20. #define SCREEN_ADDRESS 0x3C
  21.  
  22. #define HDC1000_ADDRESS 0x40  // I2C address for HDC1000 sensor
  23. #define SD_CS_PIN 5           // SD card CS pin on GPIO 5
  24.  
  25. Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
  26. Adafruit_LPS22 lps22;
  27. Adafruit_LSM6DS3TRC lsm6ds3trc;
  28.  
  29. const int button1Pin = 32;  // SW1
  30. const int button2Pin = 33;  // SW2
  31. const int irPin = 36;
  32. const int potPin = 34;
  33. const int ldrPin = 35;
  34. const int redLEDPin = 15;   // Swapped with blue LED
  35. const int blueLEDPin = 2;   // Swapped with red LED
  36. const int rgbLEDPin = 4;
  37. const int buzzerPin = 27;
  38.  
  39. Adafruit_NeoPixel rgbLED(1, rgbLEDPin, NEO_GRB + NEO_KHZ800);
  40.  
  41. int currentScreen = 0;
  42. unsigned long pulseLow, pulseHigh;
  43. unsigned long irHexValue;
  44. int potValue, ldrValue;
  45. bool buzzerActive = false;
  46. float temp = 0;
  47. float humidity = 0;
  48. float pressure = 0;
  49. float altitude = 0;
  50.  
  51. // Adjustable logging interval (1 second default)
  52. unsigned long loggingInterval = 1000;
  53. unsigned long previousMillis = 0;
  54.  
  55. // SD Card status variable
  56. bool sdCardAvailable = false;
  57. String sdCardErrorMessage = "";
  58.  
  59. // Known sea level pressure for Centurion, South Africa in hPa
  60. const float knownSeaLevelPressure = 1026.0;
  61.  
  62. // IMU sensor data
  63. sensors_event_t accelEvent;
  64. sensors_event_t gyroEvent;
  65. sensors_event_t tempEvent; // Added to hold temperature data from IMU
  66.  
  67. // Mutexes for shared resources
  68. SemaphoreHandle_t xSensorDataMutex;
  69. SemaphoreHandle_t xDataMutex;
  70.  
  71. // Button debouncing variables
  72. int button1State = HIGH;         // the current stable state of button1
  73. int lastButton1Reading = HIGH;   // the previous reading from the button1 pin
  74. unsigned long button1LastDebounceTime = 0; // the last time the button1 input pin was toggled
  75.  
  76. int button2State = HIGH;         // the current stable state of button2
  77. int lastButton2Reading = HIGH;   // the previous reading from the button2 pin
  78. unsigned long button2LastDebounceTime = 0; // the last time the button2 input pin was toggled
  79.  
  80. const unsigned long debounceDelay = 50; // the debounce time in milliseconds
  81.  
  82. void setup() {
  83.   Serial.begin(115200);
  84.   while (!Serial)
  85.     delay(10); // Wait for serial port to be available
  86.  
  87.   pinMode(button1Pin, INPUT_PULLUP);
  88.   pinMode(button2Pin, INPUT_PULLUP);
  89.   pinMode(irPin, INPUT);
  90.   pinMode(potPin, INPUT);
  91.   pinMode(ldrPin, INPUT);
  92.   pinMode(redLEDPin, OUTPUT);
  93.   pinMode(blueLEDPin, OUTPUT);
  94.   pinMode(buzzerPin, OUTPUT);
  95.  
  96.   // Initialize I2C communication
  97.   Wire.begin(SDA_PIN, SCL_PIN);
  98.  
  99.   // Initialize display
  100.   Serial.println("Initializing display...");
  101.   if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
  102.     Serial.println(F("SSD1306 allocation failed"));
  103.     for (;;);
  104.   }
  105.   display.clearDisplay();
  106.   display.display();
  107.  
  108.   // Show splash screen
  109.   displaySplashScreen();
  110.  
  111.   // Wait for user to press SW1 for IMU calibration
  112.   waitForIMUCalibration();
  113.  
  114.   // Initialize the LSM6DS3TR-C IMU
  115.   Serial.println("Initializing LSM6DS3TR-C IMU...");
  116.   if (!lsm6ds3trc.begin_I2C()) {
  117.     Serial.println("Failed to find LSM6DS3TR-C chip");
  118.     while (1) {
  119.       vTaskDelay(pdMS_TO_TICKS(10));
  120.     }
  121.   }
  122.   Serial.println("LSM6DS3TR-C Found!");
  123.  
  124.   // Initialize the LPS22HB pressure sensor
  125.   Serial.println("Initializing LPS22HB sensor...");
  126.   if (!lps22.begin_I2C(0x5C)) {  // Explicitly use address 0x5C
  127.     Serial.println("Failed to find LPS22HB sensor at 0x5C");
  128.     while (1) {
  129.       vTaskDelay(pdMS_TO_TICKS(10));
  130.     }
  131.   }
  132.   Serial.println("LPS22HB sensor initialized.");
  133.  
  134.   // Initialize RGB LED
  135.   rgbLED.begin();
  136.   rgbLED.show();
  137.  
  138.   // Print free heap memory
  139.   Serial.print("Free heap memory before mutex creation: ");
  140.   Serial.println(ESP.getFreeHeap());
  141.  
  142.   // Create mutex for sensor data
  143.   xSensorDataMutex = xSemaphoreCreateMutex();
  144.   if (xSensorDataMutex == NULL) {
  145.     Serial.println("Failed to create sensor data mutex");
  146.     while (1) {
  147.       vTaskDelay(pdMS_TO_TICKS(1000));
  148.     }
  149.   }
  150.  
  151.   // Create mutex for shared data
  152.   xDataMutex = xSemaphoreCreateMutex();
  153.   if (xDataMutex == NULL) {
  154.     Serial.println("Failed to create data mutex");
  155.     while (1) {
  156.       vTaskDelay(pdMS_TO_TICKS(1000));
  157.     }
  158.   }
  159.  
  160.   Serial.print("Free heap memory after mutex creation: ");
  161.   Serial.println(ESP.getFreeHeap());
  162.  
  163.   // Initialize SD card (Optional: Comment out if not using SD card)
  164.   /*
  165.   Serial.println("Initializing SD card...");
  166.   if (!SD.begin(SD_CS_PIN)) {
  167.     Serial.println("SD card initialization failed!");
  168.     sdCardAvailable = false;
  169.     sdCardErrorMessage = "SD Init Failed";
  170.   } else {
  171.     Serial.println("SD card initialized.");
  172.     sdCardAvailable = true;
  173.     sdCardErrorMessage = "";
  174.   }
  175.   */
  176.  
  177.   // Create FreeRTOS tasks with sufficient stack sizes
  178.   xTaskCreate(sensorTask, "Sensor Task", 4096, NULL, 1, NULL);
  179.   xTaskCreate(displayTask, "Display Task", 4096, NULL, 1, NULL);
  180.  
  181.   // Only create logTask if SD card is available (Optional)
  182.   /*
  183.   if (sdCardAvailable) {
  184.     xTaskCreate(logTask, "Log Task", 4096, NULL, 1, NULL);
  185.   }
  186.   */
  187. }
  188.  
  189. void loop() {
  190.   // Main loop is not used in this FreeRTOS implementation
  191. }
  192.  
  193. void displaySplashScreen() {
  194.   display.clearDisplay();
  195.   display.setTextSize(1);
  196.   display.setTextColor(SSD1306_WHITE);
  197.   display.setCursor(10, 0);
  198.   display.setTextWrap(false);
  199.   display.println("Welcome!");
  200.   display.println("");
  201.   display.println("Place the board on a");
  202.   display.println("stable, stationary,");
  203.   display.println("and level surface.");
  204.   display.println("");
  205.   display.println("Press SW1 to calibrate");
  206.   display.println("the IMU.");
  207.   display.display();
  208. }
  209.  
  210. void waitForIMUCalibration() {
  211.   // Wait for SW1 to be pressed
  212.   while (digitalRead(button1Pin) == HIGH) {
  213.     vTaskDelay(pdMS_TO_TICKS(100));  // Small debounce delay
  214.   }
  215.   vTaskDelay(pdMS_TO_TICKS(200)); // Additional delay to ensure button release
  216.  
  217.   // Start IMU calibration once the button is pressed
  218.   display.clearDisplay();
  219.   display.setCursor(0, 0);
  220.   display.setTextWrap(false);
  221.   display.println("Calibrating IMU...");
  222.   display.display();
  223.  
  224.   calibrateIMU();
  225. }
  226.  
  227. void calibrateIMU() {
  228.   // Calibration code can be added here if necessary
  229.   vTaskDelay(pdMS_TO_TICKS(2000));  // Simulate calibration delay
  230.   display.clearDisplay();
  231.   display.setCursor(0, 0);
  232.   display.setTextWrap(false);
  233.   display.println("Calibration complete!");
  234.   display.display();
  235.   vTaskDelay(pdMS_TO_TICKS(1000));
  236. }
  237.  
  238. void sensorTask(void *pvParameters) {
  239.   (void)pvParameters;
  240.  
  241.   for (;;) {
  242.     unsigned long currentMillis = millis();
  243.  
  244.     // Read the current state of button1
  245.     int reading1 = digitalRead(button1Pin);
  246.  
  247.     // If the switch changed, due to noise or pressing:
  248.     if (reading1 != lastButton1Reading) {
  249.       // reset the debouncing timer
  250.       button1LastDebounceTime = currentMillis;
  251.     }
  252.  
  253.     if ((currentMillis - button1LastDebounceTime) > debounceDelay) {
  254.       // whatever the reading is at, it's been there for longer than the debounce delay
  255.       // so take it as the actual current state
  256.  
  257.       // if the button state has changed:
  258.       if (reading1 != button1State) {
  259.         button1State = reading1;
  260.  
  261.         // only increment screen if the new button state is LOW (button pressed)
  262.         if (button1State == LOW) {
  263.           currentScreen++;
  264.           if (currentScreen > 11) currentScreen = 0;
  265.         }
  266.       }
  267.     }
  268.  
  269.     lastButton1Reading = reading1;
  270.  
  271.     // Similar code for button2
  272.     int reading2 = digitalRead(button2Pin);
  273.  
  274.     if (reading2 != lastButton2Reading) {
  275.       button2LastDebounceTime = currentMillis;
  276.     }
  277.  
  278.     if ((currentMillis - button2LastDebounceTime) > debounceDelay) {
  279.       if (reading2 != button2State) {
  280.         button2State = reading2;
  281.  
  282.         if (button2State == LOW) {
  283.           currentScreen--;
  284.           if (currentScreen < 0) currentScreen = 11;
  285.         }
  286.       }
  287.     }
  288.  
  289.     lastButton2Reading = reading2;
  290.  
  291.     // Read IMU data
  292.     if (xSemaphoreTake(xSensorDataMutex, pdMS_TO_TICKS(100)) == pdTRUE) {
  293.       if (!lsm6ds3trc.getEvent(&accelEvent, &gyroEvent, &tempEvent)) {
  294.         Serial.println("Failed to read IMU data");
  295.       }
  296.       xSemaphoreGive(xSensorDataMutex);
  297.     } else {
  298.       Serial.println("Failed to take sensor data mutex in sensorTask");
  299.     }
  300.  
  301.     // Read other sensors based on the current screen
  302.     switch (currentScreen) {
  303.       case 0:
  304.         readIRSensor();
  305.         break;
  306.       case 3:
  307.         readTempHumidity();
  308.         break;
  309.       case 4:
  310.         readPressureSensor();
  311.         break;
  312.       case 5:
  313.         potValue = averageAnalogRead(potPin, 20);
  314.         break;
  315.       case 6:
  316.         ldrValue = analogRead(ldrPin);
  317.         break;
  318.       case 9:
  319.         // Read potentiometer value for RGB LED control
  320.         potValue = averageAnalogRead(potPin, 5);
  321.         break;
  322.       // Cases 7-11 are for LED, buzzer, and SD card status
  323.     }
  324.  
  325.     vTaskDelay(pdMS_TO_TICKS(10)); // Adjust the delay as needed
  326.   }
  327. }
  328.  
  329. void readIRSensor() {
  330.   if (digitalRead(irPin) == LOW) {
  331.     pulseLow = pulseIn(irPin, LOW, 100000);   // Timeout of 100 ms
  332.     pulseHigh = pulseIn(irPin, HIGH, 100000); // Timeout of 100 ms
  333.     irHexValue = (pulseHigh << 16) | pulseLow;
  334.   }
  335. }
  336.  
  337. void readTempHumidity() {
  338.   if (xSemaphoreTake(xDataMutex, pdMS_TO_TICKS(100)) == pdTRUE) {
  339.     temp = readTemperature();
  340.     humidity = readHumidity();
  341.     xSemaphoreGive(xDataMutex);
  342.   } else {
  343.     Serial.println("Failed to take data mutex in readTempHumidity");
  344.   }
  345. }
  346.  
  347. void readPressureSensor() {
  348.   if (xSemaphoreTake(xDataMutex, pdMS_TO_TICKS(100)) == pdTRUE) {
  349.     sensors_event_t pressure_event;
  350.     lps22.getPressureSensor()->getEvent(&pressure_event);
  351.     pressure = pressure_event.pressure;
  352.     altitude = calculateAltitude(pressure, knownSeaLevelPressure);
  353.     xSemaphoreGive(xDataMutex);
  354.   } else {
  355.     Serial.println("Failed to take data mutex in readPressureSensor");
  356.   }
  357. }
  358.  
  359. void displayTask(void *pvParameters) {
  360.   (void)pvParameters;
  361.  
  362.   for (;;) {
  363.     display.clearDisplay();
  364.     display.setTextSize(1);
  365.     display.setTextColor(SSD1306_WHITE);
  366.     display.setCursor(0, 0);
  367.     display.setTextWrap(false);
  368.  
  369.     // Turn off RGB LED before switching screens unless on screen 9
  370.     if (currentScreen != 9) {
  371.       rgbLED.setPixelColor(0, rgbLED.Color(0, 0, 0));
  372.       rgbLED.show();
  373.     }
  374.  
  375.     // Turn off LEDs before switching screens
  376.     digitalWrite(redLEDPin, LOW);
  377.     digitalWrite(blueLEDPin, LOW);
  378.  
  379.     // Turn off buzzer before switching screens
  380.     controlBuzzer(false);
  381.  
  382.     switch (currentScreen) {
  383.       case 0:
  384.         displayIRData();
  385.         break;
  386.       case 1:
  387.         displayAccelData();
  388.         break;
  389.       case 2:
  390.         displayGyroData();
  391.         break;
  392.       case 3:
  393.         displayTempHumidity();
  394.         break;
  395.       case 4:
  396.         displayPressureData();
  397.         break;
  398.       case 5:
  399.         displayPotData();
  400.         break;
  401.       case 6:
  402.         displayLDRData();
  403.         break;
  404.       case 7:
  405.         display.println("Red LED ON");
  406.         digitalWrite(redLEDPin, HIGH);
  407.         break;
  408.       case 8:
  409.         display.println("Blue LED ON");
  410.         digitalWrite(blueLEDPin, HIGH);
  411.         break;
  412.       case 9:
  413.         displayRGBControl();
  414.         break;
  415.       case 10:
  416.         display.println("Buzzer ON");
  417.         controlBuzzer(true);
  418.         break;
  419.       case 11:
  420.         displaySDCardStatus();
  421.         break;
  422.     }
  423.  
  424.     display.display();
  425.     vTaskDelay(pdMS_TO_TICKS(100)); // Delay for task
  426.   }
  427. }
  428.  
  429. void displayIRData() {
  430.   display.setCursor(0, 0);
  431.   display.println("IR Receiver Data");
  432.   display.println("");
  433.   display.print("Pulse Low: ");
  434.   display.println(pulseLow);
  435.   display.print("Pulse High: ");
  436.   display.println(pulseHigh);
  437.   display.print("Hex Value: 0x");
  438.   display.println(irHexValue, HEX);
  439. }
  440.  
  441. void displayAccelData() {
  442.   if (xSemaphoreTake(xSensorDataMutex, pdMS_TO_TICKS(100)) == pdTRUE) {
  443.     display.setCursor(0, 0);
  444.     display.println("Accelerometer Data");
  445.     display.println("");
  446.     display.print("X: ");
  447.     display.print(accelEvent.acceleration.x / 9.81, 2); // Convert m/s² to g
  448.     display.print(" g");
  449.     display.println("");
  450.     display.print("Y: ");
  451.     display.print(accelEvent.acceleration.y / 9.81, 2); // Convert m/s² to g
  452.     display.print(" g");
  453.     display.println("");
  454.     display.print("Z: ");
  455.     display.print(accelEvent.acceleration.z / 9.81, 2); // Convert m/s² to g
  456.     display.print(" g");
  457.     xSemaphoreGive(xSensorDataMutex);
  458.   } else {
  459.     display.println("Accelerometer Data");
  460.     display.println("Unavailable");
  461.   }
  462. }
  463.  
  464. void displayGyroData() {
  465.   if (xSemaphoreTake(xSensorDataMutex, pdMS_TO_TICKS(100)) == pdTRUE) {
  466.     display.setCursor(0, 0);
  467.     display.println("Gyroscope Data");
  468.     display.println("");
  469.     display.print("X: ");
  470.     display.print(gyroEvent.gyro.x, 2);
  471.     display.print(" rad/s");
  472.     display.println("");
  473.     display.print("Y: ");
  474.     display.print(gyroEvent.gyro.y, 2);
  475.     display.print(" rad/s");
  476.     display.println("");
  477.     display.print("Z: ");
  478.     display.print(gyroEvent.gyro.z, 2);
  479.     display.print(" rad/s");
  480.     xSemaphoreGive(xSensorDataMutex);
  481.   } else {
  482.     display.println("Gyroscope Data");
  483.     display.println("Unavailable");
  484.   }
  485. }
  486.  
  487. void displayTempHumidity() {
  488.   if (xSemaphoreTake(xDataMutex, pdMS_TO_TICKS(100)) == pdTRUE) {
  489.     display.setCursor(0, 0);
  490.     display.println("Temperature & Humidity");
  491.     display.println("");
  492.     display.print("Temp: ");
  493.     display.print(temp, 1);
  494.     display.println(" C");
  495.     display.print("Humidity: ");
  496.     display.print(humidity, 1);
  497.     display.println(" %");
  498.     xSemaphoreGive(xDataMutex);
  499.   } else {
  500.     display.println("Temperature & Humidity");
  501.     display.println("Unavailable");
  502.   }
  503. }
  504.  
  505. void displayPressureData() {
  506.   if (xSemaphoreTake(xDataMutex, pdMS_TO_TICKS(100)) == pdTRUE) {
  507.     display.setCursor(0, 0);
  508.     display.println("Pressure & Altitude");
  509.     display.println("");
  510.     display.print("Pressure: ");
  511.     display.print(pressure, 1);
  512.     display.println(" hPa");
  513.     display.print("Altitude: ");
  514.     display.print(altitude, 1);
  515.     display.println(" m");
  516.     xSemaphoreGive(xDataMutex);
  517.   } else {
  518.     display.println("Pressure & Altitude");
  519.     display.println("Unavailable");
  520.   }
  521. }
  522.  
  523. void displayPotData() {
  524.   display.setCursor(0, 0);
  525.   display.println("Potentiometer");
  526.   display.println("");
  527.   display.print("Value: ");
  528.   display.println(potValue);
  529. }
  530.  
  531. void displayLDRData() {
  532.   display.setCursor(0, 0);
  533.   display.println("LDR Data");
  534.   display.println("");
  535.   display.print("Value: ");
  536.   display.println(ldrValue);
  537. }
  538.  
  539. void displayRGBControl() {
  540.   display.setCursor(0, 0);
  541.   display.println("RGB LED Control");
  542.   display.println("");
  543.   display.println("Turn pot to change");
  544.   display.println("RGB LED color");
  545.  
  546.   // Map potentiometer value to RGB color
  547.   uint16_t potValue = averageAnalogRead(potPin, 5);
  548.   uint16_t hue = map(potValue, 0, 4095, 0, 65535);
  549.   uint32_t color = rgbLED.gamma32(rgbLED.ColorHSV(hue));
  550.  
  551.   // Update RGB LED color
  552.   rgbLED.setPixelColor(0, color);
  553.   rgbLED.show();
  554. }
  555.  
  556. void displaySDCardStatus() {
  557.   display.setCursor(0, 0);
  558.   display.println("SD Card Status:");
  559.   display.println("");
  560.   if (sdCardAvailable) {
  561.     display.println("SD Card OK");
  562.   } else {
  563.     display.println("SD Card Error:");
  564.     display.println(sdCardErrorMessage);
  565.   }
  566. }
  567.  
  568. void controlBuzzer(bool state) {
  569.   if (state && !buzzerActive) {
  570.     tone(buzzerPin, 1000); // Play a 1000 Hz tone
  571.     buzzerActive = true;
  572.   } else if (!state && buzzerActive) {
  573.     noTone(buzzerPin); // Stop the tone
  574.     buzzerActive = false;
  575.   }
  576. }
  577.  
  578. float readTemperature() {
  579.   Wire.beginTransmission(HDC1000_ADDRESS);
  580.   Wire.write(0x00); // Temperature register
  581.   Wire.endTransmission();
  582.   vTaskDelay(pdMS_TO_TICKS(15)); // Wait for conversion
  583.   Wire.requestFrom(HDC1000_ADDRESS, 2);
  584.   if (Wire.available() == 2) {
  585.     uint16_t rawTemp = (Wire.read() << 8) | Wire.read();
  586.     return ((rawTemp / 65536.0) * 165.0) - 40.0;
  587.   }
  588.   return NAN; // Return NaN if no data is available
  589. }
  590.  
  591. float readHumidity() {
  592.   Wire.beginTransmission(HDC1000_ADDRESS);
  593.   Wire.write(0x01); // Humidity register
  594.   Wire.endTransmission();
  595.   vTaskDelay(pdMS_TO_TICKS(15)); // Wait for conversion
  596.   Wire.requestFrom(HDC1000_ADDRESS, 2);
  597.   if (Wire.available() == 2) {
  598.     uint16_t rawHum = (Wire.read() << 8) | Wire.read();
  599.     return (rawHum / 65536.0) * 100.0;
  600.   }
  601.   return NAN; // Return NaN if no data is available
  602. }
  603.  
  604. float calculateAltitude(float pressure, float seaLevelPressure) {
  605.   return 44330.0 * (1.0 - pow(pressure / seaLevelPressure, 0.1903));
  606. }
  607.  
  608. int averageAnalogRead(int pin, int samples) {
  609.   int sum = 0;
  610.   for (int i = 0; i < samples; i++) {
  611.     sum += analogRead(pin);
  612.     vTaskDelay(pdMS_TO_TICKS(5)); // Small delay between readings
  613.   }
  614.   return sum / samples;
  615. }
  616.  
  617. // Optional: Implement logTask if using SD card
  618. /*
  619. void logTask(void *pvParameters) {
  620.   (void)pvParameters;
  621.   for (;;) {
  622.     if (sdCardAvailable) {
  623.       unsigned long currentMillis = millis();
  624.       if (currentMillis - previousMillis >= loggingInterval) {
  625.         previousMillis = currentMillis;
  626.  
  627.         // Open the file for appending
  628.         File dataFile = SD.open("/data.txt", FILE_APPEND);
  629.         if (dataFile) {
  630.           // Prepare data to log
  631.           String dataString = "";
  632.           dataString += "Time: ";
  633.           dataString += currentMillis / 1000;
  634.           dataString += " s, ";
  635.  
  636.           // Add sensor data
  637.           dataString += "Temp: ";
  638.           dataString += temp;
  639.           dataString += " C, Humidity: ";
  640.           dataString += humidity;
  641.           dataString += " %, Pressure: ";
  642.           dataString += pressure;
  643.           dataString += " hPa, Altitude: ";
  644.           dataString += altitude;
  645.           dataString += " m";
  646.  
  647.           // Write data to file
  648.           if (dataFile.println(dataString)) {
  649.             dataFile.close();
  650.           } else {
  651.             // Write failed, possibly SD card full
  652.             Serial.println("Failed to write to SD card");
  653.             sdCardAvailable = false;
  654.             sdCardErrorMessage = "SD Write Failed";
  655.             dataFile.close();
  656.           }
  657.         } else {
  658.           // Failed to open file
  659.           Serial.println("Failed to open file on SD card");
  660.           sdCardAvailable = false;
  661.           sdCardErrorMessage = "SD Open Failed";
  662.         }
  663.       }
  664.     }
  665.     vTaskDelay(pdMS_TO_TICKS(100)); // Small delay
  666.   }
  667. }
  668. */
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement