Go Down

Topic: swRTC (Read 3 times) previous topic - next topic

leo72

I developed swRTC, a library to implement a software Real-Time Clock based on a timer.
The library is suitable for Arduino boards (2009/UNO/Mega) and for several Atmel microcontrollers:

  • Atmega640/1280/1281/2560/2561 and Arduino MEGA boards

  • Atmega48/88/168/328 and Arduino 2009/UNO boards

  • Attiny24/44/84

  • Attiny25/45/85

  • Attiny2313

  • Atmega644/1284 and Sanguino boards



The library sets up a timer to use as a counter and to have an overflow every 1 ms that calls an ISR The interrupt routine increments an internal counter and after 1000 increments it starts to update the time registers that keep the time.
The library adapt itself to the micro on which it runs because it need an 8-bit timer, so for every micro it choosed the correct timer. It can also run with different clock frequencies by computing the correct prescaler and starting value for the timer. At the moment, 1/8/16 MHz are supported.

There is also a function to introduce deltaT, a timing correction that can be used to correct some software (i.e. another library that uses interrupts) or hardware (i.e. when you use an external resonator or the internal oscillator, that aren't so accurate like a crystal) issues.

The library has been tested for a couple of months and it seems to work well.  ;)
Of course it can archive maximum precision only when you use an external crystal. The library has a limited consumption of memory and is a good replacement of external RTCs when the tolerance between the RTC and the real time is not a problem.

To download the lib and to read more about it, please go to:
http://www.leonardomiliani.com/?p=411&lang=en





Onions

I'm intruigued... What is the accuracy of it? I know other libraries using software timekeeping are extremely in-accurate, hence the use of RTCs.
Interesting project, though!

Onions.
My website: http://www.harryrabbit.co.uk/electronics/home.html Up and running now! (Feel free to look round!) :D

leo72

Consider this: the internal oscillator of a micro is said to have an accuracy of +/-10% over the nominal frequency clock... External resonators have similar problems.

Using the swRTC on an Arduino UNO with a resonator will result in differences that can reach the value of minutes/day. But you can use the deltaT to try to adjust them. I think that with a 2009, that has an external crystal for the Atmega, you will reach more precision.

This lib is intended to be useful for people that need to track the time without the necessity to have a big accuracy.

Testato

#3
Nov 30, 2011, 09:15 am Last Edit: Mar 29, 2013, 05:44 pm by Testato Reason: 1
Hi Onions,

i used and helped to test this swRTC, the DeltaT is a great idea, whit it you can adjust large error, so the only important think to do is a long test for 24hours, after this you know your error/day and start to adjust the deltaT
Whit a few test a reach the precision af a real RTC like a DS1307

to Leo: you forgotten to mention my preferred mcu, the Atmega8 on old ArduinoNG  :)
- [Guida] IDE - http://goo.gl/ln6glr
- [Lib] ST7032i LCD I2C - http://goo.gl/GNojT6
- [Lib] PCF8574+HD44780 LCD I2C - http://goo.gl/r7CstH

leo72

#4
Jan 20, 2012, 03:40 pm Last Edit: Jan 20, 2012, 03:52 pm by leo72 Reason: 1
UPDATE:
new version 0.8.4, with suppot to timestamps.
New functions:

getTimestamp([epoch]);
returns a timestamp representing the actual time of the internal clock based since epoch (it can be 1900 or 1970, the latter is the UNIX epoch)

setClockWithTimestamp(timestamp[, epoch]);
this function sets the internal clock using a timestamp. If specified, epoch will be used.

EDIT:
to download it,
http://www.leonardomiliani.com/?p=411&lang=en

tochinet

Hi Leo,

I really love swRTC. I recently added a getDeltaT method (and issued a pull request on github).
Reason is that I integrated swRTC with panstamp SWAP stack from Daniel Berenguer, and I need to be able to read that and report it over RF network. I didn't test it yet though.

I also added an overloaded setDeltaT method using a int instead of float because float is supposed to be quite inefficient. But the weird thing is that when I substitute it to your routine, I get about 300 bytes MORE with my sketch. Very strange. Anybody have an idea on why and what did I do wrong ?

I also noted that the maximum deviation supported is 1% (840.0 second a day). Is there something specific that defineds that as a hard limit ? Because it pretty much looks like my device (using the internal 8MHz clock) derives more than that, my latest calculation would say around 1512 seconds too much a day (or 1.75%). Can this limitation be relaxed to 2-3% without any side effect ?

Graynomad

#6
Mar 29, 2013, 02:55 pm Last Edit: Mar 29, 2013, 02:58 pm by Graynomad Reason: 1
Quote
(840.0 second a day). Is there something specific that defineds that as a hard limit

I haven't seen the code but if it uses a hardware timer then the best you can do is the accuracy of the CPU's oscillator. In most cases that's a crystal (not bad) or a ceramic oscillator (not great) but in your case the internal oscillator it rated (IIRC) at 10% from the factory so you're doing well.

Quote
Can this limitation be relaxed to 2-3% without any side effect ?

Not sure what you mean there, you can't make it LESS accurate unless you add random values in the code somehow, you can tune the internal oscillator and get MORE accurate, but I've not done that.

______
Rob
Rob Gray aka the GRAYnomad www.robgray.com

pito

#7
Mar 29, 2013, 03:39 pm Last Edit: Mar 29, 2013, 03:47 pm by pito Reason: 1
The internal oscillator of the 328p is factory set to aprox.(+/-10%) 8MHz at 3Volts and 25degC. So at 3V3 or 5V it will be far off. You may compensate for temperature as well (328p has got an internal diode for chip's temp measurement). In past I did some measurements and based on OSCCAL the internal oscillator ran from ~5MHZ-15.5MHz.

leo72


Hi Leo,

I really love swRTC. I recently added a getDeltaT method (and issued a pull request on github).
Reason is that I integrated swRTC with panstamp SWAP stack from Daniel Berenguer, and I need to be able to read that and report it over RF network. I didn't test it yet though.

I also added an overloaded setDeltaT method using a int instead of float because float is supposed to be quite inefficient. But the weird thing is that when I substitute it to your routine, I get about 300 bytes MORE with my sketch. Very strange. Anybody have an idea on why and what did I do wrong ?

Hi tochinet, sorry if I read and answer a little bit late  :smiley-sweat:
We had a msg exchange over Github. Just to inform you that the new code I've put online a week ago seems to me that is more efficent and generates a smaller code.
Can you confirm this?

Quote

I also noted that the maximum deviation supported is 1% (840.0 second a day). Is there something specific that defineds that as a hard limit ? Because it pretty much looks like my device (using the internal 8MHz clock) derives more than that, my latest calculation would say around 1512 seconds too much a day (or 1.75%). Can this limitation be relaxed to 2-3% without any side effect ?


That's only a choice of mine. I decided not to use bigger values.
With the last revision of swRTC I used an int type so you can extend the range between -16384 and +16383 tenths of second a day.
If you want a bigger range, try using a long int, but it doubles the RAM usage (4 bytes) and, probably, the size of the sketch.

Yifan

#9
Apr 30, 2013, 03:56 am Last Edit: Apr 30, 2013, 04:01 am by Yifan Reason: 1
Hi, leo:

First of all, thank you for developing and releasing such a great library.
I'm a beginner of Arduino and trying to build a LED clock using your swRTC library.
My LED clock is operated with Atmega8, and a 4-digit LED display is drived by MAX7219.
I also connected a DHT11 sensor for temperature and humidity report.
My sketch is running well in this hardware combination except one thing -- the deltaT value.
I found that the negative value of deltaT will be turned into positive spontaneously after calling rtc.setDeltaT() function.
I'm not sure if I made a stupid mistake in my sketch. Maybe you can give me some advice. Thank you!

Code: [Select]
#include <swRTC.h>
#include <LedControl.h>
#include <dht11.h>

#define DHT11PIN 2

#define SW_TimeSet_Pin 3
#define SW_H_Pin 4
#define SW_M_Pin 5
#define SW_S_Pin 6
#define SW_DeltaTSet_Pin 7

#define LedDataPIN 9
#define LedClkPIN 10
#define LedCsPIN 11
#define MAX7219Num 1

#define Analog_CdS_Pin 0

swRTC rtc;
LedControl lc=LedControl(LedDataPIN,LedClkPIN,LedCsPIN,MAX7219Num);
dht11 DHT11;

byte HUR,hour12F,MIN,SEC,TenHURDigit,HURDigit,TenMINDigit,MINDigit,TenSECDigit,SECDigit;
byte HunDTDigit,TenDTDigit,DTDigit;
byte ReadT,ReadH,TenTempDigit,TempDigit,TenHumidDigit,HumidDigit;
byte CdS;
int DeltaT;
char TenHURChar;
boolean set_status = false;
boolean set_DeltaT = false;
boolean Blink = true;
boolean Bol_HUR = false;
boolean Bol_MIN = false;
boolean Bol_SEC = false;

void setup() {
   
    // Initial time value
    rtc.stopRTC(); //stop the RTC
    rtc.setTime(12,0,0); //set the time here
    rtc.setDate(23,4,2013); //set the date here
    rtc.startRTC(); //start the RTC

   lc.shutdown(0,false);
   lc.clearDisplay(0);
   
   pinMode(SW_TimeSet_Pin,INPUT);
   pinMode(SW_H_Pin,INPUT);
   pinMode(SW_M_Pin,INPUT);
   pinMode(SW_S_Pin,INPUT);
   pinMode(SW_DeltaTSet_Pin,INPUT);

}

void loop() {
    CdS = analogRead(Analog_CdS_Pin)/102;
    lc.setIntensity(0,CdS);
   
    HUR = rtc.getHours();
    MIN = rtc.getMinutes();
    LED_Display_Hour_Minute();
   
    Blink = !Blink;
    delay(200);

    while (digitalRead(SW_S_Pin)){  // display second
       MIN = rtc.getMinutes();
       SEC = rtc.getSeconds();
       LED_Display_Second();
    }
 
   while (digitalRead(SW_M_Pin)){   // display temperature
       DHT11.read(DHT11PIN);
       ReadT = DHT11.temperature;
       LED_Display_temperature();
       delay(1000);
   }
 
   while (digitalRead(SW_H_Pin)){  // display humidity
      DHT11.read(DHT11PIN);
      ReadH = DHT11.humidity;
      LED_Display_humidity();
      delay(1000);
   }
 
  // Manual time adjust
   while (digitalRead(SW_TimeSet_Pin)) {
      set_status = true;
      LED_Display_Hour_Minute();
   
      while (digitalRead(SW_M_Pin)) {
         Bol_MIN = true;
         MIN = MIN++;
         if (MIN >59) MIN =0;
         LED_Display_Hour_Minute();
         delay(100);
      }
      while (digitalRead(SW_H_Pin)) {
         Bol_HUR = true;
         HUR = HUR++;
         if (HUR >23) HUR =0;
         LED_Display_Hour_Minute();
         delay(200);
      }
      while (digitalRead(SW_S_Pin)) {
         Bol_SEC = true;
         SEC = 0;
         LED_Display_Second();
         delay(300);
      }
   
    // DeltaT adjust
    while (digitalRead(SW_DeltaTSet_Pin)) {
       DeltaT = rtc.getDeltaT();
       LED_Display_DeltaT();
   
       while (digitalRead(SW_H_Pin)) {
         set_DeltaT = true;
         DeltaT = DeltaT+10;
         if (DeltaT > 8400) DeltaT = 0;
         LED_Display_DeltaT();
         delay(150);
       }
       while (digitalRead(SW_M_Pin)) {
         set_DeltaT = true;
         DeltaT = DeltaT-10;
         if (DeltaT < -8400) DeltaT = 0;
         LED_Display_DeltaT();
         delay(150);
       }
       while (digitalRead(SW_S_Pin)) {
         set_DeltaT = true;
         DeltaT = 0;
         LED_Display_DeltaT();
         delay(300);
       }
       if (set_DeltaT){
         rtc.setDeltaT(DeltaT);
         set_DeltaT = false;
      }
    }
  }
  if (Bol_HUR | Bol_MIN | Bol_SEC){
    rtc.stopRTC(); //stop the RTC
    rtc.setTime(HUR,MIN,SEC); //set the time here
    rtc.startRTC();
    set_status = false;
    Bol_MIN = false;
    Bol_HUR = false;
    Bol_SEC = false;
  }
  else if (set_status) set_status = false;
 
}

//////////////////////////////////////////////////////////

void LED_Display_Hour_Minute(){ //LED Clock Display
   // Transform 24H to 12H
   if(HUR>12) hour12F = HUR-12;
   else if(HUR == 0) hour12F = 12;
   else hour12F = HUR;
   
   // Let the Ten-Digit of Hour not to display '0' on LED  
   if(hour12F > 9) TenHURChar = '1';
   else TenHURChar = ' ';
   
   //  
    TenHURDigit = hour12F/10;
    HURDigit = hour12F % 10;
    TenMINDigit = MIN/10;
    MINDigit = MIN % 10;
   
    lc.setChar(0,0,TenHURChar,set_status);
    lc.setDigit(0,1,HURDigit,set_status | Blink); // F2481AH CB
    lc.setDigit(0,2,TenMINDigit,set_status | Blink); // F2481AH CB
    lc.setDigit(0,3,MINDigit,set_status);
     
    if (HUR <12) lc.setLed(0,0,6,true); // AM sign
    else  lc.setLed(0,0,5,true); // PM sign
    delay(300);
}

void LED_Display_Second(){
     
  TenMINDigit = MIN/10;
  MINDigit = MIN % 10;
  TenSECDigit = SEC/10;
  SECDigit = SEC % 10;
     
  lc.setDigit(0,0,TenMINDigit,false);
  lc.setDigit(0,1,MINDigit,true); // F2481AH CB on
  lc.setDigit(0,2,TenSECDigit,true); // F2481AH CB on
  lc.setDigit(0,3,SECDigit,false);
}  

void LED_Display_DeltaT(){
  HunDTDigit = abs(DeltaT / 1000);
  TenDTDigit = abs(DeltaT /100 % 10);
  DTDigit = abs(DeltaT % 100 /10);
 
  lc.setDigit(0,1,HunDTDigit,false);// F2481AH CB off
  lc.setDigit(0,2,TenDTDigit,false);// F2481AH CB off
  lc.setDigit(0,3,DTDigit,true);
 
  if (DeltaT < 0)
     lc.setChar(0,0,'-',true);
  else
     lc.setChar(0,0,' ',true);
}

void LED_Display_temperature(){
   TenTempDigit = ReadT/10;
   TempDigit = ReadT % 10;
   
   if (ReadT<0) lc.setChar(0,0,'-',false);
   else lc.setChar(0,0,' ',false);
   lc.setDigit(0,1,TenTempDigit,false);
   lc.setDigit(0,2,TempDigit,false);
   lc.setChar(0,3,'c',false);
}

void LED_Display_humidity(){
   TenHumidDigit = ReadH/10;
   HumidDigit = ReadH % 10;
   lc.setChar(0,0,' ',false);
   lc.setDigit(0,1,TenHumidDigit,false);
   lc.setDigit(0,2,HumidDigit,false);
   lc.setChar(0,3,'h',false);
}

leo72

That's my mistake  :smiley-sweat:
I forgot to return the correct sign of deltaT with getDeltaT(). But deltaT was used correctly into the function.
BTW, now it's fixed in rev. 1.1.2:
https://github.com/leomil72/swRTC

Go Up