1 | // --- [ sun.c ] --------------------------------------------------------------
|
2 | // 02.01.09
|
3 | // Der Rechenweg für den Sonnenstand kommt von:
|
4 | //-----------------------------------------------------------------------------
|
5 | // Prozessor : ATmega8
|
6 | // Sprache : C
|
7 | // Datum : 20.09.2008
|
8 | // Version : 1.0
|
9 | // Autor : Cusoe
|
10 | // Programm : vereinfachte Sonnenstandsberechnung
|
11 | //-----------------------------------------------------------------------------
|
12 |
|
13 | #include <avr\io.h> //AVR Register und Konstantendefinitionen
|
14 | #include <avr\interrupt.h> //AVR Interrupt Vektoren
|
15 | #include <stdlib.h>
|
16 | #include <inttypes.h>
|
17 | #include <math.h>
|
18 | #include "global.h"
|
19 | #include "lcd.h"
|
20 | #include "sun.h"
|
21 |
|
22 | #ifdef SUN
|
23 | // ----------------------------------------------------------------------------
|
24 | // zeigt die Daten an
|
25 | // stellt zuerst das Vorzeichen fest, wandelt ggf. in positiven Wert um
|
26 | // multipliziert mit 100, damit 2 Nachkommastellen mitgenommen werden
|
27 | // wandelt dann die Floats um in uint16_t
|
28 | // und legt upper und lower Byte in Array SUN_data ab.
|
29 | // und zeigt natürlich die Werte auch noch an.
|
30 |
|
31 | void SUN_display (void)
|
32 | {
|
33 | static uint8_t x = 0;
|
34 | uint16_t tmp;
|
35 |
|
36 | DCF_make_UTC_time(); // UTC-Zeit aus der aktuellen Uhrzeit erzeugen
|
37 |
|
38 | SUN_calc(); // Elevation und Azimuth für UTC-Zeit berechnen
|
39 | // und in die globalen Variablen schreiben
|
40 |
|
41 | // Elevation und Azimuth umwandeln von double nach 2x uint8_t/uint16_t
|
42 | // die Werte speichern und ausgeben
|
43 |
|
44 | if (elevation > 0) // Elevation -90 ... + 90, Vorzeichen bestimmen
|
45 | {
|
46 | SUN_data[SUN_EL_SIGN] = PLUS;
|
47 | }
|
48 |
|
49 | else
|
50 | {
|
51 | SUN_data[SUN_EL_SIGN] = MINUS;
|
52 | elevation = 0 - elevation; // zu positivem Wert machen
|
53 | }
|
54 | tmp = (uint16_t) (elevation * 100); // für zwei Nachkommastellen mit 100 multiplizieren
|
55 | SUN_data[SUN_EL_HIGH] = (uint8_t) (tmp / 256); // zerlegen und speichern
|
56 | SUN_data[SUN_EL_LOW] = (uint8_t) tmp;
|
57 |
|
58 | #ifdef LCD
|
59 | lcd_goto_xy(3,6); // 0 - 90
|
60 | SUN_print(tmp, SUN_data[SUN_EL_SIGN], 2); // Ausgeben
|
61 | #endif
|
62 |
|
63 | tmp = (uint16_t) (azimuth * 100); // Azimuth 0 ... 360
|
64 | SUN_data[SUN_AZ_HIGH] = (uint8_t) (tmp / 256); // zerlegen und speichern
|
65 | SUN_data[SUN_AZ_LOW] = (uint8_t) tmp;
|
66 |
|
67 | #ifdef LCD
|
68 | lcd_goto_xy(4,5);
|
69 | SUN_print(tmp, '+', 3);
|
70 | #endif
|
71 |
|
72 | if (!(x == (CLK_time[TAG]))) // 1mal am jedem Tag und direkt nach dem Programmstart
|
73 | { // Sonnenauf-Untergang berechnen
|
74 | x = CLK_time[TAG]; // das dauert einige Zeit ...
|
75 | SUN_check_sunrise(); // Durch Iteration Sonnenaufgang/Untergang bestimmen
|
76 | }
|
77 |
|
78 | #ifdef LCD
|
79 | lcd_goto_xy(3, 13); // Sonnenaufgang ausdrucken
|
80 | lcd_dezprint(SUN_data[SUN_UP_H]);
|
81 | lcd_putc('.');
|
82 | lcd_dezprint(SUN_data[SUN_UP_M]);
|
83 |
|
84 | lcd_goto_xy(4, 13); // Sonnenuntergang ausdrucken
|
85 | lcd_dezprint(SUN_data[SUN_DN_H]);
|
86 | lcd_putc('.');
|
87 | lcd_dezprint(SUN_data[SUN_DN_M]);
|
88 | #endif
|
89 |
|
90 | }
|
91 |
|
92 | //----------------------------------------------------------------------
|
93 | // Dezimaltag vom aktuellen Tag berechnen
|
94 | //----------------------------------------------------------------------
|
95 |
|
96 | float dezimal_day(void)
|
97 | {
|
98 | // wenn nur zu voller Minuten berechnet wird sollte dies ausreichen:
|
99 | // die Sekundenbruchteile werden vernachlässigt
|
100 | return(UTC_time[STUNDE] / 24.0 + UTC_time[MINUTE] / 1440.0 );
|
101 | }
|
102 |
|
103 | //----------------------------------------------------------------------
|
104 | // Anzahl Dezimaltage seit 2000 bis aktuelles Datum berechnen
|
105 | //----------------------------------------------------------------------
|
106 |
|
107 | float julian_day(void)
|
108 | {
|
109 | return((float) (UTC_time[JAHR] * 365 + floor((UTC_time[JAHR] / 4)) + day_of_year(UTC_time) - 0.5));
|
110 | }
|
111 |
|
112 | //----------------------------------------------------------------------
|
113 | // Reduzierung eines Winkel auf 0... 2PI rad, Stunden auf 0... 24 h etc.
|
114 | // x=Wert der reduziert werden soll; y=Reduzierbereich z.B. auf 24h
|
115 | //----------------------------------------------------------------------
|
116 |
|
117 | float degr(float x, float y)
|
118 | {
|
119 |
|
120 | if(x < 0) x = x + y;
|
121 | return((x - (floor(x / y) * y)));
|
122 | }
|
123 |
|
124 | // --------------------------------------------------------------------
|
125 | // Den Sonnenauf/untergang durch "Probieren" bestimmen
|
126 | // entspricht ungefähr der 'Bürgerlichen Dämmerung' ??
|
127 | // von 09.00h in 1 Stunden Intervallen bis unter -x Grad,
|
128 | // dann in 1 Minuten Intervallen zurück > -x Grad
|
129 |
|
130 | // von 15.00h in Stunden-Intervallen bis unter -x Grad,
|
131 | // dann in 1 Minuten-Intervallen zurück bis > -x Grad
|
132 |
|
133 | void SUN_check_sunrise(void)
|
134 | {
|
135 |
|
136 | // die UTC-Zeit muss am Ende der Funktion neu aufgebaut werden !
|
137 | UTC_time[MINUTE] = 0;
|
138 | UTC_time[STUNDE] = 10;
|
139 |
|
140 | do { // Sonnenaufgang bestimmen
|
141 | UTC_time[STUNDE]--; // um eine Stunde decrementieren
|
142 | SUN_calc();
|
143 | } while (elevation > (ELEVATION)); // bis der gewählte Grenzwert unterschritten ist
|
144 |
|
145 | do {
|
146 | DCF_incr_time(UTC_time, 1); // um 1 Minute incrementieren
|
147 | SUN_calc();
|
148 | } while (elevation < (ELEVATION)); // bis der gewählte Grenzwert überschritten ist
|
149 |
|
150 | SUN_data[SUN_UP_M] = UTC_time[MINUTE]; // die Uhrzeit speichern
|
151 | SUN_data[SUN_UP_H] = UTC_time[STUNDE] + 1;// für unsere Zeitzone im Winter + 1 Stunde
|
152 | // während der Sommerzeit + 2 Stunden
|
153 | if (is_summertime(CLK_time)) UTC_time[STUNDE]++;
|
154 |
|
155 | UTC_time[MINUTE] = 59;
|
156 | UTC_time[STUNDE] = 14;
|
157 |
|
158 | do { // Sonnenuntergang bestimmen
|
159 | UTC_time[STUNDE]++; // um eine Stunde incrementieren
|
160 | SUN_calc();
|
161 | }
|
162 | while (elevation > (ELEVATION)); // bis der gewählte Grenzwert unterschritten ist
|
163 |
|
164 | do {
|
165 | DCF_decr_time(UTC_time, 1); // um 1 Minute decrementieren
|
166 | SUN_calc();
|
167 | } while (elevation < (ELEVATION)); // bis der gewählte Grenzwert überschritten ist
|
168 |
|
169 | SUN_data[SUN_DN_M] = UTC_time[MINUTE]; // die Uhrzeit speichern
|
170 | SUN_data[SUN_DN_H] = UTC_time[STUNDE] + 1;// für unsere Zeitzone im Winter + 1 Stunde
|
171 | // während der Sommerzeit + 2 Stunden
|
172 | if (is_summertime(CLK_time)) UTC_time[STUNDE]++;
|
173 |
|
174 | DCF_make_UTC_time(); // UTC_Zeit neu aus der Uhr kopieren
|
175 | }
|
176 |
|
177 | //----------------------------------------------------------------------
|
178 | // Vereinfachte Sonnenstandsberechnung
|
179 | //----------------------------------------------------------------------
|
180 | void SUN_calc(void)
|
181 | {
|
182 | double j, l, g, a, e, rekt, dekl, t0, sh, t, mz, rz, el, kr;
|
183 | double jd0, dt, la, br;
|
184 | double azi, elev;
|
185 |
|
186 | jd0 = julian_day();
|
187 | dt = dezimal_day();
|
188 |
|
189 | la = geo_laenge / KO;
|
190 | br = geo_breite / KO;
|
191 |
|
192 | j = jd0 + dt;
|
193 | l = degr(4.894950420 + 0.01720279239 * j, M_2PI); // Postion der Sonne auf der Ekliptik
|
194 | g = degr(6.240040768 + 0.01720197034 * j, M_2PI); // mittlere Anomalie
|
195 | a = l + 0.03342305518 * sin(g) + 0.0003490658504 * sin(2 * g); // ekliptikale Länge der Sonne
|
196 | e = 0.4090928042 - 0.000000006981317008 * j; // Schiefe der Ekliptik
|
197 |
|
198 | rekt = atan(cos(e) * sin(a) / cos(a)); // Rektaszension
|
199 |
|
200 | if(cos(a) < 0) rekt = rekt + M_PI;
|
201 |
|
202 | dekl = asin(sin(e) * sin(a)); // Deklination
|
203 |
|
204 | t0 = jd0 / 36525.0; // Tageszahl in julianischen Jahrhunderten
|
205 | sh = degr(6.697376 + 2400.05134 * t0 + 1.002738 * dt * 24, 24); // mittlere Sternzeit
|
206 | t = sh * 0.2617993878 + la - rekt; // Stundenwinkel der Sonne bezogen auf den Ort
|
207 |
|
208 | mz = cos(t) * sin(br) - tan(dekl) * cos(br); // Nenner Azimut
|
209 | rz = atan(sin(t) / mz) + M_PI; // Azimunt wird von 0° Nord gezählt
|
210 |
|
211 | if(mz < 0) rz = rz + M_PI; // wenn Nenner vom Azimut kleiner 0
|
212 | // dann den Winkel in den richtigen Quadranten bringen
|
213 | azi = degr(rz, M_2PI); // Azimut reduzieren
|
214 | // Elevation
|
215 | el = asin(cos(dekl) * cos(t) * cos(br) + sin(dekl) * sin(br));
|
216 | // Korrekturwert für Refraktion
|
217 | kr = 0.0002967059728 / tan(el + 0.179768913 / (el + 0.08918632478));
|
218 | elev = el + kr; // Elevation einschliesslich Refraktion
|
219 |
|
220 | // Ausgabe des Ergebnisses in globale Variable
|
221 |
|
222 | azimuth = (azi * KO);
|
223 | elevation = (elev * KO);
|
224 | }
|
225 |
|
226 |
|
227 | // ---------------------------------------------------------------------------
|
228 | // eine bereits 'vorverdaute' Float-Zahl ausgeben
|
229 | #ifdef LCD
|
230 | void SUN_print(uint16_t j, uint8_t c, uint8_t vorkomma)
|
231 | {
|
232 | register uint8_t i = 0;
|
233 |
|
234 | lcd_putc(c); // Vorzeichen ausgeben
|
235 |
|
236 | if (vorkomma > 2) // bei dreistelligen Ziffern
|
237 | {
|
238 | i = 0;
|
239 | while (j > 9999)
|
240 | {
|
241 | j -= 10000;
|
242 | i++;
|
243 | }
|
244 | lcd_putc('0' + i); // Hunderterstelle
|
245 | }
|
246 |
|
247 | i = 0;
|
248 | while (j > 999)
|
249 | {
|
250 | j -= 1000;
|
251 | i++;
|
252 | }
|
253 | lcd_putc('0' + i); // Zehnerstelle
|
254 |
|
255 | i = 0;
|
256 | while (j > 99)
|
257 | {
|
258 | j -= 100;
|
259 | i++;
|
260 | }
|
261 | lcd_putc('0' + i); // Einerstelle
|
262 |
|
263 | lcd_putc('.'); // Dezimalpunkt einschmuggeln
|
264 |
|
265 | i = 0;
|
266 | while (j > 9)
|
267 | {
|
268 | j -= 10;
|
269 | i++;
|
270 | }
|
271 | lcd_putc('0' + i); // 1. Nachkommastelle
|
272 | lcd_putc('0' + j); // 2. Nachkommastelle
|
273 | }
|
274 | #endif
|
275 |
|
276 | // ----------------------------------------------------------------------------
|
277 | // Ausgabe einer Dezimalzahl mit Nachkommastellen ohne Systemfunktion
|
278 | // hier durchgängig mit float Variable (diese Code scheint kleiner zu sein)
|
279 | /*
|
280 | void out_float(double f, uint8_t vorkomma)
|
281 | {
|
282 | register uint8_t i = 0;
|
283 | double ff;
|
284 |
|
285 | if (f < 0)
|
286 | {
|
287 | f = 0 - f;
|
288 | lcd_putc('-');
|
289 | }
|
290 | else lcd_putc('+');
|
291 |
|
292 | if (vorkomma > 2)
|
293 | {
|
294 | ff = 99.9999;
|
295 | while (f > ff)
|
296 | {
|
297 | f -= 100;
|
298 | i++;
|
299 | }
|
300 | lcd_putc('0' + i); // Hunderterstelle
|
301 | }
|
302 |
|
303 | i = 0;
|
304 | ff = 9.9999;
|
305 | while (f > ff)
|
306 | {
|
307 | f -= 10;
|
308 | i++;
|
309 | }
|
310 | lcd_putc('0' + i); // Zehnerstelle
|
311 |
|
312 | i = 0;
|
313 | ff = 0.9999;
|
314 | while (f > ff)
|
315 | {
|
316 | f -= 1;
|
317 | i++;
|
318 | }
|
319 | lcd_putc('0' + i); // Einerstelle
|
320 | lcd_putc('.');
|
321 |
|
322 | i = 0;
|
323 | ff = 0.09999;
|
324 | while (f > ff)
|
325 | {
|
326 | f -= 0.1;
|
327 | i++;
|
328 | }
|
329 | lcd_putc('0' + i); // 1. Dezimalstelle
|
330 |
|
331 | i = 0; // ohne 2. Dez. können 50 Byte eingespart werden
|
332 | ff = 0.00999;
|
333 | while (f > ff)
|
334 | {
|
335 | f -= 0.01;
|
336 | i++;
|
337 | }
|
338 | lcd_putc('0' + i); // 2. Dezimalstelle
|
339 |
|
340 | }
|
341 |
|
342 | */
|
343 |
|
344 | /*
|
345 | // ----------------------------------------------------------------------------
|
346 | // Ausgabe einer Dezimalzahl mit Nachkommastellen ohne Systemfunktion
|
347 | // hier über uint16_t und Multiplikation mit 100 für 2 Nachkommastellen
|
348 | void out_float(double f, uint8_t vorkomma)
|
349 | {
|
350 | uint16_t j;
|
351 | uint8_t i;
|
352 |
|
353 | if (f < 0)
|
354 | {
|
355 | f = 0 - f;
|
356 | lcd_putc('-');
|
357 | }
|
358 | else lcd_putc('+');
|
359 |
|
360 | j = (uint16_t) (f * 100);
|
361 |
|
362 | if (vorkomma > 2)
|
363 | {
|
364 | i = 0;
|
365 | while (j > 9999)
|
366 | {
|
367 | j -= 10000;
|
368 | i++;
|
369 | }
|
370 | lcd_putc('0' + i); // Hunderterstelle
|
371 | }
|
372 |
|
373 | i = 0;
|
374 | while (j > 999)
|
375 | {
|
376 | j -= 1000;
|
377 | i++;
|
378 | }
|
379 | lcd_putc('0' + i); // Zehnerstelle
|
380 |
|
381 | i = 0;
|
382 | while (j > 99)
|
383 | {
|
384 | j -= 100;
|
385 | i++;
|
386 | }
|
387 | lcd_putc('0' + i); // Einerstelle
|
388 |
|
389 | lcd_putc('.'); // Dezimalpunkt
|
390 |
|
391 | i = 0;
|
392 | while (j > 9)
|
393 | {
|
394 | j -= 10;
|
395 | i++;
|
396 | }
|
397 | lcd_putc('0' + i); // 1. Nachkommastelle
|
398 | lcd_putc('0' + j); // 2. Nachkommastelle
|
399 |
|
400 | }
|
401 | */
|
402 | #endif
|
403 |
|
404 | // --- [ eof ] ----------------------------------------------------------------
|