Questions about internal clock of arduino

I'm trying to make a little thing about clock system.
The accurate time will getting from GPS reciver and transmitted to arduino by SoftwareSerial.
I could recived the time from GPS now, but when I displayed the GPS time and the time of internal clock at the same time in my program (displayed 1 time/ second), I found that GPS time will skipped 1 second in every about 30 seconds, but the internal clock shown normally.
look like this:

GPS(second) 10 11 12 13 14 16 17 18 19

int.clock(second) 6 7 8 9 10 11 12 13 14
^
lost second "15" in GPS time

I think that's because the internal clock is alittle bit slower. How can I adjust the internal clock?

Another question is I will use PWN in the progeam, will this clock affect the output frequency?

Could somebody help me?

I think the problem is not the clock (the internal clock is inaccurate, but not that inaccurate!) Could you show us your code?

The system clock is regulated by a ceramic resonator (newer models) or a quartz crystal (older models). You can't adjust it.

It should not be off even close to 1 in 30 so I would suspect a programming error. Show your code.

Thanks for reply.

Using this code:

#include <Time.h>  
#include <TinyGPS++.h>
#include <SoftwareSerial.h>

TinyGPSPlus gps;  
SoftwareSerial ss(5, 6);  //(Rx, Tx)
unsigned long lastUpdateTime = 0;

void setup() {
      Serial.begin(9600);
      ss.begin(4800);
         while (ss.available()){
         gps.encode(ss.read());
         }
      timeset();
      Serial.println(now());
      }

void loop() {
      while (ss.available()){
      gps.encode(ss.read());
      }
      //Timezone adjustion
      time_t ti = t_cal() + (5 * 3600);
      int wait_start = second();
      while (wait_start == second());
      unsigned long startTime = millis();
 
 //Display the time from GPS time     
  Serial.print("GPS time:");
  Serial.print(gps.date.year());
  Serial.print('/');
  Serial.print(gps.date.month());
  Serial.print('/');
  Serial.print(gps.date.day());
  Serial.print(' ');
  Serial.print(gps.time.hour());
  Serial.print(':');
  Serial.print(gps.time.minute());
  Serial.print(':');
  Serial.println(gps.time.second());
 
 //Display the time of GMT+5 (from GPS time)
  Serial.print("GMT+5:");
  Serial.print(year(ti));
  Serial.print('/');
  Serial.print(month(ti));
  Serial.print('/');
  Serial.print(day(ti));
  Serial.print(' ');
  Serial.print(hour(ti));
  Serial.print(':');
  Serial.print(minute(ti));
  Serial.print(':');
  Serial.print(second(ti));
  Serial.print('(');
  Serial.print(dayOfYear());
  Serial.println(')');   
 
 //Display the time of internal clock
  Serial.print("Internal time:");
  Serial.print(year());
  Serial.print('/');
  Serial.print(month());
  Serial.print('/');
  Serial.print(day());
  Serial.print(' ');
  Serial.print(hour());
  Serial.print(':');
  Serial.print(minute());
  Serial.print(':');
  Serial.print(second());
  Serial.print('(');
  Serial.print(dayOfYear());
  Serial.println(')');
  Serial.println("===============================================");
  
     if (millis() - lastUpdateTime > 10*60*1000L) {
     timeset();
     lastUpdateTime = millis();
     }
}

int dayOfYear() {
  time_t ti = t_cal() + (5 * 3600);
  tmElements_t tm = {0, 0, 0, 0, 1, 1, CalendarYrToTm(year(ti))};
  time_t t = makeTime(tm);
  return (ti - t) / SECS_PER_DAY + 1;
}

//make time_t of GPS time
unsigned long t_cal() {
   int y = gps.date.year();
   int M = gps.date.month();
   int d = gps.date.day();
   int h = gps.time.hour();
   int m = gps.time.minute();
   int s = gps.time.second();

    tmElements_t tm; 
    tm.Year = y - 1970;  // start from 1970
    tm.Month = M;
    tm.Day = d;
    tm.Hour = h;
    tm.Minute = m;
    tm.Second = s;
    
    time_t tt = makeTime(tm);
}

void timeset() {
      time_t ti = t_cal() + (5 * 3600);
      setTime(ti);
}

I will get this result:

GPS time:2014/11/1 15:34:28
GMT+5:2014/11/1 20:34:28(305)
Internal time:1999/12/31 5:0:43(305)

GPS time:2014/11/1 15:34:29
GMT+5:2014/11/1 20:34:29(305)
Internal time:1999/12/31 5:0:44(305)

GPS time:2014/11/1 15:34:30
GMT+5:2014/11/1 20:34:30(305)
Internal time:1999/12/31 5:0:45(305)

GPS time:2014/11/1 15:34:30
GMT+5:2014/11/1 20:34:30(305)
Internal time:1999/12/31 5:0:46(305)

GPS time:2014/11/1 15:34:33
GMT+5:2014/11/1 20:34:33(305)
Internal time:1999/12/31 5:0:47(305)

GPS time:2014/11/1 15:34:34
GMT+5:2014/11/1 20:34:34(305)
Internal time:1999/12/31 5:0:48(305)

GPS time:2014/11/1 15:34:35
GMT+5:2014/11/1 20:34:35(305)
Internal time:1999/12/31 5:0:49(305)

GPS time:2014/11/1 15:34:36
GMT+5:2014/11/1 20:34:36(305)
Internal time:1999/12/31 5:0:50(305)

GPS time:2014/11/1 15:34:37
GMT+5:2014/11/1 20:34:37(305)
Internal time:1999/12/31 5:0:51(305)

GPS time:2014/11/1 15:34:39
GMT+5:2014/11/1 20:34:39(305)
Internal time:1999/12/31 5:0:52(305)

GPS time:2014/11/1 15:34:40
GMT+5:2014/11/1 20:34:40(305)
Internal time:1999/12/31 5:0:53(305)

Hmmm. For starters, you use very slow communication rates (both GPS and Serial) but transfer much data, so it can clog things up.

Step up the Serial to 115,200 (also on the Serial Monitor, don't forget!) and see if it makes any difference. Also, just for the check, comment out all println commands which are not entirely necessary (e.g. dates and labels).

Does it help?

This part of the loop() function is wrong:

void loop() {
  while (ss.available()){
    gps.encode(ss.read());
  }

You are assuming that when ss.available() is zero, it has finished reading a valid GPS NMEA sentence. This is incorrect, especially when using SoftwareSerial. You must check that the value returned by gps.encode() is true which indicates that a new sentence has been read.

Try this:

void loop() {
  if(ss.available() == 0) return;
  if(!gps.encode(ss.read())return;

This will only proceed to print the info if a valid NMEA sentence has been read from the GPS.

Pete

oops forgot to say:
Also, remove these two statements from loop():

     int wait_start = second();
      while (wait_start == second());

Pete

el_supremo:
oops forgot to say:
Also, remove these two statements from loop():

     int wait_start = second();

while (wait_start == second());




Pete

Definitely. I missed that one.

The symptoms could be explained by a very small error in the time when data is requested - just a few microseconds could be enough to be on the wrong side of a particular second.

As part of the debug process it would probably be useful to report the data including fractions of a second.

...R

OMG....it's really not my day....
I lost what I typed when I hit "post" and then got stuck at "you are already logged in" page for several hours, I can't go anywhere in arduino website........

igendel:
Step up the Serial to 115,200 (also on the Serial Monitor, don't forget!) and see if it makes any difference. Also, just for the check, comment out all println commands which are not entirely necessary (e.g. dates and labels).
Does it help?

I set Serial.begin(115200) and Serial.begin(115200) + comment out not print the date.
The GPS time still skip a second after a period of time.
I had result but lost in my missing post..........

el_supremo:
You are assuming that when ss.available() is zero, it has finished reading a valid GPS NMEA sentence. This is incorrect, especially when using SoftwareSerial. You must check that the value returned by gps.encode() is true which indicates that a new sentence has been read.

Try this:

void loop() {

if(ss.available() == 0) return;
  if(!gps.encode(ss.read())return;




This will only proceed to print the info if a valid NMEA sentence has been read from the GPS.

I see.
I use the code to replace the original one and delete wait_start, this is result:
GPS time:5:59:55
GMT+5:10:59:55
Internal time:5:4:35

GPS time:5:59:56
GMT+5:10:59:56
Internal time:5:4:36

GPS time:5:59:56
GMT+5:10:59:56
Internal time:5:4:36

GPS time:5:59:56
GMT+5:10:59:56
Internal time:5:4:36

GPS time:5:59:56
GMT+5:10:59:56
Internal time:5:4:36

GPS time:5:59:57
GMT+5:10:59:57
Internal time:5:4:36

GPS time:5:59:57
GMT+5:10:59:57
Internal time:5:4:36

Each second will show 2-4 times in serial monitor.

I found another thing, when GPS reciver is off, the speed of internal clock seems to become normal.
So, I use real Serial port to receive data from GPS instead of using SoftwareSerial, the GPS time sohws normally (didn't skip a second for a long period of time (at least few minutes)).

Is there any code wrong in my program that made SoftwareSerial spent a lots of time to process data from GPS or just because SoftwareSrial need these time to process data?