I am trying to get the attached code to : move a servo release, record data to a micro SD card and display maximum altitude achieved to a small OLED.
I can get the program blocks to run, but as soon as I try and include any simple serial print (e.g. line 140), and open the monitor, the program stops and the OLED wont initialise.
// ALTIMETER USING A BMP180 Barometric Pressure and Temperature sensor
// Saving to a micro SD card, with servo parachute release and micro OLED
/*
Pin configuration
SERVO SIGNAL
D9
BMP180
VIN 3,3V
GND GND
SCL A5
SDA A4
SD Card
CS D4
SCK 13
MOSI 11
MISO 12
VCC 5V
GND GND
Piezo Bleeper
GND
D8
*/
unsigned long buttonPushedMillis;// when button was pressed
unsigned long turnOffDelay = 8000; // move servo to release parachute after this time
#include <Adafruit_BMP085.h> //Including the libraries
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <Servo.h>
#include "I2Cdev.h"
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
int altitudemax = 0;
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET 4 //Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
Servo myservo; // create servo object to control a servo
int inputPin = 2; //connect a switch to ground from D2 that opens on launch
Adafruit_BMP085 bmp; //using a BMP180 sensor
Sd2Card card; //Creating an object for the SD card
File dataFile; //Preparing the files
unsigned long time;
const int chipSelect = 7; //Pin for the sd card
float pressure = 0.0;
float tempC = 0.0;
float altitude = 0.0;
//void BmpSensorRead(float* pressure, float* tempC, float* altitude);
//void DisplayPresTemp(float* pressure, float* tempC, float* altitude);
void setup()
{
Serial.begin(9600);
bmp.begin ();
SD.begin(chipSelect);
//SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) // Address 0x3C for 128x32
{
Serial.println(F("SSD1306 allocation failed"));
for (;;); // Don't proceed, loop forever
}
// the library initializes this with an Adafruit splash screen.
display.display();
delay(2000); // Pause for 2 seconds
// lcdtext(); // Draw characters of the default font
myservo.attach(9);// attaches the servo on pin 9 to the servo object
myservo.write(90); // set servo to 90 degrees before launch
pinMode (inputPin, INPUT);
digitalWrite (inputPin, HIGH);
delay(1000);
File dataFile = SD.open("datalog.txt", FILE_WRITE);
if (dataFile)
{
dataFile.println("***NEW LAUNCH***"); // put this header on SD card every new power-up
dataFile.close();
}
delay(5000); // to avoid too much stored data before launch
/*
Serial.print("Initializing SD card...");
if (!SD.begin(chipSelect)) {// see if the card is present and can be initialized:
Serial.println("Card failed, or not present");
// don't do anything more:
return;
Serial.println("card initialized.");
}
*/
}
void loop(void)
{
BmpSensorRead(&pressure, &tempC, &altitude);
// DisplayPresTemp(&pressure, &tempC, &altitude);// used for OLED display
servo180();
lcdtext();
alarm();
}
// void DisplayPresTemp(float* pressure, float* tempC, float* altitude) // used for OLED display
void BmpSensorRead(float* pressure, float* tempC, float* altitude)
{
*tempC = bmp.readTemperature();
//Serial.print("Temperature = ");
//Serial.print(*tempC);
//Serial.println(" *C");
*pressure = bmp.readPressure() / 100.0;
//Serial.print("Pressure = ");
//Serial.print(*pressure );
//Serial.println(" mBar");
// Calculate altitude assuming 'standard' barometric
// pressure of 1013.25 millibar = 101325 Pascal
*altitude = bmp.readAltitude() * 3.28084;
//Serial.print("Altitude = ");
//Serial.print(*altitude *3.28084 );
//Serial.println(" feet");
//change variables to strings
String comma = String (',');
String temp = String (*tempC); //real temp in degrees, may over read initially, will take time for sensor to stabilize.
String alt = String (*altitude); //absolute altitude in feet.
String pres = String (*pressure); // pressure in milliBar
String timer = String (millis()); //puts a millis time stamp on each string.
//make a big string containing above strings
String Baro_data = String (temp + comma + alt + comma + pres + comma + timer) ;
//Serial.println (Baro_data);
File dataFile = SD.open("datalog.txt", FILE_WRITE);
// if the file is available, write to it:
if (dataFile)
{
dataFile.println(Baro_data);//put Baro_data on the SD card
dataFile.close();
}
}
void servo180()
{
unsigned long currentMillis = millis(); // get the time at the start of this loop
if (digitalRead (inputPin) == LOW) // // update the time when button was pushed, button switch closes at launch
{
buttonPushedMillis = currentMillis;
}
if ((unsigned long)(currentMillis - buttonPushedMillis) >= turnOffDelay)
{
myservo.write(180); // set servo to 180 degrees
}
}
/*
Serial.println("card write OK");
// re-open the file for reading:
(dataFile) = SD.open("datalog.txt");
if (dataFile) {
Serial.println("datalog.txt");
// read from the file until there's nothing else in it:
while (dataFile.available()) {
Serial.write(dataFile.read());
}
// close the file:
dataFile.close();
} else {
// if the file didn't open, print an error:
Serial.println("error opening logger file");
}
Serial.println("card read OK");
*/
void lcdtext(void)
{
display.clearDisplay();// clear the internal memory
display.setTextSize(1); // // Normal 1:1 pixel scale
display.setTextColor(SSD1306_WHITE);
display.setCursor(20, 0); // Start at topline (0)
display.println("MAXIMUM ALTITUDE");
display.display();
display.setCursor(30, 20); // Start at second line (20)
display.print (altitudemax);
display.setCursor(60, 20);
display.println(" FEET");
display.display(); // transfer internal memory to the display
//delay(1000);
}
void alarm()
{
if (millis() > 45000) //change this number to change alarm delay (30sec = 30000ms)
{
tone (8, 300); // change the second number to alter the tone of the peizo alarm
delay (500);
noTone(8);
delay (500);
tone (8, 300);
delay (500);
}
else
{
noTone(8);
}
}
of course i haven't done the experiments you have. But I look at the program and I see a failure case that you say occurs because there is a print when it occurs. But is sounds like if you remove the print in that failure case it doesn't occur, you have evidence that the program is running correctly without seeing any prints.
i should have asked before, how do you know the code is running without the prints?
based on what i can see and what you've told me, it seems that the SD card is an issue.
can you ifdef out the SD.open and see what happens to determine if it's the cause?
According to the library, the only thing that will cause ".begin()" to fail is if there is not enough dynamic memory available: ( width * ((height + 7) / 8 ) = 624 bytes for a display size of 128x32. How much memory is available when the sketch is compiled?
You can free memory by packing strings into flash:
Serial.println("hello"); //Requires 6 bytes of SRAM
Serial.println(F("hello")); //Requires no SRAM
When you open the serial monitor, that will normally cause the arduino to perform a reset and restart the sketch, is that going to be a problem with your code, or specifically the OLED display?
In addition to replay #9, you should also get rid of the use of the String type variables for storing the text, that can cause memory corruption on an arduino, and you are getting quite low on memory if you are using an arduino with only 2k of ram.
Thanks,
the Uno program storage is at 94% 30394 bytes, 64% dynamic memory. I was hoping to put it on a Nano to make use of it. There is another 'small' problem in that the BMP180 causes a stoppage at the moment when used in parallel with the display (SCL, SDA). I thought I could do that OK, but may need to remove one set of pull-up resistors, (if that's the problem).
gcjr:
i should have asked before, how do you know the code is running without the prints?
I will check the SD module. the program runs to conclusion as the location alarm sounds after about 45 seconds OK.
Perhaps I'm asking too much of the Arduino to do all that I need by combining?, but the individual 'blocks' work fine standalone.
64% dynamic memory : 2048 * 0,64 = 1311 bytes + 624 for the display = 1935 bytes leaving 113 bytes. My guess is that other components reserve dynamic memory during initialization and this cause an out-of-memory error in the display.
You can move your strings to flash to free some memory. The string "datalog.txt" is declared multiple times, putting it into a progmem constant would also help. You should (as already mentioned) completely remove the usage of the "String" object which will cuase problems.
If it runs on an UNO it will also run on a NANO, but you are close to the limits and you may need to look at other boards with more memory like NANO 33 IoT or ESP32.
Danois90:
If it runs on an UNO it will also run on a NANO, but you are close to the limits and you may need to look at other boards with more memory like NANO 33 IoT or ESP32.
The Nano has 1.5k less program memory than an Uno, because the bootloader is allocated 2k bytes instead of the 512 bytes used on the Uno. You can change this by using an ISP programmer to load the Uno bootloader on a Nano, and select Uno in the IDE when programming it.
One electrical difference between the Uno and the Nano is that the LED wired to pin 13 is buffered on the Uno, but not on the Nano, usually not a problem unless you are driving something with pin 13 that is sensitive to loading. The Nano also has two additional analog inputs, A6 and A7 (note these cannot be used as digital inputs/outputs like the other analog ports).