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.
Related
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?
In my program on Arduino I use a TimerInterrupt. In this TimerIntrrupt I try to display on a LCD the values returned by the methods I call. Unfortunately nothing is displayed on the LCD and I don't know where the error is in my program. Does anyone have an idea of the error? How can I handle to solve the problem
class Sensor {
float _flowRateTrinkwasser;
unsigned long _wasserMengeTrinkwasser;
float _flowRateReinwasser;
unsigned long _wasserMengeReinwasser;
public:
Sensor( float flowRateTrinkwasser, unsigned long wasserMengeTrinkwasser, float flowRateReinwasser, unsigned long wasserMengeReinwasser) { // Konstruktor
_flowRateTrinkwasser = flowRateTrinkwasser;
_wasserMengeTrinkwasser = wasserMengeTrinkwasser;
_flowRateReinwasser = flowRateReinwasser;
_wasserMengeReinwasser = wasserMengeReinwasser;
}
int get_f_ml1 () {
_flowRateTrinkwasser = 120; // Formel zur Berechnung von Flow Rate
_wasserMengeTrinkwasser = 50;
int f_ml1 = _flowRateTrinkwasser + _wasserMengeTrinkwasser ;
return f_ml1;
}
int get_f_ml () {
_flowRateReinwasser = 70;
_wasserMengeReinwasser = 40;
int f_ml = _flowRateReinwasser + _wasserMengeReinwasser ;
return f_ml;
}
};
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include "test.h"
//Durchflussmessung Variable Trinkwasser//
float flowRateTrinkwasser;
unsigned long wasserMengeTrinkwasser;
//Durchflussmessung Variable Trinkwasser//
//Durchflussmessung Variable Reinwasser//
float flowRateReinwasser;
unsigned long wasserMengeReinwasser;
//Durchflussmessung Variable Reinwasser//
Sensor sensorOne( flowRateTrinkwasser, wasserMengeTrinkwasser, flowRateReinwasser, wasserMengeReinwasser ); // Objekt vom Konstruktor Sensor1
LiquidCrystal_I2C lcd(0x27, 20, 4);
void setup() {
Serial.begin(9600);
lcd.init();
lcd.backlight();
lcd.setCursor(0, 0);
lcd.println("Willkommen bei Truu");
delay(2000);
lcd.clear();
cli(); // disable interrupts
// reset
TCCR1A = 0; //set TCCR1A register to 0000
TCCR1B = 0; //set TCCR1B register to 0
TCNT1 = 0; // reset counter value
OCR1A = 15624; //compare match register für 1 Sekunde (15624pulse vorher)
// set prescaler
TCCR1B |= (1 << CS12) | (1 << CS10);
TCCR1B |= (1 << WGM12); //turn on CTC mode
TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
sei(); //allow interrupts
}
void loop() {
}
ISR(TIMER1_COMPA_vect) { // function which will be called when an interrupt occure at timer 1
lcd.setCursor(0,0);
lcd.println(sensorOne.get_f_ml1());
lcd.setCursor(0,1);
lcd.println(sensorOne.get_f_ml());
delay(50);
}
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.
I'm using an Arduino Uno with an Adafruit Motor Shield (v2) in order to power and control a motor and a LIS3DH accelerometer. With a simpler code in which the motor just goes forward for a certain number of pulses (output by the encoder), the identical function for the accelerometer outputs correct values. The code is shown below.
#include <Wire.h>
#include <SPI.h>
#include <Adafruit_LIS3DH.h>
#include <Adafruit_MotorShield.h>
#include <Adafruit_Sensor.h>
#include "utility/Adafruit_MS_PWMServoDriver.h"
#define pi 3.14159
Adafruit_MotorShield AFMS = Adafruit_MotorShield();
Adafruit_DCMotor *myMotor = AFMS.getMotor(1);
float distance = 30;
Adafruit_LIS3DH lis = Adafruit_LIS3DH();
//
const byte encoder0pinA = 2;//A pin -> the interrupt pin 0
unsigned int pulsesperturn = 56 * 64 / 2 ;
float circumference = 5.25 * 3.14159;
int pulses;
//int count = 0;
#if defined(ARDUINO_ARCH_SAMD)
// for Zero, output on USB Serial console, remove line below if using programming port to program the Zero!
#define Serial SerialUSB
#endif
void setup(void) {
#ifndef ESP8266
while (!Serial); // will pause Zero, Leonardo, etc until serial console opens
#endif
Serial.begin(9600);
AFMS.begin();
Serial.println("LIS3DH test!");
if (! lis.begin(0x19)) { // change this to 0x19 for alternative i2c address
Serial.println("Couldnt start");
while (1);
}
Serial.println("LIS3DH found!");
lis.setRange(LIS3DH_RANGE_4_G); // 2, 4, 8 or 16 G!
//
}
void loop() {
// // }
// myMotor->setSpeed(255); // this will end up changing but is constant for testing validation purposes
// myMotor->run(FORWARD);
// delay(2500);
// myMotor->setSpeed(0);
// // right = 0;
// delay(1000);
// // right = 1;
// myMotor->run(BACKWARD);
// myMotor->setSpeed(255);
// delay(2500);
// myMotor->setSpeed(0);
// // right = 0;
// delay(1000);
// // right = 1;
myMotor->run(FORWARD);
myMotor->setSpeed(255); // this will end up changing but is constant for testing validation purposes
if (pulsesperturn <= pulses ) {
myMotor->run(RELEASE);
myMotor->run(RELEASE);
myMotor->setSpeed(0);
stoppedAccel();
pulses = 0;
}
// Then print out the raw data
// Serial.print("X: "); Serial.print(lis.x);
// Serial.print(" \tY: "); Serial.print(lis.y);
// Serial.print(" \tZ: "); Serial.print(lis.z);
// for (int a = 1; a < 20; a = a + 1) {
// lis.read(); // get X Y and Z data at once
// sensors_event_t event;
// lis.getEvent(&event);
//
// /* Display the results (acceleration is measured in m/s^2) */
// // Serial.print(" \tAngle: "); Serial.print(angle);
// //
// // Serial.print("\t\tX: "); Serial.print(event.acceleration.x);
// Serial.print(" \tY: "); Serial.print(event.acceleration.y);
// Serial.print(" \tZ: "); Serial.print(event.acceleration.z);
// // Serial.println(" m/s^2 ");
//
// Serial.println();
// //
// // char buffer[5];
// // Serial.print("#S|WRITEDATA|[");
// // Serial.print(angle); // accels
// // Serial.println("]#");
//
// // WriteAccel();
// delay(10);
// }
// myMotor->run(FORWARD);
//
// myMotor->run(RELEASE);
// myMotor->setSpeed(255);
// if (distance / circumference * pulsesperturn <= pulses) {
// myMotor->setSpeed(0);
// delay(2500);
// }
// myMotor->setSpeed(255);
// myMotor->run(FORWARD);
// pulses = 0;
Serial.print("pulses = ");
Serial.println(pulses);
attachInterrupt(digitalPinToInterrupt(encoder0pinA), counter, RISING);
/* Or....get a new sensor event, normalized */
}
void counter()
{
pulses++;
}
void stoppedAccel()
{
for (int a = 1; a < 150; a = a + 1) {
lis.read(); // get X Y and Z data at once
sensors_event_t event;
lis.getEvent(&event);
float angle = asin(event.acceleration.z / 9.81) * 180 / pi ;
Serial.print(" \tAngle: "); Serial.print(angle);
//
// Serial.print("\t\tX: "); Serial.print(event.acceleration.x);
// Serial.print(" \tY: "); Serial.print(event.acceleration.y);
// Serial.print(" \tZ: "); Serial.print(event.acceleration.z);
// Serial.println(" m/s^2 ");
Serial.println();
//
// char buffer[5];
// Serial.print("#S|WRITEDATA|[");
// Serial.print(angle); // accels
// Serial.println("]#");
delay(10);
}
}
In this code, which runs the motor forward for a distance 6 times and then runs it backward for the same distance it went forward, the motor runs correctly and the accelerometer says that it has been found but it outputs exclusively null values.
#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include "utility/Adafruit_MS_PWMServoDriver.h"
Adafruit_MotorShield AFMS = Adafruit_MotorShield();
Adafruit_DCMotor *myMotor = AFMS.getMotor(1);
#include <SPI.h>
#include <Adafruit_LIS3DH.h>
#include <Adafruit_Sensor.h>
Adafruit_LIS3DH lis = Adafruit_LIS3DH();
//The sample code for driving one way motor encoder
const byte encoder0pinA = 2;//A pin -> the interrupt pin 0
//byte encoder0PinALast;
int duration;//the number of the pulses
//unsigned long timeold;
unsigned int pulsesperturn = 56 * 64 / 2;
float widthDetector = 10; //distance needed, in cm
float circumference = 5.25 * 3.14159;
float pulses;
int count = 0;
#define pi 3.14159
//bool answered = 0;
//float distanceTotal = 100;
//float waitTime = 0.01;
//unsigned int pulsesper100forward = 56 * 64 ;
//unsigned int pulsesper100back = 56 * 64 ;
int b = 0;
float conversion = 171 / 169;
#if defined(ARDUINO_ARCH_SAMD)
// for Zero, output on USB Serial console, remove line below if using programming port to program the Zero!
#define Serial SerialUSB
#endif
void setup(void)
{
#ifndef ESP8266
while (!Serial); // will pause Zero, Leonardo, etc until serial console opens
#endif
Serial.begin(9600);
AFMS.begin();
Serial.println("LIS3DH test!");
if (! lis.begin(0x19)) { // change this to 0x19 for alternative i2c address
Serial.println("Couldnt start");
while (1);
}
Serial.println("LIS3DH found!");
lis.setRange(LIS3DH_RANGE_4_G); // 2, 4, 8 or 16 G!
// myMotor->run(FORWARD);
myMotor->setSpeed(255); // this will end up changing but is constant for testing validation purposes
}
void loop() {
motorDirection();
}
void counter()
{
pulses++;
}
void bcounter()
{
b++;
}
void motorDirection()
{
while (b < 6) {
myMotor->run(FORWARD);
readInt();
if (500 * conversion <= pulses) {
myMotor->run(RELEASE);
myMotor->run(RELEASE);
pulses = 0;
bcounter();
if (b == 6) {
stoppedAccel();
}
delay(1500);
}
// break;
}
while (b == 6) {
myMotor->run(BACKWARD);
readInt();
if (500 * b <= pulses) {
myMotor->run(RELEASE);
myMotor->run(RELEASE);
bcounter();
stoppedAccel();
pulses = 0;
delay(500);
break;
}
}
while (b > 6) {
b = 0;
break;
}
}
// 169 forward per 1000, 171 backward
void stoppedAccel()
{
for (int a = 1; a < 150; a = a + 1) {
lis.read(); // get X Y and Z data at once
sensors_event_t event;
lis.getEvent(&event);
float angle = asin(event.acceleration.z / 9.81) * 180 / pi ;
Serial.print(" \tAngle: "); Serial.print(angle);
//
// Serial.print("\t\tX: "); Serial.print(event.acceleration.x);
// Serial.print(" \tY: "); Serial.print(event.acceleration.y);
// Serial.print(" \tZ: "); Serial.print(event.acceleration.z);
// Serial.println(" m/s^2 ");
Serial.println();
//
// char buffer[5];
// Serial.print("#S|WRITEDATA|[");
// Serial.print(angle); // accels
// Serial.println("]#");
delay(100);
}
}
void readInt()
{
attachInterrupt(digitalPinToInterrupt(encoder0pinA), counter, RISING);
Serial.print("pulses = ");
Serial.println(pulses);
}
I have tried various things but I have little background in CS, especially in C++, so my attempts haven't been fruitful. Any advice would be helpful.
The issue was using delay(). How exactly the hardware works, I'm not sure, but I believe blocking it in such a way threw off the hardware so that it was outputting null. Below is the corrected code using millis().
#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include "utility/Adafruit_MS_PWMServoDriver.h"
Adafruit_MotorShield AFMS = Adafruit_MotorShield();
Adafruit_DCMotor *myMotor = AFMS.getMotor(1);
#include <SPI.h>
#include <Adafruit_LIS3DH.h>
#include <Adafruit_Sensor.h>
Adafruit_LIS3DH lis = Adafruit_LIS3DH();
//The sample code for driving one way motor encoder
const byte encoder0pinA = 2;//A pin -> the interrupt pin 0
//byte encoder0PinALast;
int duration;//the number of the pulses
//unsigned long timeold;
unsigned int pulsesperturn = 56 * 64 / 2;
float widthDetector = 10; //distance needed, in cm
float circumference = 5.25 * 3.14159;
float pulses;
int count = 0;
#define pi 3.14159
float angle;
const long interval = 1000;
unsigned long previousMillis;
//bool answered = 0;
//float distanceTotal = 100;
//float waitTime = 0.01;
//unsigned int pulsesper100forward = 56 * 64 ;
//unsigned int pulsesper100back = 56 * 64 ;
int b = 0;
float conversion = 171 / 169;
#if defined(ARDUINO_ARCH_SAMD)
// for Zero, output on USB Serial console, remove line below if using programming port to program the Zero!
#define Serial SerialUSB
#endif
void setup(void)
{
#ifndef ESP8266
while (!Serial); // will pause Zero, Leonardo, etc until serial console opens
#endif
Serial.begin(9600);
AFMS.begin();
Serial.println("LIS3DH test!");
if (! lis.begin(0x19)) { // change this to 0x19 for alternative i2c address
Serial.println("Couldnt start");
while (1);
}
Serial.println("LIS3DH found!");
lis.setRange(LIS3DH_RANGE_4_G); // 2, 4, 8 or 16 G!
// myMotor->run(FORWARD);
myMotor->setSpeed(255); // this will end up changing but is constant for testing validation purposes
}
void loop() {
motorDirection();
// stoppedAccel();
}
void counter()
{
pulses++;
}
void bcounter()
{
b++;
}
void motorDirection()
{
//serial.write
while (b < 6) {
myMotor->run(FORWARD);
readInt();
if (500 * conversion <= pulses) {
myMotor->run(RELEASE);
bcounter();
previousMillis = millis();
timing();
// previousMillis = currentMillis;
pulses = 0;
if (b == 6) {
stoppedAccel();
}
}
break;
}
while (b == 6) {
myMotor->run(BACKWARD);
readInt();
if (500 * b <= pulses) {
myMotor->run(RELEASE);
pulses = 0;
bcounter();
stoppedAccel();
break;
}
}
while (b > 6) {
b = 0;
break;
}
}
// 169 forward per 1000, 171 backward
void stoppedAccel()
{
for (int a = 1; a < 200; a = a + 1) {
lis.read(); // get X Y and Z data at once
sensors_event_t event;
lis.getEvent(&event);
angle = asin(event.acceleration.z / 9.81) * 180 / pi ;
Serial.print(" \tAngle: "); Serial.print(angle);
//
// Serial.print("\t\tX: "); Serial.print(event.acceleration.x);
// Serial.print(" \tY: "); Serial.print(event.acceleration.y);
// Serial.print(" \tZ: "); Serial.print(event.acceleration.z);
// Serial.println(" m/s^2 ");
Serial.println();
//
// char buffer[5];
// Serial.print("#S|WRITEDATA|[");
// Serial.print(angle); // accels
// Serial.println("]#");
delay(10);
}
}
void readInt()
{
attachInterrupt(digitalPinToInterrupt(encoder0pinA), counter, RISING);
Serial.print("pulses = ");
Serial.println(pulses);
}
void timing()
{
while (millis() - previousMillis <= interval) {
myMotor->run(RELEASE);
}
}
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