Ausführliche Beschreibung - Projekte
Transcrição
Ausführliche Beschreibung - Projekte
Die Geburtstagskalenderuhr Video: http://www.youtube.com/watch?v=czhl8_Aprc8 Beschreibung des Projekts Da ich leider manchmal die Geburtstage lieber Mitmenschen vergesse, habe ich mir gedacht, ein Geburtstagskalender könnte vielleicht ganz nützlich sein. Wie bei einem Geburtstagskalender in Papierform, sollten die Termine unabhängig vom jeweiligen Jahr und Wochentag am Geburtsdatum angezeigt werden. Nebenbei sollten auch andere Feiertage mit angezeigt werden. Dazu sollte die Kalenderuhr Datum, Uhrzeit und Wochentag anzeigen und optisch und akustisch daran erinnern, dass Heute ein besonderer Tag ist. Da ich gern fotografiere und bei Sonnenaufgang oder Sonnenuntergang das beste Licht ist, wollte ich, dass mir die Uhr die entsprechenden Zeiten angibt. Datum, Uhrzeit und andere Informationen sollten auf einem 16x4 LCD-Modul angezeigt werden, Uhrzeit und Datum der besseren Ablesbarkeit wegen auf einer zusätzlichen 7-Segmentanzeige. -1- Als Grundlage sollte das myAVR Board light dienen, von dem möglichst alle verfügbaren Komponenten eine Funktion bekommen sollten. Zeit und Datum sollte eine RTC-Komponente (DS1307) liefern und sämtliche Daten sollten in einem seriellen EEPROM gespeichert werden. Die Datenübertragung sollte PC-gesteuert über das myUSBtoUART-Modul erfolgen. Hardware Das myAVR Board light ist die Grundlage der Kalenderuhr, auf die eine zweite (Lochraster)Platine mit den Anzeigekomponenten gesetzt wird (Abbildung 1). Die Anzeigen sind ein 16x4 LCD-Modul (Displaytech 164A) und eine serielle 7-Segment LED Anzeige (blau, Sparkfun Electronics). Die 7Segemtanzeige sieht nicht nur super aus (wie ich finde), sie hat auch den Vorteil nur eine einzige Datenleitung zu benötigen. Der ATmega8 des myAVR Board light wird durch einen ATmega168 ersetzt, um etwas mehr Platz für das Programm zu haben. Abbildung 1: Seitenansicht der Kalenderuhr Sämtliche Daten für Geburtstage, Feiertage, Sonnenaufgänge und Sonnenuntergänge werden in einem EEPROM (24AA128-I/P, Microchip) gespeichert. Eine Echtzeituhr (DS1307, Dallas) liefert Datum und Uhrzeit. Das batteriegepufferte NV-RAM der Uhr dient als Speicher für Einstellungen. Beide Komponenten werden über den seriellen I2C-Bus angesteuert. Strom liefert ein Netzteil (5V) basierend auf dem externPowerKit von Laser & Co. Solutions GmbH. Alle diese Komponenten werden auf dem Rasterfeld des myAVR Board light untergebracht. -2- Stückliste Bauteil Anzahl Anbieter myAVR Board light, Bausatz 1 Laser & Co. Solutions GmbH 16x4 LCD-Modul 164A (Displaytech) 1 Reichelt, Art.-Nr.: LCD 164A LED 7-Segment LED Anzeige blau (seriell) 1 Watterott electronic, Art.-Nr.: COM-09765 IC1: ATmega168PA-PU 1 IC2: EEPROM 24AA128-I/P 1 IC3: RTC DS1307 1 VR1: Spannungsregler µA 1705 1 BR1: Gleichrichter DIL B80C800DIP 1 T1: Transistor BC547C 1 D1: Diode BAT46 1 D2: Diode 1A - 1N4001 1 C6,8: Kondensator 47µF 2 C7,9: Kondensator 100nF 2 P1: Einstellpotentiometer, liegend, 5 K-Ohm 1 R2,3,6: Widerstand 10 K-Ohm 3 R5: Widerstand 480 Ohm 1 Q2: Uhrenquarz 32,768kHz (12.5 pF) 1 BAT1: Lithium-Knopfzelle: CR 2032 1 Batteriehalter 20 mm 1 IC-Sockel 28-polig (optional) 1 IC-Sockel 8-polig (optional) 2 Lochrasterplatine 100 x 100 mm 1 20 pol. Buchsenleiste gerade (RM 2,54, H: 8,5 mm) 1 10 pol. Buchsenleiste gerade (RM 2,54, H: 8,5 mm) 1 50-pol Stiftleiste gerade, RM 2,54 1 Hohlstecker-Einbaubuchse, gewinkelt 1 Wannenstecker 6-polig gerade 1 Buchsen-/Stiftleisten für Anzeigen (optional) -3- Schaltplan Abbildung 2: Schaltplan -4- Zusammebau des myAVR Boards Das myAVR Board light wird fast wie in der Anleitung angegeben aufgebaut. Zusätzlich wird der 6-polige Wannenstecker aufgelötet, um den ATmega168 über die ISP-Schnittstelle programmieren zu können. Die gewinkelte Buchsenleiste wird durch eine gerade Buchsenleiste ersetzt, die auf der Rückseite des myAVR Boards angebracht wird. Eine Diode (D1) wird zwischen das myAVR Board light und myUSBtoUART-Modul gelötet. Zusätzlich wird bzw. werden: • PD2 und PD3 auf der Rückseite des Boards mit Taster 1 und 2 über Drähte verbunden • PB1 mit dem Summer verbunden. • PC2 mit der Photodiode verbunden. Bestückung des Rasterfeldes auf dem myAVR Board light Zuerst werden die Komponenten der Spannungsversorgung aufgebracht, dann die 8-poligen IC-Sockel, die Widerstände R2 und R3, der Uhrenquarz Q2 und der Batteriehalter (Abbildung 3) Nachdem die Komponenten gemäß Abb. 2 – 4 eingesetzt und verdrahtet sind, wird noch eine 10-polige Buchsenleiste auf die Rückseite des myAVR Boards gelötet und entsprechend angeschlossen (Abbildung 4). SDA und SCL werden mit PC4 und PC5 verbunden. LED-out wird mit der grünen LED verbunden. Zuletzt wird der Hohlstecker über zwei Drähte mit dem Brückengleichrichter BR1 verbunden. An diesen Hohlstecker wird später das Netzteil angeschlossen. Abbildung 3: Rasterfeld Oberseite -5- Abbildung 4: Rasterfeld Unterseite (Durchsicht) Dieser Aufbau stellt für sich genommen schon eine vollständig funktionierende Einheit dar und kann unabhängig von der Anzeigekomponente betrieben werden. Aufbau der Anzeigekomponente Die Anzeigekomponente wird auf einer herkömmlichen 100 x 100 mm Punktrasterplatine aufgebaut. Zuerst werden die Stiftleisten (20- und 10-polig) auf der Cu-Seite der Platine aufgelötet. Das gestaltet sich schwierig, da Lötzinn nicht auf der unbeschichteten Seite haftet. Man muss die Stiftleisten leicht herausziehen und diese mit der Spitze des Lötkolben auf der Cu-Seite löten (Abbildung 5). Abbildung 5: Anbringen der Stiftleiste Die Stiftleisten werden später mit dem myAVR Board verbunden. Man sollte sicherstellen, dass das Board mittig auf der Punktrasterplatine sitzt. Dann werden optional die Buchsenleisten für die -6- Anzeigeelemente angebracht. Auch hier sollte man darauf achten, dass hinterher alles so angebracht werden kann, wie man es sich gewünscht hat. Dann werden Trimmer P1, die Widerstände R5, R6 und der Transistor T1 aufgelötet und gemäß Abbildung 6 und Abbildung 7 verdrahtet. Es ist hilfreich, etwas Lötzinn von der Stiftleiste bis zum nächsten Punkt auf der Rasterplatine zu ziehen, um von hier aus die Verdrahtung durchzuführen. Die Drähte direkt an der Stiftleiste anzulöten, ist recht schwierig. Abbildung 6: Anzeigekomponente Oberseite (R4 und T1 liegen im realen Aufbau unterhalb des LCD-Moduls) -7- Abbildung 7: Anzeigekomponente Unterseite (Durchsicht) Die Anzeigekomponente kann jetzt mit dem myAVR Board verbunden werden. Mit P1 lässt sich der Kontrast des LCD-Moduls regeln, die Hintergrundbeleuchtung kann über die Software (PB2) an und ausgestellt werden. Die Kommunikation mit der seriellen 7-Segmentanzeige erfolgt über PB0. PD4-PD7 und PC0/PC1 dienen zur Ansteuerung des LCD-Moduls. Jetzt fehlt nur noch die Stromversorgung. Die erledigt ein Steckernetzteil mit 9V Spannung. Anmerkung: Auf den Fotos sind noch 3 Jumper zu erkennen. Diese hatte ich zum testen des Aufbaus genutzt (Hintergrundbeleuchtung, Direktverbindung PC > 7-Segementanzeige und RW-Modus des LCD-Moduls). Für die Funktion der Uhr sind sie nicht notwendig. -8- Abbildung 8: Bestücktes Rasterfeld mit dem myUSBtoUART-Modul und der BAT46-Diode (links) Abbildung 9: Rückseite des myAVR Boards und der Anzeigekomponente (siehe dazu auch die Anmerkung auf der vorhergehenden Seite) -9- Programmierung Als Programmiersprache wurde BASCOM v2 gewählt. Das fertige Programm gelangt über die ISPSchnittstelle auf den Mikrocontroller. Das Programm, dass die Daten vom PC überträgt, wurde mit AutoIt v3 realisiert. Programmstruktur (Atmega168) Das Programm kann in 3 Teilbereiche gegliedert werden: 1. Anzeige von Uhrzeit, Datum, Geburtstagen, Feiertagen, Sonnenaufgängen/-untergängen 2. Empfang und Speichern von Daten und Einstellungen über das myUSBtoUART-Modul 3. Einstellungen; dazu gehören: Uhrzeit und Datum Hintergrundbeleuchtung des LCD-Moduls Sommer-/Winterzeit Zeitkorrektur Anzeige von Uhrzeit, Datum, Geburtstagen, Feiertagen etc. (Übersicht) Auf dem 16x4 LCD-Modul werden jeweils nach Tastendruck nacheinander folgende Bildschirme angezeigt: Anzeige für einen: normalen Tag Geburtstag Feiertag Startbildschirm Taster1 Termine um „7:43“ wird eine Melodie abgespielt Taster1 Geburtstagskind „Klaus“ Sonnenaufgänge / Sonnenuntergänge Taster1 geboren „1951“, wird heute „60“ Datum & Uhrzeit einstellen Taster1 Abbildung 10: Verschiedene Anzeigen auf dem 16x4-LCD-Modul (für besser Lesbarkeit bitte vergrößern). Video: http://www.youtube.com/watch?v=czhl8_Aprc8 - 10 - Wie in Abbildung 10 gezeigt, ändert sich die Anzeige des Startbildschirms, wenn ein besonderes Datum erreicht ist. Die in der zweiten Zeile angegebene Uhrzeit ist dann die Zeit, an der eine Melodie abgespielt werden kann; es kann sich dabei natürlich auch um die genaue Geburtszeit handeln. Bei einem Geburtstag sieht man noch das Geburtsjahr und das erreichte Alter. Die nachfolgenden Bildschirme zeigen die nächsten 3 Termine bzw. Sonnenaufgänge / Sonnenuntergänge der nächsten 3 Tage. Der letzte Bildschirm verzweigt in den Bereich zur manuellen Zeit- bzw. Datumseinstellung. Viel komfortabler lassen sich diese Einstellungen allerdings mit dem PC-Programm machen. Die 7-Segmentanzeige zeigt unabhängig von den ersten 3 Bildschirmen in wechselnden Zeitabständen Uhrzeit & Datum wie folgt an: Uhrzeit HH:MM Anzeigedauer: 52s Datum TT.MM Anzeigedauer: 4s Datum JJJJ Anzeigedauer 4s Abbildung 11: Wechselnde Darstellung der 7-Segmentanzeige Wenn Bildschirm 4 (Datum & Uhrzeit einstellen) erreicht wird, gibt die Anzeige „Set“ aus. Der Doppelpunkt bei der Zeitanzeige und der Punkt bei der Datumsangabe blinken im 2s-Takt. Wenn das Jahr angezeigt wird, wird kein (Doppel-)Punkt angezeigt Ausgabe auf dem LCD-Modul Die Realisierung einer Ausgabe auf einem LCD-Modul ist mit BASCOM sehr komfortabel. Dazu muss am Anfang des Programms folgende Befehlssequenz eingefügt werden: Config Lcdpin = Pin , Rs = Portc.0 , E = Portc.1 , Db4 = Portd.4 , Db5 = Portd.5 , Db6 = Portd.6 , Db7 = Portd.7 Config Lcd = 16 * 4 Cursor = Off In der Hauptprogrammschleife wird dann beispielsweise folgende Befehlssequenz verwendet: Locate Locate Locate Locate 1 2 3 4 , , , , 1 1 1 1 : : : : Lcd Lcd Lcd Lcd "Datum & Uhrzeit " Weekdaystr ; Spc(spaces) Date$ ; Spc(8) Time$ ; Spc(8) Der Befehl „Cls“ wird kaum verwendet; stattdessen wird jede Zeile des LCD-Moduls vollständig überschrieben, ggf. werden Leerzeichen (Anweisung Spc) eingefügt. Die Umschaltung zwischen den einzelnen Bildschirmen (Abbildung 10) erledigt eine Select Case- 11 - Anweisung in der Hauptprogrammschleife, welche die Zahl der Tastendrücke auswertet (Variable Cntb1). Jeder Tastendruck des Tasters 1 wird über einen Debounce-Befehl ausgewertet. Debounce (eine Art Software-Entprellung) ist optimal, allzu „nervöse“ Taster zu bändigen. Um wirklich sicher zu gehen, wartet in der Button1-Subroutine noch ein Bitwait-Befehl auf den Taster. Debounce Pind.2 , 0 , Button1 , Sub ... Button1: Bitwait Pind.2 , Reset If Cntb1 = 3 Then Cntb1 = 0 Else Incr Cntb1 Cls Return Select Case Cntb1 Case 0: 'Startbildschirm ... Case 1: 'Termine ... Case 2: 'Sonnenauf/-untergänge ... Case 3: 'Datum & Uhrzeit einstellen ... End Select Ausgabe auf der seriellen 7-Segmentanzeige Für die Ausgabe auf der seriellen 7-Segmentanzeige muss zuerst ein Software-UART in BASCOM realisiert werden, da das Hardware-UART für den Datenempfang zuständig sein soll: Open "comb.0:9600,8,n,1" For Output As #1 Die serielle 7-Segementanzeige wird in der Hauptprogrammschleife dann über eine Print #1Anweisung folgendermaßen angesteuert: Timestr = Time$ ... A = Mid(timestr , 1 , 2) B = Mid(timestr , 4 , 2) ... Print #1 , A ; B; Die serielle 7-Segementanzeige kennt einige Steuerbefehle (siehe Datenblatt beim Anbieter), so etwa zum setzen des Doppelpunkts oder des Dezimalpunkts: Print #1 Printbin ... Print #1 Printbin , "w"; #1 , 16 ; , "w"; #1 , 2; Wichtig ist ein “;“ am Ende eines Print-Befehls, sonst zeigt das Modul nur „Müll“ an. Die im 2s-Takt blinkende Anzeige des (Doppel)Punktes wird über den 16 Bit-Timer des ATmega168 realisiert, dabei wird die Variable Colon_onoff auf 0 oder 1 gesetzt (ToggleAnweisung): - 12 - Config Timer1 = Timer , Prescale = 64 On Timer1 Toggle_colon Enable Timer1 Start Timer1 Enable Interrupts ... Toggle_colon: Timer1 = 7936 Toggle Colon_onoff If All_off = 1 Then Colon_onoff = 0 Return Der automatische Wechsel von Datum, Uhrzeit und (Doppel-)Punkt (siehe Abbildung 11) wird dann über einige If-Then-Else Anweisungen in der Hauptprogrammschleife realisiert (Colon_onoff/Dp_onoff/All_off schaltet :/./ / AN bzw. AUS): Timestr = Time$ Datestr = Date$ A = Mid(timestr , 1 , 2) B = Mid(timestr , 4 , 2) C = Mid(timestr , 7 , 2) If Colon_onoff = 0 And Dp_onoff = 0 Then Print #1 , "w"; Printbin #1 , 0 ; Elseif Colon_onoff = 1 And Dp_onoff = 0 And All_off = 0 Then Print #1 , "w"; Printbin #1 , 16 ; Elseif Colon_onoff = 1 And Dp_onoff = 1 And All_off = 0 Then Print #1 , "w"; Printbin #1 , 2 ; Else Print #1 , "w"; Printbin #1 , 0; End If If C > "30" And C < All_off = 0 A = Mid(datestr , B = Mid(datestr , Dp_onoff = 1 Elseif C > "34" And All_off = 1 A = "20" B = Mid(datestr , Else Dp_onoff = 0 All_off = 0 End If "35" Then 1 , 2) 4 , 2) C < "39" Then 7 , 2) If A < "10" Then A = Mid(a , 2 , 1) Print #1 , "x" ; A ; B; Else Print #1 , A ; B; End If In der letzten If-Then-Else-Anweisung wird bei einer führenden Null das erste Segment der 7Segemtanzeige ausgeschaltet ("x"). Aus z.B. „07:34“ wird „7:34“ bzw. wird aus dem „07.04“ der „7.04“. Steuerung der Hintergrundbeleuchtung des LCD-Moduls Die Hintergrundbeleuchtung des LCD-Moduls kann über das PC-Programm AN/AUS gestellt wer- - 13 - den. Daneben gibt es noch den Auto-Modus. Dieser Modus wertet die Helligkeit im Raum über den Fotowiderstand des myAVR Boards und nutzt den A/D-Wandler des ATmega. Wenn es zu dunkel ist, wird die Beleuchtung ein- und wenn es hell genug ist wieder ausgeschaltet. Unabhängig davon wird die Hintergrundbeleuchtung um 0.00 Uhr vollständig ausgestellt und ab 7.00 wieder in den Auto-Modus versetzt. Immer AN ist die Hintergrundbeleuchtung bei der manuellen Zeiteinstellung und beim Abspielen einer Melodie: Config Portc.2 -1 = Output Config Adc = Single , Prescaler = Auto , Reference = Avcc Dim Licht As Word Lcd_bl Alias Portb.2 Config Lcd_bl = Output ... Lcd_blonoff: Licht = Getadc(2) If Lcd_blst = "1" Then Lcd_bl = 1 Elseif Lcd_blst = "3" And Licht < 120 And _hour > 6 Then Lcd_bl = 1 Else Lcd_bl = 0 End If Return Die Lcd_blonoff-Subroutine wird dann in der Hauptprogrammschleife aufgerufen. Lcd_bl (ein „Alias“ für Portb.2) schaltet die Hintergrundbeleuchtung AN oder AUS. Lcd_blst bestimmt, welcher Modus vorliegt. Die Variable Licht steuert, ab wann die Beleuchtung angeschaltet wird; 120 war hier ein guter Wert. Die Variable Lcd_blst wird im NV SRAM der DS1307-RTC gespeichert. Wie das funktioniert, wird im Abschnitt Schreiben & Lesen von Daten & Zeiteinstellung beschrieben. Uhrzeit & Datum Aktuelle Uhrzeit und Datum sind in den Variablen Time$ und Date$ enthalten, die BASCOM generiert. Über den I2C-Bus wird die DS1307-RTC wie folgt angesprochen: $lib "i2c_twi.lbx" Config Sda = Portc.4 Config Scl = Portc.5 Const Ds1307w = &HD0 Const Ds1307r = &HD1 ... Config Clock = User Config Date = Dmy , Separator = . ... Getdatetime: I2cstart I2cwbyte Ds1307w I2cwbyte 0 I2cstart I2cwbyte Ds1307r I2crbyte _sec , Ack I2crbyte _min , Ack I2crbyte _hour , Ack I2crbyte Weekday , Ack I2crbyte _day , Ack 'TWI 'DS1307 schreiben 'DS1307 lesen - 14 - I2crbyte _month , Ack I2crbyte _year , Nack I2cstop _sec = Makedec(_sec) : _min = Makedec(_min) : _hour = Makedec(_hour) _day = Makedec(_day) : _month = Makedec(_month) : _year = Makedec(_year) Return Eine Ausgabe auf dem LCD-Modul wird wie oben angegeben realisiert: Locate Locate Locate Locate 1 2 3 4 , , , , 1 1 1 1 : : : : Lcd Lcd Lcd Lcd "Datum & Uhrzeit " Weekdaystr ; Spc(spaces) Date$ ; Spc(8) Time$ ; Spc(8) Der Wochentag „Weekday“ ist eine Zahl, die über eine Data-Tabelle in den entsprechenden Wochentag „Weekdaystr“ umgesetzt wird: Weekdaystr = Lookupstr(weekday , Weekdays) ... Weekdays: Data "dummy" , "Montag" , "Dienstag" , "Mittwoch" , "Donnerstag" , "Freitag" , "Samstag" , "Sonntag" Empfang von Daten über das UART Der Empfang der Zeichen erfolgt Interrupt-gesteuert. Im Gegensatz zum Input-Befehl wird das Programm weiter ausgeführt und wartet nicht auf eine Eingabe: Dim L As String * 4 Dim S As String * 30 Dim Z(31) As Byte At S Overlay Dim N As Byte ... On Urxc Onrxd Enable Urxc 'ggf. „Enable Interrupts“ falls noch nicht anderweitig aktiviert ... Onrxd: Incr N Z(n) = UDR Return Eine weitere schöne Sache an BASCOM sind „Overlays“ (siehe BASCOM-Hilfe). Die über UART empfangenen Zeichen „Z(n)“ werden zum String „S“ zusammengesetzt. Bei jeder Übertragung werden 31 Zeichen „N“ gesendet, die ersten vier Zeichen „L“ geben an, um welche Art von Daten es sich handelt und was der ATmega damit machen soll (Select Case, Case...): If N > 30 Then L = Left(s , 4) Select Case L Case "TEST": ... Case "TIME": - 15 - ... Case "SETT": ... Case "SUNS": ... Case "DATE": ... Case "CDAT": ... End Select End If Der „Case“ TEST ist der einfachste Fall, hier wird der empfangene String an den PC zurück gesendet. Das dient zur Kontrolle, ob die Kommunikation zwischen Kalenderuhr und PC funktioniert: ... Case "TEST": N = 0 Print S; ... N muss nach jeder CASE-Anweisung wieder auf 0 gesetzt werden. Schreiben & Lesen von Daten & Zeiteinstellung Zeiteinstellungen Datum, Wochentag und Uhrzeit können über folgende Unterprozeduren gesetzt werden (man beachte jeweils das I2Cwbyte nach Ds1307w): Const Ds1307w = &HD0 'DS1307 schreiben ... Setdate: _day = Makebcd(_day) : _month = Makebcd(_month) : _year = Makebcd(_year) I2cstart I2cwbyte Ds1307w I2cwbyte 4 I2cwbyte _day I2cwbyte _month I2cwbyte _year I2cstop Waitms 10 Return Setweekday: I2cstart I2cwbyte Ds1307w I2cwbyte 3 I2cwbyte Weekday I2cstop Waitms 10 Return Settime: _sec = Makebcd(_sec) : _min = Makebcd(_min) : _hour = Makebcd(_hour) I2cstart I2cwbyte Ds1307w I2cwbyte 0 I2cwbyte _sec I2cwbyte _min I2cwbyte _hour I2cstop Waitms 10 Return - 16 - Zeit und Datum lassen sich in BASCOM aber auch komfortabel über die Variablen Time$ und Date$ setzen. Die Echtzeituhr verfügt außerdem über 56 Byte batteriegepuffertes NV SRAM. In diesem werden diverse Einstellungen der Kalenderuhr gespeichert. Nachfolgend die Angabe, ob momentan Sommerzeit (Stset=1, Wtset=0) oder Winterzeit (Stset=0, Wtset=1) ist (man beachte wieder das I2Cwbyte nach Ds1307w): Const Ds1307w = &HD0 ... Writenvram: I2cstart I2cwbyte Ds1307w I2cwbyte 8 I2cwbyte Stset I2cwbyte Wtset I2cstop Waitms 10 Return 'DS1307 schreiben Die Zeitdaten, die das Programm über den PC empfängt (siehe Empfang von Daten über das UART), sehen folgendermaßen aus: TIME :07.04.1140121:56:57xxxxxx TIME kennzeichnet, dass es sich um eine Zeitübertragung handelt 07.04.11 ist das Datum 4 ist der Wochentag (Donnerstag) 01 zeigt an, dass wir Sommerzeit haben (10 wäre Winterzeit) 21:56:57 ist die Uhrzeit xxxxxx ist einfach ein Platzhalter, da immer 31 Zeichen übertragen werden. Die Echtzeituhr wird dann wie folgt eingestellt: ... Case "TIME": N = 0 Time$ = Mid(s , 18 , 8) Date$ = Mid(s , 7 , 8) Weekdayst = Mid(s , 15 , 1) Weekday = Weekdayst Call Setweekday Wtsetst = Mid(s , 16 , 1) Stsetst = Mid(s , 17 , 1) Wtset = Val(wtsetst) Stset = Val(stsetst) Call Writenvram ... Aus dem empfangenen String „s“ werden Zeit und Datum über die Mid-Anweisung extrahiert und gesetzt. Der Wochentag „Weekday“ wird über Call Setweekday gesetzt. Ob momentan Sommerbzw. Winterzeit vorliegt, wird in das NV SRAM über Call Writenvram geschrieben. - 17 - Einstellen von Sommerzeit und Winterzeit Sommer- und Winterzeit werden von der Kalenderuhr automatisch eingestellt (Letzter Sonntag im März oder Oktober). Wichtig ist, dass bei einer Zeitübertragung vom PC aus immer angegeben werden muss, ob momentan Sommerzeit oder Winterzeit vorliegt. Bei einer Übertragung werden die Variablen Stset und Wtset im NV SRAM gespeichert und von der nachfolgenden Routine ausgewertet: Dst_onoff: If _month = 3 And _day > 24 And Weekday = 7 And _hour = 2 Then _hour = _hour + 1 Waitms 10 Call Settime Stset = 1 Wtset = 0 Waitms 10 Call Writenvram End If If Wtset = 0 And _month = 10 And _day > 24 And Weekday = 7 And _hour = 3 Then _hour = _hour - 1 Waitms 10 Call Settime Wtset = 1 Stset = 0 Waitms 10 Call Writenvram End If Return Die Anweisung _hour = _hour + 1 bzw. _hour = _hour – 1 stellt die Uhr eine Stunde vor bzw. zurück. Über Call Settime wird die Uhrzeit gespeichert und die aktuellen Variablen Wtset und Stset werden im NV SRAM gespeichert (Call Writenvram). Die Subroutine Dst_onoff wird in der Hauptprogrammschleife aufgerufen. Weitere Einstellungen Weitere Einstellungen, die NV SRAM gespeichert werden, ist der Modus der Hintergrundbeleuchtung und die Zeitkorrektur. Die Variablen werden über das PC-Programm gesendet (siehe Empfang von Daten über das UART) und im NV SRAM abgelegt. Der gesendete String ist folgendermaßen aufgebaut: SETT: 310300000000000000000000x SETT kennzeichnet, dass es sich um eine Einstellung handelt 3 bedeutet, dass die Hintergrundbeleuchtung auf Auto gestellt werden soll (1 = AN; 2=AUS) 1 bedeutet, dass die nachfolgende Sekundenzahl immer nach 24h abgezogen wird (Zeitkorrektur) ; 0 würde bedeuten, dass die nachfolgende Sekundenzahl immer nach 24h addiert wird 03 ist die Zahl der Sekunden, um die nach 24h korrigiert wird die restlichen Nullen und das x sind Platzhalter, da immer 31 Zeichen übertragen werden. Um die Zeitkorrektur nach 24h durchzuführen, muss die Kalenderuhr wissen, wann die Korrektur- 18 - daten übertragen wurden. Dazu werden die BASCOM-Routinen Sysday() und Secofday() aufgerufen und die Ergebnisse zusammen mit den übertragenen Daten im NV SRAM abgelegt (Call Writenvram_sett). Die Definition der Variablen als „Overlay“ ermöglicht eine direkte Transformation der Variablen (Systemtag, Sekdestages) als abspeicherbare Bytes (Systemtagby, Sekdestagesby): Dim Systemtag As Long Dim Systemtagby(4) As Byte At Systemtag Overlay Dim Sekdestages As Long Dim Sekdestagesby(4) As Byte At Sekdestages Overlay ... Case "SETT": N = 0 Systemtag = Sysday() Sekdestages = Secofday() Call Writenvram_sett Call Readnvram ... Die Zeichen aus der Datenübertragung vom PC können direkt im NV SRAM abgelegt werden; Z(7) ist z.B. das 7. übertragene Zeichen. Das I2Cwbyte nach Ds1307w ist diesmal 10, da 8 und 9 bereits belegt sind (siehe Writenvram): Writenvram_sett: I2cstart I2cwbyte Ds1307w I2cwbyte 10 I2cwbyte Z(7) I2cwbyte 0 I2cwbyte Z(8) I2cwbyte 0 I2cwbyte Z(9) I2cwbyte Z(10) I2cwbyte 0 I2cwbyte Systemtagby(1) I2cwbyte Systemtagby(2) I2cwbyte Systemtagby(3) I2cwbyte Systemtagby(4) I2cwbyte Sekdestagesby(1) I2cwbyte Sekdestagesby(2) I2cwbyte Sekdestagesby(3) I2cwbyte Sekdestagesby(4) I2cstop Waitms 10 Return Da wichtige Einstellungsvariablen nicht im RAM des ATmega gelandet sind, muss der gerade ins NV SRAM geschriebene Inhalt sofort wieder über Call Readnvram gelesen werden (hier erfolgt dann die Zuordnung der Daten aus dem NV SRAM zu Variablen): Dim Lcd_blst As String * 1 Dim Lcd_blby(2) As Byte At Lcd_blst Overlay Dim Plusminst As String * 1 Dim Plusminby(2) As Byte At Plusminst Overlay Dim Sekundest As String * 2 Dim Sekundeby(3) As Byte At Sekundest Overlay - 19 - Dim Systemtag As Long Dim Systemtagby(4) As Byte At Systemtag Overlay Dim Sekdestages As Long Dim Sekdestagesby(4) As Byte At Sekdestages Overlay ... Readnvram: I2cstart I2cwbyte Ds1307w I2cwbyte 8 I2cstart I2cwbyte Ds1307r I2crbyte Stset , Ack I2crbyte Wtset , Ack I2crbyte Lcd_blby(1) , Ack I2crbyte Lcd_blby(2) , Ack I2crbyte Plusminby(1) , Ack I2crbyte Plusminby(2) , Ack I2crbyte Sekundeby(1) , Ack I2crbyte Sekundeby(2) , Ack I2crbyte Sekundeby(3) , Ack I2crbyte Systemtagby(1) , Ack I2crbyte Systemtagby(2) , Ack I2crbyte Systemtagby(3) , Ack I2crbyte Systemtagby(4) , Ack I2crbyte Sekdestagesby(1) , Ack I2crbyte Sekdestagesby(2) , Ack I2crbyte Sekdestagesby(3) , Ack I2crbyte Sekdestagesby(4) , Nack I2cstop Return Bei jedem Reset oder direkt nach dem Einschalten der Kalenderuhr wir vor der Hauptprogrammschleife Call Readnvram ausgeführt. Zeitkorrektur Die DS1307-RTC + Quarz ist nicht unbedingt ein hochpräzises Zeitmessinstrument, was am Quarz liegen kann oder allgemein am Aufbau. Die nachfolgende Subroutine korrigiert die Uhrzeit alle 24h zu einer bestimmten Uhrzeit um +/– x Sekunden. Die nachfolgende Routine ist recht komplex, was daran liegt, dass die Zeitkorrektur erst am darauffolgenden Tag passieren darf und dass bei einer negativen Zeitkorrektur die Kalenderuhr nicht in einer Korrekturschleife hängen bleibt. Sekundest (Sekunde, um die korrigiert wird) und Plusminst (Zeitkorrektur + oder – ) werden aus dem NV SRAM gelesen (Readnvram) (über „Overlay“ umgewandelt), ebenso Systemtag (Datum der Zeitkorrekturübertragung) und Sekdestages (Sekunde des Tages, an dem die Zeitkorrekturübertragung stattfand) (siehe vorheriger Abschnitt): Dim Korrektur As Long Dim Sekundelong As Long Dim Sysd As Long Dim Secd As Long Dim Zeitkorrekturbit As Bit ... Zeitkorrektur: Call Readnvram Sysd = Sysday() Secd = Secofday() Sekundelong = Val(sekundest) If Secd = 86399 Then Zeitkorrekturbit = 0 - 20 - If Plusminst = "0" Then Korrektur = Sekdestages + Sekundelong If Plusminst = "1" Then Korrektur = Sekdestages - Sekundelong If Sysd <> Systemtag And Secd = Sekdestages And Sekundelong <> 0 And Zeitkorrekturbit = 0 Then Time$ = Time(korrektur) Zeitkorrekturbit = 1 End If Return ' Sysd und Secd entsprechen der aktuellen Systemsekunde und dem aktuellen Systemdatum. Nur wenn diese nicht den gespeicherten Daten entsprechen, wird die Zeitkorrektur angewendet (letzte If-Then-Else-Anweisung). Die Zeit wird über die BASCOM-Funktion Time aus der korrigierten Sekunde des Tages eingestellt (Time$ = Time(korrektur)). Danach muss das Zeitkorrekturbit auf 1 gesetzt werden, um zu verhindern, dass bei einer negativen Korrektur die Zeit immer wieder neu eingestellt wird. Am Ende des Tages wird das Zeitkorrekturbit wieder auf 0 gesetzt (If Secd = 86399 Then Zeitkorrekturbit = 0). Sonnenaufgänge und Sonnenuntergänge speichern und abrufen Sonnenaufgänge und Sonnenuntergänge für einen bestimmten Standort zu berechnen, ist recht aufwendig, so dass diese Daten nur übertragen (siehe Empfang von Daten über das UART) und im EEPROM abgespeichert werden. Der gesendete String ist folgendermaßen aufgebaut: SUNS: 421704:2420:280000000000x SUNS kennzeichnet, dass es sich um einen Sonnenauf/untergang handelt 4217 ist der Tag des Sonnenauf/untergangs (gerechnet ab dem 01.01.2000) 04:24 ist der Zeitpunkt des Sonnenaufgangs 20:28 ist der Zeitpunkt des Sonnenuntergangs die restlichen Nullen und das x sind Platzhalter, da immer 31 Zeichen übertragen werden. Die nachfolgende CASE-Anweisung ruft die Subroutine Eepromwsonne auf: ... Case "SUNS": N = 0 Call Eepromwsonne ... Const Eeprw = &HA0 Const Eeprr = &HA1 Dim Adresse_sonne As Word Dim Adresse_sonne_high As Byte Dim Adresse_sonne_low As Byte Dim X As Byte ... Eepromwsonne: N = 0 For X = 7 To 20 Adresse_sonne_high = High(adresse_sonne) - 21 - Adresse_sonne_low = Low(adresse_sonne) I2cstart I2cwbyte I2cwbyte I2cwbyte I2cwbyte I2cstop Eeprw Adresse_sonne_high Adresse_sonne_low Z(x) Waitms 10 Incr Adresse_sonne Next If Adresse_sonne > 1399 Then Adresse_sonne = 0 '14 bytes pro sonnenauf/-untergang / Return Da es sich um ein größeres EEPROM handelt, muss man den Adressbereich in High- und Low trennen, was BASCOM praktischerweise über die Funktionen High und Low erledigt. Ansonsten muss man noch beachten, dass von jedem übertragenen String nur die Zeichen 7 bis 20 gespeichert (For X = 7 To 20....I2cwbyte Z(x)...). Nach 100 übertragenen Tagen wird die Adresse wieder auf 0 gesetzt. Gelesen werden diese Daten über die nachfolgende Funktion. Übergeben wird der Funktion als Argument die Adresse (adresse_sonne) und man erhält als Ergebnis einen String, der den Tag und die Uhrzeiten für Sonnenaufgang bzw. Sonnenuntergang beinhaltet: Const Eeprw = &HA0 Const Eeprr = &HA1 Dim Sonnetagst As String * 14 Dim Sonnetagby(14) As Byte At Sonnetagst Overlay Dim Dim Dim Dim Adresse_sonne As Word Adresse_sonne_high As Byte Adresse_sonne_low As Byte X As Byte Dim Dim Dim Dim Dim Dim Dim Dim Stageeprom As String * 14 Stageepromday As String * 4 Sahst As String * 2 Sarest As String * 3 Suhst As String * 2 Surest As String * 3 Sahstn As Integer Suhstn As Integer ... Function Eepromrsonne(adresse_sonne As Word) As String * 14 For X = 1 To 14 Adresse_sonne_high = High(adresse_sonne) Adresse_sonne_low = Low(adresse_sonne) I2cstart I2cwbyte Eeprw I2cwbyte Adresse_sonne_high I2cwbyte Adresse_sonne_low I2cstart I2cwbyte Eeprr I2crbyte Sonnetagby(x) , Nack I2cstop - 22 - Incr Adresse_sonne Next Stageeprom = Sonnetagst Stageepromday = Left(stageeprom , 4) If Stset = 1 And Wtset = 0 Then Sahst = Mid(stageeprom , 5 , 2) Sarest = Mid(stageeprom , 7 , 3) Suhst = Mid(stageeprom , 10 , 2) Surest = Mid(stageeprom , 12 , 3) Sahstn = Val(sahst) Incr Sahstn Sahst = Str(sahstn) Sahst = Format(sahst , "00") Suhstn = Val(suhst) Incr Suhstn Suhst = Str(suhstn) Suhst = Format(suhst , "00") Stageeprom = Stageepromday + Sahst + Sarest + Suhst + Surest End If Eepromrsonne = Stageeprom End Function Auf den ersten Blick wirkt diese Funktion recht umfangreich, da ggf. die Sommerzeit berücksichtigt werden muss. Eigentlich werden sonst nur 14 Bytes zu einem String zusammengesetzt, der den Tag und die Uhrzeiten für Sonnenaufgang bzw. Sonnenuntergang beinhaltet. Geburtstagstermine und Feiertage (kurz Termine) speichern und abrufen Im Vergleich zur Sonnenaufgangs- oder Sonnenuntergangsdaten sind die Funktionen, um Geburtstage und Feiertage im EEPROM abzuspeichern oder von dort zu lesen etwas komplexer. Das liegt hauptsächlich darin begründet, dass die Anzahl der abzuspeichernden Daten nicht konstant ist (im Fall Sonnenaufgänge und Sonnenuntergänge waren es genau 100) und das zu bestimmten Terminen bestimmte Aktionen ausgeführt werden sollen. Als erstes muss bei jeder Datenübertragung vom PC die Startadresse der Datenspeicherung auf Ihren Ursprungswert zurück gesetzt werden, da der ATmega nicht weiß, ob jetzt der erste oder irgendeinen nachfolgender Termin gesendet wird. Dazu wird vom PC vor der eigentlichen Datenübertragung folgender String gesendet (siehe Empfang von Daten über das UART): CDATxxxxxxxxxxxxxxxxxxxxxxxxxxx CDAT kennzeichnet, dass die Startadresse zur Terminspeicherung im EEPROM angesteuert werden soll die restlichen x sind Platzhalter, da immer 31 Zeichen übertragen werden. Die nachfolgende CASE-Anweisung setzt dann das EEPROM auf die Startadresse: - 23 - Dim Adresse_terminw As Word ... Case "CDAT": N = 0 Adresse_terminw = 0 ... Danach sendet der PC folgenden String (bzw. mehrere Strings, je nach der Anzahl der Termine): DATE0304195127780G1Klaus 1 DATE kennzeichnet, dass es sich um einen Termin handelt 03041951 ist das Geburtsdatum (03.04.1951) 27780 ist die Uhrzeit und gleichzeitig die Zeit, an der eine Melodie abgespielt wird; angegeben als Sekunde des Tages (07:43) G kennzeichnet, dass es sich um einen Geburtstag handelt (F = Feiertag) 1 ist die abzuspielende Melodie (0= Keine Melodie) Klaus ist das Geburtstagskind; bis zu 10 Zeichen sind hier möglich 1 kennzeichnet, dass 1 Termin übertragen wird (2 für 2 Termine, 3 für 3 usw.; max. 99). Am Ende der Übertragung werden zwei DATE-Strings gesendet, die nur Nullen enthalten, DATE000000000000000000000000000. Das hat den Zweck, das Ende der aktuell übertragenen Terminliste zu kennzeichnen. Da die Daten im EEPROM nicht gelöscht, sondern nur immer wieder überschrieben werden, könnte der Fall eintreten, dass eine evtl. vorher im EEPROM abgelegte Liste länger war als die gerade übertragene. Durch die beiden letzten DATE-Strings wird verhindert, dass die Termine der alten Liste auf der Kalenderuhr angezeigt werden. Die nachfolgende CASE-Anweisung ruft die Subroutine Eepromwtermine auf: ... Case "DATE": N = 0 Call Eepromwtermine ... Const Eeprw = &HA0 Const Eeprr = &HA1 Dim Adresse_terminw As Word Dim Adresse_termine14k As Word Dim Adresse_termine_high14k As Byte Dim Adresse_termine_low14k As Byte ... Eepromwtermine: N = 0 For X = 5 To 31 Adresse_termine14k = 1400 + Adresse_terminw Adresse_termine_high14k = High(adresse_termine14k) Adresse_termine_low14k = Low(adresse_termine14k) - 24 - I2cstart I2cwbyte I2cwbyte I2cwbyte I2cwbyte I2cstop Eeprw Adresse_termine_high14k Adresse_termine_low14k Z(x) Waitms 10 Incr Adresse_terminw Next Return Diese Subroutine ist analog zur Subroutine Eepromwsonne, mit dem Unterschied, dass die Startadresse mit 1400 addiert wird (sonst würden die Daten für den Sonnenaufgang bzw. Sonnenuntergang überschrieben werden) und dass die Startadresse am Ende nicht zurückgesetzt wird (das erledigt „CDAT“). Von jedem übertragenen String werden nur die Zeichen 5 bis 31 gespeichert (For X = 5 To 31....I2cwbyte Z(x)...). Gelesen werden diese Daten über die nachfolgende Funktion. Übergeben wird der Funktion als Argument die Speicheradresse eines Termins (adresse_termine) und man erhält als Ergebnis über die BASCOM-Funktion Dayofyear den Tag im Jahr, an dem das Ereignis stattfindet (Termindate): Const Eeprw = &HA0 Const Eeprr = &HA1 Dim Dim Dim Dim Adresse_termine As Word Adresse_termine14k As Word Adresse_termine_high14k As Byte Adresse_termine_low14k As Byte Dim Terminest As String * 28 Dim Termineby(28) As Byte At Terminest Overlay Dim Dim Dim Dim Dim Dim Dim Termine_t As String * 2 Termine_m As String * 2 Termine_j As String * 2 Termine_jv As String * 4 Termine_jvi As Integer Terminedatest As String * 8 Terminedate As Integer Dim Schaltjahr As Integer Dim Termine_ij As Integer ... Function Gettermintag(adresse_termine As Word) As Integer For X = 1 To 27 Adresse_termine14k = 1400 + Adresse_termine Adresse_termine_high14k = High(adresse_termine14k) Adresse_termine_low14k = Low(adresse_termine14k) I2cstart I2cwbyte Eeprw I2cwbyte Adresse_termine_high14k I2cwbyte Adresse_termine_low14k I2cstart I2cwbyte Eeprr I2crbyte Termineby(x) , Nack I2cstop - 25 - Incr Adresse_termine Next Termine_t = Left(terminest , 2) Termine_m = Mid(terminest , 3 , 2) Termine_j = Mid(terminest , 7 , 2) Termine_jv = Mid(terminest , 5 , 4) Terminedatest = Termine_t + "." + Termine_m + "." + Termine_j Terminedate = Dayofyear(terminedatest) Termine_ij = Val(termine_j) Schaltjahr = Termine_ij Mod 4 If Schaltjahr = 0 And Terminedate > 59 Then Decr Terminedate End If 'Schaltjahr Gettermintag = Terminedate End Function Zuerst muss das im EEPROM abgelegte Datum (z.B. 03041951) in ein für die Funktion Dayofyear verwertbares Datumsformat umgeformt werden (aus 030411951 wird 03.04.1951). Das Jahr wird noch einmal extra als Zahl in die Variable Termine_ij geschrieben. Wenn man mit Dayofyear arbeitet, muss man wissen, ob das Jahr ein Schaltjahr ist. Das lässt sich bequem über die Anweisung Schaltjahr = Termine_ij Mod 4 ermitteln (jedes Schaltjahr zwischen 1901 und 2099 ist ohne Rest durch 4 teilbar). Das betrifft natürlich nur Termine nach dem 28. Februar (...Terminedate > 59). Für die Nutzung der Terminfunktion der Kalenderuhr sind aber noch ein paar weitere Funktionen nötig. Die folgende Funktion, Getterminadresse, ermittelt die Speicheradresse eines bestimmten Termins im EEPROM. Übergeben wird der Funktion als Argument der Tag heute, der über die BASCOM-Funktion Dayofyear(Date$) in der Hauptprogrammschleife erzeugt wird und man erhält als Ergebnis die Speicheradresse des Termins des heutigen Tages: Dim Maxadressew As Word Dim Heute As Integer Dim Alarm_heute As Bit ... Function Getterminadresse(heute As Integer) As Word Maxadressew = Getmaxadressetermine(0) For Adresse_termine = 0 To Maxadressew Step 27 Terminedate = Gettermintag(adresse_termine) If Terminedate = Heute Then Alarm_heute = 1 Else Alarm_heute = 0 If Terminedate >= Heute Then Exit For Next Getterminadresse = Adresse_termine End Function Hauptsächlich bedient sich diese Funktion der Ergebnisse der Funktionen Getmaxadressetermine und Gettermintag. Falls der heutige Tag ein besonderer Tag ist - 26 - (Geburtstag oder Feiertag), setzt die Funktion die Variable Alarm_heute auf 1. Die Funktion Getmaxadressetermine ermittelt die Speicheradresse des letzten Termins einer Reihe von Terminen. Übergeben wird der Funktion als Argument adresse_termine (Speicheradresse eines bestimmten Termins), das aber im Programm immer 0 ist. Es wäre also nicht wirklich notwendig gewesen, die nachfolgenden Anweisungen in eine Funktion zu packen, der Übersichtlichkeit halber habe ich es aber so gelassen. Als Ergebnis erhält man die oben erwähnte Speicheradresse des letzten Termins: Const Eeprw = &HA0 Const Eeprr = &HA1 Dim Maxadressew As Word Dim Maxadressest As String * 2 ... Function Getmaxadressetermine(adresse_termine As Word) As Word For X = 1 To 27 Adresse_termine14k = 1400 + Adresse_termine Adresse_termine_high14k = High(adresse_termine14k) Adresse_termine_low14k = Low(adresse_termine14k) I2cstart I2cwbyte Eeprw I2cwbyte Adresse_termine_high14k I2cwbyte Adresse_termine_low14k I2cstart I2cwbyte Eeprr I2crbyte Termineby(x) , Nack I2cstop Incr Adresse_termine Next Maxadressest = Mid(terminest , 26 , 2) Maxadressew = Val(maxadressest) Maxadressew = Maxadressew * 27 Getmaxadressetermine = Maxadressew End Function Die Funktion setzt den ersten im EEPROM gespeicherten Termin-String wieder zusammen. Die letzten zwei Zeichen des Strings (Maxadressest = Mid(terminest , 26 , 2)) enthalten die maximale Anzahl an übertragenen Datensätzen (siehe DATE-String). Daraus lässt sich dann die Speicheradresse des letzten Termins ermitteln. Die Funktionen Eepromrtermine gibt einen im EEPROM abgelegten String aus. Übergeben wird der Funktion als Argument adresse_termine, also die Speicheradresse eines bestimmten Termins: Const Eeprw = &HA0 Const Eeprr = &HA1 Dim Dim Dim Dim Termine_t As Termine_m As Termine_p As Terminelcdst String * 2 String * 2 String * 10 As String * 16 - 27 - ... Function Eepromrtermine(adresse_termine As Word) As String * 16 For X = 1 To 27 Adresse_termine14k = 1400 + Adresse_termine Adresse_termine_high14k = High(adresse_termine14k) Adresse_termine_low14k = Low(adresse_termine14k) I2cstart I2cwbyte Eeprw I2cwbyte Adresse_termine_high14k I2cwbyte Adresse_termine_low14k I2cstart I2cwbyte Eeprr I2crbyte Termineby(x) , Nack I2cstop Incr Adresse_termine Next Termine_t = Left(terminest , 2) Termine_m = Mid(terminest , 3 , 2) Termine_p = Mid(terminest , 16 , 10) Terminelcdst = Termine_t + "." + Termine_m + " " + Termine_p If Termine_t = "00" Then Terminelcdst = Space(16) Eepromrtermine = Terminelcdst End Function Die Funktion setzt im ersten Schritt einen im EEPROM gespeicherten Termin-String wieder zusammen. Dabei wird aus „0304195127780G1Klaus 1“ „03.04 Klaus „. Das sind dann genau 16 Zeichen, entsprechend der Anzeigegröße des LCD-Moduls. Das Ergebnis wird in der Variable Terminelcdst gespeichert. Falls der Termin-String nur Nullen enthält (bzw. die ersten beiden Zeichen 00 sind), werden 16 Leerzeichen ausgegeben (If Termine_t = "00" Then Terminelcdst = Space(16)). Eine letzte Funktion in diesem Zusammenhang ist Eepromrtermine_alarm. Übergeben wird der Funktion als Argument adresse_termine, also die Speicheradresse eines bestimmten Termins. Als Ergebnis ermittelt die Funktion die Sekunde des Tages, an dem ggf. eine Melodie abgespielt werden soll: Const Eeprw = &HA0 Const Eeprr = &HA1 Dim Termine_sek As String * 5 Dim Termine_mu As String * 1 Dim Termine_geburtstag As String * 1 Dim Termine_alarml As Long ... Function Eepromrtermine_alarm(adresse_termine As Word) As Long For X = 1 To 27 Adresse_termine14k = 1400 + Adresse_termine Adresse_termine_high14k = High(adresse_termine14k) Adresse_termine_low14k = Low(adresse_termine14k) I2cstart I2cwbyte Eeprw I2cwbyte Adresse_termine_high14k - 28 - I2cwbyte Adresse_termine_low14k I2cstart I2cwbyte Eeprr I2crbyte Termineby(x) , Nack I2cstop Incr Adresse_termine Next Termine_sek = Mid(terminest , 9 , 5) Termine_mu = Mid(terminest , 15 , 1) Termine_geburtstag = Mid(terminest , 14 , 1) 'Musik abspielen? 'Geburtstag oder Feiertag Termine_alarml = Val(termine_sek) Eepromrtermine_alarm = Termine_alarml End Function Die Funktion ermittelt wie beschrieben aus einem im EEPROM gespeicherten Termin-String die Sekunde des Tages (Termine_sek), die Information, ob Musik abgespielt werden soll und welche (Termine_mu) und die Information, ob es sich um einen Geburtstag oder Feiertag handelt (Termine_geburtstag) (siehe dazu auch DATE-String). Die Variablen Termine_mu und Termine_geburtstag werden zwar nicht direkt als Ergebnis der Funktion übermittelt, werden aber innerhalb der Funktion mit Werten gefüllt, die in der Hauptprogrammschleife abgerufen werden. Ausgabe von gespeicherten Daten auf dem 16x4-LCD-Modul Sämtliche gespeicherten Daten, sowie Datum & Uhrzeit werden innerhalb der Hauptprogrammschleife ausgegeben. Durch drücken des Tasters kann zwischen verschiedenen Ausgabebildschirmen umgeschaltet werden. Die Zahl der Tastendrücke wird über eine CASE-Anweisung ausgewertet (siehe Anzeige von Uhrzeit, Datum, Geburtstagen, Feiertagen etc. (Übersicht)). Der erste Ausgabebildschirm zeigt normalerweise Wochentag, Datum und Uhrzeit an. Liegt ein besonderer Termin vor, wir dieser angezeigt: Dim Adresse_termine As Word Dim Termine_geburtstag As String * 1 Dim Termine_alarmst As String * 6 Dim Termine_alarml As Long Dim Alarm_heute As Bit Dim Termin_heute As String * 16 Dim Termine_jv As String * 4 Dim Termine_jvi As Integer Dim Bdate As String * 2 Dim Bdatei As Integer Dim Alter As Integer Dim Spaces As Integer ... Select Case Cntb1 Case 0: If Alarm_heute = 1 Then Adresse_termine = Getterminadresse(heute) Termin_heute = Eepromrtermine(adresse_termine) Termin_heute = Mid(termin_heute , 7 , 10) - 29 - Termine_alarml = Eepromrtermine_alarm(adresse_termine) Termine_alarmst = Time(termine_alarml) Termine_alarmst = Left(termine_alarmst , 5) Bdate = Mid(datestr , 7 , 2) Bdate = "20" + Bdate Termine_jvi = Val(termine_jv) Bdatei = Val(bdate) Alter = Bdatei - Termine_jvi Locate 1 , 1 : Lcd "Heute " ; Termin_heute If Termine_geburtstag = "G" Then Locate 2 , 1 : Lcd Termine_alarmst ; " " ; Termine_jv ; " " ; Alter ; " J" Else Locate 2 , 1 : Lcd Termine_alarmst ; Spc(11) End If Locate 3 , 1 : Lcd Date$ ; Spc(8) Locate 4 , 1 : Lcd Time$ ; Spc(8) Else Spaces = Len(weekdaystr) Spaces = 16 - Spaces Locate Locate Locate Locate 1 2 3 4 , , , , 1 1 1 1 : : : : Lcd Lcd Lcd Lcd "Datum & Uhrzeit " Weekdaystr ; Spc(spaces) Date$ ; Spc(8) Time$ ; Spc(8) End If ... Ob ein besonderer Termin vorliegt, gibt die Variable Alarm_heute an. Die auszugebenden Daten werden aus dem EEPROM geladen. Die entsprechenden Funktionen dazu (Getterminadresse, Eepromrtermine, Eepromrtermine_alarm) wurden im vorangegangenen Kapitel vorgestellt. Das Alter (Variable Alter) des Geburtstagskindes wird ebenfalls berechnet. Die Ausgabe eines Feiertages oder Geburtstages ist unterschiedlich. Die Variable Termine_geburtstag zeigt an, ob es sich bei dem Termin um einen Feiertag (F) oder Geburtstag (G) handelt. Der Variablen wird durch das Aufrufen der Funktion Eepromrtermine_alarm der entsprechende Wert zugewiesen. Die verschiedenen Ausgabebildschirme sind in Abbildung 10 dargestellt. Der nächste Ausgabebildschirm zeigt die nächsten 3 anstehenden Termine: Dim Adresse_termine As Word Dim Heute As Integer Dim Maxadressew As Word Dim Eepromrtermine_heute As String * 17 ... Case 1: Heute = Dayofyear(date$) Maxadressew = Getmaxadressetermine(0) Adresse_termine = Getterminadresse(heute) Eepromrtermine_heute = Eepromrtermine(adresse_termine) If Adresse_termine > Maxadressew Then Adresse_termine = 0 Locate 1 , 1 : Lcd "Termine" ; Spc(9) If Eepromrtermine_heute <> " " Then Locate 2 , 1 : Lcd Eepromrtermine(adresse_termine) Else Adresse_termine = 0 Locate 2 , 1 : Lcd Eepromrtermine(adresse_termine) - 30 - End If Adresse_termine = Adresse_termine + 27 Locate 3 , 1 : Lcd Eepromrtermine(adresse_termine) Adresse_termine = Adresse_termine + 27 Locate 4 , 1 : Lcd Eepromrtermine(adresse_termine) ... Zuerst wird der Variablen Heute der Tag des Jahres zugewiesen. Die Variable Maxadressew enthält die Gesamtzahl der Termine. Sollte der letzte Termin erreicht sein, wird Adresse_termine auf null gesetzt. Das bedeutet, nachdem der letzte im EEPROM abgelegte Termin angezeigt wurde, wird wieder der erste im EEPROM abgelegte Termin angezeigt. Nachdem die Adresse des ersten anzuzeigenden Termins bekannt ist, werden einfach die beiden nächsten abgespeicherten Termine angezeigt (Adresse_termine = Adresse_termine + 27). Damit nicht irgendwann Termine aus einer alten Terminliste oder Datenmüll angezeigt wird, enthalten die letzten beiden im EEPROM abgelegten Einträge nur Nullen (siehe DATE-String). Die Funktionen Getmaxadressetermine, Getterminadresse und Eepromrtermine wurden im vorangegangenen Kapitel vorgestellt. Der Ausgabebildschirm ist in Abbildung 10 dargestellt. Im nächsten Ausgabebildschirm werden die Uhrzeiten für die Sonnenaufgänge bzw. Sonnenuntergänge der heutigen Tages und der folgenden 2 Tage angegeben. Der Übersichtlichkeit halber, werden im folgenden Abschnitt Funktionsaufrufe und Berechnungen teilweise ausführlicher dargestellt, als eigentlich für die Funktion der Kalenderuhr notwendig. Dim Dim Dim Dim Dim Dim Dim Dim Stageeprom As String * 14 Stageepromday As String * 4 Sahst As String * 2 Sarest As String * 3 Suhst As String * 2 Surest As String * 3 Sahstn As Integer Suhstn As Integer Dim Sa As String * 5 Dim Su As String * 5 Dim Sysdx As Long Dim Sysdw As Word Dim Systemtageepr As String * 5 Dim Systemtageeprl As Long ... Case 2: Sa = Eepromrsonne(0) Systemtageepr = Mid(sa , 1 , 4) Systemtageeprl = Val(systemtageepr) Sysdx = Sysday() Sysdw = Sysdx - Systemtageeprl Sysdw = Sysdw * 14 Sa = Eepromrsonne(sysdw) Sa = Mid(sa , 5 , 5) Su = Eepromrsonne(sysdw) Su = Mid(su , 10 , 5) Locate 1 , 1 : Lcd "SonnenA/U 3 Tage" Locate 2 , 1 : Lcd "A " ; Sa ; Spc(2) ; "U " ; Su Sysdx = Sysday() Sysdx = Sysdx + 1 - 31 - Sysdw = Sysdx - Systemtageeprl Sysdw = Sysdw * 14 Sa = Eepromrsonne(sysdw) Sa = Mid(sa , 5 , 5) Su = Eepromrsonne(sysdw) Su = Mid(su , 10 , 5) Locate 3 , 1 : Lcd "A " ; Sa ; Spc(2) ; "U " ; Su Sysdx = Sysday() Sysdx = Sysdx + 2 Sysdw = Sysdx - Systemtageeprl Sysdw = Sysdw * 14 Sa = Eepromrsonne(sysdw) Sa = Mid(sa , 5 , 5) Su = Eepromrsonne(sysdw) Su = Mid(su , 10 , 5) Locate 4 , 1 : Lcd "A " ; Sa ; Spc(2) ; "U " ; Su ... Zuerst wird der erste im EEPROM gespeicherte String über die Funktion Eepromrsonne abgefragt (siehe dazu auch Sonnenaufgänge und Sonnenuntergänge speichern und abrufen). Aus diesem String wird der (System)Tag (gerechnet ab dem 01.01.2000) ermittelt (Systemtageeprl). Danach wird der aktuelle Systemtag über die BASCOM-Funktion Sysday ermittelt. Über die Subtraktion des aktuellen Systemtages mit dem ersten gespeicherten Systemtag (Sysdw = Sysdx - Systemtageeprl) erhält man nach der Multiplikation mit 14 (Sysdw = Sysdw * 14) die Speicheradresse des heutigen Tages im EEPROM. Der gespeicherte String, der die Daten des heutigen Tages enthält, wird über die Funktion Eepromrsonne ermittelt. Aus diesem String werden die Zeitangaben für den Sonnenaufgang (Sa) und Sonnenuntergang (Su) ermittelt. Für die Anzeige der Daten des nächsten Tages wird der aktuelle Systemtag mit 1 addiert (Sysdx = Sysdx + 1) , für den übernächsten Tag mit 2 (Sysdx = Sysdx + 2). Der Ausgabebildschirm ist in Abbildung 10 dargestellt. Der nächste Ausgabebildschirm (Case 3)widmet sich der manuellen Einstellung von Wochentag, Datum und Zeit (Abbildung 10). Auf eine ausführliche Erläuterung dieses Programmteils wird an dieser Stelle verzichtet, da sich Datum und Zeit bequemer über das PC-Programm einstellen lassen (siehe Zeiteinstellungen). Abspielen einer Melodie Ob eine und wann eine Melodie abgespielt wird, wird in der Hauptprogrammschleife ermittelt: Dim Adresse_termine As Word Dim Termine_alarml As Long Dim Alarm_heute As Bit Dim Termin_heute As String * 16 Dim Termine_mu As String * 1 ... Heute = Dayofyear(date$) ... Adresse_termine = Getterminadresse(heute) Termine_alarml = Eepromrtermine_alarm(adresse_termine) If Termine_alarml = Secofday() And Alarm_heute = 1 And Termine_mu <> "0" Then Call Play_music(termine_mu) End If ... - 32 - Zuerst wird die Speicheradresse des heutigen Tages über die Funktion Getterminadresse ermittelt. Die Funktion Eepromrtermine_alarm ermittelt die Sekunde des Tages, an dem die Melodie abgespielt werden soll. Mit der If-Anweisung wird ermittelt, ob alle Bedingungen für das Abspielen einer Melodie erfüllt sind. Den Variablen Alarm_heute und Termine_mu werden Werte durch das Aufrufen der Funktionen Getterminadresse und Eepromrtermine_alarm zugewiesen. Die aktuelle Sekunde des Tages wird über die BASCOM-Funktion Secofday ermittelt. Ist diese Sekundenzahl gleich der Sekunde, die im EEPROM gespeichert wurde und ist der heutige Tag ein besonderer Tag und ist die Variable Termine_mu ungleich “0“, wird schließlich Call Play_music(termine_mu) ausgeführt. Der Subroutine Play_music wird die Nummer der abzuspielenden Melodie übergeben. Durch den Aufruf der Subroutine und der nachfolgenden Select Case...CaseAnweisungen wir die Melodie abgespielt: Lcd_bl Alias Portb.2 Config Lcd_bl = Output Config Portb.1 = Output Speaker Alias Portb.1 ... Dim Note As Integer Dim Laenge As Integer Dim Pause As Integer ... Sub Play_music(song_nr As String * 1) If Lcd_bl = 0 Then Lcd_bl = 1 Select Case Song_nr Case "1" For I = 0 To 55 Note = Lookup(i , Happyb) Incr I If Note = 0 Then Pause = Lookup(i , Happyb) Waitms Pause Else Laenge = Lookup(i , Happyb) Sound Speaker , Note , Laenge End If Next I Case "2" For I = 0 To 57 Note = Lookup(i , Merryx) Incr I If Note = 0 Then Pause = Lookup(i , Merryx) Waitms Pause Else Laenge = Lookup(i , Merryx) Sound Speaker , Note , Laenge End If Next I End Select ... Happyb: Data 65% , 587% , 65% , 587% , 147% , 523% , 131% , 587% , 175% Data 440% , 165% , 466% , 0% , 250% , 65% , 587% , 65% , 587% , 147% Data 523% , 131% , 587% , 196% , 392% , 175% , 440% , 0% , 250% , 65% Data 587% , 65% , 587% , 262% , 294% , 220% , 349% , 175% , 440% , 165% Data 466% , 147% , 523% , 0% , 125% , 117% , 330% , 117% , 330% , 220% Data 349% , 175% , 440% , 196% , 392% , 175% , 440% - 33 - Merryx: Data 147% , 523% , 196% , 392% , 98% , 392% , 110% , 349% , 98% , 392% Data 92% , 415% , 165% , 466% , 131% , 587% , 165% , 466% , 220% , 349% Data 110% , 349% , 124% , 311% , 110% , 349% , 98% , 392% , 185% , 415% Data 294% , 523% , 247% , 311% , 124% , 311% , 131% , 294% , 124% , 311% Data 110% , 349% , 196% , 392% , 165% , 466% , 73% , 523% , 73% , 523% Data 165% , 466% , 220% , 349% , 185% , 415% , 196% , 392% Die Tonausgabe erledigt in BASCOM die Anweisung Sound mit den Variablen Speaker, Note, Laenge. Speaker ist dabei ein Alias auf Portb.1 (siehe auch Schaltplan), die Werte für Note und Laenge werden über Lookup aus einer Data-Tabelle gelesen. Die Variable I in der For-Next-Anweisung gibt die Nummer des Wertes in der Tabelle an. Pausen (ohne Ton) werden über den Wert Note = 0 ermöglicht. Im oberen Code-Abschnitt sind zwei Melodien angegeben. Insgesamt wären 9 möglich. Beim Abspielen einer Melodie wird die Hintergrundbeleuchtung des LCD-Moduls eingeschaltet. Die Berechnung der Werte für die Variablen Note und Laenge wird im nächsten Kapitel erläutert. Programmstruktur des PC-Programms (tool.au3) Die Programmierung des PC-Programms erfolgte mit AutoIt v3. Die Datenübertragung nutzt die Bibliothek CommMG.au3 v2.8 von Martin Gibson. Die Programmoberfläche wurde mit Koda erstellt. Auf die Programmierung werde ich nachfolgend nicht so ausführlich eingehen, wie im vorangegangenen Kapitel. Der Programmcode ist (so denke ich) recht übersichtlich. Innerhalb der Hauptprogrammschleife werden über Switch und Case jeweils nach bestimmten Aktionen (Mausklick) bestimmte Programmteile ausgeführt. Der Befehl _CommSendString sendet die im Kapitel Empfang von Daten über das UART erwähnten Strings an die Kalenderuhr. Die Übertragung ist relativ langsam (dafür sicher), kann aber je nach System und Anbindung auch schneller erfolgen. Das muss man individuell austesten. Wenn die Kalenderuhr nur Datenmüll anzeigen sollte, erfolgt die Übertragung jedenfalls zu schnell für das System. Daneben enthält das Programm Funktionen, um Sonnenaufgänge bzw. Sonnenuntergänge und variable Feiertage, wie etwa die Osterfeiertage zu berechnen. Das Programm besteht aus 3 Tabs, die verschiedene Funktionen des Programms zusammenfassen. Diese Funktionen werden nachfolgend kurz vorgestellt. - 34 - Datum, Uhrzeit, Einstellungen, Sonnenaufgänge und Sonnenuntergänge Nach dem Öffnen des Programms wird folgender Tab gezeigt: Auswahl des COM-Ports Test-String senden TEST: Gesendet & Empfangen 1234 Sommerzeit? Datum und Zeit individuell einstellen Datum / Zeit senden Gesendeter String Datum und Zeit des PCs TIME :18.04.1110122:27:40xxxxxx Hintergrundbeleuchtung Einstellungen senden Zeitkorrektur Gesendeter String SETT: 100000000000000000000000x Fortschrittsbalken Sonnena./u. senden Abbildung 12: Erstes Tab (Registerkarte) des PC-Programms. Die dem Screenshot hinzugefügten Erläuterungen zu den Steuerfunktionen sind Blau gedruckt. Die Funktionen sind relativ selbsterklärend. Zuerst muss der passende COM-Port ausgewählt werden. Die Einstellung kann getestet werden, in dem man einen Test-String sendet. Datum und Uhrzeit können zu Testzwecken auf jeden beliebigen Wert eingestellt und übertragen werden. Sind die Häkchen bei Systemdatum und/oder Systemzeit gesetzt, wird das aktuelle Datum bzw. die aktuelle Uhrzeit des PCs übertragen (siehe Zeiteinstellungen). Einstellungen zur Hintergrundbeleuchtung und zur Zeitkorrektur können ebenfalls gesetzt und gesendet werden (siehe Weitere Einstellungen und Steuerung der Hintergrundbeleuchtung des LCD-Moduls). Als letzte Funktion auf diesem Tab können Sonnenaufgänge und Sonnenuntergänge an die Kalenderuhr gesendet werden (siehe Sonnenaufgänge und Sonnenuntergänge speichern und abrufen). Im Programmcode des AutoItSkripts müssen ggf. noch Breitengrad und Längengrad des Ortes angepasst werden. - 35 - Geburtstage und Feiertage Eine Liste von Geburtstagen und Feiertage kann im folgenden Tab angelegt, gespeichert und an die Kalenderuhr übertragen werden: (Geburts-)Datum(Geburts-)Zeit Geburtstag oder Feiertag? Ausgabetext (10 Zeichen) Welche Melodie? Gesendeter String Hinzufügen Fortschrittsbalken DATE3112201143200F0Silvester 15 Termine: Speichern / Laden / an die Kalenderuhr senden Abbildung 13: Zweites Tab (Registerkarte) des PC-Programms. Die dem Screenshot hinzugefügten Erläuterungen zu den Steuerfunktionen sind Blau gedruckt. Die Termine werden automatisch nach Datum (Tag und Monat) sortiert und können auf dem PC gespeichert und wieder geladen werden. Feiertage hinzufügen fügt automatisch eine Reihe von Feiertagen zur Terminliste hinzu. Das Datum der variablen Feiertage (Ostern, Pfingsten und Himmelfahrt) wird vom PC-Programm jeweils vorher berechnet. Momentan kann nur zwischen 2 Melodien bzw. keiner Melodie gewählt werden. Ohne größere Anpassung des Codes wären bis zu 9 Melodien möglich. Mit Senden wird die Terminliste schließlich übertragen (siehe Geburtstagstermine und Feiertage (kurz Termine) speichern und abrufen). - 36 - Der Melodiegenerator Das ist eine Funktion des Programms, die mit Hilfe des myAVR Boards Klingeltöne, wie sie etwa um das Jahr 2000 herum üblich waren, wieder abspielbar macht. Auf der folgenden Internetseite ist recht ausführlich erklärt, wie Noten für die BASCOM-Sound Anweisung umgesetzt werden können: http://www.mcselec.com/index.php?option=com_content&task=view&id=221&Itemid=57 Anhand der dort angegebenen Berechnungen, die hauptsächlich von der Frequenz des eingesetzten Quarzes abhängen, können z.B. über eine Tabellenkalkulation für jede mögliche Note die entsprechenden Werte ausgerechnet werden. Auf der nachfolgenden Internetseite finden sich z.B. noch jede Menge Klingeltöne, die einfach nur in das Programmfenster des PC-Programms kopiert werden müssen: http://www.xs4all.nl/~vbergen/ringtones/siemens/index_2000.html Name der Melodie Klingelton im Siemens (C25/S25/C35/S35/M35)-Format BASCOM-Code Abbildung 14: Drittes Tab (Registerkarte) des PC-Programms. Die dem Screenshot hinzugefügten Erläuterungen zu den Steuerfunktionen sind Blau gedruckt. - 37 - Im unteren Bereich steht der BASCOM-Code für den entsprechenden Klingelton bzw. die Melodie, der nur noch in das Programm eingefügt werden muss. Die entsprechenden Variablen wurden zu Programmbeginn deklariert. Fazit Soviel zum Projekt der Kalenderuhr. Fast alle Funktionen des myAVR Boards konnten genutzt werden. Nur die beiden Potis sind noch frei, sowie ein Pin des ATmega. Softwareseitig ist noch etwas Speicherplatz vorhanden, der mit weiteren Melodien oder mit Programmcode gefüllt werden kann, auch das EEPROM hat noch Platz für Daten. Der Programmcode bietet bestimmt dem einen oder anderen erfahrenen BASCOM-Programmierer noch Ansätze zum optimieren. Funktionsfähig ist er jedenfalls und läuft so wie er ist, seit einiger Zeit stabil. Ohne Hilfe hätte ich die Kalenderuhr niemals zum laufen bekommen. An erster Stelle soll hier die BASCOM-Hilfe stehen, die wirklich sehr umfangreich ist und schon viele Lösungsansätze bietet: http://avrhelp.mcselec.com/index.html Sehr hilfreich bei der Programmierung waren auch die folgenden Internetseiten: http://halvar.at/elektronik/kleiner_bascom_avr_kurs/ http://www.rn-wissen.de/index.php/Kategorie:Quellcode_Bascom http://www.rowalt.de/mc/index.htm Die im PC-Programm verwendeten Funktionen sind, soweit übernommen, dort gekennzeichnet. Hardwareseitig waren mir die von der Laser & Co. Solutions GmbH bereitgestellten Schaltpläne eine große Hilfe, so wurde der Aufbau fast zum Kinderspiel. Bei der Zusammenstellung von Texten und Abbildungen bin ich mit großer Sorgfalt vorgegangen. Trotzdem kann ich Fehler nicht vollständig ausschließen. Für fehlerhafte Angaben und deren Folgen kann ich weder irgendeine Haftung noch juristische Verantwortung übernehmen. Sebastian Dechert - 38 - BASCOM-Quellcode Die wichtigsten Programmteile werden im Kapitel Programmierung ausführlich erklärt. $regfile = "m168def.dat" $crystal = 3686400 $baud = 9600 $lib "i2c_twi.lbx" Config Sda = Portc.4 Config Scl = Portc.5 Const Ds1307w = &HD0 Const Ds1307r = &HD1 Const Eeprw = &HA0 Const Eeprr = &HA1 ' Config Timer1 = Timer , Prescale = 64 On Timer1 Toggle_colon Enable Timer1 Start Timer1 Enable Interrupts Config Lcdpin = Pin , Rs = Portc.0 , E = Portc.1 , Db4 = Portd.4 , Db5 = Portd.5 , Db6 = Portd.6 , Db7 = Portd.7 Config Lcd = 16 * 4 Cursor = Off Config Clock = User Config Date = Dmy , Separator = . On Urxc Onrxd Enable Urxc Config Pind.2 = 0 Config Pind.3 = 0 Portd.2 = 1 Portd.3 = 1 Lcd_bl Alias Portb.2 Config Lcd_bl = Output Config Portb.1 = Output Speaker Alias Portb.1 Config Portc.2 -1 = Output Config Adc = Single , Prescaler = Auto , Reference = Avcc Dim Licht As Word Dim Dim Dim Dim Dim Dim Dim Dim Dim Dim Dim Dim Dim Dim Dim Dim Dim Dim Dim Dim Dim Dim A As String * 10 B As String * 10 C As String * 10 D As Integer E As Integer F As Integer G As Integer H As Integer I As Integer J As Integer K As Integer Timestr As String * 10 Datestr As String * 10 Weekdaystr As String * 10 Colon_onoff As Bit Dp_onoff As Bit All_off As Bit Weekday As Byte Weekdayst As String * 1 Cntb1 As Integer Cntb2 As Integer Exitbyte As Byte - 39 - Dim Dim Dim Dim Stset As Byte Wtset As Byte Stsetst As String * 1 Wtsetst As String * 1 Dim Dim Dim Dim L As String * 4 S As String * 30 Z(31) As Byte At S Overlay N As Byte Dim Lcd_blst As String * 1 Dim Lcd_blby(2) As Byte At Lcd_blst Overlay Dim Plusminst As String * 1 Dim Plusminby(2) As Byte At Plusminst Overlay Dim Sekundest As String * 2 Dim Sekundeby(3) As Byte At Sekundest Overlay Dim Systemtag As Long Dim Systemtagby(4) As Byte At Systemtag Overlay Dim Sekdestages As Long Dim Sekdestagesby(4) As Byte At Sekdestages Overlay Dim Dim Dim Dim Dim Korrektur As Long Sekundelong As Long Sysd As Long Secd As Long Zeitkorrekturbit As Bit Dim Sonnetagst As String * 14 Dim Sonnetagby(14) As Byte At Sonnetagst Overlay Dim Dim Dim Dim Adresse_sonne As Word Adresse_sonne_high As Byte Adresse_sonne_low As Byte X As Byte Dim Dim Dim Dim Dim Dim Dim Dim Dim Xx As Word Stageeprom As String * 14 Stageepromday As String * 4 Sahst As String * 2 Sarest As String * 3 Suhst As String * 2 Surest As String * 3 Sahstn As Integer Suhstn As Integer Dim Sa As String * 5 Dim Su As String * 5 Dim Sysdx As Long Dim Sysdw As Word Dim Systemtageepr As String * 5 Dim Systemtageeprl As Long Dim Terminest As String * 28 Dim Termineby(28) As Byte At Terminest Overlay Dim Dim Dim Dim Dim Adresse_terminw As Word Adresse_termine As Word Adresse_termine14k As Word Adresse_termine_high14k As Byte Adresse_termine_low14k As Byte Dim Dim Dim Dim Dim Dim Dim Dim Dim Dim Termine_t As String * 2 Termine_m As String * 2 Termine_j As String * 2 Termine_x As String * 1 Termine_p As String * 10 Terminedatest As String * 8 Terminedate As Integer Heute As Integer Terminelcdst As String * 16 Maxadressest As String * 2 - 40 - Dim Maxadressew As Word Dim Schaltjahr As Integer Dim Termine_ij As Integer Dim Dim Dim Dim Dim Dim Dim Dim Dim Dim Dim Dim Dim Termine_sek As String * 5 Termine_mu As String * 1 Termine_geburtstag As String * 1 Termine_alarmst As String * 6 Termine_alarml As Long Alarm_heute As Bit Termin_heute As String * 16 Termine_jv As String * 4 Termine_jvi As Integer Bdate As String * 2 Bdatei As Integer Alter As Integer Spaces As Integer Dim Eepromrtermine_heute As String * 17 Dim Dummy As Byte Dim Note As Integer Dim Laenge As Integer Dim Pause As Integer Declare Declare Declare Declare Declare Declare Declare Declare Declare Declare Declare Declare Declare Declare Declare Declare Declare Declare Declare Declare Declare Sub Sub Sub Sub Sub Sub Sub Sub Sub Sub Sub Sub Sub Sub Sub Sub Sub Sub Sub Sub Sub Happy_mel Merry_mel Setup Setupweekday Setweekday Setdate Settime Setuptime Gotomain Dst_onoff Sun_riseset Delnvram Writenvram Writenvram_sett Readnvram Setup1 Lcd_blonoff Zeitkorrektur Eepromwsonne Eepromwtermine Play_music(song_nr As String) Declare Declare Declare Declare Declare Declare Function Function Function Function Function Function Eepromrsonne(byval Adresse_sonne As Word) As String Eepromrtermine(byval Adresse_termine As Word) As String Getterminadresse(byval Heute As Integer) As Word Getmaxadressetermine(byval Adresse_termine As Word) As Word Gettermintag(byval Adresse_termine As Word) As Integer Eepromrtermine_alarm(byval Adresse_termine As Word) As Long 'Wochentag, Uhrzeit und Datum ohne Setup einstellen 'Time$ = "00:04:00" 'Date$ = "08:02:11" 'Weekday = 1 'Call Setweekday Open "comb.0:9600,8,n,1" For Output As #1 Waitms 500 Print #1 , "v"; Close #1 'Reset der 7Seg.-Anzeige 'Print #1 , "z"; 'Printbin #1 , 128 ; 'Close #1 'Helligkeit der 7Seg.-Anzeige einstellen Waitms 500 - 41 - Call Readnvram Waitms 500 'Call Delnvram 'NV-Ram der RTC loeschen Cls '##################################################### '# main loop # '##################################################### Do Call Dst_onoff Call Lcd_blonoff Call Zeitkorrektur Heute = Dayofyear(date$) Termine_j = Mid(date$ , 7 , 2) Termine_ij = Val(termine_j) Schaltjahr = Termine_ij Mod 4 If Schaltjahr = 0 And Heute >= 60 Then Decr Heute End If 'Schaltjahr Adresse_termine = Getterminadresse(heute) Termine_alarml = Eepromrtermine_alarm(adresse_termine) If Termine_alarml = Secofday() And Alarm_heute = 1 And Termine_mu <> "0" Then Call Play_music(termine_mu) Else End If Timestr = Time$ Datestr = Date$ Weekdaystr = Lookupstr(weekday , Weekdays) A = Mid(timestr , 1 , 2) B = Mid(timestr , 4 , 2) C = Mid(timestr , 7 , 2) If Colon_onoff = 0 And Dp_onoff = 0 Then Print #1 , "w"; Printbin #1 , 0 ; 'Close #1 Elseif Colon_onoff = 1 And Dp_onoff = 0 And All_off = 0 Then Print #1 , "w"; Printbin #1 , 16 ; 'Close #1 Elseif Colon_onoff = 1 And Dp_onoff = 1 And All_off = 0 Then Print #1 , "w"; Printbin #1 , 2 ; Else Print #1 , "w"; Printbin #1 , 0; End If If C > "30" And C < All_off = 0 A = Mid(datestr , B = Mid(datestr , Dp_onoff = 1 Elseif C > "34" And All_off = 1 A = "20" B = Mid(datestr , Else Dp_onoff = 0 All_off = 0 End If "35" Then 1 , 2) 4 , 2) C < "39" Then 7 , 2) If A < "10" Then A = Mid(a , 2 , 1) Print #1 , "x" ; A ; B; - 42 - Else Print #1 , A ; B; End If Select Case Cntb1 Case 0: If Alarm_heute = 1 Then Adresse_termine = Getterminadresse(heute) Termin_heute = Eepromrtermine(adresse_termine) Termin_heute = Mid(termin_heute , 7 , 10) Termine_alarml = Eepromrtermine_alarm(adresse_termine) Termine_alarmst = Time(termine_alarml) Termine_alarmst = Left(termine_alarmst , 5) Bdate = Mid(datestr , 7 , 2) Bdate = "20" + Bdate Termine_jvi = Val(termine_jv) Bdatei = Val(bdate) Alter = Bdatei - Termine_jvi Locate 1 , 1 : Lcd "Heute " ; Termin_heute If Termine_geburtstag = "G" Then Locate 2 , 1 : Lcd Termine_alarmst ; " " ; Termine_jv ; " " ; Alter ; " J" Else Locate 2 , 1 : Lcd Termine_alarmst ; Spc(11) End If Locate 3 , 1 : Lcd Date$ ; Spc(8) Locate 4 , 1 : Lcd Time$ ; Spc(8) Else Spaces = Len(weekdaystr) Spaces = 16 - Spaces Locate Locate Locate Locate 1 2 3 4 , , , , 1 1 1 1 : : : : Lcd Lcd Lcd Lcd "Datum & Uhrzeit " Weekdaystr ; Spc(spaces) Date$ ; Spc(8) Time$ ; Spc(8) End If Case 1: Heute = Dayofyear(date$) Maxadressew = Getmaxadressetermine(0) Adresse_termine = Getterminadresse(heute) Eepromrtermine_heute = Eepromrtermine(adresse_termine) If Adresse_termine > Maxadressew Then Adresse_termine = 0 Locate 1 , 1 : Lcd "Termine" ; Spc(9) If Eepromrtermine_heute <> " " Then Locate 2 , 1 : Lcd Eepromrtermine(adresse_termine) Else Adresse_termine = 0 Locate 2 , 1 : Lcd Eepromrtermine(adresse_termine) End If Adresse_termine = Adresse_termine + 27 Locate 3 , 1 : Lcd Eepromrtermine(adresse_termine) Adresse_termine = Adresse_termine + 27 Locate 4 , 1 : Lcd Eepromrtermine(adresse_termine) Case 2: Sa = Eepromrsonne(0) Systemtageepr = Mid(sa , 1 , 4) Systemtageeprl = Val(systemtageepr) - 43 - Sysdx = Sysday() Sysdw = Sysdx - Systemtageeprl Sysdw = Sysdw * 14 Sa = Eepromrsonne(sysdw) Sa = Mid(sa , 5 , 5) Su = Eepromrsonne(sysdw) Su = Mid(su , 10 , 5) Locate 1 , 1 : Lcd "SonnenA/U 3 Tage" Locate 2 , 1 : Lcd "A " ; Sa ; Spc(2) ; "U " ; Su Sysdx = Sysday() Sysdx = Sysdx + 1 Sysdw = Sysdx - Systemtageeprl Sysdw = Sysdw * 14 Sa = Eepromrsonne(sysdw) Sa = Mid(sa , 5 , 5) Su = Eepromrsonne(sysdw) Su = Mid(su , 10 , 5) Locate 3 , 1 : Lcd "A " ; Sa ; Spc(2) ; "U " ; Su Sysdx = Sysday() Sysdx = Sysdx + 2 Sysdw = Sysdx - Systemtageeprl Sysdw = Sysdw * 14 Sa = Eepromrsonne(sysdw) Sa = Mid(sa , 5 , 5) Su = Eepromrsonne(sysdw) Su = Mid(su , 10 , 5) Locate 4 , 1 : Lcd "A " ; Sa ; Spc(2) ; "U " ; Su Case 3: Exitbyte = 0 Call Setup End Select Debounce Pind.2 , 0 , Button1 , Sub If N > 30 Then L = Left(s , 4) Select Case L Case "TEST": N = 0 Print S; Case "TIME": N = 0 Time$ = Mid(s , 18 , 8) Date$ = Mid(s , 7 , 8) Weekdayst = Mid(s , 15 , 1) Weekday = Weekdayst Call Setweekday Wtsetst = Mid(s , 16 , 1) Stsetst = Mid(s , 17 , 1) Wtset = Val(wtsetst) Stset = Val(stsetst) Call Writenvram Case "SETT": N = 0 Systemtag = Sysday() Sekdestages = Secofday() - 44 - Call Writenvram_sett Call Readnvram Case "SUNS": N = 0 Call Eepromwsonne Case "DATE": N = 0 Call Eepromwtermine Case "CDAT": N = 0 Adresse_terminw = 0 End Select End If Loop '##################################################### '# UART Interuppt / Zeichen über UART empfangen # '##################################################### Onrxd: Incr N Z(n) = Udr Return '##################################################### '# Datum & Uhrzeit einstellen / CASE 2 # '##################################################### Setup: Bitwait Pind.2 , Reset Lcd_bl = 1 Cls Print #1 , "SEtx" ; Print #1 , "w"; Printbin #1 , 0 ; While Cntb1 Locate 1 Locate 2 Locate 3 Locate 4 Debounce Debounce Wend = 3 , 1 : Lcd "Datum & Uhrzeit" , 1 : Lcd " einstellen" , 1 : Lcd ">T1=Uebernehmen<" , 1 : Lcd ">T2=Einstellen<" Pind.2 , 0 , Gotomain , Sub Pind.3 , 0 , Setupweekday , Sub Return '------Setupweekday: Cls While Exitbyte = 0 Weekdaystr = Lookupstr(weekday , Weekdays) Locate 1 , 1 : Lcd "Wochentag einst." Locate 2 , 1 : Lcd Weekdaystr ; " " Debounce Pind.2 , 0 , Setupdate , Sub Debounce Pind.3 , 0 , Incrweekday , Sub Waitms 20 - 45 - Wend Return '------Incrweekday: Bitwait Pind.3 , Reset If Weekday < 7 Then Incr Weekday Else Weekday = 1 Return '-------Setupdate: Call Setweekday Locate 2 , 1 : Lcd "Tag" ; Spc(13) A = Mid(datestr , 1 , 2) B = Mid(datestr , 4 , 2) C = Mid(datestr , 7 , 2) D = Val(a) : E = Val(b) : F = Val(c) While Exitbyte = 0 A = Str(d) A = Format(a , "00") B = Str(e) B = Format(b , "00") C = Str(f) C = Format(c , "00") Locate 1 , 1 : Lcd "Datum einst. " Locate 3 , 1 : Lcd A ; "." ; B ; "." ; C Debounce Pind.2 , 0 , Setupdmy , Sub Debounce Pind.3 , 0 , Incrdmy , Sub Waitms 20 Wend Call Setuptime Return '------Incrdmy: Bitwait Pind.3 , Reset Select Case I Case 0: Locate 2 , 1 : If D < 31 Then Case 1: Locate 2 , 1 : If E < 12 Then Case 2: Locate 2 , 1 : If F < 30 Then End Select Lcd "Tag" ; Spc(13) Incr D Else D = 1 Lcd "Monat" ; Spc(11) Incr E Else E = 1 Lcd "Jahr" ; Spc(12) Incr F Else F = 11 Return '-------Setupdmy: Bitwait Pind.2 , Reset If I > 1 Then I = 0 _day = D : _month = E : _year = F Call Setdate Exitbyte = 1 - 46 - Else Incr I End If Return '-------Setuptime: Locate 2 , 1 : Lcd "Stunde" ; Spc(10) A = Mid(timestr , 1 , 2) B = Mid(timestr , 4 , 2) C = Mid(timestr , 7 , 2) G = Val(a) : H = Val(b) : J = Val(c) While Exitbyte = 1 A = Str(g) A = Format(a , "00") B = Str(h) B = Format(b , "00") C = Str(j) C = Format(c , "00") Locate 1 , 1 : Lcd "Uhrzeit einst. " Locate 4 , 1 : Lcd A ; ":" ; B ; ":" ; C Debounce Pind.2 , 0 , Setuphms , Sub Debounce Pind.3 , 0 , Incrhms , Sub Waitms 20 Wend Return '------Incrhms: Bitwait Pind.3 , Reset Select Case I Case 0: Locate 2 , 1 : If G < 23 Then Case 1: Locate 2 , 1 : If H < 59 Then Case 2: Locate 2 , 1 : If J < 59 Then End Select Lcd "Stunde" ; Spc(10) Incr G Else G = 0 Lcd "Minute" ; Spc(10) Incr H Else H = 0 Lcd "Sekunde" ; Spc(9) Incr J Else J = 0 Return '-------Setuphms: Bitwait Pind.2 , Reset If I > 1 Then I = 0 _hour = G : _min = H : _sec = J Call Settime Call Gotomain Exitbyte = 2 Else Incr I End If Return '##################################################### '# ENDE Datum & Uhrzeit einstellen # '##################################################### - 47 - '##################################################################### '# DS1307 Datum, Uhrzeit & Einstellungen auslesen und schreiben # '##################################################################### Getdatetime: I2cstart I2cwbyte Ds1307w I2cwbyte 0 I2cstart I2cwbyte Ds1307r I2crbyte _sec , Ack I2crbyte _min , Ack I2crbyte _hour , Ack I2crbyte Weekday , Ack I2crbyte _day , Ack I2crbyte _month , Ack I2crbyte _year , Nack I2cstop _sec = Makedec(_sec) : _min = Makedec(_min) : _hour = Makedec(_hour) _day = Makedec(_day) : _month = Makedec(_month) : _year = Makedec(_year) Return Setdate: _day = Makebcd(_day) : _month = Makebcd(_month) : _year = Makebcd(_year) I2cstart I2cwbyte Ds1307w I2cwbyte 4 I2cwbyte _day I2cwbyte _month I2cwbyte _year I2cstop Waitms 10 Return Setweekday: I2cstart I2cwbyte Ds1307w I2cwbyte 3 I2cwbyte Weekday I2cstop Waitms 10 Return Settime: _sec = Makebcd(_sec) : _min = Makebcd(_min) : _hour = Makebcd(_hour) I2cstart I2cwbyte Ds1307w I2cwbyte 0 I2cwbyte _sec I2cwbyte _min I2cwbyte _hour I2cstop Waitms 10 Return Delnvram: For K = 8 To 63 I2cstart I2cwbyte Ds1307w I2cwbyte K I2cwbyte 00 I2cwbyte 00 I2cstop Waitms 10 Next Return Writenvram: I2cstart I2cwbyte Ds1307w I2cwbyte 8 I2cwbyte Stset I2cwbyte Wtset I2cstop Waitms 10 Return - 48 - Writenvram_sett: I2cstart I2cwbyte Ds1307w I2cwbyte 10 I2cwbyte Z(7) I2cwbyte 0 I2cwbyte Z(8) I2cwbyte 0 I2cwbyte Z(9) I2cwbyte Z(10) I2cwbyte 0 I2cwbyte Systemtagby(1) I2cwbyte Systemtagby(2) I2cwbyte Systemtagby(3) I2cwbyte Systemtagby(4) I2cwbyte Sekdestagesby(1) I2cwbyte Sekdestagesby(2) I2cwbyte Sekdestagesby(3) I2cwbyte Sekdestagesby(4) I2cstop Waitms 10 Return Readnvram: I2cstart I2cwbyte I2cwbyte I2cstart I2cwbyte I2crbyte I2crbyte I2crbyte I2crbyte I2crbyte I2crbyte I2crbyte I2crbyte I2crbyte I2crbyte I2crbyte I2crbyte I2crbyte I2crbyte I2crbyte I2crbyte I2crbyte I2cstop Return Ds1307w 8 Ds1307r Stset , Ack Wtset , Ack Lcd_blby(1) , Ack Lcd_blby(2) , Ack Plusminby(1) , Ack Plusminby(2) , Ack Sekundeby(1) , Ack Sekundeby(2) , Ack Sekundeby(3) , Ack Systemtagby(1) , Ack Systemtagby(2) , Ack Systemtagby(3) , Ack Systemtagby(4) , Ack Sekdestagesby(1) , Ack Sekdestagesby(2) , Ack Sekdestagesby(3) , Ack Sekdestagesby(4) , Nack '##################################################################### '# Ende DS1307 Datum, Uhrzeit & Einstellungen auslesen und schreiben # '##################################################################### '##################################################################### '# I2C EEPROM Sonnenauf/-untergangsdaten lesen und schreiben # '##################################################################### Eepromwsonne: N = 0 For X = 7 To 20 Adresse_sonne_high = High(adresse_sonne) Adresse_sonne_low = Low(adresse_sonne) I2cstart I2cwbyte I2cwbyte I2cwbyte I2cwbyte I2cstop Eeprw Adresse_sonne_high Adresse_sonne_low Z(x) Waitms 10 Incr Adresse_sonne - 49 - Next If Adresse_sonne > 1399 Then Adresse_sonne = 0 Return '-----------------Function Eepromrsonne(adresse_sonne As Word) As String * 14 For X = 1 To 14 Adresse_sonne_high = High(adresse_sonne) Adresse_sonne_low = Low(adresse_sonne) I2cstart I2cwbyte Eeprw I2cwbyte Adresse_sonne_high I2cwbyte Adresse_sonne_low I2cstart I2cwbyte Eeprr I2crbyte Sonnetagby(x) , Nack I2cstop Incr Adresse_sonne Next Stageeprom = Sonnetagst Stageepromday = Left(stageeprom , 4) If Stset = 1 And Wtset = 0 Then Sahst = Mid(stageeprom , 5 , 2) Sarest = Mid(stageeprom , 7 , 3) Suhst = Mid(stageeprom , 10 , 2) Surest = Mid(stageeprom , 12 , 3) Sahstn = Val(sahst) Incr Sahstn Sahst = Str(sahstn) Sahst = Format(sahst , "00") Suhstn = Val(suhst) Incr Suhstn Suhst = Str(suhstn) Suhst = Format(suhst , "00") Stageeprom = Stageepromday + Sahst + Sarest + Suhst + Surest End If Eepromrsonne = Stageeprom End Function '##################################################################### '# ENDE I2C EEPROM Sonnenauf/-untergangsdaten lesen und schreiben # '##################################################################### '##################################################################### '# I2C EEPROM Termine lesen und schreiben # '##################################################################### Eepromwtermine: N = 0 For X = 5 To 31 Adresse_termine14k = 1400 + Adresse_terminw Adresse_termine_high14k = High(adresse_termine14k) - 50 - Adresse_termine_low14k = Low(adresse_termine14k) I2cstart I2cwbyte I2cwbyte I2cwbyte I2cwbyte I2cstop Eeprw Adresse_termine_high14k Adresse_termine_low14k Z(x) Waitms 10 Incr Adresse_terminw Next Return '-----------------Function Getterminadresse(heute As Integer) As Word Maxadressew = Getmaxadressetermine(0) For Adresse_termine = 0 To Maxadressew Step 27 Terminedate = Gettermintag(adresse_termine) If Terminedate = Heute Then Alarm_heute = 1 Else Alarm_heute = 0 If Terminedate >= Heute Then Exit For Next Getterminadresse = Adresse_termine End Function '-----------------Function Gettermintag(adresse_termine As Word) As Integer For X = 1 To 27 Adresse_termine14k = 1400 + Adresse_termine Adresse_termine_high14k = High(adresse_termine14k) Adresse_termine_low14k = Low(adresse_termine14k) I2cstart I2cwbyte Eeprw I2cwbyte Adresse_termine_high14k I2cwbyte Adresse_termine_low14k I2cstart I2cwbyte Eeprr I2crbyte Termineby(x) , Nack I2cstop Incr Adresse_termine Next Termine_t = Left(terminest , 2) Termine_m = Mid(terminest , 3 , 2) Termine_j = Mid(terminest , 7 , 2) Termine_jv = Mid(terminest , 5 , 4) Terminedatest = Termine_t + "." + Termine_m + "." + Termine_j Terminedate = Dayofyear(terminedatest) Termine_ij = Val(termine_j) Schaltjahr = Termine_ij Mod 4 If Schaltjahr = 0 And Terminedate > 59 Then Decr Terminedate End If 'Schaltjahr Gettermintag = Terminedate End Function - 51 - '------------------Function Eepromrtermine(adresse_termine As Word) As String * 16 For X = 1 To 27 Adresse_termine14k = 1400 + Adresse_termine Adresse_termine_high14k = High(adresse_termine14k) Adresse_termine_low14k = Low(adresse_termine14k) I2cstart I2cwbyte Eeprw I2cwbyte Adresse_termine_high14k I2cwbyte Adresse_termine_low14k I2cstart I2cwbyte Eeprr I2crbyte Termineby(x) , Nack I2cstop Incr Adresse_termine Next Termine_t = Left(terminest , 2) Termine_m = Mid(terminest , 3 , 2) Termine_p = Mid(terminest , 16 , 10) Terminelcdst = Termine_t + "." + Termine_m + " " + Termine_p If Termine_t = "00" Then Terminelcdst = Space(16) Eepromrtermine = Terminelcdst End Function '-----------------Function Getmaxadressetermine(adresse_termine As Word) As Word For X = 1 To 27 Adresse_termine14k = 1400 + Adresse_termine Adresse_termine_high14k = High(adresse_termine14k) Adresse_termine_low14k = Low(adresse_termine14k) I2cstart I2cwbyte Eeprw I2cwbyte Adresse_termine_high14k I2cwbyte Adresse_termine_low14k I2cstart I2cwbyte Eeprr I2crbyte Termineby(x) , Nack I2cstop Incr Adresse_termine Next Maxadressest = Mid(terminest , 26 , 2) Maxadressew = Val(maxadressest) Maxadressew = Maxadressew * 27 Getmaxadressetermine = Maxadressew End Function '--------------------------Function Eepromrtermine_alarm(adresse_termine As Word) As Long For X = 1 To 27 Adresse_termine14k = 1400 + Adresse_termine - 52 - Adresse_termine_high14k = High(adresse_termine14k) Adresse_termine_low14k = Low(adresse_termine14k) I2cstart I2cwbyte Eeprw I2cwbyte Adresse_termine_high14k I2cwbyte Adresse_termine_low14k I2cstart I2cwbyte Eeprr I2crbyte Termineby(x) , Nack I2cstop Incr Adresse_termine Next Termine_sek = Mid(terminest , 9 , 5) Termine_mu = Mid(terminest , 15 , 1) Termine_geburtstag = Mid(terminest , 14 , 1) 'Musik abspielen? 'Geburtstag oder Feiertag Termine_alarml = Val(termine_sek) Eepromrtermine_alarm = Termine_alarml End Function '##################################################################### '# ENDE I2C EEPROM Termine lesen und schreiben # '##################################################################### '------------------Toggle_colon: Timer1 = 7936 Toggle Colon_onoff If All_off = 1 Then Colon_onoff = 0 Return '-----------------Button1: Bitwait Pind.2 , Reset If Cntb1 = 3 Then Cntb1 = 0 Else Incr Cntb1 Cls Return '-----------------Button2: Bitwait Pind.3 , Reset If Cntb2 = 2 Then Cntb2 = 0 Else Incr Cntb2 Return '---------Gotomain: Bitwait Pind.2 , Reset Cntb1 = 0 Cls Return '##################################################### '# LCD BL an/aus # '##################################################### Lcd_blonoff: Licht = Getadc(2) If Lcd_blst = "1" Then Lcd_bl = 1 Elseif Lcd_blst = "3" And Licht < 120 And _hour > 6 Then Lcd_bl = 1 Else Lcd_bl = 0 End If - 53 - Return '##################################################### '# ENDE LCD BL an/aus # '##################################################### '##################################################### '# Sommer-/Winterzeit einstellen # '##################################################### Dst_onoff: If _month = 3 And _day > 24 And Weekday = 7 And _hour = 2 Then _hour = _hour + 1 Waitms 10 Call Settime Stset = 1 Wtset = 0 Waitms 10 Call Writenvram End If If Wtset = 0 And _month = 10 And _day > 24 And Weekday = 7 And _hour = 3 Then _hour = _hour - 1 Waitms 10 Call Settime Wtset = 1 Stset = 0 Waitms 10 Call Writenvram End If Return '##################################################### '# Ende Sommer-/Winterzeit einstellen # '##################################################### '##################################################### '# Zeitkorrektur # '##################################################### Zeitkorrektur: Call Readnvram Sysd = Sysday() Secd = Secofday() Sekundelong = Val(sekundest) If Secd = 86399 Then Zeitkorrekturbit = 0 If Plusminst = "0" Then Korrektur = Sekdestages + Sekundelong If Plusminst = "1" Then Korrektur = Sekdestages - Sekundelong If Sysd <> Systemtag And Secd = Sekdestages And Sekundelong <> 0 And Zeitkorrekturbit = 0 Then Time$ = Time(korrektur) Zeitkorrekturbit = 1 End If Return '##################################################### '# Ende Zeitkorrektur # '##################################################### '##################################################### '# Musik abspielen # '##################################################### Sub Play_music(song_nr As String * 1) If Lcd_bl = 0 Then Lcd_bl = 1 Select Case Song_nr Case "1" For I = 0 To 55 Note = Lookup(i , Happyb) - 54 - Incr I If Note = 0 Then Pause = Lookup(i , Happyb) Waitms Pause Else Laenge = Lookup(i , Happyb) Sound Speaker , Note , Laenge End If Next I Case "2" For I = 0 To 57 Note = Lookup(i , Merryx) Incr I If Note = 0 Then Pause = Lookup(i , Merryx) Waitms Pause Else Laenge = Lookup(i , Merryx) Sound Speaker , Note , Laenge End If Next I End Select End Sub '##################################################### '# Ende Musik abspielen # '##################################################### End Weekdays: Data "dummy" , "Montag" , "Dienstag" , "Mittwoch" , "Donnerstag" , "Freitag" , "Samstag" , "Sonntag" Happyb: Data 65% , 587% , 65% , 587% , 147% , 523% , 131% , 587% , 175% Data 440% , 165% , 466% , 0% , 250% , 65% , 587% , 65% , 587% , 147% Data 523% , 131% , 587% , 196% , 392% , 175% , 440% , 0% , 250% , 65% Data 587% , 65% , 587% , 262% , 294% , 220% , 349% , 175% , 440% , 165% Data 466% , 147% , 523% , 0% , 125% , 117% , 330% , 117% , 330% , 220% Data 349% , 175% , 440% , 196% , 392% , 175% , 440% Merryx: Data 147% , 523% , 196% , 392% , 98% , 392% , 110% , 349% , 98% , 392% Data 92% , 415% , 165% , 466% , 131% , 587% , 165% , 466% , 220% , 349% Data 110% , 349% , 124% , 311% , 110% , 349% , 98% , 392% , 185% , 415% Data 294% , 523% , 247% , 311% , 124% , 311% , 131% , 294% , 124% , 311% Data 110% , 349% , 196% , 392% , 165% , 466% , 73% , 523% , 73% , 523% Data 165% , 466% , 220% , 349% , 185% , 415% , 196% , 392% - 55 - AutoIt-Quellcode ;-----------------------------------------------------------------------------------------; Tool fuer die Geburtstagskalenderuhr ; Benutzt CommMG.au3 V2.8 von Martin Gibson ; http://www.autoitscript.com/forum/topic/45842-serial-port-com-port-udf/ ; http://www.mosaiccgl.co.uk/AutoItDownloads/confirm.php?get=COMMGv2.zip ; ; Berechnung der Zeiten für Sonnenauf bzw. -untergang aus dem AutoIt Skript ; IsItDark von JustinTime ; http://www.autoitscript.com/forum/topic/20946-script-to-determine-sunrisesunset-times-etc/ ; ; Berechnung des Osterdatums nach der Formel von Lichtenberg ; http://de.wikipedia.org/wiki/Gau%C3%9Fsche_Osterformel ;------------------------------------------------------------------------------------------#include <ButtonConstants.au3> #include <ComboConstants.au3> #include <DateTimeConstants.au3> #include <EditConstants.au3> #include <GUIConstantsEx.au3> #include <StaticConstants.au3> #include <WindowsConstants.au3> #include <Array.au3> #include <CommMG.au3>;or if you save the commMg.dll in the @scripdir use #include @SciptDir & '\commmg.dll' #Include <GuiListBox.au3> #include <File.au3> #include <GuiListView.au3> #Include <Date.au3> Const $longitude = 9.935556 ; Goettingen Const $latitude = 51.533889 ; Goettingen Const $TZ = 1 ;Zeitzone Const $pi = 3.1415926535897932384626433832795 Const $isdst=0 $RADEG=180/$pi $DEGRAD=$pi/180 $MyDocsFolder = "::{450D8FBA-AD25-11D0-98A8-0800361B1103}" Local $avArray[8] $avArray[0] = "Dummy" $avArray[1] = "Sonntag" $avArray[2] = "Montag" $avArray[3] = "Dienstag" $avArray[4] = "Mittwoch" $avArray[5] = "Donnerstag" $avArray[6] = "Freitag" $avArray[7] = "Samstag" $time = @HOUR & ":" & @MIN & ":" & @SEC $date1 = @YEAR & "/" & @MON & "/" & @MDAY $date = @MDAY & "." & @MON & "." & stringmid(@YEAR,3,2) #Region ### START Koda GUI section ### Form= $Form1_1 = GUICreate("Tool", 629, 515, 138, 42) $Tab1 = GUICtrlCreateTab(24, 24, 585, 465) $TabSheet1 = GUICtrlCreateTabItem("Einstellungen") $Combo1 = GUICtrlCreateCombo("COM1", 64, 110, 81, 25, BitOR($CBS_DROPDOWN,$CBS_AUTOHSCROLL)) GUICtrlSetData(-1, "COM2|COM3|COM4|COM5|COM6|COM7|COM8|COM9|COM10|COM11|COM12") $TimeInp = GUICtrlCreateDate($time, 184, 174, 94, 21, BitOR($DTS_UPDOWN,$DTS_TIMEFORMAT)) $DateInp = GUICtrlCreateDate($date, 64, 174, 94, 21, BitOR($DTS_SHORTDATEFORMAT,$DTS_UPDOWN)) $Sommerzeit = GUICtrlCreateCheckbox("Sommerzeit", 472, 166, 97, 25) GUICtrlSetState(-1, $GUI_CHECKED) $Sysdate = GUICtrlCreateCheckbox("Systemdatum", 472, 198, 97, 25) GUICtrlSetState(-1, $GUI_CHECKED) $Systime = GUICtrlCreateCheckbox("Systemzeit", 472, 230, 97, 25) GUICtrlSetState(-1, $GUI_CHECKED) $Label1 = GUICtrlCreateLabel("COM-Port", 160, 110, 50, 17) $Sendtime = GUICtrlCreateButton("Datum / Zeit senden", 64, 222, 121, 41) $Sendtest = GUICtrlCreateButton("Test", 264, 102, 65, 33) $Input2 = GUICtrlCreateInput("", 344, 110, 208, 22, BitOR($GUI_SS_DEFAULT_INPUT,$ES_READONLY)) - 56 - $Weekday = GUICtrlCreateCombo($avArray[@WDAY], 296, 174, 88, 25, BitOR($CBS_DROPDOWN, $CBS_AUTOHSCROLL)) GUICtrlSetData(-1, "Sonntag|Montag|Dienstag|Mittwoch|Donnerstag|Freitag|Samstag") $Input4 = GUICtrlCreateInput("", 208, 230, 208, 22, BitOR($GUI_SS_DEFAULT_INPUT,$ES_READONLY)) ;##### $Group1 = GUICtrlCreateGroup("LCD-Hintergrundbeleuchtung", 64, 289, 201, 57) $An = GUICtrlCreateRadio("An", 80, 313, 57, 17) GUICtrlSetState(-1, $GUI_CHECKED) $Aus = GUICtrlCreateRadio("Aus", 144, 313, 57, 17) $Auto = GUICtrlCreateRadio("Auto", 208, 313, 49, 17) GUICtrlCreateGroup("", -99, -99, 1, 1) $Group2 = GUICtrlCreateGroup("Korrektur", 312, 289, 225, 57) $plus = GUICtrlCreateRadio("+", 328, 313, 25, 18) GUICtrlSetState(-1, $GUI_CHECKED) $minus = GUICtrlCreateRadio("-", 368, 313, 25, 18) $Sekunden = GUICtrlCreateCombo("00", 402, 313, 51, 25, BitOR($CBS_DROPDOWN,$CBS_AUTOHSCROLL)) GUICtrlSetData(-1, "01|02|03|04|05|06|07|08|09|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26| 27|28|29|30") $Label3 = GUICtrlCreateLabel("s in 24 h", 467, 313, 54, 18) GUICtrlCreateGroup("", -99, -99, 1, 1) $Sendsettings = GUICtrlCreateButton("Einstellungen senden", 64, 360, 121, 41, $BS_MULTILINE) $Input5 = GUICtrlCreateInput("", 210, 372, 208, 22, BitOR($GUI_SS_DEFAULT_INPUT,$ES_READONLY)) $Sonnebutton = GUICtrlCreateButton(" Zeiten für Sonnenauf-/untergänge der nächsten 100 Tage senden ", 63, 420, 233, 41, $BS_MULTILINE) $ProgressSonne = GUICtrlCreateProgress(320, 424, 241, 33) $TabSheet2 = GUICtrlCreateTabItem("Geburtstage und Feiertage") $TDate = GUICtrlCreateDate($Date, 40, 72, 81, 22, 0) $Ttime = GUICtrlCreateDate($Time, 136, 72, 73, 22, BitOR($DTS_UPDOWN,$DTS_TIMEFORMAT)) $TWh = GUICtrlCreateCombo("Geburtstag", 224, 72, 76, 25, BitOR($CBS_DROPDOWN,$CBS_AUTOHSCROLL)) GUICtrlSetData(-1, "Feiertag") $TSound = GUICtrlCreateCombo("Keine Melodie", 312, 72, 105, 25, BitOR($CBS_DROPDOWN, $CBS_AUTOHSCROLL)) GUICtrlSetData(-1, "Melodie 1|Melodie 2") $TInpEreig = GUICtrlCreateInput("Klaus", 432, 72, 113, 22) GUICtrlSetLimit(-1, 10) $Tadd = GUICtrlCreateButton("+", 560, 72, 25, 25) $TChange = GUICtrlCreateButton("Eintrag ändern", 432, 136, 113, 25) $TDel = GUICtrlCreateButton("Eintrag löschen", 432, 178, 113, 25) $TDelAll = GUICtrlCreateButton("Alle löschen", 432, 218, 113, 25) $TFeiertag = GUICtrlCreateButton("Feiertage hinzufügen", 432, 256, 113, 25) $Input3 = GUICtrlCreateInput("", 264, 449, 209, 22, BitOR($GUI_SS_DEFAULT_INPUT,$ES_READONLY)) $TList = GUICtrlCreateListView("Datum|Uhrzeit|Anlass|Melodie|Text|#", 40, 121, 377, 314) GUICtrlSendMsg(-1, GUICtrlSendMsg(-1, GUICtrlSendMsg(-1, GUICtrlSendMsg(-1, GUICtrlSendMsg(-1, GUICtrlSendMsg(-1, $LVM_SETCOLUMNWIDTH, $LVM_SETCOLUMNWIDTH, $LVM_SETCOLUMNWIDTH, $LVM_SETCOLUMNWIDTH, $LVM_SETCOLUMNWIDTH, $LVM_SETCOLUMNWIDTH, 0, 1, 2, 3, 4, 5, 70) 70) 60) 60) 90) 0) $TSave = GUICtrlCreateButton("Speichern", 40, 448, 65, 25) $TLoad = GUICtrlCreateButton("Laden", 112, 448, 65, 25) $TSend = GUICtrlCreateButton("Senden", 184, 448, 65, 25) $TProgress = GUICtrlCreateProgress(480, 448, 113, 22) $TabSheet3 = GUICtrlCreateTabItem("Melodiegenerator") $MelodieName = GUICtrlCreateInput("Melodie", 52, 64, 169, 22) $Eingabe = GUICtrlCreateEdit("", 52, 97, 521, 137) $Ausgabe = GUICtrlCreateEdit("", 52, 309, 521, 161, BitOR($GUI_SS_DEFAULT_EDIT,$ES_READONLY)) ; $Generate = GUICtrlCreateButton("Code generieren", 200, 248, 217, 41) $DelAll = GUICtrlCreateButton("Alles löschen", 445, 248, 113, 41) GUICtrlCreateTabItem("") GUISetState(@SW_SHOW) #EndRegion ### END Koda GUI section ### GUICtrlSetState($Systime, $GUI_CHECKED) GUICtrlSetState($Sysdate, $GUI_CHECKED) - 57 - While 1 Local $sportSetError $nMsg = GUIGetMsg() Switch $nMsg Case $GUI_EVENT_CLOSE Exit Case $Sommerzeit Case $Sysdate Case $Systime Case $combo1 $setport = StringReplace(GUICtrlRead($Combo1), 'COM', '') _CommSetPort($setport, $sportSetError, 9600, 8, 0, 1, 0) if $sportSetError = '' Then MsgBox(262144, 'Verbunden','Verbunden mit COM' & $setport) Else MsgBox(262144, 'Verbindungsfehler', $sportSetError) EndIf $mode = 1 Case $Sendtest sleep (1000) GUICtrlSetData($input2, "") _CommSendString("TEST: Gesendet & Empfangen 1234") sleep (1000) $instr = _CommGetString() if $instr <> "" then GUICtrlSetData($input2, $instr) else GUICtrlSetData($input2, "Falscher Port oder Fehler") endif Case $Sendtime $a=GUICtrlRead($Sommerzeit) $b=GUICtrlRead($Sysdate) $c=GUICtrlRead($Systime) if $a=1 then $wt=0 $st=1 elseif $a <> 1 then $wt=1 $st=0 endif if $b=1 then $day=@MDAY $month=@MON $year2=stringmid(@YEAR,3,4) $date=$day & "." & $month & "." & $year2 & weekday2number($avArray[@WDAY]) else $date=stringmid(GUICtrlRead($DateInp),1,6) & stringmid(GUICtrlRead($DateInp),9,2) & weekday2number(GUICtrlRead($Weekday)) EndIf if $c=1 then $time=@HOUR &":"& @MIN &":"& @SEC else $time=GUICtrlRead($TimeInp) EndIf $Sendstr="TIME :" & $date & _CommSendString($Sendstr) sleep (1000) $instr = _CommGetString() if $instr <> "" then GUICtrlSetData($input4, else GUICtrlSetData($input4, GUICtrlSetData($input4, endif $wt & $st & $time & "xxxxxx" $instr) "") $sendstr) Case $Sendsettings if GUICtrlRead($an)=1 then $LCD=1 - 58 - if if if if if GUICtrlRead($aus)=1 then $LCD=2 GUICtrlRead($auto)=1 then $LCD=3 GUICtrlRead($plus)=1 then $plusminus=0 GUICtrlRead($minus)=1 then $plusminus=1 Number(GUICtrlRead($Sekunden)) < 10 then $null=0 else $null = "" EndIf $Sendstrsett = "SETT: " & $LCD & $plusminus & GUICtrlRead($Sekunden) & "00000000000000000000x" _CommSendString($Sendstrsett) sleep (1000) GUICtrlSetData($input5,$Sendstrsett) Case $Sonnebutton $b=GUICtrlRead($Sysdate) if $b=1 then $day = ( 367 * (@YEAR) - int((7 * ((@YEAR) + (((@MON) + 9) / 12))) / 4) + int((275 * (@MON)) / 9) + (@MDAY) - 730530) else $Jahr=stringmid(GUICtrlRead($DateInp),7,4) $Monat=stringmid(GUICtrlRead($DateInp),4,2) $MTag=stringmid(GUICtrlRead($DateInp),1,2) $day = ( 367 * ($Jahr) - int((7 * (($Jahr) + ((($Monat) + 9) / 12))) / 4) + int((275 * ($Monat)) / 9) + ($MTag) - 730530) EndIf For $Iday =0 to 99 $nday=$day+$Iday $SunTimes=SunTimes($nday,0) $Sendstrsonne="SUNS: " & $nday-1 & $SunTimes & "0000000000x" _CommSendString($Sendstrsonne) GUICtrlSetData($input5,$Sendstrsonne) GUICtrlSetData($ProgressSonne, $Iday+1) sleep(500) Next Case $Tadd _GUICtrlListView_RegisterSortCallBack($TList) $TerminT=StringLeft(GUICtrlRead($Tdate),2) $TerminM=StringMid(GUICtrlRead($Tdate),4,2) $TerminDatum = $TerminM & $TerminT GUICtrlCreateListViewItem(GUICtrlRead($Tdate) & "|" & GUICtrlRead($Ttime) & "|" & GUICtrlRead($Twh) & "|" & GUICtrlRead($TSound) & "|" & StringFormat("%-10s",GUICtrlRead($TInpEreig)) &"|" & $TerminDatum, $TList) _GUICtrlListView_SortItems($TList,5) _GUICtrlListView_UnRegisterSortCallBack ($TList) Case $TChange $line = _GUICtrlListView_GetItemTextString($TList,Number(_GUICtrlListView_GetSelectedIndices($TList))) $linesplit = StringSplit($line,"|") $date_tchange=StringMid($linesplit[1],7,4) & "/" & StringMid($linesplit[1],4,2) & "/" & StringMid($linesplit[1],1,2) GUICtrlSetData($Tdate,$date_tchange) GUICtrlSetData($Ttime,$date_tchange & " " & $linesplit[2]) GUICtrlSetData($Twh, $linesplit[3]) GUICtrlSetData($Tsound, $linesplit[4]) GUICtrlSetData($TInpEreig, $linesplit[5]) _GUICtrlListView_DeleteItem($TList,Number(_GUICtrlListView_GetSelectedIndices($TList))) Case $Tdel _GUICtrlListView_DeleteItemsSelected($TList) Case $TDelall _GUICtrlListView_DeleteAllItems($TList) Case $TFeiertag _GUICtrlListView_RegisterSortCallBack($TList) GUICtrlCreateListViewItem("01.01." & @YEAR & "|" & "00:00:01" & "Keine Melodie" & "|" & "Neujahr " & "|" & "0101", $TList) - 59 - & "|" & "Feiertag" & "|" GUICtrlCreateListViewItem("01.05." & "Keine Melodie" & "|" & "1. Mai " & "|" GUICtrlCreateListViewItem("08.05." & "Keine Melodie" & "|" & "Muttertag " & "|" GUICtrlCreateListViewItem("03.10." & "Keine Melodie" & "|" & "D. Einheit" & "|" GUICtrlCreateListViewItem("24.12." & "Keine Melodie" & "|" & "Heiligab. " & "|" GUICtrlCreateListViewItem("25.12." & "Keine Melodie" & "|" & "1. Weihft." & "|" GUICtrlCreateListViewItem("26.12." & "Keine Melodie" & "|" & "2. Weihft." & "|" GUICtrlCreateListViewItem("31.12." & "Keine Melodie" & "|" & "Silvester " & "|" & & & & & & & & & & & & & & @YEAR & "0501", @YEAR & "0508", @YEAR & "1003", @YEAR & "1224", @YEAR & "1225", @YEAR & "1226", @YEAR & "1231", "|" & "12:00:00" $TList) "|" & "12:00:00" $TList) "|" & "12:00:00" $TList) "|" & "12:00:00" $TList) "|" & "12:00:00" $TList) "|" & "12:00:00" $TList) "|" & "12:00:00" $TList) & "|" & "Feiertag" & "|" & "|" & "Feiertag" & "|" & "|" & "Feiertag" & "|" & "|" & "Feiertag" & "|" & "|" & "Feiertag" & "|" & "|" & "Feiertag" & "|" & "|" & "Feiertag" & "|" $Osterdatum=Ostern(@YEAR) $OsternT=StringLeft($Osterdatum,2) $OsternM=StringMid($Osterdatum,4,2) $OsternMT=$OsternM & $OsternT If (@MON & @MDAY) > $OsternMT then $Osterdatum=Ostern(@YEAR+1) $OsternT=StringLeft($Osterdatum,2) $OsternM=StringMid($Osterdatum,4,2) $OsternY=StringMid($Osterdatum,7,4) $OsternMT=$OsternM & $OsternT GUICtrlCreateListViewItem($Osterdatum & "|" & "12:00:00" "Keine Melodie" & "|" & "Ostersonn." & "|" &$OsternMT, $TList) & "|" & "Feiertag" & "|" & Dim $KarfreitagY, $KarfreitagM, $KarfreitagT $Karfreitag= _DateToDayValue ($OsternY, $OsternM, $OsternT) -2 $Karfreitag= _DayValueToDate ($Karfreitag, $KarfreitagY, $KarfreitagM, $KarfreitagT) $Karfreitag = $KarfreitagT & "." & $KarfreitagM & "." & $KarfreitagY $KarfreitagMT = $KarfreitagM & $KarfreitagT GUICtrlCreateListViewItem($Karfreitag & "|" & "12:00:00" & "|" & "Feiertag" "Keine Melodie" & "|" & "Karfreitag" & "|" & $KarfreitagMT, $TList) & "|" & Dim $OstermontagY, $OstermontagM, $OstermontagT $Ostermontag = _DateToDayValue ($OsternY, $OsternM, $OsternT) + 1 $Ostermontag = _DayValueToDate ($Ostermontag, $OstermontagY, $OstermontagM, $OstermontagT) $Ostermontag = $OstermontagT & "." & $OstermontagM & "." & $OstermontagY $OstermontagMT = $OstermontagM & $OstermontagT GUICtrlCreateListViewItem($Ostermontag & "|" & "12:00:00" "Keine Melodie" & "|" & "Ostermon. " & "|" &$OstermontagMT, $TList) & "|" & "Feiertag" & "|" & Dim $HimmelfahrtY, $HimmelfahrtM, $HimmelfahrtT $Himmelfahrt= _DateToDayValue ($OsternY, $OsternM, $OsternT) + 39 $Himmelfahrt= _DayValueToDate ($Himmelfahrt, $HimmelfahrtY, $HimmelfahrtM, $HimmelfahrtT) $Himmelfahrt = $HimmelfahrtT & "." & $HimmelfahrtM & "." & $HimmelfahrtY $HimmelfahrtMT = $HimmelfahrtM & $HimmelfahrtT GUICtrlCreateListViewItem($Himmelfahrt & "|" & "12:00:00" & "|" & "Feiertag" "Keine Melodie" & "|" & "Vatertag " & "|" & $HimmelfahrtMT, $TList) & "|" & Dim $PfingstsonntagY, $PfingstsonntagM, $PfingstsonntagT $Pfingstsonntag= _DateToDayValue ($OsternY, $OsternM, $OsternT) + 49 $Pfingstsonntag= _DayValueToDate ($Pfingstsonntag, $PfingstsonntagY, $PfingstsonntagM, $PfingstsonntagT) $Pfingstsonntag = $PfingstsonntagT & "." & $PfingstsonntagM & "." & $PfingstsonntagY $PfingstsonntagMT = $PfingstsonntagM & $PfingstsonntagT GUICtrlCreateListViewItem($Pfingstsonntag & "|" & "12:00:00" & "|" & "Feiertag" "Keine Melodie" & "|" & "Pfingstso." & "|" & $PfingstsonntagMT, $TList) Dim $PfingstmontagY, $PfingstmontagM, $PfingstmontagT - 60 - & "|" & $Pfingstmontag = _DateToDayValue ($OsternY, $OsternM, $OsternT) + 50 $Pfingstmontag = _DayValueToDate ($Pfingstmontag, $PfingstmontagY, $PfingstmontagM, $PfingstmontagT) $Pfingstmontag = $PfingstmontagT & "." & $PfingstmontagM & "." & $PfingstmontagY $PfingstmontagMT = $PfingstmontagM & $PfingstmontagT GUICtrlCreateListViewItem($Pfingstmontag & "|" & "12:00:00" & "|" & "Feiertag" "Keine Melodie" & "|" & "Pfingstmo." & "|" & $PfingstmontagMT, $TList) & "|" & _GUICtrlListView_SortItems($TList,5) _GUICtrlListView_UnRegisterSortCallBack ($TList) Case $TSave $TerminFile=FileSaveDialog ( "Termine speichern", $MyDocsFolder, "Text (*.txt)" , 2,"termine.txt" ) Fileopen($TerminFile,2) For $iIndex = 0 to _GUICtrlListView_GetItemCount($TList)-1 FileWriteLine ($TerminFile, _GUICtrlListView_GetItemTextString($TList, $iIndex)) Next FileClose($TerminFile) Case $TLoad $TerminFile=FileOpenDialog ( "Termine öffnen", $MyDocsFolder, "Text (*.txt)" , 2,"termine.txt" ) _GUICtrlListView_DeleteAllItems($TList) $endoffile = _FileCountLines($TerminFile) Fileopen($TerminFile,0) For $I = 1 to $endoffile $line = FileReadLine($TerminFile,$I) $linesplit=StringSplit($line,"|") GUICtrlCreateListViewItem($linesplit[1] & "|" & $linesplit[2] & "|" & $linesplit[3] & "|" & $linesplit[4] & "|" & $linesplit[5] &"|" & $linesplit[6], $TList) Next FileClose($TerminFile) Case $Tsend _CommSendString("CDATxxxxxxxxxxxxxxxxxxxxxxxxxxx") Sleep(500) For $iIndex = 0 to _GUICtrlListView_GetItemCount($TList)-1 $TerminString=_GUICtrlListView_GetItemTextString($TList, $iIndex) $TerminSec=Secofday(Stringmid($TerminString,12,8)) $TerminSec=StringFormat("%5s",$TerminSec) $TerminSec=StringReplace($TerminSec," ","0") $TerminString=StringReplace($TerminString,".","",2) $TerminString=StringReplace($TerminString,":","",2) $TerminString=StringReplace($TerminString,"|","") $TerminString=StringReplace($TerminString,"Geburtstag","G") $TerminString=StringReplace($TerminString,"Feiertag","F") $TerminString=StringReplace($TerminString,"Keine Melodie","0") $TerminString=StringReplace($TerminString,"Melodie ","") $TerminString="DATE" & StringLeft($TerminString, 8) & $TerminSec & StringMid($TerminString,15,12) $TerminString=StringFormat("%-29s",$TerminString) $TerminString=$TerminString & StringFormat("%2s",string(_GUICtrlListView_GetItemCount($TList))) _CommSendString($TErminString) Sleep(1000) GUICtrlSetData($Input3,$TerminString) GUICtrlSetData($TProgress, (100*($iIndex+1))/(_GUICtrlListView_GetItemCount($TList))) Next Sleep(1000) _CommSendString("DATE000000000000000000000000000") Sleep(1000) _CommSendString("DATE000000000000000000000000000") Sleep(1000) Case $Generate ;http://www.mcselec.com/index.php?option=com_content&task=view&id=221&Itemid=57 ;http://www.xs4all.nl/~vbergen/ringtones/siemens/index_2000.html $AusgabeText="" - 61 - GUICtrlSetData($Ausgabe, $AusgabeText="") Dim $AusgabeText Dim $Zaehler Dim $mP $Zaehler=0 Dim $C1[2][6] = [["C1","C1(1)","C1(1/2)","C1(1/4)","C1(1/8)","C1(1/16)"], [1174,523,262,131,65,33]] Dim $Cis1[2][6] = [["Cis1","Cis1(1)","Cis1(1/2)","Cis1(1/4)","Cis1(1/8)","Cis1(1/16)"], [1108,555,277,139,69,35]] Dim $D1[2][6] = [["D1","D1(1)","D(1/2)","D(1/4)","D(1/8)","D(1/16)"], [1046,587,294,147,73,37]] Dim $Dis1[2][6] = [["Dis1","Dis1(1)","Dis(1/2)","Dis(1/4)","Dis(1/8)","Dis(1/16)"], [987,622,311,156,78,39]] Dim $E1[2][6] = [["E1","E1(1)","E1(1/2)","E1(1/4)","E1(1/8)","E1(1/16)"], [932,659,330,165,82,41]] Dim $F1[2][6] = [["F1","F1(1)","F1(1/2)","F1(1/4)","F1(1/8)","F1(1/16)"], [880,698,349,175,87,44]] Dim $Fis1[2][6] = [["Fis1","Fis1(1)","Fis1(1/2)","Fis1(1/4)","Fis1(1/8)","Fis1(1/16)"], [830,740,370,185,92,46]] Dim $G1[2][6] = [["G1","G1(1)","G1(1/2)","G1(1/4)","G1(1/8)","G1(1/16)"], [784,784,392,196,98,49]] Dim $Gis1[2][6] = [["Gis1","Gis1(1)","Gis1(1/2)","Gis1(1/4)","Gis1(1/8)","Gis1(1/16)"], [740,830,415,208,104,52]] Dim $A1[2][6] = [["A1","A1(1)","A1(1/2)","A1(1/4)","A1(1/8)","A1(1/16)"], [698,880,440,220,110,55]] Dim $Ais1[2][6] = [["Ais1","Ais1(1)","Ais1(1/2)","Ais1(1/4)","Ais1(1/8)","Ais1(1/16)"], [659,932,466,233,117,58]] Dim $B1[2][6] = [["B1","B1(1)","B1(1/2)","B1(1/4)","B1(1/8)","B1(1/16)"], [622,988,494,247,124,62]] Dim $H1[2][6] = [["H1","H1(1)","H1(1/2)","H1(1/4)","H1(1/8)","H1(1/16)"], [622,988,494,247,124,62]] Dim $C2[2][6] = [["C2","C2(1)","C2(1/2)","C2(1/4)","C2(1/8)","C2(1/16)"], [587,1047,523,262,131,65]] Dim $Cis2[2][6] = [["Cis2","Cis2(1)","Cis2(1/2)","Cis2(1/4)","Cis2(1/8)","Cis2(1/16)"], [554,1109,554,277,139,69]] Dim $D2[2][6] = [["D2","D2(1)","D2(1/2)","D2(1/4)","D2(1/8)","D2(1/16)"], [523,1175,587,294,147,73]] Dim $Dis2[2][6] = [["Dis2","Dis2(1)","Dis2(1/2)","Dis2(1/4)","Dis2(1/8)","Dis2(1/16)"], [494,1244,622,311,156,78]] Dim $E2[2][6] = [["E2","E2(1)","E2(1/2)","E2(1/4)","E2(1/8)","E2(1/16)"], [466,1318,659,330,165,82]] Dim $F2[2][6] = [["F2","F2(1)","F2(1/2)","F2(1/4)","F2(1/8)","F2(1/16)"], [440,1396,698,349,175,87]] Dim $Fis2[2][6] = [["Fis2","Fis2(1)","Fis2(1/2)","Fis2(1/4)","Fis2(1/8)","Fis2(1/16)"], [415,1480,740,370,185,92]] Dim $G2[2][6] = [["G2","G2(1)","G2(1/2)","G2(1/4)","G2(1/8)","G2(1/16)"], [392,1567,784,392,196,98]] Dim $Gis2[2][6] = [["Gis2","Gis2(1)","Gis2(1/2)","Gis2(1/4)","Gis2(1/8)","Gis2(1/16)"], [370,1661,831,415,208,104]] Dim $A2[2][6] = [["A2","A2(1)","A2(1/2)","A2(1/4)","A2(1/8)","A2(1/16)"], [349,1760,880,440,220,110]] Dim $Ais2[2][6] = [["Ais2","Ais2(1)","Ais2(1/2)","Ais2(1/4)","Ais2(1/8)","Ais2(1/16)"], [330,1862,932,466,233,117]] Dim $B2[2][6] = [["B2","B2(1)","B2(1/2)","B2(1/4)","B2(1/8)","B2(1/16)"], [311,1976,988,494,247,124]] Dim $H2[2][6] = [["H2","H2(1)","H2(1/2)","H2(1/4)","H2(1/8)","H2(1/16)"], [311,1976,988,494,247,124]] Dim $C3[2][6] = [["C3","C3(1)","C3(1/2)","C3(1/4)","C3(1/8)","C3(1/16)"], [294,2090,1047,523,262,131]] Dim $Cis3[2][6] = [["Cis3","Cis3(1)","Cis3(1/2)","Cis3(1/4)","Cis3(1/8)","Cis3(1/16)"], [277,2218,1109,554,277,139]] Dim $D3[2][6] = [["D3","D3(1)","D3(1/2)","D3(1/4)","D3(1/8)","D3(1/16)"], [262,2345,1175,587,294,147]] Dim $Dis3[2][6] = [["Dis3","Dis3(1)","Dis3(1/2)","Dis3(1/4)","Dis3(1/8)","Dis3(1/16)"], [247,2487,1245,622,311,156]] Dim $E3[2][6] = [["E3","E3(1)","E3(1/2)","E3(1/4)","E3(1/8)","E3(1/16)"], [233,2637,1319,659,330,165]] Dim $F3[2][6] = [["F3","F3(1)","F3(1/2)","F3(1/4)","F3(1/8)","F3(1/16)"], [220,2793,1397,698,349,175]] Dim $Fis3[2][6] = [["Fis3","Fis3(1)","Fis3(1/2)","Fis3(1/4)","Fis3(1/8)","Fis3(1/16)"], [208,2954,1480,740,370,185]] Dim $G3[2][6] = [["G3","G3(1)","G3(1/2)","G3(1/4)","G3(1/8)","G3(1/16)"], [196,3135,1568,784,392,196]] Dim $Gis3[2][6] = [["Gis3","Gis3(1)","Gis3(1/2)","Gis3(1/4)","Gis3(1/8)","Gis3(1/16)"], [185,3321,1661,831,415,208]] Dim $A3[2][6] = [["A3","A3(1)","A3(1/2)","A3(1/4)","A3(1/8)","A3(1/16)"], - 62 - [179,3432,1720,880,440,220]] Dim $Ais3[2][6] = [["Ais3","Ais3(1)","Ais3(1/2)","Ais3(1/4)","Ais3(1/8)","Ais3(1/16)"], [165,3724,1865,932,466,233]] Dim $B3[2][6] = [["B3","B3(1)","B3(1/2)","B3(1/4)","B3(1/8)","B3(1/16)"], [156,3938,1976,988,494,247]] Dim $H3[2][6] = [["H3","H3(1)","H3(1/2)","H3(1/4)","H3(1/8)","H3(1/16)"], [156,3938,1976,988,494,247]] Dim $P[2][6] = [["P","P(1)","P(1/2)","P(1/4)","P(1/8)","P(1/16)"], [0,2000,1000,500,250,125]] $MelodieText=GUICtrlRead($Eingabe) $MelodieText=StringReplace($MelodieText," ","x") $MelodieText=StringSplit($MelodieText,"x") For $m=1 to $MelodieText[0] $mP=$m+1 For $C= 0 to 5 If $MelodieText[$m] = $C1[0][$C] Then $AusgabeText=$AusgabeText & $C1[1][$C] & $Zaehler=$Zaehler+1 EndIf If $MelodieText[$m] = $Cis1[0][$C] Then $AusgabeText=$AusgabeText & $Cis1[1][$C] $Zaehler=$Zaehler+1 EndIf If $MelodieText[$m] = $D1[0][$C] Then $AusgabeText=$AusgabeText & $D1[1][$C] & $Zaehler=$Zaehler+1 EndIf If $MelodieText[$m] = $Dis1[0][$C] Then $AusgabeText=$AusgabeText & $Dis1[1][$C] $Zaehler=$Zaehler+1 EndIf If $MelodieText[$m] = $E1[0][$C] Then $AusgabeText=$AusgabeText & $E1[1][$C] & $Zaehler=$Zaehler+1 EndIf If $MelodieText[$m] = $F1[0][$C] Then $AusgabeText=$AusgabeText & $F1[1][$C] & $Zaehler=$Zaehler+1 EndIf If $MelodieText[$m] = $Fis1[0][$C] Then $AusgabeText=$AusgabeText & $Fis1[1][$C] $Zaehler=$Zaehler+1 EndIf If $MelodieText[$m] = $G1[0][$C] Then $AusgabeText=$AusgabeText & $G1[1][$C] & $Zaehler=$Zaehler+1 EndIf If $MelodieText[$m] = $Gis1[0][$C] Then $AusgabeText=$AusgabeText & $Gis1[1][$C] $Zaehler=$Zaehler+1 EndIf If $MelodieText[$m] = $A1[0][$C] Then $AusgabeText=$AusgabeText & $A1[1][$C] & $Zaehler=$Zaehler+1 EndIf If $MelodieText[$m] = $Ais1[0][$C] Then $AusgabeText=$AusgabeText & $Ais1[1][$C] $Zaehler=$Zaehler+1 EndIf If $MelodieText[$m] = $B1[0][$C] Then $AusgabeText=$AusgabeText & $B1[1][$C] & $Zaehler=$Zaehler+1 EndIf If $MelodieText[$m] = $H1[0][$C] Then $AusgabeText=$AusgabeText & $H1[1][$C] & $Zaehler=$Zaehler+1 EndIf If $MelodieText[$m] = $C2[0][$C] Then $AusgabeText=$AusgabeText & $C2[1][$C] & $Zaehler=$Zaehler+1 EndIf If $MelodieText[$m] = $Cis2[0][$C] Then $AusgabeText=$AusgabeText & $Cis2[1][$C] $Zaehler=$Zaehler+1 EndIf - 63 - "%, " & $C1[1][0] & "%, " & "%, " & $Cis1[1][0] & "%, " "%, " & $D1[1][0] & "%, " & "%, " & $Dis1[1][0] & "%, " "%, " & $E1[1][0] & "%, " "%, " & $F1[1][0] & "%, " & "%, " & $Fis1[1][0] & "%, " "%, " & $G1[1][0] & "%, " & "%, " & $Gis1[1][0] & "%, " "%, " & $A1[1][0] & "%, " & "%, " & $Ais1[1][0] & "%, " "%, " & $B1[1][0] & "%, " "%, " & $H1[1][0] & "%, " "%, " & $C2[1][0] & "%, " & "%, " & $Cis2[1][0] & "%, " If $MelodieText[$m] = $D2[0][$C] Then $AusgabeText=$AusgabeText & $D2[1][$C] & $Zaehler=$Zaehler+1 EndIf If $MelodieText[$m] = $Dis2[0][$C] Then $AusgabeText=$AusgabeText & $Dis2[1][$C] $Zaehler=$Zaehler+1 EndIf If $MelodieText[$m] = $E2[0][$C] Then $AusgabeText=$AusgabeText & $E2[1][$C] & $Zaehler=$Zaehler+1 EndIf If $MelodieText[$m] = $F2[0][$C] Then $AusgabeText=$AusgabeText & $F2[1][$C] & $Zaehler=$Zaehler+1 EndIf If $MelodieText[$m] = $Fis2[0][$C] Then $AusgabeText=$AusgabeText & $Fis2[1][$C] $Zaehler=$Zaehler+1 EndIf If $MelodieText[$m] = $G2[0][$C] Then $AusgabeText=$AusgabeText & $G2[1][$C] & $Zaehler=$Zaehler+1 EndIf If $MelodieText[$m] = $Gis2[0][$C] Then $AusgabeText=$AusgabeText & $Gis2[1][$C] $Zaehler=$Zaehler+1 EndIf If $MelodieText[$m] = $A2[0][$C] Then $AusgabeText=$AusgabeText & $A2[1][$C] & $Zaehler=$Zaehler+1 EndIf If $MelodieText[$m] = $Ais2[0][$C] Then $AusgabeText=$AusgabeText & $Ais2[1][$C] $Zaehler=$Zaehler+1 EndIf If $MelodieText[$m] = $B2[0][$C] Then $AusgabeText=$AusgabeText & $B2[1][$C] & $Zaehler=$Zaehler+1 EndIf If $MelodieText[$m] = $H2[0][$C] Then $AusgabeText=$AusgabeText & $H2[1][$C] & $Zaehler=$Zaehler+1 EndIf If $MelodieText[$m] = $C3[0][$C] Then $AusgabeText=$AusgabeText & $C3[1][$C] & $Zaehler=$Zaehler+1 EndIf If $MelodieText[$m] = $Cis3[0][$C] Then $AusgabeText=$AusgabeText & $Cis3[1][$C] $Zaehler=$Zaehler+1 EndIf If $MelodieText[$m] = $D3[0][$C] Then $AusgabeText=$AusgabeText & $D3[1][$C] & $Zaehler=$Zaehler+1 EndIf If $MelodieText[$m] = $Dis3[0][$C] Then $AusgabeText=$AusgabeText & $Dis3[1][$C] $Zaehler=$Zaehler+1 EndIf If $MelodieText[$m] = $E3[0][$C] Then $AusgabeText=$AusgabeText & $E3[1][$C] & $Zaehler=$Zaehler+1 EndIf If $MelodieText[$m] = $F3[0][$C] Then $AusgabeText=$AusgabeText & $F3[1][$C] & $Zaehler=$Zaehler+1 EndIf If $MelodieText[$m] = $Fis3[0][$C] Then $AusgabeText=$AusgabeText & $Fis3[1][$C] $Zaehler=$Zaehler+1 EndIf If $MelodieText[$m] = $G3[0][$C] Then $AusgabeText=$AusgabeText & $G3[1][$C] & $Zaehler=$Zaehler+1 EndIf If $MelodieText[$m] = $Gis3[0][$C] Then - 64 - "%, " & $D2[1][0] & "%, " & "%, " & $Dis2[1][0] & "%, " "%, " & $E2[1][0] & "%, " "%, " & $F2[1][0] & "%, " & "%, " & $Fis2[1][0] & "%, " "%, " & $G2[1][0] & "%, " & "%, " & $Gis2[1][0] & "%, " "%, " & $A2[1][0] & "%, " & "%, " & $Ais2[1][0] & "%, " "%, " & $B2[1][0] & "%, " "%, " & $H2[1][0] & "%, " "%, " & $C3[1][0] & "%, " & "%, " & $Cis3[1][0] & "%, " "%, " & $D3[1][0] & "%, " & "%, " & $Dis3[1][0] & "%, " "%, " & $E3[1][0] & "%, " "%, " & $F3[1][0] & "%, " & "%, " & $Fis3[1][0] & "%, " "%, " & $G3[1][0] & "%, " $AusgabeText=$AusgabeText & $Gis3[1][$C] & "%, $Zaehler=$Zaehler+1 EndIf If $MelodieText[$m] = $A3[0][$C] Then $AusgabeText=$AusgabeText & $A3[1][$C] & "%, " $Zaehler=$Zaehler+1 EndIf If $MelodieText[$m] = $Ais3[0][$C] Then $AusgabeText=$AusgabeText & $Ais3[1][$C] & "%, $Zaehler=$Zaehler+1 EndIf If $MelodieText[$m] = $B3[0][$C] Then $AusgabeText=$AusgabeText & $B3[1][$C] & "%, " $Zaehler=$Zaehler+1 EndIf If $MelodieText[$m] = $H3[0][$C] Then $AusgabeText=$AusgabeText & $H3[1][$C] & "%, " $Zaehler=$Zaehler+1 EndIf If $MelodieText[$m] = $P[0][$C] Then $AusgabeText=$AusgabeText & $P[1][0] & "%, " & $Zaehler=$Zaehler+1 EndIf Next " & $Gis3[1][0] & "%, " & $A3[1][0] & "%, " " & $Ais3[1][0] & "%, " & $B3[1][0] & "%, " & $H3[1][0] & "%, " $P[1][$C] & "%, " Next $PrgCode = "For I = 0 To " & $Zaehler*2-1 & Chr(13) & Chr(10) & " Note = Lookup(I, " & GUICtrlRead($MelodieName) & ")" & Chr(13) & Chr(10) $PrgCode = $PrgCode & " Incr I" & Chr(13) & Chr(10) $PrgCode = $PrgCode & " If Note = 0 Then" & Chr(13) & Chr(10) & " Pause = Lookup(I ," & GUICtrlRead($MelodieName) & ")" & Chr(13) & Chr(10) $PrgCode = $PrgCode & " Waitms Pause" & Chr(13) & Chr(10) & " Else" & Chr(13) & Chr(10) $PrgCode = $PrgCode & " Laenge = Lookup(I, " & GUICtrlRead($MelodieName) & ")" & Chr(13) & Chr(10) $PrgCode = $PrgCode & " Sound Speaker , Note , Laenge " & Chr(13) & Chr(10) & " End If" & Chr(13) & Chr(10) & "Next I" & Chr(13) & Chr(10) & Chr(13) & Chr(10) $PrgCode = $PrgCode & GUICtrlRead($MelodieName) & ":" & Chr(13) & Chr(10) & "Data " $AusgabeText = StringTrimRight ($AusgabeText,2) GUICtrlSetData($Ausgabe,$PrgCode & $AusgabeText) Case $DelAll $AusgabeText="" GUICtrlSetData($Ausgabe, "") GUICtrlSetData($Eingabe, "") EndSwitch WEnd Func weekday2number (ByRef $Weekday) if $Weekday = "Montag" then $Weekdayn=1 if $Weekday = "Dienstag" then $Weekdayn=2 if $Weekday = "Mittwoch" then $Weekdayn=3 if $Weekday = "Donnerstag" then $Weekdayn=4 if $Weekday = "Freitag" then $Weekdayn=5 if $Weekday = "Samstag" then $Weekdayn=6 if $Weekday = "Sonnabend" then $Weekdayn=6 if $Weekday = "Sonntag" then $Weekdayn=7 Return $Weekdayn Endfunc Func SecOfday (ByRef $Ttime) $SecOfDay=Number(StringLeft($Ttime,2))*60*60+Number(StringMid ($Ttime,4,2))*60+Number(StringMid ($Ttime,7,2)) Return $SecOfDay EndFunc Func Ostern (Byref $Jahr) ;Ostern Wikipedia nach Lichtenberg $K = $Jahr / 100 $M = Int(15 + (3*$K + 3) / 4 - (8*$K + 13) / 25) $S = Int(2 - (3*$K + 3) / 4) $A = Mod($Jahr, 19) $D = Mod((19*$A + $M), 30) - 65 - $R = Int(($D + $A / 11) / 29) $OG = 21 + $D - $R $SZ = 7 - Mod(Int(($Jahr + $Jahr / 4 + $S)), 7) $OE = 7 - Mod(($OG - $SZ), 7) $OS = $OG + $OE If $OS > 31 then $OS=$OS -31 $Monat="04" Else $Monat="03" EndIf $OS=StringFormat("%02s",$OS) $Osterdatum = $OS &"."& $Monat& "." & $Jahr Return $Osterdatum EndFunc ; aus IsItDark von JustinTime Func SunTimes ($day, $isdst) Dim $day, $n, $i, $w, $m, $l, $e, $e1, $a, $xv, $yv, $v, $xs, $ys, $xe, $ecl, $lonsun, $ye, $ze, $ra, $dec, $h, $r, $E1 Dim $GMST0, $UT_Sun_in_south, $LHA, $hour_rise, $hour_set, $min_rise, $min_set ; Orbital elements of the Sun: $N = 0.0 $i = 0.0 $w = 282.9404 + 0.0000470935 * $day $a = 1.000000 $e = 0.016709 - 0.000000001151 * $day $M = 356.0470 + 0.9856002585 * $day $M = rev($M) $ecl = 23.4393 - 0.0000003563 * $day $L = $w + $M if ($L < 0 OR $L > 360) then $L = rev($L) Endif ; position of the Sun $E1 = $M + $e*(180/$pi) * sind($M) * ( 1.0 + $e * cosd($M) ) $xv = cosd($E1) - $e $yv = sqrt(1.0 - $e * $e) * sind($E1) $v = atan2d($yv, $xv) $r = sqrt($xv * $xv + $yv * $yv) $lonsun = $v + $w if ($lonsun < 0 OR $lonsun > 360) then $lonsun = rev($lonsun) Endif $xs = $r * cosd($lonsun) $ys = $r * sind($lonsun) $xe = $xs $ye = $ys * cosd($ecl) $ze = $ys * sind($ecl) $RA = atan2d($ye, $xe) $Dec = atan2d($ze, (sqrt(($xe * $xe)+($ye * $ye)))) $h=-0.833 $GMST0 = $L + 180 if ($GMST0 < 0 OR $GMST0 > 360) then $GMST0 = rev($GMST0) Endif $UT_Sun_in_south = ( $RA - $GMST0 - $longitude ) / 15.0 if ($UT_Sun_in_south < 0) then $UT_Sun_in_south=$UT_Sun_in_south + 24 Endif $LHA= (sind($h) - (sind($latitude) * sind($Dec)))/(cosd($latitude) * cosd($Dec)) if ($LHA > -1 AND $LHA < 1) then $LHA=acosd($LHA)/15 else $SunTimes = "No sunrise;No sunset" return $suntimes - 66 - Endif $hour_rise=$UT_Sun_in_south - $LHA $hour_set=$UT_Sun_in_south + $LHA $min_rise=int(($hour_rise-int($hour_rise)) * 60) $min_set=int(($hour_set-int($hour_set)) * 60) $hour_rise=(int($hour_rise) + ($TZ + $isdst)) $hour_set=(int($hour_set) + ($TZ + $isdst)) if ($min_rise < 10) then $min_rise = StringRight("0000" & $min_rise, 2) Endif if ($min_set < 10) then $min_set = StringRight("0000" & $min_set, 2) Endif ;slightly modified the formatting of the following line format from original version. if $hour_rise < 10 then $null=0 else $null = "" EndIf $SunTimes = $null & $hour_rise & ":" & $min_rise & $hour_set & ":" & $min_set Return $Suntimes EndFunc ;Now all the Support Funcs Func sind($qqq) $sind = sin(($qqq) * $DEGRAD) return $sind EndFunc Func cosd($qqq) $cosd = cos(($qqq) * $DEGRAD) return $cosd EndFunc Func tand($qqq) $tand = tan(($qqq) * $DEGRAD) return $tand EndFunc Func atand($qqq) $atand = ($RADEG * atan($qqq)) return $atand EndFunc Func asind($qqq) $asind = ($RADEG * asin($qqq)) return $asind EndFunc Func acosd($qqq) $acosd = ($RADEG * acos_new($qqq)) return $acosd EndFunc Func atan2d ($qqq, $qqq1) $atan2d = ($RADEG * atan2($qqq, $qqq1)) return $atan2d EndFunc Func rev($qqq) Dim $x $x = ($qqq - int($qqq/360.0) * 360.0) if ($x <= 0) then $x = $x + 360 Endif $rev = $x return $rev EndFunc Func atan2($ys,$xs) ; from the Draw Arrows tip ; @ http://www.devx.com/upload/free/features/VBPJ/techtips/techtips11.pdf ; by —Jim Deutch, Syracuse, New York - 67 - Dim $theta If $xs <> 0 Then $theta = Atan($ys / $xs) If $xs < 0 Then $theta = $theta + $pi Endif Else If $ys < 0 Then $theta = 3 * $pi / 2 ;90 Else $theta = $pi / 2 ;270 Endif Endif $atan2 = $theta return $atan2 EndFunc Func acos_new($x) $acos_new = Atan(-$X / Sqrt(-$X * $X + 1)) + 2 * Atan(1) return $acos_new EndFunc - 68 -