Using an external clock and the interrupt function

I have bought a DS3234 real-time clock because apparently they are programmable. First of all I was wondering if anyone knew how you would go about programming it to emit a signal once every minute.

Assuming it emits a signal every minute:

  • How can I put the Arduino into sleep mode whilst it waits for a signal from the external clock?
  • How can I program the external clock to send a signal once every minute?
  • How do I use the interrupt function to run the program?

By run the program, I would like to do this:

  • Use the interrupt loop to keep a count of the number of signals received from clock
  • When the count reaches 15 (or any arbitrary number) switch to loop1() (this being the first code)
  • Loop1 should run and then the count reset to 0, the interrupt will kick back in and keep count
  • When reaches 15 again then commence loop2()

Currently I am waiting for the clock to arrive, but I made a simple sketch and was trying to get it to work. It didn't run as smoothly as I wanted but was part way there. I downloaded the TimerOne library so that I could change to clock speed. I set it to cycle once every 2.5 seconds for this experiment.

#include <TimerOne.h>

volatile byte count = 0;      //
const byte interruptPin = 20; // originally I used int to define them
volatile byte state = LOW;    // but started to try different things
 
void setup() 
{
  Serial.begin(9600);
  
  pinMode(13, OUTPUT);

  pinMode(20, OUTPUT);            // Defines interupt pin
  digitalWrite(20, LOW);
  
  // This function changes the speed of the 16MHz crystal
  // Time given in microseconds, currently cycles once every 2.5  seconds
  Timer1.initialize(2500000);
//  attachInterrupt(digitalPinToInterrupt(20), Timer, state);
  Timer1.attachInterrupt(Timer);  // Attach the service routine here
  attachInterrupt(digitalPinToInterrupt(20), Timer, HIGH); // The interrupt conditions?
}
 
void loop()
{
  Serial.println("You done it!");  // Code success
    
  count = 0; // Resets the count

  delay(50000);
  digitalWrite(20, LOW);  // Sets interrupt pin to low to start void Timer() again
}
 
void Timer()
{
  if (count < 5 && digitalRead(13) == LOW)
  {
    digitalWrite(20, LOW);
    
    digitalWrite( 13, HIGH); // Visual representation of clock cycle
    delay(50000);
    digitalWrite(13, LOW);
    
    count = count + 1;
    Serial.println(count);
    delay(5000);
  }
  else (count >= 5);        // 
  {                         // When count is high enough, interrupt pin = HIGH 
    digitalWrite(20, HIGH); // therefore switch to main loop
  }
}

Within this code I have not figured out how to make it sleep between cycles, however is that possible when using the internal clock?

matthewd139:
First of all I was wondering if anyone knew how you would go about programming it to emit a signal once every minute.

Even opened the datasheet yet?

You can use alarm2 and set ALARM 2 REGISTER MASK BITS: A2M4, A2M3, A2M2 to 111. Don't forget to enable alarm to and to set the int/SQ pin to INT.

matthewd139:
How can I put the Arduino into sleep mode whilst it waits for a signal from the external clock?

Connect the alarm int to an external interrupt pin, set up the interrupt, config sleep and let it sleep.

matthewd139:
How can I program the external clock to send a signal once every minute?
See above

matthewd139:
How do I use the interrupt function to run the program?

Just read up upon how to use interrupts. The interrupt should be SHORT. So just let it wake the micro and set a flag and let it return to the loop. In the loop check for the flag. If set, do your thing and go back to sleep after that.

matthewd139:
Use the interrupt loop to keep a count of the number of signals received from clock

Simple count++ will do. If you want to use that variable somewhere else, don't forget to make it volatile.

matthewd139:
When the count reaches 15 (or any arbitrary number) switch to loop1() (this being the first code)

Do the checking in the loop(). And please don't call the function loop1().

matthewd139:
]Loop1 should run and then the count reset to 0, the interrupt will kick back in and keep count

Easy peasy

matthewd139:
When reaches 15 again then commence loop2()

Again, just look in the loop. And again, please don't call it loop2(). And simply have a variable to keep track which of the two functions you want to run

Pseudo code

volatile byte count = 0;

byte functionSelect = 0;

const byte Interval = 15;

void onInterrupt(){
  count++;
}

void loop(){
  if(count >= Interval){
    if(functionSelect){
      firstFunction();
    }
    else{
      secondFunction();
    }
   
    count = 0;
  }
  goBackToSleep();
}

septillion:
You can use alarm2 and set ALARM 2 REGISTER MASK BITS: A2M4, A2M3, A2M2 to 111. Don't forget to enable alarm to and to set the int/SQ pin to INT.

I did but I didn't realise it was called alarm (in hindsight pretty obvious). When you say "set ALARM 2 REGISTER MASK BITS" does that mean I will be able to set more than 1 alarm essentially? It would be nice to have it go off once every 5 or 15 mins.

septillion:
Just read up upon how to use interrupts. The interrupt should be SHORT. So just let it wake the micro and set a flag and let it return to the loop. In the loop check for the flag. If set, do your thing and go back to sleep after that.

So all my interrupt will do is keep the count, and then once it reaches 15 swap back to my function loops?

How does count++ increase the count? Or what is the ++ function called so I can read up on it?

septillion:
Do the checking in the loop(). And please don't call the function loop1().

So I will have my attachInterrupt's in this section and references to the other functions() in the main loop?

This has been really helpful by the way thanks :slight_smile:

matthewd139:
When you say "set ALARM 2 REGISTER MASK BITS" does that mean I will be able to set more than 1 alarm essentially?

Again, opened the datasheet? The device has 2 programmable alarms.

matthewd139:
It would be nice to have it go off once every 5 or 15 mins.

Although possible it's a bit different. The alarms have two modes.
a) Fixed pulse every x, for alarm1 that's once every second and for alarm 2 that's once every minute.
b) Match a certain time. So just like your alarm clock only here you can set what should match. Only seconds, seconds and minutes, seconds&minutes&hours, seconds&minutes&hours&day or seconds&minutes&hours&date. See page 13 of the datasheet.

So it's no possible to just set it up to pulse every 5 of 15 minutes. But what you can do is alter the alarm time (aka add 5 or 15 minutes) every time the alarm went off.

But both alarms share the same INT pin. To know which alarm went off check the flags A1F and A2F in status register 0x8F.

matthewd139:
So all my interrupt will do is keep the count, and then once it reaches 15 swap back to my function loops?

No, not swap back to your functions. The interrupt will wake the micro, increase the count and after that it return to the loop() (wherever it ended in the loop()). In the loop() you check if it's time to execute a function. If so, do so. After that/if not needed, just go to sleep.

matthewd139:
How does count++ increase the count? Or what is the ++ function called so I can read up on it?

It's a C operator. It's just shorthand for count += 1 which is shorthand for count = count + 1.

matthewd139:
So I will have my attachInterrupt's in this section and references to the other functions() in the main loop?

No, you attach the interupt in setup(), Once it's attached it's attached, no need to do that every loop.

All you do in the loop is to check if it's time to execute a function and if not, just go back to sleep.

Sorry I have, I meant can I set more than 2.

But from what you are saying, alarm 2 can pulse every minute? If this is the case that would be perfect, all I need to do is keep track of the pulse count during the interrupt and then at 15 start my other function.

septillion:
But both alarms share the same INT pin. To know which alarm went off check the flags A1F and A2F in status register 0x8F.

Forgive my basic knowledge as this is my first Arduino project, but what do you mean by check the flags?

So with regard to interrupt, it is just incrementing the count? Say I wanted to increment this count without the RTC but just by using the internal timer, how could I increment the count in this loop by 1 every 5 seconds?

For the attachInterrupt function, if I define the alarm to be pin 20 could I then write:

volatile byte count = 0;

byte functionSelect = 0;

volatile byte alarm = 20

const byte Interval = 5;



voidsetup()
{
   pinMode(20, INPUT);
   digitalWrite(20, LOW);
   
   attachInterrupt(alarm, onInterrupt, RISING);
}



void onInterrupt()
{
   count++;
}



void loop
{
   if (count >= Interval)
   {
       if (functionSelect == 0)
          {
              F_1()
          }
       else
          {
              count = 0;
          }
   else if (count >= Interval)
   {
       if (functionSelect == 1)
          {
              F_2()
          }
       else
          {
              count = 0;
          }
   else
   {
       //programs finished
       while(1){} //enters infinite loop
   }     
}



void F_1()
{
   // Runs program
   // Code ends with functionSelect = 1
}


void F_2()
{
   //runs program
   // Code ends with functionSelect = 2
}

I confused myself a bit while I was writing this, I am not sure how to correctly implement the attachInterrupt or how to change the state of pin 20 from low to high without putting that command in with a continuous loop. Unless the RTC provides the high input but even then I am not sure how I would go about doing this

matthewd139:
Sorry I have, I meant can I set more than 2.
But from what you are saying, alarm 2 can pulse every minute?

Like I said, open op the datasheet and start reading!

No, it has two and yes, alarm2 can go off each minute.

matthewd139:
If this is the case that would be perfect, all I need to do is keep track of the pulse count during the interrupt and then at 15 start my other function.

That's what I showed you in the pseudo code :wink:

matthewd139:
Forgive my basic knowledge as this is my first Arduino project, but what do you mean by check the flags?

Have you googled it? For short, when a alarm goes off the int line goes high (IF you set it so). In register 0x8F the corresponding bit the the alarm is set. Called A1F and A2F in the datasheet. So by reading that register and checking for a set bit, you can determine which alarm caused the interrupt pin to go high.

matthewd139:
So with regard to interrupt, it is just incrementing the count?

Yes, and waking the micro if you want it to sleep. But that's a bit of a more advanced feature...

matthewd139:
Say I wanted to increment this count without the RTC but just by using the internal timer, how could I increment the count in this loop by 1 every 5 seconds?

Pff, that's not as easy as with a RTC. But for testing you can fake it.

Small edit of my pseudo code. It now compiles but what it does isn't that much...

volatile byte count = 0;
byte functionSelect = true;

const byte Interval = 15;

void onInterrupt(){
  count++;
}

void setup(){
  Serial.begin(115200);
}

void loop(){
  Serial.print("Count is @ ");
  Serial.println(count);
  
  if(count >= Interval){
    if(functionSelect){
      firstFunction();
      functionSelect = false;
    }
    else{
      secondFunction();
      functionSelect = true;
    }
   
    count = 0;
  }
  //goBackToSleep(); //no sleep today
  
  //let's fake it kind off_type
  //I'll use delay just for testing!!!!
  //I will loop every second and I will call the fake interrupt every 5 x 1 second
  delay(1000);
  static byte minCounter = 0;
  minCounter++;
  if(minCounter >= 5){
    minCounter = 0;
    onInterrupt();
  }
}

void firstFunction(){
  Serial.println("FIRST function");
}

void secondFunction(){
  Serial.println("SECOND function");
}

And about your code, please pay attention to teh makeup. Press crtl + T and see the difference.

F_1() and F_2() are terrible function names. Just call them what you want them to do later on.

This

else
    {
      count = 0;
    }
    else if (count >= Interval)

Will give you an error. Why is the count rest in an else? Wasn't in my pseudo code...

volatile byte alarm = 20

Should not be volatile. const should be better. And why don't you use the name everywhere?

Ow, and you can't just random pick a pin. Read attachInterrupt() reference

But the attach should look a bit like (assuming a Mega?)

const byte AlarmPin = 20;

pinMode(AlarmPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(AlarmPin), onInterrupt, FALLING);
[/url]
alarm pin will go low when there is an alarm (again, read the datasheet). And it needs a pull up resistor so I enabled internal pull up.

Ok right you'll be glad to know I have read through the datasheet! And yes now I see what you are saying makes sense. Would you have any clue about programming the clock though? I have read various tutorials which look sort of helpful, but a lot of them have a lot of pointless code and don't make it obvious if they contain the alarm function.

This one talks a fair bit about alarms but it looks pretty dense.

The clock came today so I will try it out when im back in my lab on monday.

septillion:

volatile byte count = 0;

byte functionSelect = true;

const byte Interval = 15;

void onInterrupt(){
  count++;
}

void setup(){
  Serial.begin(115200);
}

void loop(){
  Serial.print("Count is @ ");
  Serial.println(count);
 
  if(count >= Interval){
    if(functionSelect){
      firstFunction();
      functionSelect = false;
    }
    else{
      secondFunction();
      functionSelect = true;
    }
 
    count = 0;
  }
  //goBackToSleep(); //no sleep today
 
  //let's fake it kind off_type
  //I'll use delay just for testing!!!!
  //I will loop every second and I will call the fake interrupt every 5 x 1 second
  delay(1000);
  static byte minCounter = 0;
  minCounter++;
  if(minCounter >= 5){
    minCounter = 0;
    onInterrupt();
  }
}

void firstFunction(){
  Serial.println("FIRST function");
}

void secondFunction(){
  Serial.println("SECOND function");
}




And about your code, please pay attention to teh makeup. Press crtl + T and see the difference.

With the addition of the clock and actual program functions, could this pseudo code now be adapted for what I want to?

Do you mean crtl + T in the Arduino sketch? If so I tried it and it didn't do anything.

You wrote a section of code:

if(count >= Interval){
if(functionSelect){
firstFunction();
functionSelect = false;
}
else{
secondFunction();
functionSelect = true;
}

So this essentially flicks between logic 1 and 0, but how would it look if you wanted to add 3 or more functions in?

septillion:
F_1() and F_2() are terrible function names. Just call them what you want them to do later on.

Ha yeah sorry I was being really unimaginative, don't worry I'll give my functions badass name :wink:

For the clock interrupt, would a 4.7K or 10K pull up resistor be better?

I'm a bit confused knowing when I should define something as a volatile, const or int

matthewd139:
Would you have any clue about programming the clock though?

Yes, it uses SPI. You can use the hardware SPI of the Arduino. On pins 10, 11, 12 and 13 of the Uno. Arduino talks about SS (slave Select) and the datasheet talks about CS (Chip Select) but that's the same. To use it you make a SPISettings ojbject. The DS3234 goes up to 4Mhz but I think 1Mhz is just fine here (less change of interference). The mode bit on the Arduino site is a bit weird but most use mode0. So an oject of SPISettings(1000000, MSBFIRST, SPI_MODE0) should be fine.

To start talking you pull the SS line low and you send out the address you want to read or write. As you can see in figure 1 of the datasheet every register has two adresses, one for reading and one for writing. For example, to read the current second you first send out the byte 0x00 and if you wan tot write to that same register you write 0x80. Every write register is just 0x80 higher.

And after that, if you want to write you just send out the byte you want to write. If you send out 2 bytes (after the address) the second will automatically be stored in the next register. While writing, the data the Arduino receives is nothing.

Example to read seconds and minutes and to write the month

SPISettings DsSpi = SPISettings(14000000, MSBFIRST, SPI_MODE0);

void setup(){
  //setup SPI
  SPI.begin();
}



void doRead(){
  //Start SPI with correct settings and select the chip
  SPI.beginTransaction(DsSpi);
  digital(SS, LOW);
  
  //Select seconds register in read mode = 0x00
  SPI.transfer(0x00);
  
  //read seconds and minutes after that
  //What to write does not matter
  byte seconds = SPI.transfer(0);
  byte minutes = SPI.transfer(0);
  
  //deselect chip and stop further SPI
  digitalWrite(SS, HIGH);
  SPI.endTransaction();
}

void doWrite(){
  byte date = 0x10; //the 10th, watch the weird format! 10 is not the same as 0x10
  
  //Start SPI with correct settings and select the chip
  SPI.beginTransaction(DsSpi);
  digital(SS, LOW);
  
  //Select seconds register in read mode = 0x84
  SPI.transfer(0x84);
  
  //now write the value we want
  SPI.transfer(date);
  
  //deselect chip and stop further SPI
  digitalWrite(SS, HIGH);
  SPI.endTransaction();
}

But remember, once you set it up there is no need to change it as long as the battery is in the DS. But the most complex part will be the setup of the device. Suggestion, make a serial monitor interface for it. See serial basics for that.

matthewd139:
With the addition of the clock and actual program functions, could this pseudo code now be adapted for what I want to?

The first code will, the last code has a replacement for the DS and that part you don't need. But in the code I have put nothing to acually setup the DS. It purely relies on it being set up and running giving a pulse every minute. Like I said, making code so you can set it up via serial or something else is harder then the part to do something every x minutes :stuck_out_tongue:

matthewd139:
Do you mean crtl + T in the Arduino sketch? If so I tried it and it didn't do anything.

The key combo Ctrl + T. On a Mac it might be cmd/apple + T because mac likes to be different...

matthewd139:
So this essentially flicks between logic 1 and 0, but how would it look if you wanted to add 3 or more functions in?

Uhm, just add more. BUT, only do that when those functions are really really different. But I have no idea what you want to do. But let's say for example you want to blink led[0] as first function, led[1] for the second and led[2] as third this would of course make more sens:

void loop(){
  if(count >= Interval){
    blink(select);
    
    select++;
    if(select >= 3){ //we only have 3 leds here)
      select = 0; //back to the first
    }
   
    count = 0;
  }
}

void blink(byte x){
  digitalWrite(led[x], HIGH);
  delay(500);
  digitalWrite(led[x], LOW);
}

matthewd139:
For the clock interrupt, would a 4.7K or 10K pull up resistor be better?

I expect the internal pull up to be just fine. And if you bought a DS3234 module (not a single IC) changes are the Pull up is already on the board.

matthewd139:
I'm a bit confused knowing when I should define something as a volatile, const or int

const => never changing while the program runs. But you are free to change it before uploading
volatile => when a variable is shared between a interrupt routine and other function/parts of the code

And int is just a type of variable. You have a couple, have a look here. int is a 16-bit time and if you don't put "unsigned" in front it's signed aka can be negative, so it can hold a value between -32768 and 32767. It's always wise to pick the smallest sufficient type. So because all pin numbers are less then 255 a variable of type byte (8-bit) will do fine.

Just a bit of background about what I am doing and hoping to achieve (this is a bit long so read it if your interested). This is for my masters thesis, I have an experimental setup where a structure is attached to a tank which allows water to flow past it. I am using strain gauges (at least 12 but aiming for 24) to measure the vibrations in the body and legs. The signals are amplified and fed into an Arduino Mega. This only has 16 analog inputs and I want to keep as many free as possible to save on processing time. My plan is to link two Megas together, both with 12 inputs. This way I could run 10 inputs on each fairly comfortable with the potential option of 24.

The devices will be near enough identical. The Arduino has a couple of functions

  • Controls the speed of the water pump
  • Uses the clock to wait while the flow develops between speeds
  • Logs the readings to an SD card for a certain amount of time
  • Repeat to collect a complete set of data for a period of around 5 hours or so

Initially I thought about using an I2C bus to connect to two Megas but I designed the amplification circuit and have the means PCB's. So my plan is to still have a master device with a slightly different code, and this will contain the clock. Everything is going to fit into a 3D printed box, so if I create a connection which plugs into both boxes to link the Ardunios to the SPI connection of the clock I can still use the interrupt without the need for two clocks. They will write to separate SD cards.

septillion:
And after that, if you want to write you just send out the byte you want to write. If you send out 2 bytes (after the address) the second will automatically be stored in the next register. While writing, the data the Arduino receives is nothing.

How do I specify how many bytes I want to write? As in select the relevant data to read/write

That code was just for the initial setup of the clock? Just a thought, what if I didnt use a battery and ran that setup every time. I am only interested in the pulse every minute so it doesn't matter if the register starts from 0 every time? I bought some batteries if not.

How would I setup a separate serial monitor? I can't find anything about it.

When programming the DS would I just use the void doWrite to setup the alarm and then SPI.transfer(0xalarm) in the interrupt to increment the count?

The programs will be pretty much identical, bar the clock setup in the master. Whilst writing this response I realise that theres a way to simplify what I want to do. The only difference in the functions was going to be the title of the text file they wrote to the SD card.

//Variables
volatile byte count = 0;
byte cycle = 0;

const C1 = 0;
const C2 = 15;
const C3 = 20;
const C4 = 25;
const C5 = 30;

//Setup

//Clock setup

//Interupt

void loop() {

  count = 0;

  if (cycle == 0 && count == C1) {
    // pumpSpeed = 5%
  }
  else if (cycle == 0 && count >= C2) {
    // Write to SD
  }
  else if (cycle == 0 && count >= C3) {
    // stop writing to SD card and wait
    // What would be a good way to tell it to stop writing till SD till count = 25?
  }
  else if (cycle == 0 && count >= C4) {
    // Write to SD
  }
  else if (cycle == 0 && count == C5) {
    // cycle++;
    // count = 0;
  }
  else if (cycle == 1 && count == C1) {
    // pumpSpeed = 10%
  }
  else if(cycle == 1 && count == C2) {
    // repeats through to cycle 20
  }
  ...
  else if (cycle == 20) {
    Serial.print("Test finished");
    while (1) {} // Enters infinite while loop to stop program
  }
}

I was wondering if there would be a way to increment the pump speed using a for loop or something? So as to avoid the repetitiveness of the else if functions. Also when I stop the SD card in the middle, would I use a while loop?

I have a windows laptop, just didn't see what crtl + T did at first

septillion:
I expect the internal pull up to be just fine. And if you bought a DS3234 module (not a single IC) changes are the Pull up is already on the board.

I guess its your turn to read the datasheet now :stuck_out_tongue: when using the SQW alarm pin, it needs a pull up resistor. Its cool though, thats a minor problem.

The variables make more sense now thanks

Thanks for the background info!

But why use two Arduino's? Each Arduino only had one ADC which is multiplexed. The program doesn't sound complicated at all so could run on one. And to be a bit more effective, why not add an external ADC? Is probably better then the internal one as well. And saving data to two separate SD-cards doesn't sound very convenient.

matthewd139:
How do I specify how many bytes I want to write?

That's up to you. Just call SPI.transfer() for each byte you want to read/write.

matthewd139:
As in select the relevant data to read/write

Just check the table in the datasheet to see which register contains what. Select the right address and select that to read/write from/to. The first byte you went out after you pull CS low is the start address of the transaction. So

//Start SPI with correct settings and select the chip
SPI.beginTransaction(DsSpi);
digital(SS, LOW);

//Select the first register we want to read, here address 0x00 which is the seconds register in read mode (seconds register in write mode is 0x80)
SPI.transfer(0x00);

byte seconds = SPI.transfer(0); // read register 0x00 aka seconds
byte minutes = SPI.transfer(0); //Next read will automatically read the next register, so 0x01 aka minutes.

//if you would now do another read it would read 0x02 aka hours etc
//while reading it doesn't matter what you send to the DS, here we just send 0 but the DS does not care.

matthewd139:
That code was just for the initial setup of the clock?

No, it was just an example how to interface with it. How to set it up depends on what you want.

matthewd139:
Just a thought, [...]

You could do that (it would not matter is the battery is in or out). But do you really want to just use the pulse? No timedate stamp in the log or something? Seems like a waste to me...

matthewd139:
How would I setup a separate serial monitor?

Serial monitor is part of the Arduino IDE. To send data to it, just read about Arduino serial basics.

matthewd139:
When programming the DS would I just use the void doWrite to setup the alarm and then SPI.transfer(0xalarm) in the interrupt to increment the count?

Huh, no. doWrite() is just a not very useful example how to interface with the DS. It's not very useful to always just write the 10th to the date register...

In the interrupt you do noting with the DS. The interrupt would just be called because of the pulse from the DS and all you do is update the counter on the Arduino. The DS knows nothing about the counter on the Arduino...

About the code:

const C1 = 0;
[/quote]
Does not work. Const of what? You need to define a type.

And the name Cx is terrible. Not only is it way more convenient to put similar variable into an array instead of calling the 1, 2, 3 etc, a variable name should tell what it does. Global variable names of less then +-4 characters are never explaining enough and are considered bad variable names.

[code]
count = 0;

Wasn't count suppose to count the number of interrupts? Then why set it to zero every loop?

while (1) {}

While you can end like this I would say, just let the loop() loop and just don't do anything. Or better, make it look for a button to start over or something.

matthewd139:
I was wondering if there would be a way to increment the pump speed using a for loop or something?

There is probably a why to vary the speed but then we have to know what kind of pump and how you're planning to connect it.

And a small rule of thumb. The loop() should just run freely so it can check if it need to act on something. For/while/do-loops should just be used to loop over something quick and then just continue with the flow of the program.

Btw, logging something every 15 minutes seems a bit slow for me...

matthewd139:
I guess its your turn to read the datasheet now :stuck_out_tongue:

Or for you to read the ATmega datasheet / Arduino reference pages :wink: I meant the internal pull up of the Arduino. Turned on with pinMode(pin, INPUT_PULLUP). Then you don't need a physical resistor.

septillion:
But why use two Arduino's? Each Arduino only had one ADC which is multiplexed. The program doesn't sound complicated at all so could run on one. And to be a bit more effective, why not add an external ADC? Is probably better then the internal one as well. And saving data to two separate SD-cards doesn't sound very convenient.

To optimise processing speed, besides which each Mega only has 16 analog inputs and I want 24. I looked into external chips and the possibility of using a Raspberry Pi but the Arduino is faster than the ADC chips (the ones I was looking at were mcp3008). Its not so bad, I just copy the final data to excel in one click and MATLAB processes the rest.

septillion:

//Start SPI with correct settings and select the chip

SPI.beginTransaction(DsSpi);
digital(SS, LOW);

//Select the first register we want to read, here address 0x00 which is the seconds register in read mode (seconds register in write mode is 0x80)
SPI.transfer(0x00);

byte seconds = SPI.transfer(0); // read register 0x00 aka seconds
byte minutes = SPI.transfer(0); //Next read will automatically read the next register, so 0x01 aka minutes.

//if you would now do another read it would read 0x02 aka hours etc
//while reading it doesn't matter what you send to the DS, here we just send 0 but the DS does not care.

So all I need is the top two statements and then byte seconds = SPI.transfer(0x00) and byte minures = SPI.transfer(0x01)?

septillion:
You could do that (it would not matter is the battery is in or out). But do you really want to just use the pulse? No timedate stamp in the log or something? Seems like a waste to me...

I see what your saying but my original intention was to use it so that the Arduino sleeps to save battery power as well as communicate between the two. If its able to time stamp between 1ms - 0.1ms then I could include it in my data as that would be useful but I think it only does seconds? Saying that a stamp every second or so could be a good reference point

Googling Arduino serial basics is pretty broad, I'm just not getting what you mean. Are you saying setup a separate serial line to transfer the clock data simultaneously? If so could you post a web link relating to what you mean?

septillion:
About the code:

const C1 = 0;

Does not work. Const of what? You need to define a type.

And the name Cx is terrible. Not only is it way more convenient to put similar variable into an array instead of calling the 1, 2, 3 etc, a variable name should tell what it does. Global variable names of less then +-4 characters are never explaining enough and are considered bad variable names.

[code]
count = 0;



Wasn't count suppose to count the number of interrupts? Then why set it to zero every loop?

My idea was that it would be easy for the user to change the program., and set their own time for running certain tests. C1 - 5 could be called testInterval1 - 5. What would you use instead of const? Once the program started it wouldn't change. const byte?

The count gets reset to 0 because it increments the "cycle" every time count = 30 using two condition statements in the else if loops.

How would you use the while function (or whatever) to say wait for serial monitor to say "start" and then repeat loop()?

I was going to go into the lab today but I'm working from home, will let you know tomorrow what pump I'm using. Can't tell from the pictures I have but someone on another feed I posted reckoned it was a "VFD (Variable Frequency Drive) controlling the motor speed".

https://1drv.ms/f/s!AhL5fVz5ZvJVmnBoIGdmYNZ-Aw4O

Would you just say to write lots of else if functions until the program is finished then? My device will be used for research over the next few years and will probably be modified at some point. I only thought of using a for loop to increment the pump speed to allow the user to easily change how fast the pump should go and the number of readings to be taken without scrolling through a couple hundred lines of code. Any suggestions?

The timings I've stated are similar to what I will use but not definite, but the initial wait allows the flow to reach full speed to prevent anomalies in the readings. The whole point of this though is so you can disappear for 6 or so hours and let it record data automatically.

septillion:
Or for you to read the ATmega datasheet / Arduino reference pages :wink: I meant the internal pull up of the Arduino. Turned on with pinMode(pin, INPUT_PULLUP). Then you don't need a physical resistor.

Oh I see, so do all the digital pins have pull up resistors on them?

matthewd139:
To optimise processing speed, besides which each Mega only has 16 analog inputs [...]

If you only want to take a log in the order of minutes (and that's what I get from the story) I doubt one Mega is to slow. :wink:

And yes, a Mega has 16 analog in but actually one ADC. And I don't know the speed of the Arduino ADC but it's not fast either... So I still think you're better off using a couple of external ADC's and one Arduino. Heck, I even think an Uno/Nano/Pro Mini can handle it with ease.

And why open it first in Excel? You can open the log in MATLAB directly...

matthewd139:
So all I need is the top two statements [..]

Uhm, the above two start a transaction between the DS and the Arduino. Then you send out the address you want to read/write (< 0x80 for read, >= 0x80 for write) and then you read/write as many register you like, starting at that register address you send out. So it depends on what you want. It's just an example of how to use the DS, not how to set it up for this task.

Don't forget to end the transaction as well! It's in my examples :wink:

matthewd139:
I see what your saying but my original intention was to use it so that the Arduino sleeps to save battery power

Does it really need to be battery powered? And I think if you use a pump on a batter the power consumption of the Arduino isn't really any concern. The pump will draw wayyy more power.

matthewd139:
If its able to time stamp between 1ms - 0.1ms then I could include it in my data as that would be useful but I think it only does seconds?

The DS indeed only does seconds but you can get more resolution by using the square wave out. But what has ms to do with it? You wanted to take measurements every 15 minutes... Stamping the minutes sound way more usefull then. So I think you really need to explain it into more detail.

matthewd139:
Googling Arduino serial basics is pretty broad, [..]

I'm saying, if you want to actually set the time of the DS you need a way to input it. Using the serial monitor to tell the Arduino to set the time sounds like the easiest solution. Using a DS without actually using the time seems like a wast to me.

matthewd139:
C1 - 5 could be called testInterval1 - 5.

Better already. But if you start numbering variables, use arrays instead :wink:

matthewd139:
What would you use instead of const?

I would use const, but const itself isn't a variable! It's just a keyword to tell the compiler the variable after it is constant. So you use it like
[code
const byte MyByte = 5; //here i specify a constant byte!
[/code]

matthewd139:
const byte?

The type of variable depends on the size of the value you want to put in. If you don't want anything bigger then 255 a byte is fine. If you need bigger you need to search for a better type :wink:

matthewd139:
The count gets reset to 0 because it increments the "cycle" every time count = 30 using two condition statements in the else if loops.

First of all, I never see you increment cycle, whatever the variable cycle may be (aka, bad name :wink: ) And second, if you reset count every time, how is it suppose to get bigger? Only way it can grow is if the interrupt (which increments it) is indeed called 15 (/20/25/30) times in ONE iteration of the loop() and that is not very likely...

matthewd139:
How would you use the while function (or whatever) to say wait for serial monitor to say "start" and then repeat loop()?

I would not. I would check if I need to run or not. And if i don't need to do anything I would just pass. Search about state machines.

void loop(){
  if(doINeedToDoAnyThing){
    doMyThing();
  }
}

matthewd139:
[..]it was a "VFD (Variable Frequency Drive) controlling the motor speed".

Still says nothing. You first have to figure out how to control it. So start by trying that. So without the RTC or any of the functions you would like, just start by making test skeches that actually control the speed of that thing. Once you know how to do that you can use it in a more complex program.

matthewd139:
Would you just say to write lots of else if functions until the program is finished then?

Programs are all about making decisions, yes... But I don't know what you mean specific. Maybe a hint, running the test/task you want it to do does NOT mean you run the loop() once. You let the loop() run and you do whatever you need to to when you need to do it.

matthewd139:
Any suggestions?

Use variables. Learn how to write code...

matthewd139:
Oh I see, so do all the digital pins have pull up resistors on them?

Googling things yourself does not hurt :wink:

Well now you say all this it makes sense, and I've learnt a lot of new things through this project. But I have all these parts and am running out of time so will leave the hardware as is for now.

Im only doing that as I showed my supervisor the data in excel, he then wrote a MATLAB code that extrapolates and plots all the data. I just have to press run and change the file name :stuck_out_tongue:

Sorry I've been tied up with other stuff for the past couple of days. Have some things to do and then will finally try and setup the DS so will let you know how it goes later today.

Im using a battery because of the pump, when its running and the arduino is plugged into the mains the data picks up a lot of electromagnetic noise (the faster it goes the more there is). So im isolating the power with a couple of lead acid batteries.

septillion:
The DS indeed only does seconds but you can get more resolution by using the square wave out. But what has ms to do with it? You wanted to take measurements every 15 minutes... Stamping the minutes sound way more usefull then. So I think you really need to explain it into more detail.
I'm saying, if you want to actually set the time of the DS you need a way to input it. Using the serial monitor to tell the Arduino to set the time sounds like the easiest solution. Using a DS without actually using the time seems like a wast to me.

So I want to take a set of readings every 15 mins. In these 5 minute periods I am taking a reading from each sensor every 0.1 ms so I end up with 10's of thousands of data every 5 mins. A stamp every 15 seconds would be useful tho as it will help give a reference. The reason 1 speed gets two sets of data is so that they can be compared and checked for anomalies in the results.

When specifying an array it would just be:
const byte testInterval[] = {5, 15, 20, 25, 30};

void loop(){
testInterval[0]
testInterval[1] ... etc??

septillion:
First of all, I never see you increment cycle, whatever the variable cycle may be (aka, bad name :wink: ) And second, if you reset count every time, how is it suppose to get bigger? Only way it can grow is if the interrupt (which increments it) is indeed called 15 (/20/25/30) times in ONE iteration of the loop() and that is not very likely...

In this case I think else if will suffice and the arrays will work perfectly. Question though, I want to set up 20 speeds of 5 interval functions. that makes 100 possible timings to run the test. Say I only want to run 10 without changing to much of the code (preferably only the timings) is there an else else if function or anything? And what could be a suitable condition to skip the function?

I'm looking into the pump, according to someone else its either controlled by a 4 - 20 mA current or 0 - 10V source. Hopefully will order a part for that today...

Its ok if not but this is the manual for the pump control if you know anything about how to control it
http://www.parker.com/Literature/SSD%20Drives/AC%20Drives/AC650/HA464828U003.pdf
https://1drv.ms/f/s!AhL5fVz5ZvJVmnBoIGdmYNZ-Aw4O

I wouldn't mind telling the loop to repeat itself, the only things it would need to do be able to do would be to increment the pump speed and to stop the test.

septillion:
Use variables. Learn how to write code...

Googling things yourself does not hurt :wink:

Fair enough, well for the record this has been really helpful so thanks man :stuck_out_tongue:

matthewd139:
Im only doing that as I showed my supervisor the data in excel, he then wrote a MATLAB code that extrapolates and plots all the data. I just have to press run and change the file name :stuck_out_tongue:

Lucky you! Wished my supervisors did that..

matthewd139:
Im using a battery because of the pump, when its running and the arduino is plugged into the mains the data picks up a lot of electromagnetic noise (the faster it goes the more there is). So im isolating the power with a couple of lead acid batteries.

Very much sounds like a hack / bodge. Just grab a (preferably switch mode) power supply and and decent filtering. Don't use breadboards and if you want to be real great, put it in a metal grounded box.

matthewd139:
So I want to take a set of readings every 15 mins. In these 5 minute periods I am taking a reading from each sensor every 0.1 ms

I totally lost what the difference is between your 15 min, 5 min or 0,1ms. Can you explain what you want to do when?

matthewd139:
When specifying an array it would just be:
const byte testInterval[] = {5, 15, 20, 25, 30};

That would indeed make a array. But why save all those if you just want to have something every 5 minutes between 0 and 30... Not that hard to check without a look up table.

matthewd139:
void loop(){
testInterval[0]
testInterval[1] ... etc??

Will do absolutely nothing... Yes, with testInterval[0] you call the array but it will only give you the value back (here 5) but you do nothing with it...

matthewd139:
In this case I think else if will suffice and the arrays will work perfectly.

Coding is basicly nothing more then if and else. But you really need to design a basic program or pseudo code or, maybe better, a flow diagram.

But FIRST, master each piece of the puzzle. So get the RTC set up, get it to fire interrupts, use them. Next, seperate sketch, play with writing to an SD card. And also seperate, control themotor. Only AFTER you mastered the individual pieces you can make a complete program.

matthewd139:
Question though, I want to set up 20 speeds of 5 interval functions. that makes 100 possible timings to run the test.

Don't see the problem? Setting the speed has nothing to do with the other intervals. So you just split the two. Alter then speed when and how is one process. Logging the data is another. Sampling might be another. And looking for user input might be another again. They might use each others data but have no hard link. You don't need to set the speed to be able to take a reading. You might want to have a certain speed when you take a reading but it's not impossible. The just check if the speed is set before you take the reading...

matthewd139:
I'm looking into the pump, according to someone else its either controlled by a 4 - 20 mA current or 0 - 10V source. Hopefully will order a part for that today...

You have to be sure... Might even check it with a supply etc.

And 0-10V is the easiest. Just grab an opamp, connect it to 12V, set the gain to two. And as an input you use a PWM pin via a RC-filter. Done.

Filter depends on the PWM speed and the kind of response time you need and what kind of ripple you can allow.

matthewd139:
I wouldn't mind telling the loop to repeat itself,

You don't tell the loop() to repeat itself, it will just do! And that's how it's suppose to be. Running you program once should NOT mean running the loop once.

I used filters in my amp circuit but wouldn't hurt to put them in with the power supply.

Ok so the process of obtaining data for 1 speed is:

  • Pump speed changes, Arduino does nothing for 15 mins to let the pump reach full speed and to allow the flow of water to develop
  • Arduino takes readings for 5 mins, over this 5 min period a reading from each sensor is logged to an SD card every 0.1ms
  • Arduino stops taking readings for 5 mins, this allows enough time to obtain a different set of readings to compare similarities or differences
  • Readings are taken again every 0.1 ms for 5mins
  • Repeat at different speed

Thats good though, I get what your saying about array's.

Ok fantastic, the op amp method sounds pretty cheap and easy. I think your right though, one thing at a time.

I have been trying to get the DS up and running, but as you can probably guess nothing seems to work first time round for me ...

First off, whats the difference between slave select (SS) and chip select (CS). Do I have to have it plugged into pin 53 on the Mega? Also the SQW pin is the interrupt pin for the alarm, therefor it should be connected to pin 20?

#include <SPI.h>

SPISettings DsSpi = SPISettings(14000000, MSBFIRST, SPI_MODE0);

void setup(){
  //setup SPI
  SPI.begin();
}

void doRead(){
  //Start SPI with correct settings and select the chip
  SPI.beginTransaction(DsSpi);
  digital(SS, LOW);
  
  //Select seconds register in read mode = 0x00
  SPI.transfer(0x00);
  
  //read seconds and minutes after that
  //What to write does not matter
  byte seconds = SPI.transfer(0);
  byte minutes = SPI.transfer(0);
  
  //deselect chip and stop further SPI
  digital(SS, HIGH);
  SPI.endTransaction();
}

void doWrite(){
  byte date = 0x10; //the 10th, watch the weird format! 10 is not the same as 0x10
  
  //Start SPI with correct settings and select the chip
  SPI.beginTransaction(DsSpi);
  digitalWrite(SS, LOW);
  
  //Select seconds register in read mode = 0x84
  SPI.transfer(0x84);
  
  //now write the value we want
  SPI.transfer(date);
  
  //deselect chip and stop further SPI
  digitalWrite(SS, HIGH);
  SPI.endTransaction();
}

I've been trying to adapt your code (admittedly it hasn't been modified but I've been reading up on it and the different registers).
Arduino sketch says theres an error in the the doRead() function, "digital(SS, HIGH);" where digital was not declared in the scope. Is this right or wrong?

Arduino: 1.6.8 (Windows 10), Board: "Arduino/Genuino Mega or Mega 2560, ATmega2560 (Mega 2560)"

C:\Users\matth\Documents\Arduino\sketch_jul13a\sketch_jul13a.ino: In function 'void doRead()':

sketch_jul13a:91: error: 'digital' was not declared in this scope

digital(SS, LOW);

Then I would say you have 4 states
a) set speed and wait 15 minutes, continue with b)
b) take readings for 5 minutes, if(first wait?) => c), else if(all speeds done?) => e), else => a)
c) Wait 5 minutes, => b)
e) We are done if(user input?) => start over?

Included the jumps between states. And the loop just executes what needs to be done when.

matthewd139:
First off, whats the difference between slave select (SS) and chip select (CS).

Quote from my reply #7
[/quote]

septillion:
Arduino talks about SS (slave Select) and the datasheet talks about CS (Chip Select) but that's the same.

So on a Mega CS/SS is indeed pin 53 but you are not limited to that pin. You can use others to be able t select more then one device.

matthewd139:
Also the SQW pin is the interrupt pin for the alarm, therefor it should be connected to pin 20?

Connect it to any of the Mega's external interrups. Choose one of 2, 3, 18, 19, 20 or 21.

matthewd139:
Arduino sketch says theres an error in the the doRead() function, "digital(SS, HIGH);" where digital was not declared in the scope. Is this right or wrong?

Yeah yeah, that's just a typo. Should not be to hard to understand what I wanted to say there... :wink:

Btw, the functions are just examples! Don't implement them. It's idiotic to have a function called doWrite(). Write what? Make in the base functions like

void DsWrite(byte register, byte &value, byte size)
//and
void DsRead(byte register, byte &value, byte size)

That do the simple task of reading and writing anything.

Then use those to make functions like

void dsSetupMinuteAlarm()
//or
void dsSetupTime(byte hour, byte minute, byte second)
//etc
[code]
Extend them with little baby steps.

Ok so I have spent the day reading and doing stuff with the clock.

#include <SPI.h>

//Read and write examples

//digitalWrite(10, LOW); // select the DS3234 that has its CS line on digital 10
//SPI.transfer(0x08); // tell the DS3234 device we're requesting data from the register at 08h
//data=SPI.transfer(0); // the DS3234 sends the data back and stores it in the byte data
//digitalWrite(10, HIGH);  // deselect the DS3234 if finished with it
//
//digitalWrite(10, LOW);
//SPI.transfer(0x80); // tells the device which address to write to
//SPI.transfer(b00001010);   // you can send any representation of a byte
//digitalWrite(10, HIGH);

const int  cs = 10; //chip select

void setup() {
  Serial.begin(9600);
  RTC_init();
  //day(1-31), month(1-12), year(0-99), hour(0-23), minute(0-59), second(0-59)
  SetTimeDate(00, 00, 00, 00, 00, 00);

  SPI.transfer(0x8E); // write to control register 8Eh (page 14 data sheet)
  SPI.transfer(0x60); // oscillator on, 1Hz, alarms off (b01100000) Do I need this???

  
// My input, I want to initiate the alarm

  digitalWrite(10, LOW);
  SPI.transfer(0x8B); // tells the device which address to write to
//  SPI.transfer(b00000110); // See page 14 of data sheet, this line does not work

  

SPI.transfer(0x0E); // tell the DS3234 device we're requesting data from the register at 08h
  data = SPI.transfer(0); // the DS3234 sends the data back and stores it in the byte data
  digitalWrite(10, HIGH); // the top two lines came with the code, not to sure about them??
  
  // Alarm 2: read minutes = 0x08 && write minutes = 0x8B, my input ends
 
}

void loop() {
  Serial.println(ReadTimeDate());
  delay(1000);
}
//=====================================
int RTC_init() {
  pinMode(cs, OUTPUT); // chip select
  // start the SPI library:
  SPI.begin();
  SPI.setBitOrder(MSBFIRST);
  SPI.setDataMode(SPI_MODE3); // both mode 1 & 3 should work HOWEVER USE MODE3
  //set control register
  digitalWrite(cs, LOW);
  SPI.transfer(0x8E); // function= control
  SPI.transfer(0x60); //60= disable Osciallator and Battery SQ wave @1hz, temp compensation, Alarms disabled
  digitalWrite(cs, HIGH);
  delay(10);
}
//=====================================
int SetTimeDate(int d, int mo, int y, int h, int mi, int s) {
  int TimeDate [7] = {s, mi, h, 0, d, mo, y};
  for (int i = 0; i <= 6; i++) {
    if (i == 3)
      i++;
    int b = TimeDate[i] / 10;
    int a = TimeDate[i] - b * 10;
    if (i == 2) {
      if (b == 2)
        b = B00000010;
      else if (b == 1)
        b = B00000001;
    }
    TimeDate[i] = a + (b << 4);

    digitalWrite(cs, LOW);
    SPI.transfer(i + 0x80);
    SPI.transfer(TimeDate[i]);
    digitalWrite(cs, HIGH);
  }
}
//=====================================
String ReadTimeDate() {
  String temp;
  int TimeDate [7]; //second,minute,hour,null,day,month,year
  for (int i = 0; i <= 6; i++) {
    if (i == 3)
      i++;
    digitalWrite(cs, LOW);
    SPI.transfer(i + 0x00);
    unsigned int n = SPI.transfer(0x00);
    digitalWrite(cs, HIGH);
    int a = n & B00001111;
    if (i == 2) {
      int b = (n & B00110000) >> 4; //24 hour mode
      if (b == B00000010)
        b = 20;
      else if (b == B00000001)
        b = 10;
      TimeDate[i] = a + b;
    }
    else if (i == 4) {
      int b = (n & B00110000) >> 4;
      TimeDate[i] = a + b * 10;
    }
    else if (i == 5) {
      int b = (n & B00010000) >> 4;
      TimeDate[i] = a + b * 10;
    }
    else if (i == 6) {
      int b = (n & B11110000) >> 4;
      TimeDate[i] = a + b * 10;
    }
    else {
      int b = (n & B01110000) >> 4;
      TimeDate[i] = a + b * 10;
    }
  }
  temp.concat(TimeDate[4]);
  temp.concat("/") ;
  temp.concat(TimeDate[5]);
  temp.concat("/") ;
  temp.concat(TimeDate[6]);
  temp.concat("     ") ;
  temp.concat(TimeDate[2]);
  temp.concat(":") ;
  temp.concat(TimeDate[1]);
  temp.concat(":") ;
  temp.concat(TimeDate[0]);
  return (temp);
}

Bar the bit of code I wrote at the top I sourced this from ds3234 | tronixstuff.com and it works, I am able to set the time in my DS chip but am struggling with the alarm. I understand what writing to the control register in bits means (e.g b00010110) but I do not know when to state it.

Would the alarm 2 interrupt just be stated in the void setup()? I have connected the DS SQW output to pin 20 on my Mega.

Oh wow didn't realise you'd posted on the second page of the forum :stuck_out_tongue:

septillion:
Yeah yeah, that's just a typo. Should not be to hard to understand what I wanted to say there... :wink:

Haha maybe so, but I tried writing digitalRead and it told me it was an error.

Theres a bit of unnecessary code in what I just posted but its a good basis to be modified.

I feel like I have a better understanding of what I am doing but am just a bit confused about how to implement what I want to do with this clock.

In the example code (where you have to watch the indentation!) I see SPI writes before you initiallize the SPI or set it to use the setting. So SPI.begin() and SPI.beginTransaction(). While it might work it's not how it's designed and can give you errors. So call SPI.begin() in setup and call SPI.beginTransaction() before each transaction and end with SPI.endTransaction().

And like I said, start with making smaller functions. Take smaller bits at a time. Smaller functions are easier to reuse and saves you coding :wink:

So make for example a dsWrite() and dsRead() function.

//functions to read or write a multiple bytes

//data is an array to write to, size is the number of registers to read into that buffer. 
//Be sure to NOT read more then the size of the arrray
void dsRead(byte reg, byte data[], byte size){
  //start transaction and select chip
  SPI.beginTransaction(DsSpi);
  digitalWrite(SS, LOW);
  
  //select register to read
  SPI.transfer(reg);
  
  //now read the register (doesn't matter what we write)
  for(byte i = 0; i < size; i++){
    data[i] = SPI.transfer(0);
  }
  
  //end transaction
  digitalWrite(SS, HIGH);
  SPI.endTransaction();
}

void dsWrite(byte reg, byte data[], byte size){
    //just so we can just use the low (<0x80) read register names for write as well
  if(reg < 0x80){
    reg += 0x80;
  }
  
  //start transaction and select chip
  SPI.beginTransaction(DsSpi);
  digitalWrite(SS, LOW);
  
  //select register to read
  SPI.transfer(reg);
  
  //now write the value
  for(byte i = 0; i < size; i++){
    SPI.transfer(data[i]);
  }
  
  //end transaction
  digitalWrite(SS, HIGH);
  SPI.endTransaction();
}

//Functions to read/write a single reg based on the multiple variant

byte dsRead(byte reg){
  byte out;
  dsRead(reg, &out, 1);
  
  return out;
}

void dsWrite(byte reg, byte val){
  dsWrite(reg, &val, 1);
}

To set alarm2 to trigger every minute you want to write to register alarm 2 minutes, alarm 2 hours and alarm 2 day and set A2M2, A2M3 and A2M4 to 1. The actual time/date don't matter.
So when we write
register 0x0B = 0x80 (which is 0b10000000, most left is A2M2 and it's set, rest we don't care)
register 0xB1 = 0x80
register 0xB2 = 0x80

This will set it up.

void setupDsAlarm2(){
  byte alarm2Settings = {0x80, 0x80, 0x80}
  dsWrite(0x0B, alarm2Settings, 3);
}

See how I use the previous functions?

NOTE, this is not all you need to setup but it shows how it's done.

The INT pin of the DS goes to one of the interrupt pins of the Arduino. You indeed set it up ONCE in the setup.

OK so I know its been a while but I got the clock up and running and mostly understand how it has happened. My challenge for now is setting up the if and else loops (say if this isn't the best way?) to carry out the program.

This is a simplified version of my code so far, I left the bits at the top in but its the main loop at the bottom which I am interested in.

p.s I know its messy, I tried to put it into different tabs but it wasn't having it.

#include <SD.h>
#include <SPI.h>
#include "ds3234.h"

#define BUFF_MAX 256

//====================== Define variables for DS3234 RTC ==========================//

const int days = 0;     //
const int months = 0;   // Sets the date on the RTC at start up
const int years = 0;    //

const int hours = 0;    //
const int minutes = 0;  // Sets the time on the RTC at start up
const int seconds = 0;  //

//=================== Define variables for interrupt function =====================//

volatile byte alarmIntPin = 18; // Define interrupt pin
volatile byte count = 0;  // Incremental count

//==================== Define variables usedwith the SD card ======================//

// Note the count will alwaysbe offset by 2 as this is when the program will properly begin
int testInterval [] = {1, 2, 3, 5, 6};  // Intervals between loop functions
char textFile [] = "five.txt"; //Defines the file name for the data
boolean tellTime = false;

int SD_cs = 53;  // SD card chip select pin

int BG1 = A1;       // Defines the body gauges
int BG2 = ...       //

          int LG1 = A5;     // Defines the leg gauges
int LG2 = ...     //

          const int supplyVoltage = 4.96;

int BG_V1 = ((supplyVoltage / 1024) * (analogRead(BG1) + 1.0)) * 1000;
int BG_V2 = ((supplyVoltage / 1024) * (analogRead(BG2) + 1.0)) * 1000;

//================= This sets up the alarm function in the RTC ====================//

void set_next_alarm(void) {
  insertRealFunctionHere
}

//===================== This writes to the RTC register ===========================//

void RTCRegisterWrite() {
  insertRealFunctionHere
}

//================ This writes to the RTC and resets the time =====================//

int SetTimeDate(int d, int mo, int y, int h, int mi, int s) {
  insertRealFunctionHere
}

//========================== Prepares the SD card =================================//

void InitiateSD() {
  insertRealFunctionHere
}

//================================ Initial setup ==================================//

void setup()
{
  Serial.begin(115200);
  InitiateSD();
  RTCRegisterWrite();                 // Run function
  SetTimeDate (days, months, years, hours, minutes, seconds);
  // The variables at the top specify clockstart point

  DS3234_init(DS_cs, DS3234_INTCN);   // Initiates alarm
  DS3234_clear_a2f(DS_cs);            // Clears previous data
  set_next_alarm();                   // Resets alarm
}

//================== The alarm triggers an interrupt function =====================//

void alarmInterrupt() {
  count++;
  digitalWrite(alarmIntPin, LOW);
}

//============================ The alarm loop function ============================//

void alarmLoop() {
  insertRealFunctionHere
} // This resests the alarm every minute

//======================= Seperates test data on SD card ==========================//

void testDataSeperation() {
  File testData = SD.open(textFile, FILE_WRITE); // Opens the text file to write data
  if (testData) {
    Serial.println("Data seperation begin");

    testData.println();
    testData.println();
    testData.println();       // I would  like thisfunction to happen once, without looping over and over
    testData.println();       // Its purpose is to create a gap between the data when the speed is changed
    testData.println();
    testData.println();
    testData.close();
    return;
  }
  else if (!testData) {
    Serial.print("Data not written at minute count = ");
    Serial.println(count);
    while (!Serial.available()) {} // Type any character into serial port to continue
  }
}

//========================= Writes test data to SD card ===========================//

void writeTestData() {
  Serial.println("Data write begin");   // I want away to make this happen once, then repeatedly print the data bellow

  File testData = SD.open(textFile, FILE_WRITE); // Opens the text file to write data
  if (testData) {
    testData.print("          "); // 10 space gap
    testData.print(abs(BG_V1));
    testData.print("     "); // 5 space gap
    testData.print(abs(BG_V2));
    testData.print("     ");
    testData.print(abs(BG_V3));
    testData.print("     ");
    testData.println(abs(BG_V4));  // Change Println to print
    //      testData.print("     ");
    //      testData.print(abs(LG_V1));
    //      testData.print("     ");
    //      testData.print(abs(LG_V2));
    //      testData.print("     ");
    //      testData.print(abs(LG_V3));
    //      testData.print("     ");
    //      testData.print(abs(LG_V4));
    //      testData.print("     ");
    //      testData.print(abs(LG_V5));
    //      testData.print("     ");
    //      testData.print(abs(LG_V6));
    //      testData.print("     ");
    //      testData.print(abs(LG_V7));
    //      testData.print("     ");
    //      testData.println(abs(LG_V8));
    testData.close();

    //      delayMicroseconds(150);  // Repeats program loop and writes data every 0.15 ms
    delay(500);

  }
}

//============================= Main program loop =================================//

void loop() {
  char buff[BUFF_MAX];
  struct ts t;

  DS3234_get(DS_cs, &t);
  alarmLoop();
  snprintf(buff, BUFF_MAX, "%02d:%02d:%02d", t.hour, t.min, t.sec);
  Serial.println(buff);
  delay (1000);

  //  testInterval [] = {1, 2, 3, 5, 6};

  if (count >= testInterval[0]) {
    testDataSeperation();
    delay(60000);           // I thought maybe if I can make it wait, it would go to the next bit but this causes it to mess up the clock
  }
  else if (count >= testInterval[1]) {
    writeTestData();
    DS3234_get(DS_cs, &t);
    alarmLoop();
  }

  //  Serial.println("Stop writing data");

  else if (count >= testInterval[2]) {
    snprintf(buff, BUFF_MAX, "%02d:%02d:%02d", t.hour, t.min, t.sec);
    Serial.println(buff);
    delay (1000);
  }

  // Bellow are some failed attempts of trying to implement the different functions
  
  //  Serial.println("End of data write");
  //
  //  if (count == testInterval[1]) {
  //    snprintf(buff, BUFF_MAX, "%02d:%02d:%02d", t.hour, t.min, t.sec);
  //    Serial.println(buff);
  //    delay (1000);
  //  }
  //  if (count >> testInterval[1]) {
  //    writeTestData();
  //    alarmLoop();
  //  }
  //  if (count == testInterval[2]) {
  //    Serial.println("Test finished");
  //    while (!Serial.available()) {}
  //  }
}

So basically I want to know if there is a way to carry a function out once without looping it. I know it appears IN the loop but by that I mean how could it carry out an if function repeatedly whilst only printing a message to Serial just the once?