Hello,
I am building a "GrainBrain" that helps a small farm monitor and control a grain drying bin. My programming skills are remedial, please forgive me!
When I added the section of code to write data to the microSD card, the program compiled but did not run, instead appeared to get "stuck" after a few loops.
If I comment out the microSD card part, the program works, printing to the serial monitor and LCD.
If I uncomment the microSD section, and comment out the code section that reads the values from the dht-22 sensors, the code runs well, printing simply zeros to the microSD card!
The program only needs to check the sensors every 5 minutes, and only needs to write data to the micro SD every 10 minutes.
I attempted to use an attachInterrupt function for the microSD part of the code that uses a timer. It sort of worked, in the sense that the program ran and didn't get stuck, but failed to open the file and write the data. I also attempted to use a simple timer and/or a "loop counter" to "stagger" the sensor and the microSD parts of the code, but I just couldn't get it to work, probably because of lack of programming ability?
I very much appreciate any suggestions! Thank you.
```cpp
/*
*This sketch combines a arduino nano with a DS3231 clock module, two DHT-22 temperature/humidity sensors, and a micro-sd card module
*It also allows as input the type of grain being dried (as reference to a look-up table of equilibrium Moisture Contents)
*And allows as input the latest measured MC as inputed with a potentiometer by the farmer
*Remember, to first set time and date on ds3231 use DS3231Serial_Easy_Lu
*/
//============================================================================BEGIN DECLARATIONS===========================================
#include <DS3231.h> //includes the library for using the DS3231 Time module
DS3231 rtc(SDA, SCL); //sets up the time module
#include <LiquidCrystal_I2C.h> //includes the library for using the 2x16 display with the built in I2C adapter
LiquidCrystal_I2C lcd(0x27, 20, 4); // I2C address 0x27, 20 column and 4 row
#include "DHT.h" //library for dht sensors
#define DHTPIN_inlet 2 // first dht22 input pin
#define DHTPIN_outlet 3 // second dht22 input pin
#define DHTTYPE DHT22 // DHT 22 (AM2302), AM2321
DHT dht_inlet(DHTPIN_inlet, DHTTYPE);
DHT dht_outlet(DHTPIN_outlet, DHTTYPE);
float inletTemp; //these 4 variables will store the temperatures (in Celcius!) and humidities (%rH) from the sensors
float inletHum;
float outletTemp;
float outletHum;
#include <SPI.h>
#include <SD.h> //library for microSD card
const int chipSelect = 10;// sets pin 10 for CS on the microSD module pinout
File myFile; //creates a file for the micro SD card
int potPin = A0; //declare the potentiometer pin A0
int potVolt = 0; // will be the voltage of the dimmer (0-5 volts), read as a integer from 0-1023
float grainMCx2 = 0; //a variable for the entering of the grain moisture content times two to avoid the integer math problem of the mapping function
float grainMC = 0; //a varialble for entering the grain moisture content with resolution of 0.5%
const int buttonPin = 4; // the number of the pushbutton pin
// Variables for the button debouncer will change;
int buttonState; // the current reading from the input pin
int lastButtonState = LOW; // the previous reading from the input
// the following variables for the button debouncer are unsigned longs because the time, measured in
// milliseconds, will quickly become a bigger number than can be stored in an int.
unsigned long lastDebounceTime = 0; // the last time the output pin was toggled
unsigned long debounceDelay = 10; // the debounce time; increase if the output flickers
char *grainType[7] = {"Corn", "Hard Wheat", "Soft Wheat","Barley", "Rye", "Sunflower"}; //this string array holds the different types of grain
//eventually there will be h files with the EMC charts for each of the above grains
int i = 0;
//============================================================END DECLARATIONS=======================================================
//=============================================================BEGIN SETUP==========================================================
void setup() {
Serial.begin(9600);
/*
// wait for Serial Monitor to connect. Needed for native USB port boards only:
while (!Serial);
Serial.print("Initializing SD card...");
if (!SD.begin(chipSelect)) {
Serial.println("initialization failed. Things to check:");
Serial.println("1. is a card inserted?");
Serial.println("2. is your wiring correct?");
Serial.println("3. did you change the chipSelect pin to match your shield or module?");
Serial.println("Note: press reset button on the board and reopen this Serial Monitor after fixing your issue!");
while (true);
}
Serial.println("initialization done.");
delay(20);
*/
rtc.begin(); // Initialize the DS3231 realtimeclock object
lcd.init(); // Initialize the lcd object, clear it, turn on the backlight, set the cursor (?)
lcd.clear();
lcd.backlight();
lcd.setCursor(0,0);
//initialize dht sensors
dht_inlet.begin();
dht_outlet.begin();
pinMode (potPin, INPUT); //turn on potPin as input this will input the grain MC
pinMode(buttonPin, INPUT); //this is the input push button this will select type of grain
}
//====================================================================END SETUP============================================================
//=============================================================================MAIN LOOP================================================================
void loop() {
//===============================================SUBROUTINE TO READ TEMPERATURE AND HUMIDITY WITH DHT-22=============================================
//read the temp and humidity sensors
float inletHum = dht_inlet.readHumidity();
float inletTemp = dht_inlet.readTemperature();//Celcius
float outletHum = dht_outlet.readHumidity();
float outletTemp = dht_outlet.readTemperature(); //Celciius
//=================================================END TEMPERATURE AND HUMIDITY SUBROUTINE===========================================================
// =================================================SUBROUTINE TO DETECT BUTTON PUSH AND UPDATE GRAIN TYPE SELECTION==================================
// read the state of the button into a local variable:
int reading = digitalRead(buttonPin);
// check to see if you just pressed the button
// (i.e. the input went from LOW to HIGH), and you've waited long enough
// since the last press to ignore any noise:
// If the switch changed, due to noise or pressing:
if (reading != lastButtonState) {
// reset the debouncing timer
lastDebounceTime = millis();
}
if ((millis() - lastDebounceTime) > debounceDelay) {
// whatever the reading is at, it's been there for longer than the debounce
// delay, so take it as the actual current state:
// if the button state has changed:
if (reading != buttonState) {
buttonState = reading;
// move the grain type to the next position if the new button state is HIGH
if (buttonState == HIGH) {
i = i+1; //increments the grain type to the next word in the array
//clear the lcd line with the grain type (line 3)
lcd.setCursor(0,2); //sets lcd cursor to collum one, row three
lcd.print(" "); //prints 20 blank spaces to clear row
if (i==6){ //if the counter i gets to. 6 have it wrap around to zero...
i=0;
}
}
}
}
// save the button reading. Next time through the loop, it'll be the lastButtonState:
lastButtonState = reading;
Serial.println(grainType[i]);
//==============================================END BUTTON PUSH DETECTION SUBROUTINE==================================================
// ================================================SUBROUTINE TO READ POTENTIOMETER FOR LATEST GRAIN MC INPUT===============================================
potVolt = analogRead (potPin); //read the potentiometer voltage into the variable potVolt (0-1023), more resistance means lower voltage
grainMCx2 = map(potVolt,1023,0,0,60); //creates the grainMC variable from the pot input allows grianMC from 0%-30%
grainMC = grainMCx2/2; // to get the resolution to 0.5% it's necessary to change the integer (0-60) to a decimal (0-30 in increments of 0.5)
Serial.print("moisture content: ");
Serial.println(grainMC);
// ========================================================END READ POTENTIOMETER SUBROUTINE===================================================
//==================================================SUBROUTINE TO DISPLAY INFO ON THE LCD SCREEN======================================================
// Now display the temperature and humidity on the lcd
lcd.setCursor(0,0);
lcd.print("In: ");
lcd.print((inletTemp * 9.0) / 5.0 + 32.0);
lcd.print("F--");
lcd.print(inletHum);
lcd.print ("%rH");
lcd.setCursor(0,1);
lcd.print("Out:");
lcd.print((outletTemp * 9.0) / 5.0 +32);
lcd.print("F--");
lcd.print(outletHum);
lcd.print("%rH");
lcd.setCursor(0,2);
lcd.print(grainType[i]);
lcd.setCursor(0,3);
lcd.print("grain MC: ");
lcd.print(grainMC);
delay(20);
//===================================================END LCD SUBROUTINE================================================================================
//=====================================================SUBROUTINE TO PRINT TO SERIAL MONITOR===========================================================
// Send date to serial monitor
Serial.print(rtc.getDateStr());
Serial.print(" -- ");
// Send time to serial monitor
Serial.println(rtc.getTimeStr());
// Printing the temperature and humidity on the serial monitor
Serial.print("Inlet Temperature F: ");
Serial.println(((inletTemp * 9.0) / 5.0 + 32.0));
Serial.print("Inlet Humidity: ");
Serial.println(inletHum);
Serial.print("Outlet Temperature F: ");
Serial.println(((outletTemp * 9.0) / 5.0 + 32.0));
Serial.print("Outlet Humidity: ");
Serial.println(outletHum);
delay(50);
//=======================================================END SERIAL MONITOR SUBROUTINE===============================================
/*
//=======================================================SUBROUTINE TO WRITE DATA TO MICROSD CARD=====================================
//open file on micro-sd card and write data to file
// open the file. note that only one file can be open at a time,
// so you have to close this one before opening another.
//myFile = SD.open("TempRH.txt", FILE_WRITE); //tempRH.txt is the file name, FILE_WRITE tells the computer that this is a write operation
// open the file. note that only one file can be open at a time,
// so you have to close this one before opening another.
//myFile = SD.open("test.txt", FILE_WRITE);
// if the file opened okay, write to it:
if (myFile) {
Serial.print("Writing to test.txt...");
// with the file open, write the date, time, temp, and humidity separated by commas
//myFile.print(rtc.getDateStr());
//myFile.print(",");
//myFile.print(rtc.getTimeStr());
//myFile.print(",");
//myFile.print((inletTemp * 9.0) / 5.0 + 32.0);
//myFile.print(",");
//myFile.println(inletHum);
// close the file:
//myFile.close();
Serial.println("done.");
} else {
// if the file didn't open, print an error:
Serial.println("error opening test.txt");
}
//=======================================================END MICRO SD CARD SUBROUTINE=======================================================
*/
delay(300); //
}
//==========================================================END MAIN LOOP=================================================================