Assistance correcting code please

Hello all. I have the following code. For the frequency counter part - it works fine on its own. For the Datalogger/Thermistor part - works pretty good on its own. Put the two together....all of a sudden everything works great except for the frequency reading. Any coders know where I've gone wrong?

#include <math.h>
#include <SD.h>
#include "Wire.h"
#include "RTClib.h"
#include <FreqCounter.h>
//---------------------------
//---------------------------

// A simple data logger for the Arduino analog pins
#define LOG_INTERVAL  1000 // mills between entries
#define ECHO_TO_SERIAL   1 // echo data to serial port
#define DS1307_I2C_ADDRESS 0x68  // This is the I2C address

const int chipSelect = 10;
RTC_DS1307 RTC;

// the logging file
File datafile;
 byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
 
//--------------
//--------------

void setup(void) {
  Serial.begin(9600);
  Serial.println();
 Wire.begin();  
// initialize the SD card
  Serial.print("Initializing SD card...");
  pinMode(10, OUTPUT);
  
// see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
// don't do anything more:
    return;
  }
  Serial.println("card initialized.");  
 
}
//-----------------------------------
//-----------------------------------

//Reference Voltage
long readVcc() {
  long result;
  // Read 1.1V reference against AVcc
  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  delay(2); // Wait for Vref to settle
  ADCSRA |= _BV(ADSC); // Convert
  while (bit_is_set(ADCSRA,ADSC));
  result = ADCL;
  result |= ADCH<<8;
  result = 1125300L / result; // Back-calculate AVcc in mV
  return result;
}
String printDouble( double val, unsigned int precision){
// prints val with number of decimal places determine by precision
// example: printDouble( 3.1415, 100); // prints 3.14 (two decimal places)

    String retval;
    retval += String(int(val));
    retval += ".";
    unsigned int frac;
    if(val >= 0)
	  frac = (val - int(val)) * precision;
    else
	  frac = (int(val)- val ) * precision;
    retval += frac;
    return retval;
}

//--------------------
//--------------------

float pad = 2267;                       // balance/pad resistor value
float thermr = 2001;                   // thermistor nominal resistance
 
double Thermister(int RawADC) {
  delay(100);
  long Resistance;  
  float Temp;  // Dual-Purpose variable to save space.
 
  Resistance=((1024 * pad / RawADC) - pad); 
  Temp = log(Resistance); // Saving the Log(resistance) so not to calculate  it 4 times later
  Temp = 1 / (0.00032939375 + (0.00044329916 * Temp) + (-0.00000077648923 * Temp * Temp * Temp));
  Temp = Temp - 273.15;  // Convert Kelvin to Celsius                      
  double Vcc=readVcc()/1000.0;
  
  #if ECHO_TO_SERIAL
  Serial.print("ADC: "); 
  Serial.print(RawADC); 
  Serial.println("/1024");                           // Print out RAW ADC Number
  Serial.println(" Kohms");
  Serial.print("Volts: "); 
  Serial.println(((RawADC*Vcc)/1024.0),3);   
  Serial.print("Resistance: "); 
  Serial.print(Resistance);
  Serial.println(" ohms ");
 #endif
 
  return Temp;                                     
}
//-----------------------------------------
//-----------------------------------------
void printTherm(void) {
  double therm = Thermister(analogRead(0));  // Read sensor
   
 #if ECHO_TO_SERIAL
  Serial.print("Therm Temperature is: ");
  Serial.print(therm,2);
  Serial.print((char)176);("Date, Time, Freq, ThermT");
  Serial.println("");
  #endif  //end ECHO_TO_SERIAL
}
//---------------------------------------------------------
//---------------------------------------------------------
void loop(void) {
  
  //detect frequency input from pressure transducer
  delay (50);
  long int frq;
  FreqCounter::f_comp = 8;
  FreqCounter::start(1000);
  while (FreqCounter::f_ready == 0)
  
  frq=FreqCounter::f_freq;
  delay(50);
 //-----------------------------------------------------
//------------------------------------------------------
 
  // make a string for assembling the data to log:
  String dataString = getDateDs1307();
  dataString += String(", ");
  dataString += String(frq);
  //String sensor2 = (frq,1);
  //dataString += sensor2;
  dataString += ", ";
  String sensor1 = printDouble (Thermister(analogRead(0)),100);
  dataString += sensor1;
  dataString += ", ";
  
  #if ECHO_TO_SERIAL
  printTherm();
  Serial.print("Frequency: ");
  Serial.println(frq);
 // printTemp();
  #endif
  
 File dataFile = SD.open("logger.csv", FILE_WRITE);
 
  if (dataFile) 
  {
    datafile.println(", , , ,");///just a blank line
    datafile.println("Date, Time, Freq, ThermT");
    datafile.close();
    dataFile.println(dataString);
    dataFile.close();
    // print to the serial port too:
    #if ECHO_TO_SERIAL
    Serial.println("\nDate, Time, Freq, ThermT");
    Serial.println(dataString);
    Serial.println("");
    #endif
  }  
  // if the file isn't open, pop up an error:
  else 
  {
    Serial.println("error opening test.csv");
  } 
  delay(20000);
}
//-----------------------------------------------------
//-----------------------------------------------------
void setDateDs1307()                
{
  // Use of (byte) type casting and ascii math to achieve result.  
  second = (byte) ((Serial.read() - 48) * 10 + (Serial.read() - 48)); 
  minute = (byte) ((Serial.read() - 48) *10 +  (Serial.read() - 48));
  hour  = (byte) ((Serial.read() - 48) *10 +  (Serial.read() - 48));
  dayOfWeek = (byte) (Serial.read() - 48);
  dayOfMonth = (byte) ((Serial.read() - 48) *10 +  (Serial.read() - 48));
  month = (byte) ((Serial.read() - 48) *10 +  (Serial.read() - 48));
  year= (byte) ((Serial.read() - 48) *10 +  (Serial.read() - 48));
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.write(byte(0x00));
  Wire.write(decToBcd(second));  // 0 to bit 7 starts the clock
  Wire.write(decToBcd(minute));
  Wire.write(decToBcd(hour));    // If you want 12 hour am/pm you need to set
  // bit 6 (also need to change readDateDs1307)
  Wire.write(decToBcd(dayOfWeek));
  Wire.write(decToBcd(dayOfMonth));
  Wire.write(decToBcd(month));
  Wire.write(decToBcd(year));
  Wire.endTransmission();
}

String getDateDs1307()
{
  // Reset the register pointer
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.write(0x00);
  Wire.endTransmission();

  Wire.requestFrom(DS1307_I2C_ADDRESS, 7);

  // A few of these need masks because certain bits are control bits
  second     = bcdToDec(Wire.read() & 0x7F);
  minute     = bcdToDec(Wire.read());
  hour       = bcdToDec(Wire.read() & 0x3F);  
  dayOfWeek  = bcdToDec(Wire.read());
  dayOfMonth = bcdToDec(Wire.read());
  month      = bcdToDec(Wire.read());
  year       = bcdToDec(Wire.read());
  
  String dataString = "";
  
  dataString += Print2Digit(dayOfMonth); 
  dataString += String("/");
  dataString += Print2Digit(bcdToDec(month)); 
  dataString += String("/"); // Y2k1 bug!
  dataString += Print2Digit(bcdToDec(year));
  dataString += String(", ");
  dataString += Print2Digit(hour);
  dataString += String(":");
  dataString += Print2Digit(minute);
  dataString += String(":");
  dataString += Print2Digit(second);

  return dataString;
}
//-------------------------------------------------
//-------------------------------------------------

// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val)
{
  return ( (val/16*10) + (val%16) );
}
// Convert normal decimal numbers to binary coded decimal
byte decToBcd(byte val)
{
  return ( (val/10*16) + (val%10) );
}

String Print2Digit(byte Val)
{
  String dataString = "";
  if (Val < 10)
  {
    dataString = "0";
  }  
  dataString += String(Val, DEC);
  return dataString;
}
  FreqCounter::start(1000);
  while (FreqCounter::f_ready == 0)
     frq=FreqCounter::f_freq;

Are you SURE you want to copy f_freq repeatedly while the frequency counter is not ready?

Perhaps you meant to write:

  FreqCounter::start(1000);
  while (FreqCounter::f_ready == 0)
    {/* DO NOTHING */}
  frq=FreqCounter::f_freq;

Perhaps you meant to write:

Code:
FreqCounter::start(1000);
while (FreqCounter::f_ready == 0)
{/* DO NOTHING */}
frq=FreqCounter::f_freq;

I hadn't realized that the space in between made the difference. Although, now that I have fixed that it seems to not have made any difference. My readings are jumpy and incorrect. Could it be a problem with noise? or a problem with the readings interfering with each other?

wwdd:

Perhaps you meant to write:

Code:
FreqCounter::start(1000);
while (FreqCounter::f_ready == 0)
{/* DO NOTHING */}
frq=FreqCounter::f_freq;

I hadn't realized that the space in between made the difference. Although, now that I have fixed that it seems to not have made any difference. My readings are jumpy and incorrect. Could it be a problem with noise? or a problem with the readings interfering with each other?

The space does not. What he wrote is equivalent to:

  FreqCounter::start(1000);
  while (FreqCounter::f_ready == 0); // the loop ENDS at the test, if true it loops again
  frq=FreqCounter::f_freq;

What you wrote is easier read as:

  FreqCounter::start(1000);
  while (FreqCounter::f_ready == 0)
  {
    frq=FreqCounter::f_freq;
  }

If you -always- put in the brackets -always- at the same indent level THEN
it will -always- be easier to check your code.

Try running the old frequency sketch just to see if the wiring has not changed.

Try running the old frequency sketch just to see if the wiring has not changed.

I ran the old sketch again and was getting the correct results. Unfortunately its when I combine the frequency sketch with the datalogger sketch that everything goes wrong with the frequency reading.

I'm thinking it might have something to do with timing. Or could it be that I am using the ARef pin on the arduino to help level shift my frequency circuit, and I am doing the following for the reference voltage reading:

long readVcc() {
  long result;
  // Read 1.1V reference against AVcc
  ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1);
  delay(2); // Wait for Vref to settle
  ADCSRA |= _BV(ADSC); // Convert
  while (bit_is_set(ADCSRA,ADSC));
  result = ADCL;
  result |= ADCH<<8;
  result = 1125300L / result; // Back-calculate AVcc in mV
  return result;
}

If it of any assistance attached is my circuit

I don't know, I don't have your hardware and don't want to dig through the libraries.

The wiring is okay and the parts are okay alone. If the frequency reader depends on interrupts and the Wire part also runs on interrupts then you might want to turn each one off while the other is running.

If the frequency reader depends on interrupts and the Wire part also runs on interrupts then you might want to turn each one off while the other is running.

I am unsure if I am able to do this as the Freq Counter part is coded in the .cpp file, which I am inexperienced to be able to decipher.

Can a .cpp file be created into its own function and then called in the main program void loop? Would that perhaps fix the problem?

Side Note: i got the FreqCounter library and sketch from: http://interface.khm.de/index.php/lab/experiments/arduino-frequency-counter-library/

There's a forum and author at that site. That would be the logical place to first ask about (it might have) or ask for an on/off function.

I'm the kind of guy who would try and raise the AC to pulsing DC and watch for a digital pin to cross LOW to HIGH.

There's a forum and author at that site. That would be the logical place to first ask about (it might have) or ask for an on/off function.

I have already emailed the author of the site, but have yet to receive a response. That was my first action.

I'm the kind of guy who would try and raise the AC to pulsing DC and watch for a digital pin to cross LOW to HIGH.

This way would never have occurred to me. Would this option still allow me to turn the result into a pressure reading?

It could get you frequency but no amplitude or wave shape. To use a rising edge interrupt you might have to use some extra electronics (beyond my know how).

What kind of frequencies are you looking at?

It could get you frequency but no amplitude or wave shape. To use a rising edge interrupt you might have to use some extra electronics (beyond my know how).

What kind of frequencies are you looking at?

Frequency is all I need. The frequency I am looking at is 36kHz-38kHz. I have a level shifter circuit hooked up to keep my wave above 0.

Is there an example of the sketch that you are thinking of that I could take a look at?

I had a look to see what I could crank out to test since I don't have a solid frequency source, but I do have 2 UNO's. The thing about UNO's is that the 328P oscillator is a resonator so solid is relative. So what should have generated and received 50k Hz tells me 46761 Hz. There is also some error in that micros() is only good to 4 usecs, but that's small.

An RTC (and more code) can help or after making sure the error is always the same (changes due to temperature I think), a correction in software, -or- someone spotting a fixable error in my routines.

Here's my reader sketch, pulse input is to pin 2. Note the turn on/off code is in there.
You could try this out with your pressure source just to see what you get.

byte inputPin = 2; // interrupt 0 on UNO
byte countFreq = 1;
volatile unsigned long count = 0UL;

unsigned long timeNow, timeStart;
unsigned long timeWait = 1000000UL; // 1 second in micros()

void countWaves()
{
  count++;
}

void setup()
{
  Serial.begin( 57600 );
  pinMode( inputPin, INPUT );
}

void loop()
{
  if ( countFreq )
  {
    countFreq = 0;
    count = 0UL;
    attachInterrupt( 0, countWaves, RISING ); // interrupt on pin 2
    timeStart = micros();
  }

  timeNow = micros();
  if ( timeNow - timeStart >= timeWait )
  {
    detachInterrupt( 0 );
    Serial.print( F( "freq = " ));
    Serial.println( count );
    countFreq = 1; 
  }
}

And here is my generator code:

byte outputPin = 8; 
unsigned long timeNow, timeStart;
unsigned long timeWait = 20UL; // 50k freq

void setup()
{
  pinMode( outputPin, OUTPUT );
}

void loop()
{
  timeNow = micros();
  if ( timeNow - timeStart >= timeWait )
  {
    digitalWrite( outputPin, HIGH );
    delayMicroseconds( 1 );
    digitalWrite( outputPin, LOW );
    timeStart = timeNow;
  }
}

Here's my reader sketch, pulse input is to pin 2. Note the turn on/off code is in there.
You could try this out with your pressure source just to see what you get.

@GoForSmoke
It seems to be giving me the same readings I was getting from the FreqCounter sketch. Your sketch is far easier for me to understand as well. My coding experience is very limited, so this has been a great help. Thank you.

I will next try and combine this with the datalogging sketch and see how it goes.

The problem is happening again when I merge the two codes together. It is always the frequency part that goes off. Must me some noise/interference . I will post again if I get this corrected after some googling.

The problem seems to exist when trying to use the frequency count variable in a calculation, like below, to get pressure.

Pressure = ACount^2 + BCount + C;

I will have to go back to figuring something out for the previous code I had. The one suggested is not proving to be reliable.

Have you made it so that when it finds frequency, that is -all- the sketch is doing?

This is a quadratic equation.

Pressure = ACount^2 + BCount + C;

You may be able to replace it with a table lookup or by interpolating between table values.

The sketch I gave, did you try to have it calculate pressure and print that in the printout part?

Do you see how countFreq turns the counting on and off? Put the other parts but not the time-check code (any time-check code) inside of

if ( countFreq == 0 )
{
   // here is where to check the other pin
}

You can have countFreq be more than just 0 or 1 and use that value to determine what code should run on any pass through loop(). But remember, loop() +must+ be fast or the time check and frequency count will be off.

  • With table lookup and using integer math you can greatly speed your calculating up.
  • The table would be kept in flash memory. With small code the table can be pretty big.

You see there are ways and there are ways. I learned to code when we could only dream of the speed of Arduino and had no FPU. Where I worked we had equivalent to 1 MHz AVR but more RAM (32k to 64k) and 360k floppy drives to run business on. But I was good with math before then and learned tricks to make it faster than human which for my needs was all that counted.
You, OTOH, need to keep up with signal frequency. You can do it but need to not do the other parts at the same time. If you have errors then, they can be tracked down and fixed as long as the principle formula does work.