Problem with decoding and logging dial gauge signals

Hello there,

I am more or less a beginner in programming the Arduino (made several really easy codes up until now).

First of all the code:

/*
 * Data Logger for digital dial gauges.
 * Up to 4 gauge signals can be connected and interpreted.
 */

#include <SPI.h>
#include "SdFat.h"

// SD chip select pin
const uint8_t chipSelect = 4;

// Log file base name
#define FILE_BASE_NAME "LOG"
//=======================================================
// File system object
SdFat sd;

// Log file
SdFile file;

// Time in millis for next data record
uint32_t logTime;
//======================================================
// User functions.
//------------------------------------------------------
int i;
int sign;
long value;
float result;
float result1;
int clockpin1 = 5;  
int datapin1 = 10;
int clockpin2 = 2;
int datapin2 = 3;
int clockpin3 = 6;
int datapin3 = 7;
int clockpin4 = 8;
int datapin4 = 9; 
unsigned long tempmicros;

const uint8_t GAUGE_COUNT = 5;
const uint8_t DATA_COUNT = 4;
float RESULTS[DATA_COUNT];

// Write data header
void writeHeader() {
  file.print(F("MICROS"));
  for (uint8_t i = 1; i < GAUGE_COUNT; i++) {
    file.print(F(",MESSUHR_"));
    file.print(i, DEC);
  }
  file.println();
}
//-----------------------------------------------------
//Funktion zum Decodieren der Messuhr-Signale
float decode(int x, int y) {
  sign=1;
  value=0;
  for (i=0;i<23;i++) {
    while (digitalRead(x)==HIGH) {} //wait until clock returns to HIGH- the first bit is not needed
    while (digitalRead(x)==LOW) {} //wait until clock returns to LOW
    if (digitalRead(y)==LOW) {
      if (i<20) {
        value|= 1<<i;
      }
      if (i==20) {
        sign=-1;
      }
    }
  }
  result=(value*sign)/100.00;    
  return result;
  delay(300);
}
//-----------------------------------------------------
// Log a data record
void logData() {
  uint16_t data[DATA_COUNT];
  
  for (uint8_t i = 0; i < DATA_COUNT; i++) {
    data[i] = RESULTS[i];
  }
  // Write data to file.  Start with log time in millis.
  file.print(logTime);

  // Write GAUGE data to CSV record
  for (uint8_t i = 0; i < DATA_COUNT; i++) {
    file.write(',');
    file.print(data[i]);
  }
  file.println();
}
//===================================================
// Error messages stored in flash.
#define error(msg) sd.errorHalt(F(msg))
//===================================================
void setup() {
//CLK und DATA-Pins für Messuhren belegen
  pinMode(clockpin1, INPUT_PULLUP);
  pinMode(datapin1, INPUT_PULLUP);
  /*pinMode(clockpin2, INPUT_PULLUP);
  pinMode(datapin2, INPUT_PULLUP);
  pinMode(clockpin3, INPUT_PULLUP);
  pinMode(datapin3, INPUT_PULLUP);
  pinMode(clockpin4, INPUT_PULLUP);
  pinMode(datapin4, INPUT_PULLUP);
*/
  
  const uint8_t BASE_NAME_SIZE = sizeof(FILE_BASE_NAME) - 1;
  char fileName[13] = FILE_BASE_NAME "00.csv";

  Serial.begin(9600);

  // Initialize at the highest speed supported by the board that is
  // not over 50 MHz. Try a lower speed if SPI errors occur.
  if (!sd.begin(chipSelect, SD_SCK_MHZ(4))) {
    sd.initErrorHalt();
  }
  
  // Find an unused file name.
 /* if (BASE_NAME_SIZE > 6) {
    error("FILE_BASE_NAME too long");
  }
  while (sd.exists(fileName)) {
    if (fileName[BASE_NAME_SIZE + 1] != '9') {
      fileName[BASE_NAME_SIZE + 1]++;
    } else if (fileName[BASE_NAME_SIZE] != '9') {
      fileName[BASE_NAME_SIZE + 1] = '0';
      fileName[BASE_NAME_SIZE]++;
    } else {
      error("Can't create file name");
    }
  }
  if (!file.open(fileName, O_CREAT | O_WRITE | O_EXCL)) {
    error("file.open");
  }

  // Write data header.
  writeHeader();*/
}

void loop() {
  //Prozedur zur Auswertung der Messuhrsignale (MESSUHR1)
  while (digitalRead(clockpin1)==HIGH) {} //if clock is LOW wait until it turns to HIGH
  tempmicros=micros();
  while (digitalRead(clockpin1)==LOW) {} //wait for the end of the HIGH pulse
  if ((micros()-tempmicros)>500) { //if the HIGH pulse was longer than 500 micros we are at the start of a new bit sequence
  result1 = decode(clockpin1,datapin1); //decode the bit sequence
  }
  logTime = millis();
  Serial.print(logTime);
  Serial.print("\t");
  Serial.println(result1,2);
  
  
  
  //logData();  
  

  // Force data to SD and update the directory entry to avoid data loss.
  //if (!file.sync() || file.getWriteError()) {
  //  error("write error");
  //}
}

As can be seen, I took a couple of snippest from the SDfat examples to build the code.

What I want to do is reading data from dial gauges, decoding the signals (which already works, code is also taken from another project) and writing the data to an SD Card.

My problem is that as soon as I uncomment these lines:

if (!sd.begin(chipSelect, SD_SCK_MHZ(4))) {
    sd.initErrorHalt();
  }

I am not able to get readings anymore. In the serial monitor I can still see printed values, but every value is 0.00.
If I comment these lines, the readings are correct.

So communication with the SD Card kind of destroys what I want to do and I have no idea why.

I am hoping that some of you might help me work the problem out.

Big thanks in advance.

Have a nice day.

Best regards,
Matthias

Maybe show a schematic diagram so it is clear what devices you have connected.

You have a large amount of blocking code e.g. :

while (digitalRead(clockpin1)==HIGH) {} //if clock is LOW wait until it turns to HIGH

Hey there,

the blocking code is for decoding the dial gauge signals. I do not want to touch that since it works as it should.

The only devices I have connected right now are:

  • one dial gauge --> connected to pins 5 and 10
  • a micro SD Card breakout board using ISP

Both devices work individually, so decoding the signal on its own works and writing data to the SD card on its own also works.

When trying to merge these two functions something goes wrong :frowning:

OK. But one part of the code can only block so much before it starts affecting other parts of the code.
What are these dial gauges and what is the frequency of the clock signal. Post a link if available. There is probably a much better way of reading them which is also compatible with the simultaneous use of the SD card.

Hey again and thanks for your quick response :slight_smile:

I followed this guide to get it working, hope it helps.

OK. I guess the device is more or less continuously sending a bitstream. However, you don't want to be continuously watching it.

Try restructuring your code so that at the frequency you want to log data, say every 1000mS, you execute the code to capture a measurement, that is start reading from the device, wait for the long pulse, then interpret the data, then stop reading the device. After that, log the result.

The code will still block, but the blocking is restricted to the length of time it takes to read a single measurement.

Use the "blink without delay" example sketch to see how to perform a non-blocking cycle, in this example case, of 1000 mS.

Thanks again, I will look into it to find a more appropriate way to read the data.

I think I found a hint to the solution of the problem.
Looking at the Arduino Nano pinout I learned that PIN 10 is the designated SS Pin.

In my case I used PIN 4 and it still works but I think that PIN 10 is somehow software driven as the SPI Pin by default and therefore also tries to start a connection as soon as I enable the SPI protocol.

I connected my dial gauge to other pins (my PCB allows for a total of 4 dial gauges to be connected and read simultaneously) and voila, it works.

So is there a way to disable the SPI activities of PIN 10? Of course just in case this is really the problem here.

If pin 10 on the nano is anything like pin 10 on the Arduino, it must be configured as an output. This is not something that can be addressed in software, as it's a hardware part of the SPI bus implemented in the Atmegas. If the hardware SS pin is configured as an input, the SPI assumes "slave" mode, rendering the SPI.h library (which is master only) useless. Move your input to another pin and use pin 10 AS your SS for the SD card or something else.

Thanks for your advice. I guess I have to resolder a little bit then.

Have nice weekend :slight_smile:

Oh by the way:

is it possible to enable SPI, write to SD card, disable it again, then read data, enable SPI, ...... and so forth?

This way I could avoid resoldering the connection paths.

make89:
Oh by the way:

is it possible to enable SPI, write to SD card, disable it again, then read data, enable SPI, ...... and so forth?

This way I could avoid resoldering the connection paths.

It's possible to toggle pin 10 in code between input and output... so output when you want to use SPI in master mode and input when you want to read the pin state.

int datapin1 = 10; << change to one of 13, 14, 15, 16, 17, 18, 19 (A0 to A5)

to prevent the device from going into SPI slave mode and acting hung.

All those pin assignments can be byte vs int, save the SRAM for when it’s needed.