 # 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.

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"
// 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 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.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();
}
byte *minute,
byte *hour,
byte *dayOfWeek,
byte *dayOfMonth,
byte *month,
int *year)
{
Wire.write(0); // set DS3231 register pointer to 00h
Wire.endTransmission();
// request seven bytes of data from DS3231 starting from register 00h
}
void displayTime(int second, int minute, int hour, int dayOfWeek, int dayOfMonth, int month, int year)
{
char buf;
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 HourAngle;
float Cos_Latitude;
float Sin_Latitude;
float Cos_HourAngle;
GreenwichMeanSiderealTime = 6.6974243242 +
0.0657098283*ElapsedJulianDays
+ DecimalHours;
LocalMeanSiderealTime = (GreenwichMeanSiderealTime*15
HourAngle = LocalMeanSiderealTime - RightAscension;
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;
// Parallax Correction
*sin(ZenithAngle);
ZenithAngle=(ZenithAngle //Zenith angle is from the top of the visible sky (thanks breaksbassbleeps)
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”
// 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 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.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();
}
byte *minute,
byte *hour,
byte *dayOfWeek,
byte *dayOfMonth,
byte *month,
int *year)
{
Wire.write(0); // set DS3231 register pointer to 00h
Wire.endTransmission();
// request seven bytes of data from DS3231 starting from register 00h
}
void displayTime(int second, int minute, int hour, int dayOfWeek, int dayOfMonth, int month, int year)
{
char buf;
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
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 HourAngle;
float Cos_Latitude;
float Sin_Latitude;
float Cos_HourAngle;
GreenwichMeanSiderealTime = 6.6974243242 +
0.0657098283*ElapsedJulianDays

• DecimalHours;
LocalMeanSiderealTime = (GreenwichMeanSiderealTime*15
HourAngle = LocalMeanSiderealTime - RightAscension;
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;
// Parallax Correction
*sin(ZenithAngle);
ZenithAngle=(ZenithAngle //Zenith angle is from the top of the visible sky (thanks breaksbassbleeps)
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.``````