Using SD.remove() and SD library in Arduino - c++

I'm building a program which takes 10 measurements of an analog voltage on pin0 and is printing it to a log file. The issue I'm running into comes when I try to ensure that the file is blank. I am using SD.remove() in order to remove a previous logfile. When I do this, the new log file is never actually written to. When I remove the call to SD.remove(), the program works correctly. Is this some known bug in the SD library or is there some sneaky way around this?
The code is below.
#include <SD.h>
#define OUTPUT_PIN 9 //Using SparkFun MP3 shield
#define DEFAULT_OUTPUT 10
#define VOLTAGE_REF (5)
//Reads a voltage on pin0. by default, the reference voltage is set to 5 V, but
//it can be changed by changing VOLTAGE_REF.
void setup() {
Serial.begin(9600);
Serial.println("Program Initialized");
pinMode(DEFAULT_OUTPUT ,OUTPUT); //Needs to be on to use the library
pinMode(0, INPUT);
if (!SD.begin(OUTPUT_PIN)) {
//init error
Serial.println("Error initializing SD card. Reset the Arduino and try again");
return;
}
Serial.println("Card sucessfully initialized");
if (SD.exists("LOGFILE.LOG") {
SD.remove("LOGFILE.LOG"); //We don't want to use the same file <<THIS IS THE BUG?
}
delay(10); //Make sure changes are applied
File logFile = SD.open("ANALOG.LOG", FILE_WRITE); //Create a new one every time
if (!SD.exists("LOGFILE.LOG")) {
Serial.println("There was some error making a new instance of the logfile?");
delay(1000);
SD.open("ANALOG.LOG", FILE_WRITE);
}
int i;
if (logFile) {
for(i=0;i<10;i++) {
int j = 0;
char str[64];
Serial.print("Reading analog sensor value");
for(j=0;j<=i;j++) {
Serial.print(".");
}
Serial.println();
logFile.print("Read #");
logFile.print(i+1);
logFile.print(" : ");
logFile.print(doVoltageRead(0));
unsigned char l = logFile.println(" V");
if (!l)
Serial.println("No data written");
delay(500);
}
Serial.println("Done.");
logFile.close(); //Close the logfile
Serial.println("Data sucessfully written");
}
else {
//Couldn't create file
Serial.println("There was an error creating the logfile");
}
}
void loop() {
//We don't really need to do anything here
}
float doVoltageRead(int pin) {
int voltageRead = analogRead(pin);
double divisor = (voltageRead * 0.00097752);
float finalVoltage =(VOLTAGE_REF * divisor);
Serial.println(finalVoltage);
return finalVoltage;
}

So.. First you see if LOGFILE.LOG exists, if it does you delete ANALOG.LOG. Then you create ANALOG.LOG. After that you check if LOGFILE.LOG exists. If it doesn't, you print an error and open ANALOG.LOG.
What exactly is the purpose of LOGFILE.LOG? Shouldn't you just change LOGFILE to ANALOG?

I have found the source of the error. When I called if(SD.exists()) after opening a new logfile, the library didn't like that. I am assuming SD.exists() just checks if the address or object returned by open is NULL. However, calling it when the file is already open would cause some strange behaviors. After removing that call inside open, all is well. Thanks for all the suggestions!

Related

BLE using ESP 32

I am trying to program a BLE client using an ESP32. I have used the attached code (which is the example code from the example section). My problem right now is, how do I get it to show the MAC address of the scanned device only, and how do I change this MAC address into a JSON format for a LoRa chip to transmit? Thank you so much for your time to read this post.
/*
Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleScan.cpp
Ported to Arduino ESP32 by Evandro Copercini
*/
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEScan.h>
#include <BLEAdvertisedDevice.h>
int scanTime = 5; //In seconds
BLEScan* pBLEScan;
class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
void onResult(BLEAdvertisedDevice advertisedDevice) {
Serial.printf("Advertised Device: %s \n", advertisedDevice.toString().c_str());
}
};
void setup() {
Serial.begin(115200);
Serial.println("Scanning...");
BLEDevice::init("");
pBLEScan = BLEDevice::getScan(); //create new scan
pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
pBLEScan->setActiveScan(true); //active scan uses more power, but get results faster
pBLEScan->setInterval(100);
pBLEScan->setWindow(99); // less or equal setInterval value
}
void loop() {
// put your main code here, to run repeatedly:
BLEScanResults foundDevices = pBLEScan->start(scanTime, false);
Serial.print("Devices found: ");
Serial.println(foundDevices.getCount());
Serial.println("Scan done!");
pBLEScan->clearResults(); // delete results fromBLEScan buffer to release memory
delay(2000);
}
The result of your scan is foundDevices, which contains a list of all found devices. We can iterate through it to access the devices. The List contains BLEAdvertisedDevices which have a method called getAddress(). The address can be converted to a string using toString(). You can print the string or put it into your json container.
Your loop-code could look like this:
void loop() {
// put your main code here, to run repeatedly:
BLEScanResults foundDevices = pBLEScan->start(scanTime, false);
Serial.print("Devices found: ");
for (int i = 0; i < foundDevices.getCount(); ++i)
{
std::string address = foundDevices.getDevice(i).getAddress().toString();
int rssi = foundDevices.getDevice(i).getRSSI();
Serial.print(address.c_str());
Serial.print(rssi);
// TODO: Insert into JSON
}
Serial.println(foundDevices.getCount());
Serial.println("Scan done!");
pBLEScan->clearResults(); // delete results fromBLEScan buffer to release memory
delay(2000);
}

How to create a function: Get a single value from SD card file using the file name as function parameter

I appreciate any guidance or help I can get on this. I am writing a program with values for a PID stored on an SD card so I can change them on the touchscreen without the need to hook it up to my computer. I want a single function that I can call with parameters allowing me to increase or decrease the number and change the file name. The below function is what I have to change whether "pnum.txt" increases or decreases; however I cannot figure out how to make a File work as a parameter.
I have tried making " "pnum.txt" " (with quotes) as a char and as a String, and even though it prints out as it should, it doesn't work when inserted into the function. I have also tried passing the whole SD.open("pnum.txt", FILE_WRITE) and myFile = SD.open("pnum.txt", FILE_WRITE) as a File, but that does something odd - it will create the file when I open it, but it won't write to the file. I'm finding myself just trying the same things over and over, so I clearly have a lack of understanding that I'm not finding anywhere. Thank you again for any help on this!
float incDecValue(float value) {
//This is important, because the libraries are sharing pins
pinMode(XM, OUTPUT);
pinMode(YP, OUTPUT);
value;
SD.remove("pnum.txt");
myFile = SD.open("pnum.txt", FILE_WRITE);
myFile.print(value);
myFile.close();
counter = 0;
myFile = SD.open("pnum.txt");
if (myFile) {
while (myFile.available()) {
testChar[counter] = myFile.read();
counter++;
}
myFile.close();
}
float convertedValue = atof(testChar);
return convertedValue;
}
And I will call it like this.
pValue = incValue(pValue+=.5);
As not exactly knowing what you really want I did the following assumptions:
You want to save a single float value to a file called pnum.txt
You want to do something with that value
You want the processed value to write back to the file pnum.txt (overwriting the content)
Two different functions parametrized each with fileName as input and the value for write
So here a complete sequence (works as posted) you could easily implement into your code. No String class is used and its a one line file read/write only:
/* SD card pid read/write
The circuit:
SD card attached to SPI bus as follows:
** MOSI - pin 11
** MISO - pin 12
** CLK - pin 13
** CS - pin 4 */
#include <SPI.h>
#include <SD.h>
const uint8_t chipSelect = 4;
char dataChar[16] = {'\0'};
void setup() {
// Open serial communications and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect.
}
Serial.print("Initializing SD card...");
// see if the card is present and can be initialized:
if (!SD.begin(chipSelect)) {
Serial.println("Card failed or no card present");
return;
}
Serial.println("Card initialized");
}
void loop() {
float pValue = readFileValue ("pnum.txt") + 0.5;
writeFileValue ("pnum.txt", pValue);
}
float readFileValue (const char* fileName) {
/* Open the file. note that only one file can be open at a time,
so you have to close this one before opening another.*/
File dataFile = SD.open(fileName, FILE_READ);
// if the file is available, write to it:
if (dataFile) {
char c;
uint8_t i = 0;
while (dataFile.available()) {
c = dataFile.read(); // Read char by char
if (c != '\n') { // As long no line terminator
dataChar[i] = c;
i++;
}
else {
dataChar[i] = '\0'; // Terminate char array properly
dataFile.close();
break;
}
}
Serial.print("Success writing content: ");
Serial.println(dataChar);
}
else { // If the file isn't open, pop up an error:
Serial.print("Error opening requested file: ");
Serial.println(fileName);
}
float fileVal = atof(dataChar);;
return fileVal;
}
bool writeFileValue (const char* fileName, float fileVal) {
SD.remove(fileName); // Delete the existing file if existing
File dataFile = SD.open(fileName, FILE_WRITE);
// If the file opened okay, write to it
if (dataFile) {
// dtostrf(floatvar, StringLengthIncDecimalPoint, numVarsAfterDecimal, charbuf);
dtostrf(fileVal, 5, 2, dataChar); // Not really needed for this simple issue, but ..
Serial.print("Writing to file: ");
Serial.println(fileName);
dataFile.println(dataChar);
// Close the file
dataFile.close();
Serial.println("Success saving done");
return true;
} else {
// if the file didn't open, print an error:
Serial.println("Error opening file: ");
Serial.println(fileName);
return false;
}
}

Write from Serial Port to SD card

I am trying to write from the Serial Port to an SD Card in my Arduino Mega 2560, using a card module.
I want to be able to write in a txt file what I type in the serial com.
#include <SPI.h>
#include <SD.h>
const int chipSelect = 4;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
Serial.print("This is a test and should be ignored");
if (!SD.begin(chipSelect)) {
Serial.println("\nCard failed, or not present");
// don't do anything more:
return;
}
else{
Serial.println("\ncard initialized.");
}
}
void loop() {
// put your main code here, to run repeatedly
File OpenFile = SD.open("test.txt", FILE_WRITE);
if(OpenFile and Serial.available());
{
OpenFile.println(Serial1.read());
OpenFile.close();
}
}
However a continous line of "-1" and "1", without the ", is written to the SD.
Yes, I am able to write to the SD card through other methods...
Cheers, PoP
I notice you are checking Serial.available() but using Serial1 to read from :)
As you have a Mega, you wouldn't get an error as there is Serial and Serial1. I'd say this is your culprit!
The Stream read function will return -1 when there is no data. Also you could lessen the load on your Arduino and do the operation all at once (not open/close for each byte) and purge all available data (Serial.read() only reads a single byte in case you did not know).
void loop() {
File OpenFile = SD.open("test.txt", FILE_WRITE);
if(OpenFile){
while(Serial.available()){
OpenFile.println(Serial.read());
}
OpenFile.close();
}
}
You may want to check if the SD lib supports appending by default or a flag like FILE_APPEND as you will overwrite the file on the next loop if more data becomes available (Serial data isn't instant, your code may loop while receiving the rest of the data).

Arduino: AT Commands - Read the last line of the serial output using Serial.read()

I constantly pass AT commands to get GSM Signal Strength
My code copies the entire serial output
Kindly advise how to read the latest serial output (last line)
find the output below, in which i need to assign the output from last line (21,0) to the variable "signal"
My Output:
AT
OK
AT+CREG?
+CREG: 0,1
ok
AT+CSQ
+CSQ: 21,0
My code:
byte gsmDriverPin[3] = {
3,4,5};
char signal[10];
char inChar;
int index;
char inData[200];
void setup()
{
//Init the driver pins for GSM function
for(int i = 0 ; i < 3; i++){
pinMode(gsmDriverPin[i],OUTPUT);
}
digitalWrite(5,HIGH);//Output GSM Timing
delay(1500);
digitalWrite(5,LOW);
digitalWrite(3,LOW);//Enable the GSM mode
digitalWrite(4,HIGH);//Disable the GPS mode
delay(2000);
Serial.begin(9600); //set the baud rate
delay(5000);//call ready
delay(5000);
delay(5000);
start_GSM();
}
void loop()
{
Signal_Strength();
Serial.println("AT+CMGF=1");
delay(1000);
Serial.println("AT+CMGS=\"1234567890\"");//Change the receiver phone number
delay(1000);
Serial.println(signal);
delay(1000);
Serial.write(26);
}
void Signal_Strength(){
Serial.println("AT+CSQ");
delay(2000);
read_String();
strtok(inData, ",");
strcpy(signal,strtok(NULL, ","));
}
void read_String() {
index=0;
while(Serial.available() > 0) // Don't read unless
// there you know there is data
{
if(index < 199) // One less than the size of the array
{
inChar = Serial.read(); // Read a character
inData[index] = inChar; // Store it
index++; // Increment where to write next
inData[index] = '\0'; // Null terminate the string
}
}
}
void start_GSM(){
//Configuracion GPRS Claro Argentina
Serial.println("AT");
delay(2000);
Serial.println("AT+CREG?");
delay(2000);
}
First of all, you must seriously redo your AT command handling to
Read and parse the every single response line given back from the modem until you get a final result code. This applies for every single command line invocation, no exceptions whatsoever. See this answer for more details.
Never ever call delay in any code that handles AT commands. See this answer for more details about the risk of aborting the next command.
Before fixing these fundamental issues you cannot expect any successful behaviour. Parsing AT command responses is not that complicated, have a look at the source code for atinout for an example.

SD.remove() is not removing a file on Arduino C++

I have two sketches I am running on an Arduino Uno. The first one dumps a file to the serial if it exists. This is one of the examples that comes with the Arduino, but I've modified it as such:
/*
SD card file dump
This example shows how to read a file from the SD card using the
SD library and send it over the serial port.
The circuit:
* SD card attached to SPI bus as follows:
** MOSI - pin 11
** MISO - pin 12
** CLK - pin 13
** CS - pin 4
Created 22 December 2010 by Limor Fried
Modified 9 Apr 2012 by Tom Igoe
This example code is in the public domain.
*/
#include <SD.h>
// On the Ethernet Shield, CS is pin 4. Note that even if it's not
// used as the CS pin, the hardware CS pin (10 on most Arduino boards,
// 53 on the Mega) must be left as an output or the SD library
// functions will not work.
const int chipSelect = 4;
void setup()
{
// Open serial communications and wait for port to open:
Serial.begin(115200);
while (!Serial) {
; // Wait for serial port to connect. Needed for Leonardo only.
}
Serial.print("Initializing SD card...");
// Make sure that the default chip select pin is set to
// output, even if you don't use it:
pinMode(10, OUTPUT);
// See if the card is present and can be initialized:
if (!SD.begin(chipSelect)) {
Serial.println("Card failed, or not present");
// Don't do anything more:
return;
}
Serial.println("card initialized.");
// Open the file. note that only one file can be open at a time,
// so you have to close this one before opening another.
File dataFile = SD.open("datalog.txt");
// If the file is available, write to it:
if (dataFile) {
while (dataFile.available()) {
Serial.write(dataFile.read());
}
dataFile.close();
}
// If the file isn't open, pop up an error:
else {
Serial.println("error opening datalog.txt");
}
}
void loop()
{
}
My other sketch is supposed to remove a file. When I run this remove sketch it says there is no file found. Yet I can continually run the above sketch and dump the contents to the serial. My remove sketch is as follows:
#include <SD.h>
const int chipSelect = 4;
void setup(){
Serial.begin(115200);
Serial.print("Initializing SD card...");
// Make sure that the default chip select pin is set to
// output, even if you don't use it:
pinMode(10, OUTPUT);
if(SD.exists("datalog.txt"))
{
SD.remove("datalog.txt");
Serial.println("file removed");
}
else
{
Serial.println("no file to remove");
}
}
void loop(){
}
Am I missing something here?
Just after posting this I realized I was not making this remove sketch fault tolerant and added the following code after the pinmode line:
// See if the card is present and can be initialized:
if (!SD.begin(chipSelect)) {
Serial.println("Card failed, or not present");
// don't do anything more:
return;
}
Serial.println("card initialized.");
Thus the new remove sketch was as follows:
#include <SD.h>
const int chipSelect = 4;
void setup(){
Serial.begin(115200);
Serial.print("Initializing SD card...");
// Make sure that the default chip select pin is set to
// output, even if you don't use it:
pinMode(10, OUTPUT);
// See if the card is present and can be initialized:
if (!SD.begin(chipSelect)) {
Serial.println("Card failed, or not present");
// Don't do anything more:
return;
}
Serial.println("card initialized.");
if(SD.exists("datalog.txt"))
{
SD.remove("datalog.txt");
Serial.println("file removed");
}
else
{
Serial.println("no file to remove");
}
}
void loop(){
}
Upon running that sketch it now removes the files. Why is it that new version works but the old one did not?
Adding SD.begin() doesn't make it fault tolerant. It initializes the library. You need to call that before calling other functions. From the Reference:
begin() Initializes the SD library and card. This begins use of the
SPI bus (digital pins 11, 12, and 13 on most Arduino boards; 50, 51,
and 52 on the Mega) and the chip select pin, which defaults to the
hardware SS pin (pin 10 on most Arduino boards, 53 on the Mega).