Interrupts and RTC

Hello dear forum :slight_smile:
First post, please be gentle.

I’am trying to read 4 IR temp sensors and writing that data to an sdcard, all with an attached interrupt using timerone library.

All this is working great until i try to add my function setupTime(), wich is (from my understanding) just checking if a few things are done right with the RTC.
The problem occurring is that this line of code in the void setup() is never being finished: Timer1.attachInterrupt(priouppgift);

Main loop is just using serial.println the same global values the interrupted function is reading but with a delay.

Any help is greatly appreciated

#include <Arduino.h>
#define SDA_PORT PORTD
#define SDA_PIN 1
#define SCL_PORT PORTD
#define SCL_PIN 0
#include <SoftI2CMaster.h>

//Interrupt
#include <TimerOne.h>

//SD KORT
const int chipSelect = 10;
#include <SPI.h>
#include <SdFat.h>
SdFat sd;
SdFile myLog;

//Time and date
#include <RTClib.h>
#include <Wire.h>
RTC_DS1307 rtc;
char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};

//tempsensor adress
int AA1 = 0x5B<<1; //stod 0x5A<<1 innan och i exempel.
int AA2 = 0x5C<<1; 
int AA3 = 0x5D<<1;
int AA4 = 0x5E<<1;  

//temp values that change in the attached timer.
volatile float celcius1 = 0;
volatile float celcius2 = 0;
volatile float celcius3 = 0;
volatile float celcius4 = 0;

void setup()
{
 Serial.begin(115200);
 Serial.println("Setup...");

 //setupTime(); //<-- this is my terrorist...

 setupI2CBus(); //stup i2c bus

 setupSDFat(); //setup SDfat

 Timer1.initialize(1000000); //slow update rate
Serial.println("initiate timer");

 Timer1.attachInterrupt(priouppgift); //start function for reading values and writing to SD card
Serial.println("attach timer");

}

void loop()
{
//prints values
 Serial.println(celcius1);
 Serial.println(celcius2);
 Serial.println(celcius3);
 Serial.println(celcius4);
 
 //refresh rate on screen
 delay(500); 
Serial.println("delay i loop");
}

/////////////////////////////////////////////////////////
//
// helper functions
//
void setupI2CBus()
{
 i2c_init(); //Initialise the i2c bus
 //PORTC = (1 << PORTC4) | (1 << PORTC5); //enable pullups
Serial.println("satt i2c bus");
}


void setupTime()
{
  Serial.println("innan time");
  
  if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  }

  if (! rtc.isrunning()) {
    Serial.println("RTC is NOT running!");
    // following line sets the RTC to the date & time this sketch was compiled
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
    // This line sets the RTC with an explicit date & time, for example to set
    // January 21, 2014 at 3am you would call:
    // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
  }
Serial.println("Time is set");
}

void setupSDFat()
{
  // Initialize SdFat or print a detailed error message and halt
  // Use half speed like the native library.
  // change to SPI_FULL_SPEED / SPI_HALF_SPEED for more performance.
     if (!sd.begin(chipSelect, SPI_FULL_SPEED)) {
     sd.initErrorHalt();
  }
Serial.println("sdfat done");
}

void priouppgift(void)
{

//populera med nya tempvärden
 celcius1 = readDevice(AA1);
 celcius2 = readDevice(AA2);
 celcius3 = readDevice(AA3);
 celcius4 = readDevice(AA4);

  // make a string for assembling the data to log:
  String dataString = "";
  dataString += String(celcius1);
  dataString += ",";
  dataString += String(celcius2);
  dataString += ",";
  dataString += String(celcius3);
  dataString += ",";
  dataString += String(celcius4);

   if (!myLog.open("test.txt", O_RDWR | O_CREAT | O_AT_END)) {
     sd.errorHalt("opening test.txt for write failed");
   }
   myLog.println(dataString);
   myLog.close();
   Serial.println(dataString);
}


float readDevice(int address)
{
 int dev = address << 1;
 int data_low = 0;
 int data_high = 0;
 int pec = 0;

 // RAW READ
 i2c_start_wait(dev + I2C_WRITE);
 i2c_write(0x07);

 i2c_rep_start(dev + I2C_READ);

    data_low = i2c_read(false); //Read 1 byte and then send ack
    data_high = i2c_read(false); //Read 1 byte and then send ack
    pec = i2c_read(true);
    i2c_stop();

   //This converts high and low bytes together and processes temperature, MSB is a error bit and is ignored for temps
    double tempFactor = 0.02; // 0.02 degrees per LSB (measurement resolution of the MLX90614)
    double tempData = 0x0000; // zero out the data
    int frac; // data past the decimal point
    
    // This masks off the error bit of the high byte, then moves it left 8 bits and adds the low byte.
    tempData = (double)(((data_high & 0x007F) << 8) + data_low);
    tempData = (tempData * tempFactor)-0.01;
    
    float temp = tempData - 273.15;
  
  return temp;
}

I'am trying to read 4 IR temp sensors and writing that data to an sdcard, all with an attached interrupt using timerone library.

Why? The blink without delay philosophy lacks what, that makes a timer necessary?

The problem occurring is that this line of code in the void setup() is never being finished: Timer1.attachInterrupt(priouppgift);

That does not happen in setupTime(), so it is wrong to blame setupTime() for your problems.

 Timer1.attachInterrupt(priouppgift); //start function for reading values and writing to SD card

That function does not start a function. It registers a function to be called at the appropriate time.

  String dataString = "";
  dataString += String(celcius1);

A massive waste of resources. Output to an SD card is buffered. Collecting all the data in one memory mangling String object does not make writing to the SD card more efficient or faster. So, why are you doing this?

You are aware that priouppgift() is a interrupt service routine, and that interrupts are disabled while the function is running, aren't you? You know that Serial relies on interrupts to send data, making more room in the outgoing buffer, right? You know what will happen if that buffer gets full, right? So, why are you using Serial.print() in an ISR?

Do you know whether the SD class uses interrupts? If not, why are you using the functions anyway?

PaulS:
You are aware that priouppgift() is a interrupt service routine, and that interrupts are disabled while the function is running, aren’t you?

He did say he was a beginner, Paul. So he probably doesn’t know this stuff.

@TobbeW - you can probably do away with interrupts and timers. See: Gammon Forum : Electronics : Microprocessors : How to do multiple things at once ... like cook bacon and eggs

I Really do appreciate your input.

I was not aware of the "blink without delay philosophy, so i will absolutely try that.
And thanks for the Example Nick :slight_smile:

I went for the interrupt because later on i will try to add a TFT and did want to favor reading values from sensors and writing to SD card instead of updating the graphics. But i will probably be able to that with this blink example.

The reason the String was there was simply because i found it in an example. But i will absolutely remove it as i want this code to be fast.

And i was Not aware of the buffer limits.

I have now tried to narrow it down as much as i can, and make it really simple.
And i still have a problem with RTC and reading i2c sensor.
I have to comment out DS1307RTC.h and associated functions in the below code to be able to read sensor values… i really have no idea why.

#include <Arduino.h>
#define SDA_PORT PORTD
#define SDA_PIN 1
#define SCL_PORT PORTD
#define SCL_PIN 0
#include <SoftI2CMaster.h>

#include <TimeLib.h>
#include <Wire.h>
//#include <DS1307RTC.h>  // a basic DS1307 library that returns time as a time_t


void setup()  {
  Serial.begin(9600);
 // setSyncProvider(RTC.get);   // the function to get the time from the RTC
  i2c_init();
}

void loop()
{
//  digitalClockDisplay();  
  Serial.println(readDevice(0x5B<<1)); 
  delay(1000);
}

void digitalClockDisplay(){
  // digital clock display of the time
  Serial.print(hour());
  printDigits(minute());
  printDigits(second());
  Serial.print(" ");
  Serial.print(day());
  Serial.print(" ");
  Serial.print(month());
  Serial.print(" ");
  Serial.print(year()); 
  Serial.println(); 
  
}

void printDigits(int digits){
  // utility function for digital clock display: prints preceding colon and leading 0
  Serial.print(":");
  if(digits < 10)
    Serial.print('0');
  Serial.print(digits);
}


float readDevice(int address)
{
 int dev = address << 1;
 int data_low = 0;
 int data_high = 0;
 int pec = 0;

 // RAW READ
 i2c_start_wait(dev + I2C_WRITE);
 i2c_write(0x07);

 i2c_rep_start(dev + I2C_READ);

    data_low = i2c_read(false); //Read 1 byte and then send ack
    data_high = i2c_read(false); //Read 1 byte and then send ack
    pec = i2c_read(true);
    i2c_stop();

   //This converts high and low bytes together and processes temperature, MSB is a error bit and is ignored for temps
    double tempFactor = 0.02; // 0.02 degrees per LSB (measurement resolution of the MLX90614)
    double tempData = 0x0000; // zero out the data
    int frac; // data past the decimal point
    
    // This masks off the error bit of the high byte, then moves it left 8 bits and adds the low byte.
    tempData = (double)(((data_high & 0x007F) << 8) + data_low);
    tempData = (tempData * tempFactor)-0.01;
    
    float temp = tempData - 273.15;
  
  return temp;
}

I have to comment out DS1307RTC.h and associated functions in the below code to be able to read sensor values... i really have no idea why.

You are using software i2c for the sensors and hardware i2c for the RTC. Why are you using the software i2c?

Are you using a Mega? If so, the software i2c is set for PD0/PD1 which are the same as the hardware pins.

Thank you :slight_smile:
Yes i'am using a Mega2560.

I thought i had to use softwarei2c when reading from MLX90614 sensors as stated here:
http://playground.arduino.cc/Main/SoftwareI2CLibrary

(will try to change those pins now :)) )

EDIT: AND It works great. Thank you all very much, i'd like to believe i've learned alot ;).