Time dependent data acquisition from DHT22 - problem with initial loops - c++

I'm trying to gather the data from DHT22 Humidity and Temperature sensor based on millis() function to avoid the buffer overload and due to how fast the sensor is itself. The point is, that the project has to manage the 72h constant routines, to control the air valve. Because of that 2 actions to be handled, delay is out of range. The problem is, that after setup() and filling in the buffer for average, the loop starts from 12 readings one after another, and eventually after these 12 readings it starts to perform 2 sec. interval readings.
#include <DHT.h>
#include <Adafruit_Sensor.h>
#include <CircularBuffer.h>
#include <time.h>
#define DHTPIN 2
#define DHTTYPE DHT22
using namespace std;
const int sample_rate = 4; // Defining how many samples are gathered to calculate the average
const int temper_low = -3; // Defining lower range of temperature
const int temper_high = 20;// Defining high range for temperature
float sum_temper, sum_humid, avg_temp, avg_humid = 0; // variables to calculate the Simple Moving Average
int pre_fill_count = 0; // iterator used for preFill buffer, goes up to 9 and then gets cleared
float test = -255.0;
int mins = 0; //Next 3 vars used for valve control timer
int hours = 0;
int days = 0;
DHT dht(DHTPIN, DHTTYPE); // Defining the dht object
CircularBuffer<float, sample_rate> temper_buffer; // Defining the CircularBuffer for FILO with Moving Average
CircularBuffer<float, sample_rate> humid_buffer; // Same as above
const unsigned long DHT_reads_interval = 2000; //interval used to perform reading action considering the speed of DHT sensor
unsigned long currentMillis = 0; //stores the value of millis() in each iteration of loop()
unsigned long previous_sens_readout = 0; //last time temperature was readed
//State machine for humidity readouts
enum state{
preFill,
measure,
fail
};
state sensorState = preFill;
bool measurmentFlag = false;
//Functions definitions
void calculateAverageTemperature(
const int& sample_rate,
float& sum_temper,
float& sum_humid,
float& avg_temp,
float& avg_humid
);
void getSensorReadings(
DHT &sensor,
CircularBuffer<float, sample_rate> &temper_buffer,
CircularBuffer<float, sample_rate> &humid_buffer
);
float readTemperature
(
state &sensorState,
DHT &dht
);
float readHumidity
(
state &sensorState,
DHT &dht
);
void setup() {
// Setup, runs once after uC boot
Serial.begin(9600);
Serial.println(F("DHTxx test!"));
dht.begin();
Serial.println("test value ");
Serial.println(test);
// Wait a few seconds between measurements.
currentMillis = millis();
// Reading temperature or humidity takes about 250 milliseconds!
// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
///////////////////////////////////////////////////////////////////////////
//////////////////////////////INIT BUFFER FILL SECTION////////////////////
/////////////////////////////////////////////////////////////////////////
Serial.println("INITIALISING THE BUFFER, PLEASE WAIT... ");
while(sensorState == preFill && (pre_fill_count <=9)) {
//PUSHING READINGS TO THE BUFFER
//DUE TO BUFFER INIT ACTION, IT TAKES C.A. 20 SECS TO MOVE FROM preFill TO measure state!!!
if(currentMillis - previous_sens_readout >= DHT_reads_interval){
temper_buffer.push(readTemperature(sensorState, dht));
Serial.print(pre_fill_count);
Serial.print(" it Temperature measurement from temper buffer: ");
Serial.println(temper_buffer[pre_fill_count]);
humid_buffer.push(readHumidity(sensorState, dht));
Serial.print(pre_fill_count);
Serial.print(" it Humidity measurement from temper buffer: ");
Serial.println(humid_buffer[pre_fill_count]);
previous_sens_readout = previous_sens_readout + DHT_reads_interval;
pre_fill_count++;
}
currentMillis = millis();
}
sensorState = measure;
previous_sens_readout = 0;
currentMillis = millis();
Serial.print("Program time on the exit of preFill: ");
Serial.print(int(currentMillis/1000));
Serial.println(" seconds");
measurmentFlag = true;
}
void loop() {
///////////////////////////////////////////////////////////////////////////////////
////////////////////////////MAIN STATE MACHINE OF PROGRAM/////////////////////////
/////////////////////////////////////////////////////////////////////////////////
Serial.println("--------------------HELLO THERE------------------------");
currentMillis = millis();
//TOTO - IMPLEMENT ACTUAL USE OF THE calculateAverageTemperature function
if(sensorState == measure && measurmentFlag == true){
calculateAverageTemperature(
sample_rate,
sum_temper,
sum_humid,
avg_temp,
avg_humid
);
if(currentMillis - previous_sens_readout >= DHT_reads_interval){
getSensorReadings(dht,
temper_buffer,
humid_buffer
);
previous_sens_readout = previous_sens_readout + DHT_reads_interval;
}
if(sensorState == fail){
Serial.println("FAKAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP!");
delay(2000);
//TODO: RETRY MEASUREMENT AND RAISE LED INDICATOR OF FAIL!
}
}
}
void calculateAverageTemperature(
const int& sample_rate,
float& sum_temper,
float& sum_humid,
float& avg_temp,
float& avg_humid
){
//iter to gather the sum of 10 values
for (int k = 0; k < sample_rate; k++) {
Serial.println("-----------------HERE I AM!---------------------");
sum_temper = sum_temper + temper_buffer[k];
sum_humid = sum_humid + humid_buffer[k];
}
//calculate the sum of values
avg_temp = sum_temper / sample_rate;
avg_humid = sum_humid / sample_rate;
sum_temper = sum_humid = 0;
measurmentFlag = false;
}
void getSensorReadings(
DHT &sensor,
CircularBuffer<float, sample_rate> &temper_buffer,
CircularBuffer<float, sample_rate> &humid_buffer
){
//get next measurings
temper_buffer.push(readTemperature(sensorState, dht));
humid_buffer.push(readHumidity(sensorState, dht));
Serial.print(F("Avg Humidity: "));
Serial.print(avg_humid);
Serial.print(F("% Temperature: "));
Serial.print(avg_temp);
Serial.print(F("°C \n"));
measurmentFlag = true;
}
//GATHERING TEMPERATURE MEASUREMENT
float readTemperature
(
state &sensorState,
DHT &dht
){
float t = 0;
bool readed = false;
for (int r = 0; r < 4; r++) {
if ((!readed) && (!isnan(t = dht.readTemperature()))) {
Serial.print("Temperature readed on iteration: ");
Serial.println(r);
readed = true;
break;
}
else if ((r == 3) && (!readed)) {
Serial.println("Something went wrong with temperature");
sensorState = fail;
return -255;
}
}
return t;
}
//GATHERING HUMIDITY MEASUREMENT
float readHumidity
(
state &sensorState,
DHT &dht
){
float h = 0;
bool readed = false;
for (int o = 0; o < 4; o++) {
if (!readed && !isnan(h = dht.readHumidity())) {
Serial.print("Humidity readed on iteration: ");
Serial.println(o);
readed = true;
break;
}
else if ((o == 3) && (!readed)) {
//raise error, blink LED, Kill software
Serial.println("Something went wrong with Humidity");
sensorState = fail;
return -255;
}
}
return h;
}
I've tried many times using some extra flags inside code, nothing seem to really help.

DHT_reads_interval is defined as 2000. It should be expected that
(currentMillis - previous_sens_readout >= DHT_reads_interval)
is satisfied approximately every 2000 ms, which is 2 seconds.
Regarding the first 12 readings coming one after another, ask yourself what is currentMillis, and what is previous_sens_readout after setup completes?
In fact, currentMillis retains its value, but previous_sens_readout = 0; is spelled loud and clear. Do you see the consequences?

Related

Temp was not declared in this scope when getting values from bool

Hello I wanted to change some voids to bools and I am a little lost. I understand if you write a void or a bool and want to add the values to the next void you just insert the code to add the previous function
I don't know how to explain it I am just gonna tell you what I want to do:
created a new bool getValues and added all the value getting code from the sensors then I wanted to send the data to void loop that will send the data through mqqt to raspberry.
I understand that bool is for true and false. but I don't really understand the etiquette of using it
so the problem I am getting 'temp' was not declared in this scope at the void loop function
I highlighted the function with // where I get the error it's almost at the bottom
#include "DHT.h"
#include <WiFi.h>
#define DHTPIN 25 // Digital pin connected to the DHT sensor
#define DHTTYPE DHT11 // DHT 11
//MQTT Setup Start
#include <PubSubClient.h>
#define mqtt_server "192.168.1.210"
WiFiClient espClient;
PubSubClient client(espClient);
#define mqttlightReadingpercent "greenHouse/light"
#define mqttsoilmoisturepercent "greenHouse/soil"
#define mqtttemp "greenHouse/temp"
#define mqtthum "greenHouse/hum"
//MQTT Setup End
const char* ssid = "Cgates_E031F1"; // ESP32 and ESP8266 uses 2.4GHZ wifi only
const char* password = "60E541C32F";
DHT dht(DHTPIN, DHTTYPE);
const byte lightPin = 33;
int lightReading;
int lightReadingpercent=0;
//const int RELAY_PIN = 15; // the Arduino pin, which connects to the IN pin of relay
// soil moisture
const int AirValue = 4095; //you need to replace this value with Value_1
const int WaterValue = 2200; //you need to replace this value with Value_2
const int SensorPin = 32;
int soilMoistureValue = 0;
int soilmoisturepercent=0;
const int Lightvalue = 0;
const int Darkvalue = 4095;
unsigned long millisNow = 0; //for delay purposes
unsigned int sendDelay = 20000; //delay before sending sensor info via MQTT
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
Serial.println();
// begin Wifi connect
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.mode(WIFI_STA);
WiFi.disconnect();
delay(2000);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
//end Wifi connect
client.setServer(mqtt_server, 1883);
// pinMode(RELAY_PIN, OUTPUT);//relay
pinMode(lightPin, INPUT);
pinMode(SensorPin, INPUT);
Serial.println(F("DHTxx test!")); //dht
;
dht.begin();
}
void reconnect() {
// Loop until we're reconnected
int counter = 0;
while (!client.connected()) {
if (counter == 5) {
ESP.restart();
}
counter+=1;
Serial.print("Attempting MQTT connection...");
// Attempt to connect
if (client.connect("greenHouseController")) {
Serial.println("connected");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
bool getValues() {
lightReading = analogRead(lightPin); //0-4095 12bit -- esp8266 10bit 0-1023 -- arduino 8bit 0-254
Serial.print("Light reading = ");
lightReadingpercent = map(lightReading, Darkvalue, Lightvalue, 0, 100 );
Serial.print(lightReadingpercent);
Serial.println(" %");
Serial.println();
soilMoistureValue = analogRead(SensorPin); //put Sensor insert into soil
soilmoisturepercent = map(soilMoistureValue, AirValue, WaterValue, 0, 100);
if (soilmoisturepercent > 100) {
Serial.println("Soil moisture ");
Serial.println("100 %");
delay(500);
}
else if(soilmoisturepercent <0) {
Serial.println("Soil moisture ");
Serial.println("0 %");
delay(500);
}
else if (soilmoisturepercent >=0 && soilmoisturepercent <= 100) {
Serial.println("Soil moisture "); //go to next line
Serial.print(soilmoisturepercent);
Serial.println("%");
delay(500); // soil end
}
delay(500);
// Reading temperature or humidity takes about 250 milliseconds!
// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
float hum = dht.readHumidity();
// Read temperature as Celsius (the default)
float temp = dht.readTemperature();
// Read temperature as Fahrenheit (isFahrenheit = true)
float f = dht.readTemperature(true);
// Check if any reads failed and exit early (to try again).
if (isnan(hum) || isnan(temp) || isnan(f)) {
Serial.println(F("Failed to read from DHT sensor!"));
return 1;
}
// Compute heat index in Fahrenheit (the default)
float hif = dht.computeHeatIndex(f, hum);
// Compute heat index in Celsius (isFahreheit = false)
float hic = dht.computeHeatIndex(temp, hum, false);
Serial.print(F(" Humidity: "));
Serial.print(hum);
Serial.print(F("% Temperature: "));
Serial.print(temp);
Serial.print(F("C "));
Serial.print(f);
Serial.print(F("F Heat index: "));
Serial.print(hic);
Serial.print(F("C "));
Serial.print(hif);
Serial.println(F("F"));
delay(500); //wait 0.5seconds
}
void loop() {
if (!client.connected()) {
reconnect();
}
if (millis() > millisNow + sendDelay) {
if (getValues()) {
client.publish(mqttlightReadingpercent, String(lightReadingpercent).c_str(),true);
client.publish(mqttsoilmoisturepercent, String(soilmoisturepercent).c_str(),true);
client.publish(mqtttemp, String(temp).c_str(),true); // the problem is here
client.publish(mqtthum, String(hum).c_str(),true);
millisNow = millis();
}
}
client.loop();
/*if (moisture_level < 10) {
digitalWrite(RELAY_PIN, HIGH); // turn on pump 5 seconds
delay(5000);
}
else {
digitalWrite(RELAY_PIN, LOW); // turn off pump 5 seconds
delay(5000);
}*/
}
By moving your code to getValues, you also changed the scope in which your temp variable exists in. Variables are not automatically globally available. If you declare a variable inside a function (which getValues is), it's only available in this function.
When you try to access the temp variable in your loop function, the compiler rightly tells you, that there is no such variable available.
You could solve the problem by declaring temp as a global variable, which you would do by adding float temp = 0 up on top where you also declare variables like soilMoistureValue. Make sure not to redeclare the variable in getValues then, so instead of declaring like so float temp = dht.readTemperature(); you just assign a new value like so temp = dht.readTemperature();
A quick note on your first paragraph: The voids and bools how you call it, define the return type of a function. If your function does not return anything, you define it as void. If it returns a boolean value (so true or false), you define so bool. In the case of your getValues function, since it does not return anything, it should be void getValues.

Why the GSM Module data signal makes the PIR Motion sensor value to HIGH Arduino

I was creating a PIR Motion sensor and GSM Module SMS 800A based Security System with Arduino UNO
But I am facing a problem from 2 to 3 days that whenever I send a SMS from my phone to my GSM module then the Motion sensor automatically detects a motion and makes the system active.
Please tell me why is this happening?
This is my code :->
#include <SoftwareSerial.h>
#include <Sim800L.h>
#include <MemoryFree.h>
Sim800L GSM(10, 11);
SoftwareSerial sim800(10, 11); //2 is TX and 3 is RX
int day, month, year, minute, second, hour;
int onDay, onMonth, onYear, onMinute, onSecond, onHour;
int offDay, offMonth, offYear, offMinute, offSecond, offHour;
unsigned long prevMillis;
unsigned long currentMillis;
const long interval = 30000;
boolean timeStatus = false;
int RTCPerm;
int led = 13;
int pin = 5;
int x = 1;
int m = 0;
char y;
char t;
int value = 0;
int pirState = LOW;
char n[3];
int j = 0;
int i = 0;
char data[200] = {};
int condition = 0;
char DTMF[200] = {};
int z;
int delayOnMinute, delayOffMinute, delayOnHour, delayOffHour;
// connections
//
// GSM ARDUINO UNO
//
// GND -----> GND
// TX -----> 2
// RX -----> 3
// Power Supply -----> 12V 1A or 5V 2A
//
// Motion Sensor Arduino UNO
//
// VCC -----> 5V
// GND -----> GND
// OUT -----> 4
void setup() {
pinMode(led, OUTPUT);
pinMode(12, OUTPUT);
pinMode(pin, INPUT);
Serial.begin(9600);
sim800.begin(9600);
delay(6000);
sim800.println(F("AT+CMGF=1"));
sim800.println(F("AT+CNMI=2, 2, 0, 0, 0"));
sim800.println(F("AT+DDET=1"));
GSM.begin(9600); // for RTC data input
delay(5000);
onMinute = 30;
onHour = 17;
offMinute = 00;
offHour = 15;
}
void loop() {
while (RTCPerm == 0) {
RTCStatus();
prevMillis = millis();
while (currentMillis - prevMillis != interval) {
// save the last time you blinked the LED
currentMillis = millis();
SMSRecieve();
if (timeStatus == true) {
value = digitalRead(pin);
if (value == HIGH) {
digitalWrite(led, HIGH);
if (pirState == LOW) {
goto Motion;
}
}
}
}
}
Serial.println("Hello");
value = digitalRead(pin);
if (value == HIGH) {
digitalWrite(led, HIGH);
if (pirState == LOW) {
Motion:
Serial.println(F("Motion Detected!"));
sim800.begin(9600);
So in the loop function you can see the SMS Receive function that checks whether there is any incoming SMS or not. So whenever I send a SMS to my GSM then my Motion sensor gets active and goes to label Motion which activates other functioning like starting the alarm etc.
This is the code of SMSRecieve() Function :->
void SMSRecieve() {
Samarth:
/* if (condition == 2) {
memset(data, 0, sizeof(data));
y = 0;
condition = 1;
}*/
if (sim800.available())
{ // Printing the collected data
y = sim800.read();
Serial.write(y);
if (y == '#') {
goto skip;
}
data[i] = y;
i++;
skip:
if (strstr(data, "off") || strstr(data, "OFF") || strstr(data, "Off")) {
// Do Something
} else if (strstr(data, "Lighton") || strstr(data, "lighton") || strstr(data, "LightOn") || strstr(data, "LIGHTON")) {
// Do Something
}else if (strstr(data, "Lightoff") || strstr(data, "lightoff") || strstr(data, "LightOff") || strstr(data, "LIGHTOFF")) {
// Do Something
}
}
}
Please help me where I am doing wrong ?
After testing the situation again and again I got the solution and the reason why that was happening.
REASON:- PIR Motion Sensors also detect the RF and other unseen frequencies in the air. So whenever I sent a SMS to my GSM, it was detected by my PIR Motion Sensor.
SOLUTION:- The GSM Module should be kept with at least 2 feet of distance from the PIR Motion Sensor

Arduino LCD Display showing jumbled letters

When switching between states, the lines get jumbled and the characters get mixed up. Nothing I've seen online helps and example code in the library works just fine. The main issue I think comes from when the LCD is wiped clean, but then I don't know where it should be wiped. I've moved it from loop() to the cases multiple times, and delays don't help.
#include <TimeLib.h>
#include <DS1307RTC.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(7, 8, 9, 10, 11, 12);
#include "RTClib.h"
RTC_DS1307 rtc;
const int hourButton = 2; // Interrupt Pin 0 -- TOP
const int minuteButton = 3; // Interrupt Pin 1 -- 2nd
const int displayStateButton = 18; // Interrupt Pin 5 -- 3rd
const int alarmButton = 19; // Interrupt Pin 4 -- BOTTOM
int buttonState = LOW;
int redPin = 4;
int greenPin = 5; // RGB LED Pins
int bluePin = 6;
int alarmPin = 13; // Alarm Pin
enum DeviceDisplayState {CLOCK, ALARM, DATE, YEAR}; // All different states
DeviceDisplayState displayState = CLOCK; // Initially in Clock State
#ifdef DEBOUNCE
long lastDebounceTime = 0;
long debounceDelay = 60;
#endif
void setup() {
lcd.begin(16, 2);
Serial.begin(57600);
// Set the time:: //
const int hourInit = 1;
const int minuteInit = 2;
const int secondInit = 1;
const int dayInit = 3;
const int monthInit = 4;
const int yearInit = 2020;
rtc.adjust(DateTime(yearInit, monthInit, dayInit, hourInit , minuteInit, secondInit));
pinMode(hourButton, INPUT_PULLUP);
pinMode(minuteButton, INPUT_PULLUP);
pinMode(displayStateButton, INPUT_PULLUP);
attachInterrupt(0, increaseHour, FALLING);
attachInterrupt(1, increaseMinute, FALLING);
attachInterrupt(5, SwitchToNextDisplayState, FALLING);
pinMode(redPin, OUTPUT);
pinMode(greenPin, OUTPUT);
pinMode(bluePin, OUTPUT);
pinMode(alarmPin, OUTPUT);
SwitchToClockState();
};
void RGB_color(int red_light_value, int green_light_value, int blue_light_value)
{
analogWrite(redPin, red_light_value);
analogWrite(greenPin, green_light_value);
analogWrite(bluePin, blue_light_value);
}
void increaseHour()
{
DateTime dt = rtc.now();
Serial.print("Previous Time: " + dt.hour());
if (dt.hour() < 23)
{
TimeSpan ts(3600);
dt = dt + ts;
}
else // do not roll over the day by upping the hour, go back to zero hours
{
TimeSpan ts(3600 * 23);
dt = dt - ts;
}
Serial.print("Changed Time: " + dt.hour());
Serial.println();
rtc.adjust(dt);
}
void increaseMinute()
{
DateTime dt = rtc.now();
if (dt.minute() < 59)
{
TimeSpan ts(60);
dt = dt + ts;
}
else // Don't roll over the minutes into the hours
{
TimeSpan ts(60 * 59);
dt = dt - ts;
}
rtc.adjust(dt);
}
void SwitchToClockState()
{
displayState = CLOCK;
RGB_color(255, 0, 0);
}
void SwitchToAlarmState()
{
displayState = ALARM;
RGB_color(255, 125, 0);
}
void SwitchToDateState()
{
displayState = DATE;
RGB_color(0, 255, 0);
}
void SwitchToYearState()
{
displayState = YEAR;
RGB_color(0, 0, 255);
}
void SwitchToNextDisplayState()
{
switch (displayState) {
case CLOCK:
SwitchToAlarmState();
Serial.print("Switching to Alarm State...");
Serial.println();
lcd.clear();
break;
case ALARM:
SwitchToDateState();
Serial.print("Switching to Date State...");
Serial.println();
lcd.clear();
break;
case DATE:
SwitchToYearState();
Serial.print("Switching to Year State...");
Serial.println();
lcd.clear();
break;
case YEAR:
SwitchToClockState();
Serial.print("Switching to Clock State...");
Serial.println();
lcd.clear();
break;
default:
// assert()
digitalWrite(redPin, LOW);
digitalWrite(greenPin, LOW);
digitalWrite(bluePin, LOW);
break;
}
}
String WithLeadingZeros(int number)
{
if (number < 10)
{
return "0" + String(number);
}
else
{
return String(number);
}
}
void loop() {
DateTime now = rtc.now();
int yearInt = now.year();
int monthInt = now.month();
int dayInt = now.day();
int hourInt = now.hour();
int minuteInt = now.minute();
int secondInt = now.second();
switch (displayState) {
case CLOCK:
lcd.print("Robot Slave");
lcd.setCursor(0, 1);
lcd.print("Time> " + WithLeadingZeros(now.hour()) + ":" + WithLeadingZeros(now.minute()) + ":" + WithLeadingZeros(now.second()));
break;
case ALARM:
lcd.print("Robot Slave");
case DATE:
lcd.print("Robot Slave");
lcd.setCursor(0, 1);
lcd.print("Date> " + WithLeadingZeros(now.month()) + " - " + WithLeadingZeros(now.day()));
break;
//case YEAR:
lcd.print("Robot Slave");
lcd.setCursor(0, 1);
lcd.print("Year> " + String(now.year()));
break;
}
}
You're creating nonsense instructions for your LCD if you execute commands in an ISR while already executing instructions in your normal program.
Let's say the serial command to write letter A is "WRITEA" and the command for clearing the display is "CLEAR".
Now while sending the letter A to your display you push the button, your display will receive something like "WRCLEARTEB" which it cannot make sense of. Or maybe it receives "WRITECLEARA" and it will write C instead of A.
Please note that this is just to give you an idea what is going on. Of course the data sent to the display is different.
But you're creating a mess by interleaving commands.
Update your display in a loop and use ISRs only to update variables that are then used in the next frame. Clocks with second precision are usually updated once per second.

Arduino (C++) sketc periodically freezes or resets: suspected overflow

I'm having trouble identifying the cause of a recurrent issue with some arduino code. The code below reads two temperature sensors, sends the result to a PID library, and uses the output to control some relays on a fridge (adding accurate temperature control to a fridge, basically).
The code freezes or the Arduino resets periodically. This happens periodically, but the period changes - it freezes every minimum 30 minutes, maximum about 30 hours.
I suspect that there's an overflow or that I'm writing beyond the range of an array, but I can't find the issue. It's very unlikely that there's a power issue - the arduino is on a 10A 12v supply with a dedicated 5v regulator, so I doubt it.
I'm fairly new to all this and would be very grateful for any pointers or advice - even some tips on how to troubleshoot this unpredictable error would be very appreciated!
Here's the code:
Setup and main loop, also checks an analog input for the set temperature:
// Call libraries for display, sensor, I2C, and memory. Library setup included as well.
#include <avr/pgmspace.h>
char buffer[20];
#include <Time.h>
#include <TimeLib.h>
#include <OneWire.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x3f,20,4);
#include <DallasTemperature.h>
#include <PID_v1.h>
// Special Characters for the display and display animations
#if defined(ARDUINO) && ARDUINO >= 100
#define printByte(args) write(args);
#else
#define printByte(args) print(args,BYTE);
#endif
#define ONE_WIRE_BUS 5 //DS18S20 Signal pin on digital 2
uint8_t heart[8] = { 0x0,0xa,0x1f,0x1f,0xe,0x4,0x0};
uint8_t deg[8] = { 0x1c,0x14,0x1c,0x0,0x3,0x4,0x4,0x3};
uint8_t Pv[8] = { 0x1c,0x14,0x1c,0x10,0x10,0x5,0x5,0x2};
uint8_t Sv[8] = { 0xc,0x10,0x8,0x4,0x18,0x5,0x5,0x2};
// end special chars
//************* Begin Variables Setup ***************//
//Sensors (ds18s20 needs additional chatter)
byte addr1[8]= {0x28, 0x3F, 0xB5, 0x3C, 0x05, 0x00, 0x00, 0x25};
byte addr2[8]= {0x28, 0xC7, 0xCD, 0x4C, 0x05, 0x00, 0x00, 0x0D};
byte data1[12];
byte data2[12];
byte MSB = 0;
byte LSB = 0;
float tempRead = 0;
float TemperatureSum = 0;
OneWire ds(ONE_WIRE_BUS);
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
//controller outputs
int ControlCpin = 6; // control to fridge
int ControlTpin = 8; // control to temperature/heater (get aquarium heater)
int ControlLpin = 7; // control to light
int ControlApin = 9; // control to airflow
//operational vars (the button)
//int buttonPushCounter = 0; // counter for the number of button presses DEPRACATED
int buttonState = 0; // current state of the button
int lastButtonState = 0; // previous state of the button
boolean buttonstate = false; // calculastate of the button (includes timer delay. use this in menus)
int buttontime = 0; // press length measure
int buttontimeon = 0; // necessary for press length measure
//operational vars (sensors and timing)
unsigned int sensorInterval = 20000; // time between readings
unsigned long int sensorTime = 0; // current time
unsigned long int sensorTime2 = 0; // time of last sensor reading
// fans, lights, and timers
unsigned long int fanONmillis = 0;
unsigned long int fanOFFmillis = 0;
byte fanON = 0;
byte fanOFF = 0;
boolean fanstate = false;
unsigned long int Time = 0;
unsigned long int TimeAdjust = 0;
unsigned long int LightON = 0;
unsigned long int LightOFF = 0;
unsigned int Hours = 0;
unsigned int Minutes = 0;
unsigned int Days = 0;
byte daysAdj = 0; //not implemented yet
float tempDiff = 0;
//key var storage
float PvH = 0;
double PvT = 0;
float SvH = 0;
double SvT = 12;
float SvTdisplay = 5.5;
float SvTdisplayOld = 5.5;
float Temp1; //Current readings
float Temp2; //Current readings
float Temp3; //Current readings
// Fridge limits
unsigned int safetyRest = 5; // off this long every hour (minimum) to let the compressor rest in minutes
int minCool = 10; // minimum cooling period in minutes
int coolStart = 0;
byte coolON = 0; // PID attached to this
// Heat limits
byte heatON = 0; // PID attached to this
//cool
double Kp = 0.5;
double Ki = 0.5;
double Kd = 0.5;
double Output;
PID coolPID(&PvT, &Output, &SvT ,Kp,Ki,Kd, REVERSE);
unsigned coolWindowSize = 600; // minutes*10
unsigned long coolWindowStartTime;
unsigned long coolOffElapsed = 0;
long unsigned PIDpos = 0;
unsigned long Outputx = 0;
unsigned long PIDposx = 0;
unsigned long safetyRestx = 0;
// ensure setpoint, input, and outpit are defined
//************* End Variables Setup ***************//
void setup(){
//Sensor start
sensors.begin();
//Pin declarations
pinMode(ControlTpin, OUTPUT); //set outputs
pinMode(ControlLpin, OUTPUT);
pinMode(ControlApin, OUTPUT);
pinMode(ControlCpin, OUTPUT);
digitalWrite(ControlTpin, HIGH); // write outputs HIGH (off in this case) FIRST to prevent startup jitters.
digitalWrite(ControlLpin, HIGH);
digitalWrite(ControlApin, HIGH);
digitalWrite(ControlCpin, HIGH);
//LCD and special chars
Serial.begin(9600);
lcd.begin();
lcd.backlight();
lcd.createChar(0, heart);
lcd.createChar(1, deg);
lcd.createChar(2, Pv);
lcd.createChar(3, Sv);
lcd.clear();
LoadScreen();
HomeSetup();
//PID setup
coolPID.SetOutputLimits(0, coolWindowSize);
coolPID.SetMode(AUTOMATIC);
coolOffElapsed = millis();
}
void loop(){
//if interval has passed, check the sensors, update the triggers, and update the screen
if (millis() - sensorTime2 > sensorInterval){
sensorTime2 = millis();
SensorCheck();
Triggers();
HomeSetup ();
}
SvTdisplay = (float)analogRead(A0);
SvTdisplay = SvTdisplay/40+5;
if(abs(SvTdisplay-SvTdisplayOld) > 0.2){
SvTdisplayOld = SvTdisplay;
lcd.setCursor(2,0);
lcd.print(SvTdisplayOld,1); //svt
lcd.printByte(1);
lcd.print(" ");
SvT = analogRead(A0)/4+50;
}
PIDpos = ((millis()/60000) % (coolWindowSize/10));
}
The following codes a loading screen and updates the screen with current values:
void LoadScreen (){
lcd.clear();
lcd.home();
lcd.setCursor(0,0);
lcd.print(" LaggerLogger ");
lcd.printByte(0);
lcd.setCursor(0,1);
lcd.print(" V2.0 Beepboop!");
delay(3000);
lcd.clear();
}
//write the home screen to the LCD with current data
void HomeSetup(){
lcd.setCursor(0,0);
lcd.printByte(3);
lcd.print(" ");
lcd.print(SvTdisplayOld,1); //svt
lcd.printByte(1);
lcd.print(" ");
lcd.setCursor(0,1);
lcd.printByte(2);
lcd.print(" ");
lcd.print(PvT/10,1); //pvt
lcd.printByte(1);
lcd.print(" ");
lcd.setCursor(8,1);
lcd.print(day()-1);
lcd.print("/");
lcd.print(hour());
lcd.print(":");
lcd.print(minute());
lcd.print(" ");
lcd.setCursor(8,0);
lcd.print(Output/10,1);
lcd.print("m/h ");
}
The following checks output values and 'triggers' the relay if its appropriate to do so:
void Triggers () {
coolPID.Compute();
// Check PID
if ((Output/10) > (coolWindowSize/10-PIDpos) && PIDpos > safetyRest ) { //
coolON = 1;
coolStart = millis();
}
else if ((millis() - coolStart) > (minCool * 60000)){
coolON = 0;
}
else {}
// Write to temp relay pins
if (coolON == 1) {
digitalWrite(ControlCpin, LOW);
}
else {
digitalWrite(ControlCpin, HIGH);
}
// Control fans
if (coolON == 1 || heatON == 1 || tempDiff > 1) {
fanOFFmillis = millis();
fanONmillis = millis();
fanstate = true;
digitalWrite(ControlApin, LOW);
}
else {
fanstate = false;
digitalWrite(ControlApin, HIGH);
}
}
The following checks the temperature sensors and does some clock calculations:
void SensorCheck(){
Temp1 = getTemp1();
Temp2 = getTemp2();
//average readings and note the difference
if(Temp1 > 0 && Temp2 >0) {
PvT = (Temp1 + Temp2) / .2;
tempDiff = abs(Temp1 - Temp2);
}
//... unless there's only one thermometer...
else if (Temp1 > 0){
PvT = Temp1*10;
tempDiff = 0;
}
else {
PvT = 999;
tempDiff = 0;
}
//clock update
Time = millis() + TimeAdjust;
Hours = hour();
Minutes = minute();
Days = day();
}
float getTemp1(){
sensors.requestTemperatures();
float z = sensors.getTempCByIndex(0);
return z;
}
float getTemp2(){
sensors.requestTemperatures();
float z = sensors.getTempCByIndex(1);
return z;
}
The problem was that an integer (declared as int coolStart) was later updated to hold the value of millis().
Millis() can be much larger than the 16 bits available to ints - creating an overflow.
Changing the variable declaration to 'unsigned long coolStart = 0;' appears to have solved the problem.
Thanks to everyone for the troubleshooting advice.

SD.h not compatible with other libraries in Arduino/C++ environment

I'm having some very weird issues using the following hardware elements:
Arduino Uno
Wi-Fi shield
GPS receiver
Accelerometer
Barometer
I wanted to off-load the sensor readings to an SD card as needed, but before I can even code the SD functions, the mere inclusion of the SD.h library renders my code useless.
My code is as follows:
#include <SoftwareSerial.h>
#include <TinyGPS.h>
#include <SD.h>
/* This sample code demonstrates the normal use of a TinyGPS object.
It requires the use of SoftwareSerial, and assumes that you have a
4800-baud serial GPS device hooked up on pins 3(rx) and 4(tx).
*/
//For baraometer
#include <Wire.h>
#define BMP085_ADDRESS 0x77 // I2C address of BMP085
const unsigned char OSS = 2; // Oversampling Setting
// Calibration values
int ac1;
int ac2;
int ac3;
unsigned int ac4;
unsigned int ac5;
unsigned int ac6;
int b1;
int b2;
int mb;
int mc;
int md;
// b5 is calculated in bmp085GetTemperature(...), this variable is also used in bmp085GetPressure(...)
// So ...Temperature(...) must be called before ...Pressure(...).
long b5;
//End of baraometer
//ACcelerometer
// These constants describe the pins. They won't change:
const int xpin = A1; // x-axis of the accelerometer
const int ypin = A2; // y-axis
const int zpin = A3; // z-axis (only on 3-axis models)
//end of accel
TinyGPS gps;
SoftwareSerial nss(3, 4);
static void gpsdump(TinyGPS &gps);
static bool feedgps();
static void print_float(float val, float invalid, int len, int prec);
static void print_int(unsigned long val, unsigned long invalid, int len);
static void print_date(TinyGPS &gps);
static void print_str(const char *str, int len);
void setup()
{
//Make sure the analog-to-digital converter takes its reference voltage from
// the AREF pin
analogReference(EXTERNAL);
pinMode(xpin, INPUT);
pinMode(ypin, INPUT);
pinMode(zpin, INPUT);
//Barometer
Wire.begin();
bmp085Calibration();
//GPS
Serial.begin(115200);
nss.begin(57600);
Serial.print("Testing TinyGPS library v. "); Serial.println(TinyGPS::library_version());
Serial.println("by Mikal Hart");
Serial.println();
Serial.print("Sizeof(gpsobject) = "); Serial.println(sizeof(TinyGPS));
Serial.println();
Serial.println("Sats HDOP Latitude Longitude Fix Date Time Date Alt Course Speed Card Distance Course Card Chars Sentences Checksum");
Serial.println(" (deg) (deg) Age Age (m) --- from GPS ---- ---- to London ---- RX RX Fail");
Serial.println("--------------------------------------------------------------------------------------------------------------------------------------");
}
void loop()
{
//Accelerometer
Serial.print( analogRead(xpin));
Serial.print("\t");
//Add a small delay between pin readings. I read that you should
//do this but haven't tested the importance
delay(1);
Serial.print( analogRead(ypin));
Serial.print("\t");
//add a small delay between pin readings. I read that you should
//do this but haven't tested the importance
delay(1);
Serial.print( analogRead(zpin));
Serial.print("\n"); // delay before next reading:
bool newdata = false;
unsigned long start = millis();
// Every second we print an update
while (millis() - start < 1000)
{
if (feedgps())
newdata = true;
}
//barometer
float temperature = bmp085GetTemperature(bmp085ReadUT()); //MUST be called first
float pressure = bmp085GetPressure(bmp085ReadUP());
float atm = pressure / 101325; // "standard atmosphere"
float altitude = calcAltitude(pressure); //Uncompensated caculation - in Meters
Serial.print("Temperature: ");
Serial.print(temperature, 2); //display 2 decimal places
Serial.println(" C");
Serial.print("Pressure: ");
Serial.print(pressure, 0); //whole number only.
Serial.println(" Pa");
Serial.print("Standard Atmosphere: ");
Serial.println(atm, 4); //display 4 decimal places
Serial.print("Altitude: ");
Serial.print(altitude, 2); //display 2 decimal places
Serial.println(" M");
Serial.println();//line break
//end of barometer
gpsdump(gps);
}
static void gpsdump(TinyGPS &gps)
{
float flat, flon;
unsigned long age, date, time, chars = 0;
unsigned short sentences = 0, failed = 0;
static const float LONDON_LAT = 51.508131, LONDON_LON = -0.128002;
print_int(gps.satellites(), TinyGPS::GPS_INVALID_SATELLITES, 5);
print_int(gps.hdop(), TinyGPS::GPS_INVALID_HDOP, 5);
gps.f_get_position(&flat, &flon, &age);
print_float(flat, TinyGPS::GPS_INVALID_F_ANGLE, 9, 5);
print_float(flon, TinyGPS::GPS_INVALID_F_ANGLE, 10, 5);
print_int(age, TinyGPS::GPS_INVALID_AGE, 5);
print_date(gps);
print_float(gps.f_altitude(), TinyGPS::GPS_INVALID_F_ALTITUDE, 8, 2);
print_float(gps.f_course(), TinyGPS::GPS_INVALID_F_ANGLE, 7, 2);
print_float(gps.f_speed_kmph(), TinyGPS::GPS_INVALID_F_SPEED, 6, 2);
print_str(gps.f_course() == TinyGPS::GPS_INVALID_F_ANGLE ? "*** " : TinyGPS::cardinal(gps.f_course()), 6);
print_int(flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0UL : (unsigned long)TinyGPS::distance_between(flat, flon, LONDON_LAT, LONDON_LON) / 1000, 0xFFFFFFFF, 9);
print_float(flat == TinyGPS::GPS_INVALID_F_ANGLE ? 0.0 : TinyGPS::course_to(flat, flon, 51.508131, -0.128002), TinyGPS::GPS_INVALID_F_ANGLE, 7, 2);
print_str(flat == TinyGPS::GPS_INVALID_F_ANGLE ? "*** " : TinyGPS::cardinal(TinyGPS::course_to(flat, flon, LONDON_LAT, LONDON_LON)), 6);
gps.stats(&chars, &sentences, &failed);
print_int(chars, 0xFFFFFFFF, 6);
print_int(sentences, 0xFFFFFFFF, 10);
print_int(failed, 0xFFFFFFFF, 9);
Serial.println();
}
static void print_int(unsigned long val, unsigned long invalid, int len)
{
char sz[32];
if (val == invalid)
strcpy(sz, "*******");
else
sprintf(sz, "%ld", val);
sz[len] = 0;
for (int i=strlen(sz); i<len; ++i)
sz[i] = ' ';
if (len > 0)
sz[len-1] = ' ';
Serial.print(sz);
feedgps();
}
static void print_float(float val, float invalid, int len, int prec)
{
char sz[32];
if (val == invalid)
{
strcpy(sz, "*******");
sz[len] = 0;
if (len > 0)
sz[len-1] = ' ';
for (int i=7; i<len; ++i)
sz[i] = ' ';
Serial.print(sz);
}
else
{
Serial.print(val, prec);
int vi = abs((int)val);
int flen = prec + (val < 0.0 ? 2 : 1);
flen += vi >= 1000 ? 4 : vi >= 100 ? 3 : vi >= 10 ? 2 : 1;
for (int i=flen; i<len; ++i)
Serial.print(" ");
}
feedgps();
}
static void print_date(TinyGPS &gps)
{
int year;
byte month, day, hour, minute, second, hundredths;
unsigned long age;
gps.crack_datetime(&year, &month, &day, &hour, &minute, &second, &hundredths, &age);
if (age == TinyGPS::GPS_INVALID_AGE)
Serial.print("******* ******* ");
else
{
char sz[32];
sprintf(sz, "%02d/%02d/%02d %02d:%02d:%02d ",
month, day, year, hour, minute, second);
Serial.print(sz);
}
print_int(age, TinyGPS::GPS_INVALID_AGE, 5);
feedgps();
}
static void print_str(const char *str, int len)
{
int slen = strlen(str);
for (int i=0; i<len; ++i)
Serial.print(i<slen ? str[i] : ' ');
feedgps();
}
static bool feedgps()
{
while (nss.available())
{
if (gps.encode(nss.read()))
return true;
}
return false;
}
// Stores all of the bmp085's calibration values into global variables
// Calibration values are required to calculate temp and pressure
// This function should be called at the beginning of the program
void bmp085Calibration()
{
Serial.write("\n\nCalibrating ... ");
ac1 = bmp085ReadInt(0xAA);
ac2 = bmp085ReadInt(0xAC);
ac3 = bmp085ReadInt(0xAE);
ac4 = bmp085ReadInt(0xB0);
ac5 = bmp085ReadInt(0xB2);
ac6 = bmp085ReadInt(0xB4);
b1 = bmp085ReadInt(0xB6);
b2 = bmp085ReadInt(0xB8);
mb = bmp085ReadInt(0xBA);
mc = bmp085ReadInt(0xBC);
md = bmp085ReadInt(0xBE);
Serial.write("Calibrated\n\n");
}
// Calculate temperature in deg C
float bmp085GetTemperature(unsigned int ut){
long x1, x2;
x1 = (((long)ut - (long)ac6)*(long)ac5) >> 15;
x2 = ((long)mc << 11)/(x1 + md);
b5 = x1 + x2;
float temp = ((b5 + 8)>>4);
temp = temp /10;
return temp;
}
// Calculate pressure given up
// calibration values must be known
// b5 is also required so bmp085GetTemperature(...) must be called first.
// Value returned will be pressure in units of Pa.
long bmp085GetPressure(unsigned long up){
long x1, x2, x3, b3, b6, p;
unsigned long b4, b7;
b6 = b5 - 4000;
// Calculate B3
x1 = (b2 * (b6 * b6)>>12)>>11;
x2 = (ac2 * b6)>>11;
x3 = x1 + x2;
b3 = (((((long)ac1)*4 + x3)<<OSS) + 2)>>2;
// Calculate B4
x1 = (ac3 * b6)>>13;
x2 = (b1 * ((b6 * b6)>>12))>>16;
x3 = ((x1 + x2) + 2)>>2;
b4 = (ac4 * (unsigned long)(x3 + 32768))>>15;
b7 = ((unsigned long)(up - b3) * (50000>>OSS));
if (b7 < 0x80000000)
p = (b7<<1)/b4;
else
p = (b7/b4)<<1;
x1 = (p>>8) * (p>>8);
x1 = (x1 * 3038)>>16;
x2 = (-7357 * p)>>16;
p += (x1 + x2 + 3791)>>4;
long temp = p;
return temp;
}
// Read 1 byte from the BMP085 at 'address'
char bmp085Read(byte address)
{
Wire.beginTransmission(BMP085_ADDRESS);
Wire.write(address);
Wire.endTransmission();
Wire.requestFrom(BMP085_ADDRESS, 1);
while(!Wire.available()) {};
return Wire.read();
}
// Read 2 bytes from the BMP085
// First byte will be from 'address'
// Second byte will be from 'address'+1
int bmp085ReadInt(byte address)
{
unsigned char msb, lsb;
Wire.beginTransmission(BMP085_ADDRESS);
Wire.write(address);
Wire.endTransmission();
Wire.requestFrom(BMP085_ADDRESS, 2);
while(Wire.available()<2)
;
msb = Wire.read();
lsb = Wire.read();
return (int) msb<<8 | lsb;
}
// Read the uncompensated temperature value
unsigned int bmp085ReadUT(){
unsigned int ut;
// Write 0x2E into Register 0xF4
// This requests a temperature reading
Wire.beginTransmission(BMP085_ADDRESS);
Wire.write((byte)0xF4);
Wire.write((byte)0x2E);
Wire.endTransmission();
// Wait at least 4.5 ms
delay(5);
// Read two bytes from registers 0xF6 and 0xF7
ut = bmp085ReadInt(0xF6);
return ut;
}
// Read the uncompensated pressure value
unsigned long bmp085ReadUP(){
unsigned char msb, lsb, xlsb;
unsigned long up = 0;
// Write 0x34+(OSS<<6) into register 0xF4
// Request a pressure reading w/ oversampling setting
Wire.beginTransmission(BMP085_ADDRESS);
Wire.write(0xF4);
Wire.write(0x34 + (OSS<<6));
Wire.endTransmission();
// Wait for conversion, delay time dependent on OSS
delay(2 + (3<<OSS));
// Read register 0xF6 (MSB), 0xF7 (LSB), and 0xF8 (XLSB)
msb = bmp085Read(0xF6);
lsb = bmp085Read(0xF7);
xlsb = bmp085Read(0xF8);
up = (((unsigned long) msb << 16) | ((unsigned long) lsb << 8) | (unsigned long) xlsb) >> (8-OSS);
return up;
}
void writeRegister(int deviceAddress, byte address, byte val) {
Wire.beginTransmission(deviceAddress); // Start transmission to device
Wire.write(address); // Send register address
Wire.write(val); // Send value to write
Wire.endTransmission(); // End transmission
}
int readRegister(int deviceAddress, byte address){
int v;
Wire.beginTransmission(deviceAddress);
Wire.write(address); // Register to read
Wire.endTransmission();
Wire.requestFrom(deviceAddress, 1); // Read a byte
while(!Wire.available()) {
// waiting
}
v = Wire.read();
return v;
}
float calcAltitude(float pressure){
float A = pressure/101325;
float B = 1/5.25588;
float C = pow(A,B);
C = 1 - C;
C = C /0.0000225577;
return C;
}
Granted, right now, it is merely a conglomeration of multiple example sketches, but they work. I get a sampled reading from the accelerometer, the GPS unit and the barometer once a second. However once I simply add the line #include <SD.h> to the sketch, it fails to run correctly. The serial monitor does not display anything. I have similar versions of the above sketch (omitted as they are much lengthier), but I get the same result: either jumbled text or nothing on the Serial monitor. If I comment out the line that include the SD.h library, everything works fine....
Are there known issues with the SD.h library or conflicts? And yes, I am NOT using the necessary pins for the SD access (digital pin #4) for my sensor connections....
UPDATE:
I at least figured out it has something to do with the SoftSerial (SoftSerial.h) library and the use of the SoftSerial object (which I called nss). I can load all libraries and get everything to work if I do not call nss.begin. Is there a reason why that would conflict?
Turns out I was out of memory. Having the Serial go unresponsive like that is a common symptom. This link ultimately is what I used to trace and conclude my memory issue.
First thing would be to check the Arduino site, on the SD documentation (here) there's a mention that the communication between the microcontroller and the SD card uses SPI (documentation here) which takes place on digital pins 11, 12 and 13. I wouldn't be surprised if this was the source of your problems with the Serial monitor.
Reading some comments in Sd2Card.h, it might be tricky to get your setup to work properly:
/**
* Define MEGA_SOFT_SPI non-zero to use software SPI on Mega Arduinos.
* Pins used are SS 10, MOSI 11, MISO 12, and SCK 13.
*
* MEGA_SOFT_SPI allows an unmodified Adafruit GPS Shield to be used
* on Mega Arduinos. Software SPI works well with GPS Shield V1.1
* but many SD cards will fail with GPS Shield V1.0.
*/
Even if you put MEGA_SOFT_SPI to a non 0 value, you'd probably still fail to pass the (defined(__AVR_ATmega1280__)||defined(__AVR_ATmega2560__)) check.
I would suggest trying your same sketch without the TinyGPS to try to pinpoint the issue.
Also, check out this sketch it seems to be doing something similar to what you're doing, maybe you can fix yours based on what's done here.
Use pin 4 for CS and change the MOSI, MISO and SCK pins in the library SD in Sd2card.h, hope you will get rid of the problem