Help with to connect DS3231 module to Suntrackercode.

Hi

I am a newbie to arduino, I work mostly with PLC system.

Now I have a project that should follw the sun with a accuracy of 0.1 degree.

I use the DS3231 RTC modul and I have found a code from Mowcius that use static time but I will use the RTC to transfer the UTC time to his code.

I have tried the codes separetly and everything works nice, but I cant find a solution to get the output from RTC to the input for the suntracker code.

Sunclock.ino (7.51 KB)

Danhill:
Now I have a project that should follw the sun with a accuracy of 0.1 degree.

I use the DS3231 RTC modul and I have found a code from Mowcius that use static time but I will use the RTC to transfer the UTC time to his code.

I have tried the codes separetly and everything works nice, but I cant find a solution to get the output from RTC to the input for the suntracker code.

Your sunpos() algorithm does not work for 0.1° accuracy.

Just look at this line:

DecimalHours = Hours + (Minutes / 60.0);

The algorithm is not using seconds to calculate the sun position, but only minutes.
But as the earth is rotating by 360 degrees in circa 24 hours = 1440 minutes, your position calculation for “azimuth” will jump each minute by circa:
360 degrees / 1440 = 0,25 degrees

That way you can NEVER achieve an 0.1 degrees accuracy, even if the algorightm itself should be accurate up to 0.01 degrees (which it is surely NOT).

Do you want to use that algorithm anyway, despite of its much bigger inaccuracy than 0.1 degrees?

Thanks for the replie.

I have notice this before, and will use a special sunsensor that we will connect to the PLC and that will then be a input of where the sun are and if its nott correct then the PLC will rotate until its in correct position.

What I need help with is how I can connect the year,date,hour and minuts from the RTC to the input for the suntrackercode.

We need a simple way to turn the solar tracker to the nearest correct positions fast.

Regards Kent Andersson

Danhill:
What I need help with is how I can connect the year,date,hour and minuts from the RTC to the input for the suntrackercode.

Typically you use something called “function parameters” to pass parameters to a function.

Here is your code a little bit modified:

//Sun Position Calculation by Mowcius (mowcius.co.uk)
//Provides sun position (relative) from static variables

#include "Wire.h"
#define DS3231_I2C_ADDRESS 0x68
// Convert normal decimal numbers to binary coded decimal
byte decToBcd(byte val)
{
  return( (val/10*16) + (val%10) );
}

// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val)
{
  return( (val/16*10) + (val%16) );
}
#include <math.h>
#define pi    3.14159265358979323846
#define twopi (2*pi)
#define rad   (pi/180)
#define EarthMeanRadius     6371.01 // In km
#define AstronomicalUnit    149597890 // In km

float Longitude = 16.348883; //enter longitude here   
float Latitude = 48.991569; //enter latitude here
//--------

//Program Variables
 float ZenithAngle;
 float Azimuth;
  float RightAscension;
 float Declination;
  float Parallax;
  float ElevationAngle;

 float ElapsedJulianDays;
 float DecimalHours;
 float EclipticLongitude;
 float EclipticObliquity;
//--------

void setup() 
{
  Wire.begin();
  Serial.begin(9600);
  // set the initial time here:
  // DS3231 seconds, minutes, hours, day, date, month, year
  // setDS3231time(00,58,16,3,7,7,15);
}
void setDS3231time(byte second, byte minute, byte hour, byte dayOfWeek, byte
dayOfMonth, byte month, byte year, float Minutes)
{
  // sets time and date data to DS3231
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0); // set next input to start at the seconds register
  Wire.write(decToBcd(second)); // set seconds
  Wire.write(decToBcd(minute)); // set minutes
  Wire.write(decToBcd(hour)); // set hours
  Wire.write(decToBcd(dayOfWeek)); // set day of week (1=Sunday, 7=Saturday)
  Wire.write(decToBcd(dayOfMonth)); // set date (1 to 31)
  Wire.write(decToBcd(month)); // set month
  Wire.write(decToBcd(year)); // set year (0 to 99)
  Wire.endTransmission();
}
void readDS3231time(byte *second,
byte *minute,
byte *hour,
byte *dayOfWeek,
byte *dayOfMonth,
byte *month,
int *year)
{
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0); // set DS3231 register pointer to 00h
  Wire.endTransmission();
  Wire.requestFrom(DS3231_I2C_ADDRESS, 7);
  // request seven bytes of data from DS3231 starting from register 00h
  *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 = 2000+bcdToDec(Wire.read());
}
void displayTime(int second, int minute, int hour, int dayOfWeek, int dayOfMonth, int month, int year)
{
  char buf[26];
  snprintf(buf,sizeof(buf),"%02d.%02d.%04d  %02d:%02d:%02d  ", dayOfMonth, month, year, hour, minute, second);
  Serial.print(buf);
}


void sunPos(int Minutes, int Hours, int Day, int Month, int Year){


 // Auxiliary variables
 float dY;
 float dX;

 // Calculate difference in days between the current Julian Day
 // and JD 2451545.0, which is noon 1 January 2000 Universal Time

 float JulianDate;
 long int liAux1;
 long int liAux2;
 // Calculate time of the day in UT decimal hours
 DecimalHours = Hours + (Minutes / 60.0);
 // Calculate current Julian Day
 liAux1 =(Month-14)/12;
 liAux2=(1461*(Year + 4800 + liAux1))/4 + (367*(Month
 - 2-12*liAux1))/12- (3*((Year + 4900
 + liAux1)/100))/4+Day-32075;
 JulianDate=(float)(liAux2)-0.5+DecimalHours/24.0;
 // Calculate difference between current Julian Day and JD 2451545.0
 ElapsedJulianDays = JulianDate-2451545.0;

 // Calculate ecliptic coordinates (ecliptic longitude and obliquity of the
 // ecliptic in radians but without limiting the angle to be less than 2*Pi
 // (i.e., the result may be greater than 2*Pi)

 float MeanLongitude;
 float MeanAnomaly;
 float Omega;
 Omega=2.1429-0.0010394594*ElapsedJulianDays;
 MeanLongitude = 4.8950630+ 0.017202791698*ElapsedJulianDays; // Radians
 MeanAnomaly = 6.2400600+ 0.0172019699*ElapsedJulianDays;
 EclipticLongitude = MeanLongitude + 0.03341607*sin( MeanAnomaly )
 + 0.00034894*sin( 2*MeanAnomaly )-0.0001134
 -0.0000203*sin(Omega);
 EclipticObliquity = 0.4090928 - 6.2140e-9*ElapsedJulianDays
 +0.0000396*cos(Omega);

 // Calculate celestial coordinates ( right ascension and declination ) in radians
 // but without limiting the angle to be less than 2*Pi (i.e., the result may be
 // greater than 2*Pi)

 float Sin_EclipticLongitude;
 Sin_EclipticLongitude= sin( EclipticLongitude );
 dY = cos( EclipticObliquity ) * Sin_EclipticLongitude;
 dX = cos( EclipticLongitude );
 RightAscension = atan2( dY,dX );
 if( RightAscension < 0.0 ) RightAscension = RightAscension + twopi;
 Declination = asin( sin( EclipticObliquity )*Sin_EclipticLongitude );

 // Calculate local coordinates ( azimuth and zenith angle ) in degrees

 float GreenwichMeanSiderealTime;
 float LocalMeanSiderealTime;
 float LatitudeInRadians;
 float HourAngle;
 float Cos_Latitude;
 float Sin_Latitude;
 float Cos_HourAngle;
 GreenwichMeanSiderealTime = 6.6974243242 +
 0.0657098283*ElapsedJulianDays
 + DecimalHours;
 LocalMeanSiderealTime = (GreenwichMeanSiderealTime*15
 + Longitude)*rad;
 HourAngle = LocalMeanSiderealTime - RightAscension;
 LatitudeInRadians = Latitude*rad;
 Cos_Latitude = cos( LatitudeInRadians );
 Sin_Latitude = sin( LatitudeInRadians );
 Cos_HourAngle= cos( HourAngle );
 ZenithAngle = (acos( Cos_Latitude*Cos_HourAngle
 *cos(Declination) + sin( Declination )*Sin_Latitude));
 dY = -sin( HourAngle );
 dX = tan( Declination )*Cos_Latitude - Sin_Latitude*Cos_HourAngle;
 Azimuth = atan2( dY, dX );
 if ( Azimuth < 0.0 )
  Azimuth = Azimuth + twopi;
 Azimuth = Azimuth/rad;
 // Parallax Correction
 Parallax=(EarthMeanRadius/AstronomicalUnit)
 *sin(ZenithAngle);
 ZenithAngle=(ZenithAngle //Zenith angle is from the top of the visible sky (thanks breaksbassbleeps)
 + Parallax)/rad;
    ElevationAngle = (90-ZenithAngle); //Retrieve useful elevation angle from Zenith angle
}

void loop(){
  int year;
  byte month,dayOfWeek,dayOfMonth,hour,minute,second;
  readDS3231time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year);
  displayTime(second, minute, hour, dayOfWeek, dayOfMonth, month, year);
  sunPos(minute, hour, dayOfMonth, month, year); //Run sun position calculations
  Serial.print("Elevation Angle:  ");
  Serial.print(ElevationAngle, 3); //Print Elevation (Vertical) with no decimal places as accuracy is not really great enough
  Serial.print("\tAzimuth:  ");
  Serial.print(Azimuth, 3); //Print Azimuth (Horizontal) with no decimal places
  if(ElevationAngle < 0) Serial.println("  The sun has set. Get some sleep!");
  else Serial.println();
  delay(1000); // every second
}

Please be aware, that your DS3231 code provided just a 2-digit year, while your sunpos() code is most likely expecting a 4-digit year for its algorithm.

So I also changed your DS3231 code and add 2000 years to make a 4-digit year from the 2-digit year stored in the RTC.

Thanks this really helped me now I can start testing if the data will be same as we think its should bee.
/kent

jurs:
Typically you use something called “function parameters” to pass parameters to a function.

Here is your code a little bit modified:

//Sun Position Calculation by Mowcius (mowcius.co.uk)

//Provides sun position (relative) from static variables

#include “Wire.h”
#define DS3231_I2C_ADDRESS 0x68
// Convert normal decimal numbers to binary coded decimal
byte decToBcd(byte val)
{
  return( (val/10*16) + (val%10) );
}

// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val)
{
  return( (val/1610) + (val%16) );
}
#include <math.h>
#define pi    3.14159265358979323846
#define twopi (2
pi)
#define rad  (pi/180)
#define EarthMeanRadius    6371.01 // In km
#define AstronomicalUnit    149597890 // In km

float Longitude = 16.348883; //enter longitude here 
float Latitude = 48.991569; //enter latitude here
//--------

//Program Variables
float ZenithAngle;
float Azimuth;
  float RightAscension;
float Declination;
  float Parallax;
  float ElevationAngle;

float ElapsedJulianDays;
float DecimalHours;
float EclipticLongitude;
float EclipticObliquity;
//--------

void setup()
{
  Wire.begin();
  Serial.begin(9600);
  // set the initial time here:
  // DS3231 seconds, minutes, hours, day, date, month, year
  // setDS3231time(00,58,16,3,7,7,15);
}
void setDS3231time(byte second, byte minute, byte hour, byte dayOfWeek, byte
dayOfMonth, byte month, byte year, float Minutes)
{
  // sets time and date data to DS3231
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0); // set next input to start at the seconds register
  Wire.write(decToBcd(second)); // set seconds
  Wire.write(decToBcd(minute)); // set minutes
  Wire.write(decToBcd(hour)); // set hours
  Wire.write(decToBcd(dayOfWeek)); // set day of week (1=Sunday, 7=Saturday)
  Wire.write(decToBcd(dayOfMonth)); // set date (1 to 31)
  Wire.write(decToBcd(month)); // set month
  Wire.write(decToBcd(year)); // set year (0 to 99)
  Wire.endTransmission();
}
void readDS3231time(byte *second,
byte *minute,
byte *hour,
byte *dayOfWeek,
byte *dayOfMonth,
byte *month,
int *year)
{
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0); // set DS3231 register pointer to 00h
  Wire.endTransmission();
  Wire.requestFrom(DS3231_I2C_ADDRESS, 7);
  // request seven bytes of data from DS3231 starting from register 00h
  *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 = 2000+bcdToDec(Wire.read());
}
void displayTime(int second, int minute, int hour, int dayOfWeek, int dayOfMonth, int month, int year)
{
  char buf[26];
  snprintf(buf,sizeof(buf),"%02d.%02d.%04d  %02d:%02d:%02d  ", dayOfMonth, month, year, hour, minute, second);
  Serial.print(buf);
}

void sunPos(int Minutes, int Hours, int Day, int Month, int Year){

// Auxiliary variables
float dY;
float dX;

// Calculate difference in days between the current Julian Day
// and JD 2451545.0, which is noon 1 January 2000 Universal Time

float JulianDate;
long int liAux1;
long int liAux2;
// Calculate time of the day in UT decimal hours
DecimalHours = Hours + (Minutes / 60.0);
// Calculate current Julian Day
liAux1 =(Month-14)/12;
liAux2=(1461*(Year + 4800 + liAux1))/4 + (367*(Month

  • 2-12liAux1))/12- (3((Year + 4900
  • liAux1)/100))/4+Day-32075;
    JulianDate=(float)(liAux2)-0.5+DecimalHours/24.0;
    // Calculate difference between current Julian Day and JD 2451545.0
    ElapsedJulianDays = JulianDate-2451545.0;

// Calculate ecliptic coordinates (ecliptic longitude and obliquity of the
// ecliptic in radians but without limiting the angle to be less than 2Pi
// (i.e., the result may be greater than 2
Pi)

float MeanLongitude;
float MeanAnomaly;
float Omega;
Omega=2.1429-0.0010394594ElapsedJulianDays;
MeanLongitude = 4.8950630+ 0.017202791698
ElapsedJulianDays; // Radians
MeanAnomaly = 6.2400600+ 0.0172019699ElapsedJulianDays;
EclipticLongitude = MeanLongitude + 0.03341607
sin( MeanAnomaly )

  • 0.00034894sin( 2MeanAnomaly )-0.0001134
    -0.0000203sin(Omega);
    EclipticObliquity = 0.4090928 - 6.2140e-9
    ElapsedJulianDays
    +0.0000396*cos(Omega);

// Calculate celestial coordinates ( right ascension and declination ) in radians
// but without limiting the angle to be less than 2Pi (i.e., the result may be
// greater than 2
Pi)

float Sin_EclipticLongitude;
Sin_EclipticLongitude= sin( EclipticLongitude );
dY = cos( EclipticObliquity ) * Sin_EclipticLongitude;
dX = cos( EclipticLongitude );
RightAscension = atan2( dY,dX );
if( RightAscension < 0.0 ) RightAscension = RightAscension + twopi;
Declination = asin( sin( EclipticObliquity )*Sin_EclipticLongitude );

// Calculate local coordinates ( azimuth and zenith angle ) in degrees

float GreenwichMeanSiderealTime;
float LocalMeanSiderealTime;
float LatitudeInRadians;
float HourAngle;
float Cos_Latitude;
float Sin_Latitude;
float Cos_HourAngle;
GreenwichMeanSiderealTime = 6.6974243242 +
0.0657098283*ElapsedJulianDays

  • DecimalHours;
    LocalMeanSiderealTime = (GreenwichMeanSiderealTime*15
  • Longitude)rad;
    HourAngle = LocalMeanSiderealTime - RightAscension;
    LatitudeInRadians = Latitude
    rad;
    Cos_Latitude = cos( LatitudeInRadians );
    Sin_Latitude = sin( LatitudeInRadians );
    Cos_HourAngle= cos( HourAngle );
    ZenithAngle = (acos( Cos_Latitude*Cos_HourAngle
    *cos(Declination) + sin( Declination )*Sin_Latitude));
    dY = -sin( HourAngle );
    dX = tan( Declination )Cos_Latitude - Sin_LatitudeCos_HourAngle;
    Azimuth = atan2( dY, dX );
    if ( Azimuth < 0.0 )
      Azimuth = Azimuth + twopi;
    Azimuth = Azimuth/rad;
    // Parallax Correction
    Parallax=(EarthMeanRadius/AstronomicalUnit)
    *sin(ZenithAngle);
    ZenithAngle=(ZenithAngle //Zenith angle is from the top of the visible sky (thanks breaksbassbleeps)
  • Parallax)/rad;
        ElevationAngle = (90-ZenithAngle); //Retrieve useful elevation angle from Zenith angle
    }

void loop(){
  int year;
  byte month,dayOfWeek,dayOfMonth,hour,minute,second;
  readDS3231time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year);
  displayTime(second, minute, hour, dayOfWeek, dayOfMonth, month, year);
  sunPos(minute, hour, dayOfMonth, month, year); //Run sun position calculations
  Serial.print(“Elevation Angle:  “);
  Serial.print(ElevationAngle, 3); //Print Elevation (Vertical) with no decimal places as accuracy is not really great enough
  Serial.print(”\tAzimuth:  “);
  Serial.print(Azimuth, 3); //Print Azimuth (Horizontal) with no decimal places
  if(ElevationAngle < 0) Serial.println(”  The sun has set. Get some sleep!”);
  else Serial.println();
  delay(1000); // every second
}




Please be aware, that your DS3231 code provided just a 2-digit year, while your sunpos() code is most likely expecting a 4-digit year for its algorithm.

So I also changed your DS3231 code and add 2000 years to make a 4-digit year from the 2-digit year stored in the RTC.