Serial communication between arduino uno and arduino SD Logger

I’m trying to simulate a clock using an arduino uno and send the time to an SD Logger which is periodically sleeping and therefore unable to time stamp correctly (as it is losing seconds).
The code on the uno looks like this:


#include <Time.h>
#include

#define rxPin 0
#define txPin 1

SoftwareSerial mySerial = SoftwareSerial (rxPin, txPin);

void setup(){
pinMode(rxPin, INPUT);
pinMode(txPin, OUTPUT);
mySerial.begin(9600);
setTime(0);
}

void loop(){
mySerial.print(hour());
mySerial.print(minute());
mySerial.print(second());
}


If I want the SDlogger to read the time and print it to a file which is already created earlier in the SDLoggers programme, how would I do it?
I’ve tried declaring a variable incomingByte and used file.print(incomingByte); but it gives random values instead of the time

You can’t (or at least shouldn’t) use software serial on the hardware serial pins. What’s the point, you already have a UART on those pins. Use two other pins.

void loop(){
mySerial.print(hour());
mySerial.print(minute());
mySerial.print(second());
}

This will send a constant stream of data that will fill your SD card with redundant data in no time.

I’ve tried declaring a variable incomingByte and used file.print(incomingByte); but it gives random values instead of the time

Means nothing to us, post your code.


Rob

Sorry, there’s supposed to be a delay of 250 millis in the void loop at the end, but even if there wasn’t the SD card won’t copy everything because it’s asleep, I only need the time to be readily available to it so it can copy it down and time stamp.

the code on the SD Logger is quite long, the sleeping bit is working fine so I’ll post the remaining piece, all I want it to do is to take the time from the serial and record it with the data in the file:

#include <Wire.h>
#include <Time.h>
#include <DS1307RTC.h>
#include <SdFat.h>
#include <SdFatUtil.h>
#include <SoftwareSerial.h>

#define SENSOR_COUNT     3 // number of analog pins to log
#define ECHO_TO_SERIAL   1 // echo data to serial port
#define SYNC_INTERVAL 1000 // mills between calls to sync()
uint32_t syncTime = 0;     // time of last sync()
Sd2Card card;
SdVolume volume;
SdFile root;
SdFile file;

SoftwareSerial mySerial(10, 11); //RX TX
byte incomingByte=0;

void setup() {

 mySerial.begin(9600);
 Serial.begin(9600);
 pinMode(10, INPUT);
 pinMode(11, OUTPUT);

  if (!card.init(SPI_HALF_SPEED)) error("card.init failed");
  
  if (!volume.init(&card)) error("volume.init failed");
  
  if (!root.openRoot(&volume)) error("openRoot failed");
  
  // create a new file
  char name[] = "LOGGER00.CSV";
  for (uint8_t i = 0; i < 100; i++) {
    name[6] = i/10 + '0';
    name[7] = i%10 + '0';
    if (file.open(&root, name, O_CREAT | O_EXCL | O_WRITE)) break;
  }
  if (!file.isOpen()) error ("file.create");
  Serial.print("Logging to: ");
  Serial.println(name);

  // write header
  file.print("Time");
#if ECHO_TO_SERIAL 
  Serial.print("Time");
#endif //ECHO_TO_SERIAL

#if SENSOR_COUNT > 6
#error SENSOR_COUNT too large
#endif //SENSOR_COUNT

  for (uint8_t i = 0; i < SENSOR_COUNT; i++) {
    file.print(",sens");file.print(i, DEC);    
#if ECHO_TO_SERIAL
    Serial.print(",sens");Serial.print(i, DEC);
#endif //ECHO_TO_SERIAL
  }
  file.println();  
#if ECHO_TO_SERIAL
  Serial.println();
#endif  //ECHO_TO_SERIAL

  if (file.writeError || !file.sync()) {
    error("write header failed");
  }
}

void loop() {
  
        if(mySerial.available() >0)
        {
          incomingByte = mySerial.read();
          incomingByte = (char) incomingByte;
        //Print time 
        Serial.println(incomingByte);
        file.println(incomingByte);
        delay(200);
        }
      
  // add sensor data 
    for (uint8_t ia = 0; ia < SENSOR_COUNT; ia++) {
    uint16_t data = analogRead(ia);
    file.print(',');    
    file.print(data);
#if ECHO_TO_SERIAL
    Serial.print(',');   
    Serial.print(data);
    delay(200);
#endif //ECHO_TO_SERIAL
  }
  file.println();  
#if ECHO_TO_SERIAL
  Serial.println();
#endif //ECHO_TO_SERIAL

  if (file.writeError) error("write data failed");
  
  if ((millis() - syncTime) <  SYNC_INTERVAL) return;
  syncTime = millis();
  if (!file.sync()) error("sync failed");
}
         incomingByte = (char) incomingByte;

This does nothing as far as I can tell.

You send 3 bytes but only read 1, that's a problem.

Also, do the time function return ASCII characters? I doubt it, so

       Serial.println(incomingByte);

Will send non-printable characters all of the time for hours and most of time for minutes and seconds. Use

Serial.println(incomingByte, DEC);

To see the exact values.


Rob

So should I have multiple variables to deal with the incoming bytes?

Such as:

incomingByte1 = mySerial.read();
incomingByte2 = mySerial.read();
incomingByte3 = mySerial.read();

Or is there another way?

is there another way?

Yes there is but that's as good as any really, however better names would be good

hours = mySerial.read();
minutes = mySerial.read();
seconds = mySerial.read();

Rob

Thanks this has been hugely helpful, one issue left I tested the program and tried sending times using Serial.print(hours,DEC); etc... but for an example time of 11:48:23 (no colons) I received these values instead:

49255255 49255255 52255255 56255255 50255255 51255255

obviously each value corresponds to a number and the first two digits in each value is the ASCII value for each number but what's the rest and how do I return it to the time and piece it together?

I'd have to look up an ASCII table but I'd say

49 = '1' 52 = '4' 56 = '8' 50 = '2' 51 = '3'

As for the 255s, that's -1 so I'd say you are printing before you get a valid character.

Show us the printing code.


Rob

The data printing won’t normally be inside the if statement, I’m entering the time manually from the computer and this is to slow down the scroll. And how would I change the ASCII characters back to the numbers they represent for printing?

if(Serial.available() >0)
        {
          hours = Serial.read();
          minutes=Serial.read();
          seconds=Serial.read();
        //Print time back
        Serial.print(hours,DEC);
        file.print(hours,DEC);
        Serial.print(minutes,DEC);
        file.print(minutes,DEC);
        Serial.print(seconds,DEC);
        file.print(seconds,DEC);
        delay(200);
        
      
  // add sensor data 
  for (uint8_t ia = 0; ia < SENSOR_COUNT; ia++) {
    uint16_t data = analogRead(ia);
    file.print(',');    
    file.print(data);
#if ECHO_TO_SERIAL
    Serial.print(',');   
    Serial.print(data);
    delay(200);
#endif //ECHO_TO_SERIAL
  }
  file.println();  
#if ECHO_TO_SERIAL
  Serial.println();
#endif //ECHO_TO_SERIAL
}
if(Serial.available() >0)
        {
          hours = Serial.read();
          minutes=Serial.read();
          seconds=Serial.read();

The second and third reads() get -1 because those two characters have not yet been received, the sender is still transmitting them. Try

if(Serial.available() >= 3)
        {
          hours = Serial.read();
          minutes=Serial.read();
          seconds=Serial.read();

I suspect the following prints of the data don't show because data is not a printable ASCII character, you should use the DEC option with them as well to verify that.

You should also add delimiters (say a comma) between all prints or you will never know what number are what.


Rob

That part of my code now looks like this:

if(Serial.available() >= 3)
        {
          hours = Serial.read();
          minutes=Serial.read();
          seconds=Serial.read();
        
        //Print time back
        Serial.print(hours,DEC);
        file.print(hours,DEC);
        Serial.print(":");
        file.print(":");
        Serial.print(minutes,DEC);
        file.print(minutes,DEC);
        Serial.print(":");
        file.print(":");
        Serial.print(seconds,DEC);
        file.print(seconds,DEC);
        delay(200);

But when i enter say 11 48 23 or 114823, I get:

49:49:52,258,393,381 56:50:51,275,392,379

(the other 3 numbers are accelerometer data)

You first example had

mySerial.print(hour());
mySerial.print(minute());
mySerial.print(second());

That’s 3 bytes in which case the code should work.

But when i enter say 11 48 23 or 114823

Are you now saying that you are entering 6 character via another means?

If so change the >= test to 6 and read into 6 variables (but that will mean other changes in the code to print them properly).


Rob

what it's receiving should be the hour minutes and seconds of the timer but they start at 0:0:0 and go up and eventually will each have two digits e.g. 11:48:23, I'm trying to test this by inputting the values manually through the serial monitor before I connect it to the uno

inputting the values manually through the serial monitor before I connect it to the uno

Which is totally different to sending three bytes from another Arduino.

eventually will each have two digits

However they will not do this when sending bytes form an Arduino.

For testing purposes just send single-digit times.

Note that in the real thing you will have to convert the bytes coming in to ASCII if you want the file to be easily readable.


Rob

Note that in the real thing you will have to convert the bytes coming in to ASCII if you want the file to be easily readable.

can I do that by casting or is there a different method?

Check out itoa()


Rob

I've looked through as much as I can find on itoa(), do you suggest I do something like:

          hours = mySerial.read();
          minutes = mySerial.read();
          seconds = mySerial.read();
itoa(hours,2,10);
itoa(minutes,2,10);
itoa(seconds,2,10);

If so what do I tell Serial to print? Also without any of this I'm receiving output like so:

145:154:145,228,362,356 156:148:154,278,360,356 134:133:145,283,362,356 154:145:152,285,361,356 148:154:135,286,361,357 133:145:154,286,360,356 145:152:148,287,362,355

As far as I can tell, it looks like the 3 bytes are being jumbled up and printed in random order. (This is with the uno giving the time, not me doing it manually anymore)

From an on-line C page

char *itoa(int value, char *string, int radix);
DESCRIPTION
The itoa() function constructs a string representation of an integer.
PARAMETERS
value
Is the integer to be converted to string representation.
string
Points to the buffer that is to hold resulting string. The resulting string may be as long as seventeen bytes.
radix
Is the base of the number; must be in the range 2 - 36.

You have

itoa(hours,2,10);

So 2 is a pointer to a string?

Try

char strHours[10];
...
itoa(hours, strHours, 10);
...
Serial.print (strHours);

Rob

Ok, I've tried that so the code now has strings for each

hours = mySerial.read();
          minutes = mySerial.read();
          seconds = mySerial.read();
          
          //convert to string
        itoa(hours, strHours, 10);
        itoa(minutes, strMinutes, 10);
        itoa(seconds, strSeconds, 10);
        
        //Print time back
        Serial.print(strHours);
        file.print(strHours);
        Serial.print(":");
        file.print(":");
        Serial.print(strMinutes);
        file.print(strMinutes);
        Serial.print(":");
        file.print(":");
        Serial.print(strSeconds);
        file.print(strSeconds);
        delay(200);

The output still looks like this though: 145:154:148,220,363,355 152:145:133,271,365,356 133:145:154,278,360,356 148:152:145,281,363,356 133:133:145,282,361,355 154:148:152,284,363,355

the values are the same as they were before and are still coming out in a random order.. :/

I admit that has me baffled, the numbers aren't random but I can't see a pattern either.

Firstly let's get rid of most of the code because it's just confusing the issue, and only send a single value.

hours = mySerial.read();
Serial.print(hours, DEC);
delay (200);

If that shows a bogus value then we have a problem with the data being received. If not it's atio() or the definition of strHours that's wrong.

How have you defined strHours?


Rob