TL;DR: When testing my code, writing an audio file to an SD card and writing a CSV file to an SD card individually both work. However, when I combine the two functions, it doesn't work. I suspect that the SD card may still be open or writing something when I try to record the audio.
Hi there,
I'm facing an issue with my code that involves multiple functionalities. Here's what I'm trying to achieve: I have a program that displays three questions on an LCD display. The user answers these questions using a keypad. The three answers, along with a timestamp, sensor data (temperature and pressure), are then saved to an SD card in the form of a CSV file. Afterward, a relay is activated, and I want to record sound using a MAX9814 board for two seconds and save it to the SD card.
Here's the problem: when I test the code separately for writing the CSV file to the SD card and recording audio, both functionalities work fine. However, when I combine them together, it doesn't work as expected. I suspect that the SD card may still be open or in the middle of a write operation when I try to record the audio.
I'm using an Arduino Uno with a micro SD card adapter, and the SD card I'm using has a capacity of 32GB. The sensor data is obtained from a BMP280.
I would greatly appreciate any help in identifying the cause of this issue. Thank you in advance!
#include <LiquidCrystal_I2C.h>
#include <Keypad.h>
#include <SD.h>
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include <SPI.h>
// LCD Setup
LiquidCrystal_I2C lcd(0x27, 16, 2); // Set the LCD I2C address and dimensions
// Microphone pin
const int micPin = A3;
// Recording duration
const unsigned long recordingDuration = 2000; // 2 seconds
File audioFile;
// Keypad Setup
const byte ROWS = 4; // Number of rows
const byte COLS = 4; // Number of columns
char keys[ROWS][COLS] = {
{'1', '2', '3', 'A'},
{'4', '5', '6', 'B'},
{'7', '8', '9', 'C'},
{'*', '0', '#', 'D'}
};
byte rowPins[ROWS] = {3, 2, 1, 0}; // Connect to the row pinouts of the keypad
byte colPins[COLS] = {7, 6, 5, 4}; // Connect to the column pinouts of the keypad
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);
// Relay Setup
const int relayPin = 8;
// SD Card Setup
const int chipSelect = 10; // Set the chip select pin for the SD card module
// BME280 Sensor Setup
Adafruit_BME280 bme;
// Global Variables
int questionNumber = 1;
String answer1 = "";
String answer2 = "";
String answer3 = "";
// RVK Function
void RVK() {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("recording");
lcd.setCursor(0, 1);
lcd.print("RVK NIACS");
delay(2000); // Display "RVK" for 2 seconds
}
// Function to display the question on the LCD
void displayQuestion(const char* question, int startPos, int endPos) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print(question);
lcd.setCursor(startPos, 0);
// Clear the previous answer
lcd.print(" "); // Print two spaces to clear the answer field
lcd.setCursor(0, 1);
lcd.print("NIACS");
}
void recordAndSaveAudio() {
// Create a new audio file
audioFile = SD.open("recording.wav", FILE_WRITE);
if (!audioFile) {
Serial.println("Error creating audio file!");
while (1);
}
// Start recording
unsigned long startTime = millis();
unsigned long elapsedTime;
while (1) {
// Calculate elapsed time
elapsedTime = millis() - startTime;
// Check if recording duration is reached
if (elapsedTime >= recordingDuration) {
// Close the audio file
audioFile.close();
Serial.println("Recording finished!");
break;
}
// Read audio sample from the microphone
int sample = analogRead(micPin);
// Write the audio sample to the SD card
audioFile.write(sample & 0xFF); // Write the lower 8 bits
audioFile.write((sample >> 8) & 0xFF); // Write the upper 8 bits
}
}
// Function to save the data to the SD card
void saveData(const char* filename, const String& answer1, const String& answer2, const String& answer3, float temperature, float humidity, float pressure) {
File dataFile = SD.open(filename, FILE_WRITE); // Open the file in write mode
if (dataFile) {
unsigned long currentMillis = millis(); // Get the current timestamp
dataFile.print(currentMillis);
dataFile.print(",");
dataFile.print(answer1);
dataFile.print(",");
dataFile.print(answer2);
dataFile.print(",");
dataFile.print(answer3);
dataFile.print(",");
dataFile.print(temperature);
dataFile.print(",");
dataFile.print(humidity);
dataFile.print(",");
dataFile.println(pressure);
dataFile.close(); // Close the file
} else {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Error1 saving file!");
delay(2000); // Display error message for 2 seconds
}
}
void setup() {
Serial.begin(9600); // Initialize the serial communication
lcd.begin(16, 2);
lcd.backlight();
pinMode(relayPin, OUTPUT);
digitalWrite(relayPin, LOW);
// Initialize the SD card
if (!SD.begin(chipSelect)) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("SD Card initialization failed!");
delay(2000); // Display error message for 2 seconds
while (1); // Stop the program
}
// Initialize the BME280 sensor
if (!bme.begin(0x76)) {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("BME280 initialization failed!");
delay(2000); // Display error message for 2 seconds
while (1); // Stop the program
}
}
void loop() {
char key = keypad.getKey();
switch (questionNumber) {
case 1:
displayQuestion("Cannister?: ______", 11, 18);
break;
case 2:
displayQuestion("Row?: ______", 5, 12);
break;
case 3:
displayQuestion("Level?: ______", 7, 14);
break;
default:
break;
}
if (key) {
if (key == '#') {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Answer received!");
delay(1000); // Display answer received message for 1 second
questionNumber++;
if (questionNumber > 3) {
questionNumber = 1; // Reset the question number for the next iteration
lcd.clear();
// Read BME280 sensor data
float temperature = bme.readTemperature();
float humidity = bme.readHumidity();
float pressure = bme.readPressure() / 100.0; // Convert pressure to hPa
// Save data to CSV file
char filename[] = "data.csv";
if (!SD.exists(filename)) {
// If the file doesn't exist, create it and write the header
File dataFile = SD.open(filename, FILE_WRITE);
if (dataFile) {
dataFile.println("timestamp,cannister,row,level,temperature,humidity,pressure");
dataFile.close(); // Close the file
} else {
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Error creating file!");
delay(2000); // Display error message for 2 seconds
}
}
// Save the data to the file
saveData(filename, answer1, answer2, answer3, temperature, humidity, pressure);
// Reset the answer variables
answer1 = "";
answer2 = "";
answer3 = "";
delay(2000); // wait to make sure we are done saving
digitalWrite(relayPin, HIGH); // Activate the relay
delay(50); // Activation time of the relay
digitalWrite(relayPin, LOW); // Deactivate the relay
recordAndSaveAudio();
delay(2000);
RVK(); // Call the RVK function
}
} else if (isdigit(key) || key == '.') {
if (questionNumber == 1) {
if (answer1.length() < 2) {
answer1 += key;
} else {
answer1[0] = answer1[1];
answer1[1] = key;
}
lcd.setCursor(11, 0);
lcd.print(answer1);
} else if (questionNumber == 2) {
if (answer2.length() < 2) {
answer2 += key;
} else {
answer2[0] = answer2[1];
answer2[1] = key;
}
lcd.setCursor(11, 0);
lcd.print(answer2);
} else if (questionNumber == 3) {
if (answer3.length() < 2) {
answer3 += key;
} else {
answer3[0] = answer3[1];
answer3[1] = key;
}
lcd.setCursor(11, 0);
lcd.print(answer3);
}
delay(200); // Delay to display the pressed digit
}
}
}