|
|
View previous topic :: View next topic |
Author |
Message |
JAM2014
Joined: 24 Apr 2014 Posts: 138
|
Sunrise & Sunset routine..... |
Posted: Tue Apr 03, 2018 8:39 am |
|
|
Hi All,
There is some code in the Code Library for calculating Sunrise and Sunset times based on current date & geographical (latitude/longitude) location. I took this code to create the module shown below, which I include in my main code. When I compile, however, I get a lot of errors.
One thing I'm unsure about is the #device ANSI statement. I don't want to do this, so I've commented it out and explicitly defined the required variables as signed or unsigned. Perhaps I'm missing something here?
Edit: This code has been updated so that is now compiles and works correctly!
Edit: A bug corrected that performed UT sanity checking before the UTC offset was applied. Corrected and tested.
Code: |
#define ZENITH 90.833333333
float calc_suntime(signed int8 offset, int1 riseorset, int16 day, int16 month, int16 year, float lat, float lon)
{
//offset: offset to apply from UTC (in hours)
//riseorset: 1 for rise time, 0 for set time
float lngHour, Time, M, L, RA, Lquadrant, RAquadrant, sinDec;
float cosDec, cosH, H, T, UT, localT;
signed int16 N1, N2, N3, N;
N1 = floor(275 * month / 9);
N2 = floor((month + 9) / 12);
N3 = (1 + floor((year - 4 * floor(year / 4) + 2) / 3));
N = N1 - (N2 * N3) + day - 30;
lngHour = lon / 15;
if (riseorset)
{
//sunrise time
Time = N + ((6 - lngHour) / 24);
}
else
{
//sunset time
Time = N + ((18 - lngHour) / 24);
}
M = (0.9856 * Time) - 3.289;
L = M + (1.916 * sin((PI/180) * M)) + (0.020 * sin((PI/180) * 2 * M)) + 282.634;
//need to adjust L to be in range (0,360)
while ((L > 360) || (L < 0))
{
if (L > 360) L -= 360;
if (L < 0) L += 360;
}
RA = (180/PI) * atan(0.91764 * tan((PI/180) * L));
//need to adjust RA to be in range (0,360)
while ((RA > 360) || (RA < 0))
{
if (RA > 360) RA -= 360;
if (RA < 0) RA += 360;
}
Lquadrant = (floor( L/90)) * 90;
RAquadrant = (floor(RA/90)) * 90;
RA = RA + (Lquadrant - RAquadrant);
RA = RA / 15;
sinDec = 0.39782 * sin((PI/180) * L);
cosDec = cos((PI/180) * ((180/PI) * asin(sinDec)));
cosH = (cos((PI/180) * ZENITH) - (sinDec * sin((PI/180) * lat))) / (cosDec * cos((PI/180) * lat));
/*
if (cosH > 1)
the sun never rises on this location (on the specified date)
if (cosH < -1)
the sun never sets on this location (on the specified date)
*/
if (riseorset)
{
//sunrise time
H = 360 - ((180/PI) * acos(cosH));
}
else
{
//sunset time
H = (180/PI) * acos(cosH);
}
H = H / 15;
T = H + RA - (0.06571 * Time) - 6.622;
UT = T - lngHour;
localT = UT + offset;
//Here we do some sanity checking!
if(localT > 24)
localT -=24;
else if (localT < 0)
localT += 24;
return localT;
}
|
Here is my main program that uses the module code shown above:
Code: |
#include <18F44K22.h>
#fuses INTRC_IO, NOWDT, PUT, NOLVP, NOPBADEN, FCMEN
#use delay(clock=8000000)
#include <math.h>
#include <suntime.c>
#define PWR_LED Pin_B1
#define Serial_TxD Pin_B4 // serial debug port
#use rs232(baud=9600, xmit=Serial_TxD, stream = Diag)
void main()
{
int8 iIndex;
//Sunrise & Sunset variables.....
float fSunRise = 0;
float fSunRiseHour = 0;
float fSunRiseMinute = 0;
unsigned int8 iSunRiseHour = 0;
unsigned int8 iSunRiseMinute = 0;
float fSunSet = 0;
float fSunSetHour = 0;
float fSunSetMinute = 0;
unsigned int8 iSunSetHour = 0;
unsigned int8 iSunSetMinute = 0;
// Here we turn off the Pwr LED
output_low(PWR_LED);
delay_ms(500);
// Here we blip the Power LED at power-up to show that the Lighting interface is working
for ( iIndex = 0 ; iIndex < 3 ; iIndex++ )
{
output_high(PWR_LED);
delay_ms(250);
output_low(PWR_LED);
delay_ms(250);
}
// Here we leave the Power LED ON
output_high(PWR_LED);
delay_ms(3000);
//Here we calculate the current Sunrise and Sunset times.....
//Format: UTC Offset, Rise/Set, Day, Month, Year, Latitude, Longitude)
fSunRise = calc_suntime(-4, 1, 3, 4, 2018, 41.610717, -73.227455);
fSunSet = calc_suntime(-4, 0, 3, 4, 2018, 41.610717, -73.227455);
fSunRiseHour = floor(fSunRise);
iSunRiseHour = (int8)(fSunRiseHour);
fSunRiseMinute = (fSunRise - fSunRiseHour) * 60;
iSunRiseMinute = (int8)(fSunRiseMinute);
fSunSetHour = floor(fSunSet);
iSunSetHour = (int8)(fSunSetHour);
fSunSetMinute = (fSunSet - fSunSetHour) * 60;
iSunSetMinute = (int8)(fSunSetMinute);
fprintf(Diag, "\n\rSunrise: %02d:%02d\n\r", iSunRiseHour, iSunRiseMinute);
fprintf(Diag, "\n\rSunset: %02d:%02d\n\r", iSunSetHour, iSunSetMinute);
while(1){}
} |
Thanks,
Jack
Last edited by JAM2014 on Wed Apr 18, 2018 12:33 pm; edited 4 times in total |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9240 Location: Greensville,Ontario
|
|
Posted: Tue Apr 03, 2018 9:57 am |
|
|
Hay, I got it running NOW ! One of those..'interesting' things I was meaning to do...so chickens get more 'daylight'.
Anyway using ANSI does TWO things...
1) makes all variables SIGNED ( CCS default is UNsigned)
and
2) ENABLES 'CASE' so that names like 'Variablex' and 'VariableX' are NOT the same!
getting around #1 is easy. #2 was 'fun' for me as 'streams' didn't work..it was that CCS requires stream names to be ALL UPPER CASE.
I did have to make some code changes though as it got 'hung up' in this code...
while ((UT > 24) || (UT < 0))
{
if (UT > 360) UT -= 24;
if (UT < 0) UT += 24;
}
Just PM me if you want the code, it's been within a minute of 'official sunrise/set' numbers so I'm happy.
Jay |
|
|
Gabriel
Joined: 03 Aug 2009 Posts: 1067 Location: Panama
|
|
Posted: Tue Apr 03, 2018 10:50 am |
|
|
Jay, you got Chickens?
I got about 30 layers (and love them) and ive been thinking of automating the coop too!
Im liking this thread.
G. _________________ CCS PCM 5.078 & CCS PCH 5.093 |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Apr 03, 2018 10:57 am |
|
|
Quote: | Just PM me if you want the code
|
You always ask everybody else to post their code when they have it
working. Why now the secrecy ? |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9240 Location: Greensville,Ontario
|
|
Posted: Tue Apr 03, 2018 11:06 am |
|
|
Code: |
// calculate sunrise or sunset function
float calc_suntime(int8 cst_oft, int1 riseorset, int16 cst_day, int16 cst_mth, int16 cst_yer, float lat, float lon)
{
//cst_oft: offset to apply from UTC (in hours)
//riseorset: 1 for rise time, 0 for set time
float cst_lhr, cst_t, cst_m, cst_l, cst_ra, cst_lq, cst_rq, cst_sd;
float cst_cd, cst_ch, cst_h, cst_uh, localT,cst_t1;
int16 cst_n1, cst_n2, cst_n3, cst_n;
// check dst flag to properly compute sunrise/sunset times
if(dstflg==0)
{
cst_oft=-5;
}
else
{
cst_oft=-4;
}
cst_n1 = floor(275 * cst_mth / 9);
cst_n2 = floor((cst_mth + 9) / 12);
cst_n3 = (1 + floor((cst_yer - 4 * floor(cst_yer / 4) + 2) / 3));
cst_n = cst_n1 - (cst_n2 * cst_n3) + cst_day - 30;
cst_lhr = lon / 15;
if (riseorset)
{
cst_t = cst_n + ((6 - cst_lhr) / 24); //sunrise
}
else
{
cst_t = cst_n + ((18 - cst_lhr) / 24); //sunset
}
cst_m = (0.9856 * cst_t) - 3.289;
cst_l = cst_m + (1.916 * sin((PI/180) * cst_m)) + (0.020 * sin((PI/180) * 2 * cst_m)) + 282.634;
//need to adjust L to be in range (0,360)
while ((cst_l > 360) || (cst_l < 0))
{
if (cst_l > 360) cst_l -= 360;
if (cst_l < 0) cst_l += 360;
}
cst_ra = (180/PI) * atan(0.91764 * tan((PI/180) * cst_l));
//need to adjust RA to be in range (0,360)
while ((cst_ra > 360) || (cst_ra < 0))
{
if (cst_ra > 360) cst_ra -= 360;
if (cst_ra < 0) cst_ra += 360;
}
cst_lq = (floor( cst_l/90)) * 90;
cst_rq = (floor(cst_ra/90)) * 90;
cst_ra = cst_ra + (cst_lq - cst_rq);
cst_ra = cst_ra / 15;
cst_sd = 0.39782 * sin((PI/180) * cst_l);
cst_cd = cos((PI/180) * ((180/PI) * asin(cst_sd)));
cst_ch = (cos((PI/180) * ZENITH) - (cst_sd * sin((PI/180) * lat))) / (cst_cd * cos((PI/180) * lat));
if (riseorset)
{
cst_h = 360 - ((180/PI) * acos(cst_ch)); //sunrise
}
else
{
cst_h = (180/PI) * acos(cst_ch); //sunset
}
cst_h = cst_h / 15;
cst_t1 = cst_h + cst_ra - (0.06571 * cst_t) - 6.622;
cst_uh = cst_t1 - cst_lhr;
if(cst_uh>24 )
{
cst_uh=cst_uh-24;
}
else if (cst_uh <0)
{
cst_uh=cst_uh+24;
}
localT = cst_uh + cst_oft;
return localT;
}
|
OK, it ain't C pretty, but it works. It's now a file I can '#include' into other programs.
I had to rename the variables as they conflicted with ones I already was using. cst stands for 'calculatesuntimes'. Also the last IF section I had to make, cause the original kept staying in the 'loop' forever.
BTW ANSI does two things, one makes variable default to signed AND enables #CASE, which means VariableA is NOT the same as variablea.
update:edit:sigh
this line, close to the end of the 'compute times function'..
else if (cst_uh <0)
does NOT work for April 13th ! Sunset comes back as -4:00, should be 20:00. change it to..
else if (cst_uh <2)
.. and it'll work for the rest of the year
I'm convinced it's a 'floating point vs conditional' fight, but after 4 days and 72 tries I finally got good code for the year. I sure hope the chickens will be happy !
Jay
Last edited by temtronic on Tue Apr 17, 2018 7:19 pm; edited 1 time in total |
|
|
JAM2014
Joined: 24 Apr 2014 Posts: 138
|
|
Posted: Wed Apr 04, 2018 10:18 am |
|
|
Hi All,
Yes, the problem with the code was that there were two variables, 't' & 'T', that were suddenly the same without the #device ANSI statement. I renamed one of them, and now the code compiles and operates correctly.....
OK, now I'll mention that I really dislike float variables! Adding this module to my project totally chewed up my available ROM I looked at possibly converting the code to use scaled integers instead of floats, but I'm not sure the Trig. functions will allow that?
So, I guess I'm off to order some PIC's with larger Program memory available!
Jack |
|
|
alan
Joined: 12 Nov 2012 Posts: 357 Location: South Africa
|
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9240 Location: Greensville,Ontario
|
|
Posted: Wed Apr 04, 2018 1:27 pm |
|
|
I've settled on the PIC18F46K22 DIP as my goto PIC. Yes way overkill for most projects but with 2 HW UARTS, 2 HW SSP, LOTS of memories and I/O pins my clients have yet to run out of 'stuff'. Yes, it may cost a few pennies more BUT by standardizing on this device I've made a large library of known, working code which saves a LOT of time..and well, time is money !
BTW there are other algorithms for computing sunrise/set but this one works. It may be worth your time to google about it.
Jay |
|
|
JAM2014
Joined: 24 Apr 2014 Posts: 138
|
|
Posted: Wed Apr 18, 2018 12:36 pm |
|
|
Hi All,
I further updated this code to correct a bug that occasionally yielded negative sunset times. The issue was that the sanity checking for the time (ie. <0 or >24) needs to be done after the UTC correction is applied. This has now been changed and tested.
Jack |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|