Hi Charlie,
Thanks for clarifying that for me, I think I get it now.
I think I can probably work with the 512 byte write each time... My program is monitoring a temperature reading and the voltages of a battery and a solar panel, in an enclosure housing a camera to take a few photos each day, producing 10 bytes of data per minute. I could probably drop this down to 8 bytes if writing 10 bytes/min causes problems with the 512 byte sector size, but I'd prefer not to.
Here's my code (over 2 posts):
#include <Wire.h>
#include <math.h>
#include <DateTime.h>
#include <avr/pgmspace.h>
#include <wprogram.h>
#include <microfat2.h>
#include <mmc.h>
#define ThermistorPIN 0 // input read pin for LM335 is Analog Pin 0
float temperature = 0; // variable which will be calculated in process
long val=0; // variable to store the value coming from the thermistor
float temp;
unsigned long sector = 0;
unsigned long byteSize;
unsigned long WriteAddress = 0; // initial address for writing to the SD card.
byte value; // will be used...
int incomingByte = 0; // ...for incoming serial data
byte tempBytes[10]; // for sending data to the SD card
byte sector_buffer[512]; // for sending AND retrieving data to/from the SD card
int hour;
int minute;
int second;
int month;
int day_of_week;
int day;
int year;
char* dow[7] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};
float Thermistor(int RawADC) { // Inputs ADC Value from Thermistor and outputs Temperature in Celsius
long Resistance;
float Temp; // Dual-Purpose variable to save space.
Resistance=((10240000/RawADC) - 10000); // Assuming a 10k Thermistor. Calculation is actually: Resistance = (1024/ADC)
Temp = log(Resistance); // Saving the Log(resistance) so not to calculate it 4 times later. "Temp" means "Temporary" on this line.
Temp = 1 / (0.001129148 + (0.000234125 * Temp) + (0.0000000876741 * Temp * Temp * Temp)); // Now it means both "Temporary" and "Temperature"
Temp = Temp - 273.15; // Convert Kelvin to Celsius Now it only means "Temperature"
return Temp; // Return the Temperature
}
void print_prompt_P(const char *data) { // print prompts and messages from program flash to save SRAM
while (pgm_read_byte(data) != 0x00)
Serial.print(pgm_read_byte(data++));
}
void TakePhoto() {
digitalWrite(3,HIGH); // first, switch on the fans to blow away dust or bugs...
delay(10000);
digitalWrite(3,LOW);
delay(2000);
digitalWrite(9,HIGH); // then send power to the camera
delay(500); // time for current to get to camera - not sure if this is needed...
digitalWrite(6,HIGH); // trigger the solenoid for 100 msec
delay(100);
digitalWrite(6,LOW);
delay(15000); // wait 15 seconds for the camera to take a photo then shutdown
digitalWrite(9,LOW); // stop sending power to the camera.
}
void DataDump () {
int DaysToDump = WriteAddress;
Serial.println("");
print_prompt_P(PSTR(" Data dump initiated: dumping "));
Serial.print(DaysToDump/10);
print_prompt_P(PSTR(" days of data.\n"));
print_prompt_P(PSTR("Date,Time,Temp,VBatt,VPanel\n"));
for(int p=0;p<DaysToDump;p=p+10) {
sector_buffer[p]=digitalRead(13);
Serial.print(sector_buffer[p]);
Serial.print(analogRead(0)); // this bit dumps the date in 'dd/mm/yy' format...
print_prompt_P(PSTR("/"));
// ++f;
Serial.print(analogRead(0));
print_prompt_P(PSTR("/"));
delay(50);
Serial.print(analogRead(0));
print_prompt_P(PSTR(","));
Serial.print(analogRead(0)); // this bit prints the time, as ',HH:MM,'...
print_prompt_P(PSTR(":"));
// ++f;
Serial.print(analogRead(0));
print_prompt_P(PSTR(","));
// ++f;
delay(50);
Serial.print(analogRead(0)); // this bit prints the temperature...
print_prompt_P(PSTR(","));
// ++f;
delay(50);
Serial.print(analogRead(0)); // this bit prints the Battery Voltage in 'VV.vv,' format...
print_prompt_P(PSTR("."));
// ++f;
Serial.print(analogRead(0));
print_prompt_P(PSTR(","));
// ++f;
delay(50);
Serial.print(analogRead(0)); // this bit prints the Solar Panel Voltage in 'VV.vv,' format...
print_prompt_P(PSTR("."));
// ++f;
Serial.print(analogRead(0));
// ++f;
delay(50);
Serial.println();
}
WriteAddress = 0;
}
void error(const char* s)
{
print_prompt_P(PSTR("Error: "));
print_prompt_P(s);
print_prompt_P(PSTR("<press reset>\n"));
for( /* ever */ ; ; )
{
digitalWrite(13, (millis() / 250) & 1);
}
}
void SDWrite() {
// Pass in the sector-sized buffer we'll be using ourselves later.
// uFat doesn't own it, it just needs to use it temporarily.
// We also pass in the address of a function that is used to read
// sectors from our device.
//
if (!microfat2::initialize(sector_buffer, &mmc::readSectors))
{
error(PSTR("uFat init failed.\n"));
}
prog_char string_0[] PROGMEM = "DATA BIN";
if (microfat2::locateFileStart(PSTR("DATA BIN"), sector, byteSize)) // check if the target file exists
{
if (byteSize >= 512) // check it's bigger than 512 bytes
{
if (RES_OK == mmc::readSectors(sector_buffer, sector, 1)) // checks a single-SECTOR read works OK
{
print_prompt_P(PSTR("Data read test SUCCESSFUL.\n"));
delay(500);
if (RES_OK == mmc::writeSectors(sector_buffer, sector, 1)) // checks a single-SECTOR write works OK
{
print_prompt_P(PSTR("Data write test SUCCESSFUL.\n"));
delay(500);
}
else
{
print_prompt_P(PSTR("Failed to write updated data.")); // if the write fails, end here...?
}
}
else
{
print_prompt_P(PSTR("Failed to read data.bin."));
}
}
else
{
error(PSTR("Found data.bin, but it's too small."));
}
}
else
{
print_prompt_P(PSTR("data.bin not present on card."));
}
Serial.println("Initialisation COMPLETE!!");
}
void setup() {
pinMode(3,OUTPUT); // FANS control - YELLOW wire
digitalWrite(3,LOW);
pinMode(6,OUTPUT); // SOLENOID power control - WHITE wire
digitalWrite(6,LOW);
pinMode(9,OUTPUT); // CAMERA power control - BLUE wire
digitalWrite(9,LOW);
// pinMode(13,OUTPUT);
Serial.begin(115200);
Wire.begin();
// The rest of this setup() procedure is checking that the SD card is present & working.
while(mmc::initialize() != RES_OK)
{
print_prompt_P(PSTR("SD init failed. retrying...\n"));
delay(100);
}
SDWrite;
}
void loop() {
// Below required to reset the register address to 0.
Wire.beginTransmission(104); // transmit to device #104, the ds 1307
Wire.send(0x00);
Wire.endTransmission(); // stop transmitting
Wire.requestFrom(104, 7); // request 7 bytes from slave ds1307, we'll assume it'll send them all even though it doesn't have to
second = Wire.receive();
minute = Wire.receive();
hour = Wire.receive();
day_of_week=Wire.receive();
day = Wire.receive();
month = Wire.receive();
year = Wire.receive();
// Convert all the BCD values that might have "tens" to decimal.
second = second/16 * 10 + second % 16;
minute = minute/16 * 10 + minute % 16;
hour = hour/16 * 10 + hour % 16;
day = day/16 * 10 + day % 16;
month = month/16 * 10 + month % 16;
year = 2000 + year/16 * 10 + year % 16;
// Change times below to desired photo times. Copy & paste to add more photos per day.
// NOTE: for some reason, 8's & 9's cause an error, so don't use them on their own below;
// 18 & 19 work fine, but 08 & 09 do not.
if (hour == 6) { if (minute == 00) { if (second == 00) { TakePhoto();}}}
if (hour == 12) { if (minute == 00) { if (second == 00) { TakePhoto();}}}
if (hour == 14) { if (minute == 00) { if (second == 00) { TakePhoto();}}}
if (hour == 18) { if (minute == 00) { if (second == 00) { TakePhoto();}}}
Serial.print(hour);
print_prompt_P(PSTR(":"));
if (minute < 10) { print_prompt_P(PSTR("0")); }
Serial.print(minute);
print_prompt_P(PSTR(":"));
if (second < 10) { print_prompt_P(PSTR("0")); }
Serial.print(second);
print_prompt_P(PSTR(" on "));
Serial.print(dow[day_of_week]);
print_prompt_P(PSTR(", "));
Serial.print(day);
print_prompt_P(PSTR("/"));
Serial.print(month);
print_prompt_P(PSTR("/"));
Serial.print(year);
Serial.println();
byte span = 20; int aRead = 0;
for (byte i = 0; i < span; i++) { //loop to get average of 20 readings
aRead = aRead + analogRead(ThermistorPIN);
}
aRead = aRead / span;
temperature = Thermistor(aRead);
...continued next post...