CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

Sunrise & Sunset routine.....

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
JAM2014



Joined: 24 Apr 2014
Posts: 138

View user's profile Send private message

Sunrise & Sunset routine.....
PostPosted: Tue Apr 03, 2018 8:39 am     Reply with quote

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: 9243
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Tue Apr 03, 2018 9:57 am     Reply with quote

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

View user's profile Send private message

PostPosted: Tue Apr 03, 2018 10:50 am     Reply with quote

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

View user's profile Send private message

PostPosted: Tue Apr 03, 2018 10:57 am     Reply with quote

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: 9243
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Tue Apr 03, 2018 11:06 am     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Apr 04, 2018 10:18 am     Reply with quote

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 Crying or Very sad 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

View user's profile Send private message

PostPosted: Wed Apr 04, 2018 11:25 am     Reply with quote

There is some code in the code library that uses integers for Trig functions. Maybe have a look.
http://www.ccsinfo.com/forum/viewtopic.php?t=27947
temtronic



Joined: 01 Jul 2010
Posts: 9243
Location: Greensville,Ontario

View user's profile Send private message

PostPosted: Wed Apr 04, 2018 1:27 pm     Reply with quote

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

View user's profile Send private message

PostPosted: Wed Apr 18, 2018 12:36 pm     Reply with quote

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
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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