4 independent counters on SDcard

Hello,

This is my first post so I hope it's the right place and I'm not bothering.

I am working on a project for my University.

I am reading temperatures and I try to count pulses generated by water-meters. I have a loop for writing the temperatures in a txt file on SD Card, time-synced via an RTC. Temperatures are on the same line, separated by commas but I also want to write the number of interrupts.

The problem : if an interrupt is happening in less than a second (on which my loop is set), I miss the count. How can I count the interrupts separately and just write the no. of counts at each loop(each second)?

I want to count interrupts for each water meter in order to show the number of counts at each loop.

LE: the thing is that I might have high frequency interrupts (1 impulse per 50 milliseconds). And I want this to be counted and see how many were counted between loops.

//Arduino UNO
#include <SD.h>
#include <SPI.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <DS3231.h>

// Firul de date este atribuit pinului 2
#define ONE_WIRE_BUS 2

//setează o singură instanță de comunicare cu orice OneWire
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

// Addresses of 5 DS18B20s
uint8_t sensor1[8] = { 0x28, 0x60, 0xCF, 0x79, 0xA2, 0x01, 0x03, 0x34 };
uint8_t sensor2[8] = { 0x28, 0xEC, 0x87, 0x79, 0xA2, 0x01, 0x03, 0x74 };
uint8_t sensor3[8] = { 0x28, 0x41, 0xA6, 0x79, 0xA2, 0x01, 0x03, 0x57 };
uint8_t sensor4[8] = { 0x28, 0xD1, 0x6C, 0x79, 0xA2, 0x01, 0x03, 0x79 };
uint8_t sensor5[8] = { 0x28, 0x9D, 0x3E, 0x79, 0xA2, 0x01, 0x03, 0x67 };
// Variables will change:
int buttonPushCounter = 0;   // counter for the number of button presses
int buttonState = 0;         // current state of the button
int lastButtonState = 0;     // previous state of the button

const int buttonPin = 9; //pentru impulsuri - firul galben de la IWMPL3

File myFile;
DS3231  rtc(SDA, SCL);
int pinCS = 10; // Pin 10 on Arduino Uno
void setup() {

  Serial.begin(9600);
  pinMode(pinCS, OUTPUT);
  pinMode(buttonPin, INPUT_PULLUP);

  // SD Card Initialization
  if (SD.begin())
  {
    Serial.println("Card SD initializat.");
  } else
  {
    Serial.println("Initialiuzare card SD esuata!");
    return;
  }
  sensors.begin();
  rtc.begin();
}
void loop(void)
{
  if (SD.begin())
    lastButtonState = buttonState;
  // read the pushbutton input pin:
  buttonState = digitalRead(buttonPin);
  // compare the buttonState to its previous state
  if (buttonState != lastButtonState) {
    // if the state has changed, increment the counter
    if (buttonState == LOW) {
      // if the current state is HIGH then the button went from off to on:
      buttonPushCounter++;
    }
    // if the file didn't open, print an error:
    else {
      Serial.println("error opening test.txt");
    }
  }
  sensors.requestTemperatures();
  myFile = SD.open("test.txt", FILE_WRITE);
  if (myFile) {
    sensors.requestTemperatures();
    myFile.print(rtc.getDateStr());
    myFile.print(",");
    myFile.print(rtc.getTimeStr());
    myFile.print(",");
    //myFile.print(" senzor exterior: ");
    printTemperature(sensor1);
    myFile.print(",");
    printTemperature(sensor2);
    myFile.print(",");
    printTemperature(sensor3);
    myFile.print(",");
    printTemperature(sensor4);
    myFile.print(",");
    printTemperature(sensor5);
    myFile.print(",");
    myFile.println(buttonPushCounter);
    myFile.close(); // close the file
  }
  delayMicroseconds (5000);
  // Delay a little bit to avoid bouncing
}
void printTemperature(DeviceAddress deviceAddress)
{
  float tempC = sensors.getTempC(deviceAddress);
  Serial.print(tempC);
  myFile.print(tempC);
  //  Serial.print("C  |  ");
  //  Serial.print(DallasTemperature::toFahrenheit(tempC));

}

WELCOME !! welcome to the forum.

great job in posting code to show what you have done.

one of the things this forum has is a special way to post code. called code tags.
it puts code into a box that makes it easier for us to view.

please read the sticky post at the top of every forum called how to use this forum and scroll down to #7.

to edit your first post,
on the bottom right of the post is more, modify.
the details in #7 should show what to do next.

as you can see, your code is not formatted with proper indents.
this should be fixed if you re-post your code in the box and erase what you have in your post.

if you want to format it, use the auto-format in the IDE.

dave-in-nj:
...

Thank you

I modified the format, hope it's the right one now.

if an interrupt is happening in less than a second (on which my loop is set), I miss the count.

But you are not using interrupts!

if (SD.begin())
    lastButtonState = buttonState;

These lines make no sense to me. Why would you initialise the sd card in loop() when you did that already in setup()? And even more strangely, why would you update lastButtonState only if the sd card initialised successfully?

Another strange piece of code:

  if (buttonState != lastButtonState) {
    // if the state has changed, increment the counter
    if (buttonState == LOW) {
      // if the current state is HIGH then the button went from off to on:
      buttonPushCounter++;
    }
    // if the file didn't open, print an error:
    else {
      Serial.println("error opening test.txt");
    }
  }

Why would you print that error simply because buttonState changed from low to high?

I think you got muddled up when you were making this code. I suggest you review it, line by line, and correct any further cut & paste errors.

PaulRB:
But you are not using interrupts!

if (SD.begin())

lastButtonState = buttonState;



These lines make no sense to me. Why would you initialise the sd card in loop() when you did that already in setup()? And even more strangely, why would you update lastButtonState only if the sd card initialised successfully?

Hello, thank you for replying

This is my first project, I started learning Arduino in August. I know much of the code doesn't make sense. I tried to initialize the SD card in order to avoid resetting the Arduino when I eject the card while the system works.

What I managed to accomplish so far is to write temperatures in a text file in order to use the data: date, time, temperature readings, and I also need the number of pulses generated by water meters (at least one but I need this for 4 water meters).

I tried to look at it as an button that is being pressed and it counts how many times does that. I get a counter but only when it syncs with the loop.

I am trying to figure out how can I count the number of pulses (or interrupts - I don't know exactly the difference) and write them on the SDcard right after temperature readings.

DATE, Time, T1, T2, T3, T4, T5, WaterMeter1, WaterMeter2, WaterMeter3, WaterMeter4

A new line each second.

This code is just a sketch and I cannot figure out how can I count the interrupts or pulses and write them like above.

OK, once you have corrected the crazyness in your code and re-posted it, we can suggest some ways to achieve what you need. There is no point us suggesting changes to your code if it already contains numerous cut & paste errors. If you cannot find and fix those errors, you are not going to be able to make the changes we could suggest, because our suggestions will make the code more complex.

This is the code that works for me so far. I get date, time, temperature readings in my text file.

//Arduino UNO
#include <SD.h>
#include <SPI.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <DS3231.h>

// Firul de date este atribuit pinului 2
#define ONE_WIRE_BUS 2

//setează o singură instanță de comunicare cu orice OneWire
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

// Addresses of 5 DS18B20s
uint8_t sensor1[8] = { 0x28, 0x60, 0xCF, 0x79, 0xA2, 0x01, 0x03, 0x34 };
uint8_t sensor2[8] = { 0x28, 0xEC, 0x87, 0x79, 0xA2, 0x01, 0x03, 0x74 };
uint8_t sensor3[8] = { 0x28, 0x41, 0xA6, 0x79, 0xA2, 0x01, 0x03, 0x57 };
uint8_t sensor4[8] = { 0x28, 0xD1, 0x6C, 0x79, 0xA2, 0x01, 0x03, 0x79 };
uint8_t sensor5[8] = { 0x28, 0x9D, 0x3E, 0x79, 0xA2, 0x01, 0x03, 0x67 };
// Variables will change:

const int buttonPin = 9; //pentru impulsuri - firul galben de la IWMPL3

File myFile;
DS3231  rtc(SDA, SCL);
int pinCS = 10; // Pin 10 on Arduino Uno
void setup() {

  Serial.begin(9600);
  pinMode(pinCS, OUTPUT);

}
void loop(void)
{

  // SD Card Initialization
  if (SD.begin())
  {
    Serial.println("Card SD initializat.");
  } else
  {
    Serial.println("Initialiuzare card SD esuata!");
    return;
  }
  sensors.begin();
  rtc.begin();
  sensors.requestTemperatures();
  myFile = SD.open("test.txt", FILE_WRITE);
  if (myFile) {
    sensors.requestTemperatures();
    myFile.print(rtc.getDateStr());
    myFile.print(",");
    myFile.print(rtc.getTimeStr());
    myFile.print(",");
    //myFile.print(" senzor exterior: ");
    printTemperature(sensor1);
    myFile.print(",");
    printTemperature(sensor2);
    myFile.print(",");
    printTemperature(sensor3);
    myFile.print(",");
    printTemperature(sensor4);
    myFile.print(",");
    printTemperature(sensor5);
    myFile.print(",");
    myFile.println(",");
    myFile.close(); // close the file
  }
  delayMicroseconds (5000);
  // Delay a little bit to avoid bouncing
}
void printTemperature(DeviceAddress deviceAddress)
{
  float tempC = sensors.getTempC(deviceAddress);
  Serial.print(tempC);
  myFile.print(tempC);
  //  Serial.print("C  |  ");
  //  Serial.print(DallasTemperature::toFahrenheit(tempC));

}

01.01.2000,00:19:30,21.94,22.94,-127.00,22.56,22.62,,
01.01.2000,00:19:31,21.94,22.94,-127.00,22.56,22.62,,
01.01.2000,00:19:31,21.94,22.94,-127.00,22.50,22.62,,
01.01.2000,00:19:31,21.94,22.94,-127.00,22.50,22.62,,
01.01.2000,00:19:31,21.94,22.94,-127.00,22.56,22.62,,
01.01.2000,00:19:32,21.94,22.94,-127.00,22.56,22.62,,
01.01.2000,00:19:32,22.00,23.00,-127.00,22.62,22.62,,
01.01.2000,00:19:32,22.00,23.00,-127.00,22.62,22.62,,
01.01.2000,00:19:32,21.94,22.94,-127.00,22.56,22.62,,

After the temperatures I want to add counters for each water meters. So far I found this topic : Counting pulses with interrupts - Programming Questions - Arduino Forum

For example, if the first water meter counts 3 pulses and the second counts 9, I want to write this information in my text file like this.

01.01.2000,00:19:32,21.94,22.94,-127.00,22.56,22.62, 3, 9
01.01.2000,00:19:33,21.94,22.94,-127.00,22.56,22.62, 5, 13

After one second, let's say I have 5 pulses and 13.
The pulses, depending on the waterflow, could be very fast (let's say 2 in 50 milliseconds) or slow. I cannot figure out a way to start on these kind of readings.
If one of the water meters is not counting, I want to keep the last count on each line

01.01.2000,00:19:32,21.94,22.94,-127.00,22.56,22.62, 3, 9
01.01.2000,00:19:33,21.94,22.94,-127.00,22.56,22.62, 5, 13
01.01.2000,00:19:34,21.94,22.94,-127.00,22.56,22.62, 5, 17
01.01.2000,00:19:35,21.94,22.94,-127.00,22.56,22.62, 5, 21

The problem is that I don't know how and where to start regarding pulse counting and write the count as above.

PaulRB:
But you are not using interrupts!

And it is most unlikely that you would need to use them, so do not get the impression that you should! :astonished:

That is a common "trap for young players". :grinning:

I know using ds18b20 and 1-wire can be slow, if not handled correctly. The required precision of the temp readings can make a big difference too. If you request readings but don't wait for the required amount of time, then readTempC() will wait, I think. So it's important to wait before requesting the readings, but it's important to monitor the pulses during that waiting time, and between reading each of the sensors, too.

How often do you need the record to the sd card?

Please post a link to the water meters. Debouncing may or may not be required, depending on their internal circuits.

  SD.begin()
  sensors.begin();
  rtc.begin();

These three lines belong in setup().

I tried to initialize the SD card in order to avoid resetting the Arduino when I eject the card while the system works.

Coding for a restart of the SD after pulling and reinserting a card us best done with the use of a push button. It's best to disable writing before pulling, and then re-enable writing and call SD.begin() with specifically designed code.

Calling SD.begin() every pass through loop is not the way to go. I would recommend that you leave this functionality out of the code until you have everything else working as it should.

There are a few people asking the same question in different ways the last few days.

Are you all in the same class?

I have a hunch that a few are asking and others are lurking

PaulRB:
How often do you need the record to the sd card?

Thanks for replying

I want 1 line of readings per minute. 5 temps and 4 counters. How can I store the counter between the lines?

cattledog:

  SD.begin()

sensors.begin();
 rtc.begin();



I would recommend that you leave this functionality out of the code until you have everything else working as it should.

Thank you for the suggestion, it makes sense!

How can I store the counter between the lines?

I would suggest an array to hold the counts. Also a constant array to hold the pin numbers for each water meter.

Because you need to monitor the water meters, you cannot use delay() to time writing each line to the sd card. Instead, use millis(). See the "blink without delay" example sketch to see how this can be done.

PaulRB:
I would suggest an array to hold the counts. Also a constant array to hold the pin numbers for each water meter.

Because you need to monitor the water meters, you cannot use delay() to time writing each line to the sd card. Instead, use millis(). See the "blink without delay" example sketch to see how this can be done.

I use industrial pulse modules on which the voltage of MOSFET collector can work up to 30 volts.

What if I imagine these pulse generators as simple buttons and count the pushing of a button (one pulse = 1 liter/revolution)?

Is there any way to keep the count inside a variable and print it on each line per minute? For example, if I have three water meters, just to imagine having 3 buttons and press them independently. I need 3 variables to store the number of presses.

What if I imagine these pulse generators as simple buttons and count the pushing of a button (one pulse = 1 liter/revolution)?

Yes, counting a state change on a button can model the state change of a sensor.

For example, if I have three water meters, just to imagine having 3 buttons and press them independently. I need 3 variables to store the number of presses.

It has been suggested that you can do this with an array.

For example, Instead of

unsigned int CountMeter1; 
unsigned int CountMeter2; 
unsigned int CountMeter3;

you could use an array

unsigned int CountMeter[3];

Arrays are zero indexed, and the the count values will be in CountMeter[0], CountMeter[1], CountMeter[2],

In the ide window under File>Examples>05Control there are two examples "Arrays" and "ForLoopIteration" which will be useful.

cattledog:

unsigned int CountMeter[3];

Arrays are zero indexed, and the the count values will be in CountMeter[0], CountMeter[1], CountMeter[2],
In the ide window under File>Examples>05Control there are two examples "Arrays" and "ForLoopIteration" which will be useful.

Can I use pinMode(button) with arrays?
I don't know exactly how to store the number of presses of buttons outside the loop.

int button=8;
int val;
int count=0;
int press; int Y;


void setup() {
  Serial.begin(9600);
  pinMode(button,INPUT_PULLUP);
}

void loop() {
   Serial.print("No of presses:");
 Serial.println(press);
  //delay(1000);
  val=digitalRead(button);
  if(val==HIGH){
    press=count++;
    delayMicroseconds(9000);
  }
}

This simple code is kinda what I am looking for.
The problems are:

  1. Is working only with one button
  2. It will increment values until I release (because of that small delay)
  3. It will not increment values if the delay is 1 minute and i press it for several seconds (and I will miss important countings).

Can I use pinMode(button) with arrays?

Yes. The "ForLoopIteration" example previously referenced does this. Did you take a look at it?

It will increment values until I release (because of that small delay)

You can not use any delays in a program to read the flow sensors. You need to go back and use the state change code that you attempted in your original post.

cattledog:
Yes. The "ForLoopIteration" example previously referenced does this.
[...]
You can not use any delays in a program to read the flow sensors. You need to go back and use the state change code that you attempted in your original post.

Thank you for replying. I am trying to adapt the ForLoopIteration for four buttons but I cannot figure it out.

The for loop iteration looks like this.

int timer = 100;           // The higher the number, the slower the timing.

void setup() {
  // use a for loop to initialize each pin as an output:
  for (int thisPin = 2; thisPin < 8; thisPin++) {
    pinMode(thisPin, OUTPUT);
  }
}

void loop() {
  // loop from the lowest pin to the highest:
  for (int thisPin = 2; thisPin < 8; thisPin++) {
    // turn the pin on:
    digitalWrite(thisPin, HIGH);
    delay(timer);
    // turn the pin off:
    digitalWrite(thisPin, LOW);
  }

  // loop from the highest pin to the lowest:
  for (int thisPin = 7; thisPin >= 2; thisPin--) {
    // turn the pin on:
    digitalWrite(thisPin, HIGH);
    delay(timer);
    // turn the pin off:
    digitalWrite(thisPin, LOW);
  }
}

But how can I add 4 counters for 4 buttons that can count the number of times one button has been pressed?

buttonCounter 1 = no. of times the first button has been pressed
buttonCounter 2 = no. of times the second button has been pressed
buttonCounter 3 = no. of times the third button has been pressed
buttonCounter 4 = no. of times the fourth button has been pressed

Can I add this inside the for loop, but for 4 buttons?

void loop()
{
  lastButtonState1 = buttonState1;
  lastButtonState2 = buttonState2;
  lastButtonState3 = buttonState3;
  lastButtonState4 = buttonState4;
  // read the pushbutton input pin:
  buttonState1 = digitalRead(buttonPin1);
  // compare the buttonState to its previous state
  if (buttonState1 != lastButtonState1) {
    // if the state has changed, increment the counter
    if (buttonState1 == LOW) {
      // if the current state is HIGH then the button went from off to on:
      buttonPushCounter1++;
    }
    // read the pushbutton input pin:
    buttonState2 = digitalRead(buttonPin2);
  }
  // compare the buttonState to its previous state
  if (buttonState2 != lastButtonState2) {
    // if the state has changed, increment the counter
    if (buttonState2 == LOW) {
      // if the current state is HIGH then the button went from off to on:
      buttonPushCounter2++;
    }
    // read the pushbutton input pin:
    buttonState1 = digitalRead(buttonPin3);
  }
  // compare the buttonState to its previous state
  if (buttonState3 != lastButtonState3) {
    // if the state has changed, increment the counter
    if (buttonState1 == LOW) {
      // if the current state is HIGH then the button went from off to on:
      buttonPushCounter3++;
    }
    // read the pushbutton input pin:
    buttonState4 = digitalRead(buttonPin4);
  }
  // compare the buttonState to its previous state
  if (buttonState4 != lastButtonState4) {
    // if the state has changed, increment the counter
    if (buttonState4 == LOW) {
      // if the current state is HIGH then the button went from off to on:
      buttonPushCounter4++;
    }
  }

Can I add this inside the for loop, but for 4 buttons?

Yes. That code is for 4 buttons! But it is also 4 times longer than it needs to be.