Forum: Mikrocontroller und Digitale Elektronik Terrariensteuerung: DCF & 1-Wire zugleich?


von Andi M. (rootsquash)


Angehängte Dateien:

Lesenswert?

Hallo,

ich habe letztes Jahr ja bereits begonnen mir Gedanken zur einer 
Terrariensteuerung zu machen: 
Beitrag "Erste Schaltung: Terrariensteuerung/DCF77/Dimmer/Schalter"
Das Grundgerüstist von der Mikrocontroller-Seite her ist jetzt 
eigentlich fertig.*
Was mir zur Zeit Sorgen macht ist das Auslesen der Temperatur via 1-wire 
Bus:

Bisher basiert der ganze Ablauf, wie das DCF77-Projekt das ich als 
Grundlage genommen habe, darauf, dass jede Millisekunde ein Interrupt 
ausgelöst wird, dann passiert der ganze interessante Kram in der 
Interrupt-Routine und in der Hauptschleife setze ich dann einmal pro 
Sekunde den Inhalt vom Display und die Ausgänge neu.

Wie kriege ich da jetzt die 1-wire-Kommunikation untergebracht?
Meine bisher "beste" Idee ist das auch in der Interrupt-Routine zu 
machen, jede Millisekunde eine Aktion, z.B. ein Reset, ein Bit lesen 
oder ein Bit schreiben.
Andererseits möchte ich die ISR nicht unnötig aufblähen.


main.c im Anhang. Bitte nicht erschrecken, ich bin immernoch Anfänger 
;-)


Grüße, Andi M



*Nachts um 2 oder 3 (Sommer/Winterzeit, so gewählt dass ich immer nur 1 
mal syncen muss) geht die Funkuhr an, wenn das Signal 3 mal in Folge 
korrekte (Prüfbit) Werte geliefert hat die zueinander passen, wird die 
Uhr synchronisiert.
Ein 4x16 Display zeigt die Infos an die ich haben möchte und ich kann 
mit FETs Relais schalten.
Taktquelle ist ein 8 MHz Quarzoszillator.
Die einfachen Funktionen sind somit fertig.

Das Terrarium habe ich in der Zwischenzeit umgebaut, was einer der 
Gründe dafür ist dass das alles so lang gedauert hat.
Vorteil: Für die Beleuchtung brauche ich erstmal keinen Dimmer mehr. Im 
Winter würde ich gerne eine Heizung (Heizkabel oder -Strahler) per 
Dimmer steuern, aber dafür brauche ich ja keine Mikrosekundengenaue 
Steuerung.

von Frank K. (fchk)


Lesenswert?

Andi M. schrieb:

> Wie kriege ich da jetzt die 1-wire-Kommunikation untergebracht?
> Meine bisher "beste" Idee ist das auch in der Interrupt-Routine zu
> machen, jede Millisekunde eine Aktion, z.B. ein Reset, ein Bit lesen
> oder ein Bit schreiben.

Es gibt auch die Möglichkeit, das kritische 1-w Timing mit einem UART zu 
erzeugen. Hier ist das erklärt:

http://www.maxim-ic.com/app-notes/index.mvp/id/214

Der Rest ist vom Timing her unkritisch und kann im Hauptprogramm gemacht 
werden.

fchk

von Andi M. (rootsquash)


Lesenswert?

Ich habe bisher nichts mit dem UART gemacht aber eben schonmal etwas 
dazu gelesen.

Sehe ich das richtg dass der U(S)ART "alleine" arbeitet?
Also einfach einstellen wie schnell er was ausgeben/einlesen soll und 
den ganzen Timing-Kram macht der automatisch, ohne dass der sonstige 
Programmablauf unterbrochen wird?

von Andi M. (rootsquash)


Lesenswert?

Frank K. schrieb:

[...]
> http://www.maxim-ic.com/app-notes/index.mvp/id/214
[...]

Ich habe eine Frage zu dem open-drain buffer circuit:
Die benutzen da 2 2n7002, das Schaltzeichen entspricht einem "normalen" 
MOSFET mit einer parallelgeschalteten, in Sperrichtung gepolten Diode 
zwischen Drain und Source, was auch immer die tun soll.

Ich hätte BS170 und 1N4148. Das sollte auch funktionieren, oder?

von Frank K. (fchk)


Lesenswert?

Andi M. schrieb:
> Ich habe bisher nichts mit dem UART gemacht aber eben schonmal etwas
> dazu gelesen.
>
> Sehe ich das richtg dass der U(S)ART "alleine" arbeitet?
> Also einfach einstellen wie schnell er was ausgeben/einlesen soll und
> den ganzen Timing-Kram macht der automatisch, ohne dass der sonstige
> Programmablauf unterbrochen wird?

Genau. Für den Reset/Presence Detect Puls wird der USART auf 9600bps 
eingestellt, für die Daten auf 115200bps. Das Teil empfängt bei Senden, 
und so bekommst Du die Rückmeldung des Slaves mit.

Zeitkritisch ist nur der Teil beginnend von der fallenden Flanke des 
Startpulses, den der Master vorgibt, bis zur Antwort des Slaves auf den 
Reset bzw auf das jeweilige Bit. Das macht der USART. Die Zeit zwischen 
zwei Bits bzw zwischen Reset/Presence Detect und dem ersten Bit ist 
unkritisch, hier macht ein Interrupt nichts. Das nutzt man aus.

fchk

von Frank K. (fchk)


Lesenswert?

Andi M. schrieb:


> Ich habe eine Frage zu dem open-drain buffer circuit:
> Die benutzen da 2 2n7002, das Schaltzeichen entspricht einem "normalen"
> MOSFET mit einer parallelgeschalteten, in Sperrichtung gepolten Diode
> zwischen Drain und Source, was auch immer die tun soll.

Diese parasitäre Diode ist im MOSFET immer eingebaut und entsteht 
während der Fertigung. Dagegen kann man sich nicht wehren.

> Ich hätte BS170 und 1N4148. Das sollte auch funktionieren, oder?
Streiche die Diode. Ein BC548 sollte es auch tun.

Siehe auch AppNote AVR318.

Ich nehme immer einen 74HC1G125. !OE an TXD, Y(Ausgang) an RXD, 
A(Eingang) fest auf Ground. Wenn Du den nicht bekommst, ist ein ganzer 
HC125 das nächst einfache, wobei Du da ja nur ein von 4 Gattern 
brauchst. Die anderen kannst Du anderweitig verwenden.

fchk

von B. Grzimek (Gast)


Lesenswert?

Hättest du nicht einfach gläserner Temperaturraum o.ä. schreiben können? 
Terrarium klingt so nach Tierquälerei.

von Andi M. (rootsquash)


Lesenswert?

Frank K. schrieb:

> Diese parasitäre Diode ist im MOSFET immer eingebaut und entsteht
> während der Fertigung. Dagegen kann man sich nicht wehren.

Okay, ich war mir nicht sicher ob das ein Sondertyp ist bei dem man 
besonderen Wert auf diese Diode legt. Wenn die einfach den PN-Übergang 
vom Substrat zur Drain-Schicht meinen ist ja alles gut.

>> Ich hätte BS170 und 1N4148. Das sollte auch funktionieren, oder?
> Streiche die Diode. Ein BC548 sollte es auch tun.
mh, ich hätte  BS 170, BS 250, BD 135, 2SK 170, 2SJ 74, ZTX 450 und ZVP 
3310

Frank K. schrieb:
> Genau. Für den Reset/Presence Detect Puls wird der USART auf 9600bps
> eingestellt, für die Daten auf 115200bps. Das Teil empfängt bei Senden,
> und so bekommst Du die Rückmeldung des Slaves mit.
>
> Zeitkritisch ist nur der Teil beginnend von der fallenden Flanke des
> Startpulses, den der Master vorgibt, bis zur Antwort des Slaves auf den
> Reset bzw auf das jeweilige Bit. Das macht der USART. Die Zeit zwischen
> zwei Bits bzw zwischen Reset/Presence Detect und dem ersten Bit ist
> unkritisch, hier macht ein Interrupt nichts. Das nutzt man aus.
>
> fchk


Ah, ja, sehr schön, dann habe ich Sonntag ja was zu tun :D

Vielen Dank

von Peter D. (peda)


Lesenswert?

Andi M. schrieb:
> Bisher basiert der ganze Ablauf, wie das DCF77-Projekt das ich als
> Grundlage genommen habe, darauf, dass jede Millisekunde ein Interrupt
> ausgelöst wird

Warum?
Was muß denn unbedingt alle 1ms gemacht werden?

Die kleinste Dauer bei DCF77 ist 100ms, Eine Abtastung alle 10 oder 20ms 
ist daher dicke ausreichend.

Immer nur so schnell rechnen, wie nötig.


Peter

von Andi M. (rootsquash)


Lesenswert?

Hallo Peter,

das habe ich einfach so gelassen.
Grundlage des Programms ist (wenn ich das gerade nicht verwechsel) das 
DCF-Projekt von hier: Beitrag "DCF-Uhr mit LCD in C"



Zu dem 1-wire über UART-Problem:
Ich habe heute erst mal das Display an einen andere Port verschieben 
müssen, was länger dauerte als ich gedacht hätte und dann habe ich 
angefangen Dinge für den UART zu basteln/programmieren, was bisher so 
mehr oder weniger erfolgreich war:
Ich habe den open drain-Ausgang mit 2 BS170 aufgebaut (woran merke ich 
dass das funktioniert?) und ein paar Funktionen geschrieben, von denen 
ich hoffte dass sie den 1-wire-Baustein nach seiner ID fragen, kriege 
aber eine nicht endende Folge von Zweien und Fünfen.

Demnächst werde ich wohl mal den Beispielquelltext ausprobieren den es 
zur Application Note AVR318 gibt.

von Andi M. (rootsquash)


Lesenswert?

Mh, ich kriege das nicht dazu zu funktionieren.

Ich habe die zu dieser Appnote: http://www.atmel.com/Images/doc2579.pdf
gehörende Software: http://www.atmel.com/Images/AVR318.zip genommen und 
folgende Anpassungen gemacht:

- aus #include <ioavr.h> wurde <avr/io.h>, aus <inavr.h> wurde 
<avr/interrupt.h>
- \ in Pfadnamen durch / ersetzt
- ln -s OWIUARTBitFuntions.c OWIBitFunctions.c
- ./common_files/OWIDeviceSpecific.h: "#define __ATmega8__" eingefügt
- PORTB auf PORTC geändert (die Ausgabe soll auf LEDs landen, nicht auf 
dem Display das ich an PORTB hängen habe)
- Versorgungsspannungspin des DS18S20 auf +5V gelegt, da im Quelltext 
irgendwo in einem Kommentar steht dass diese Funtkion(en) nur dann 
funktionieren würde(n).

Ich übersetze es mit dem "üblichen" Makefile mit:
1
MCU = atmega8
2
F_CPU=8000000UL
3
F_OSC = 8.000MHz
4
FORMAT = ihex
5
TARGET = main
6
SRC = $(TARGET).c ../common_files/OWIcrc.c OWIUARTBitFunctions.c OWIHighLevelFunctions.c 
7
ASRC =
8
OPT = s
9
DEBUG = dwarf-2
10
EXTRAINCDIRS =
11
CSTANDARD = -std=gnu99
12
CDEFS = -DF_CPU=$(F_CPU)
13
CINCS =
14
CFLAGS = -g$(DEBUG)
15
CFLAGS += $(CDEFS) $(CINCS)
16
CFLAGS += -O$(OPT)
17
CFLAGS += -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums
18
CFLAGS += -Wall -Wstrict-prototypes
19
CFLAGS += -Wa,-adhlns=$(<:.c=.lst)
20
CFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS))
21
CFLAGS += $(CSTANDARD)
22
CFLAGS += -DF_OSC=$(F_OSC)
23
[...]
Er meckert nicht allzu viel:
1
In file included from OWIHighLevelFunctions.c:26:0:
2
OWIBitFunctions.h:38:1: warning: function declaration isn’t a prototype [-Wstrict-prototypes]
3
OWIBitFunctions.h:41:1: warning: function declaration isn’t a prototype [-Wstrict-prototypes]
4
OWIBitFunctions.h:44:1: warning: function declaration isn’t a prototype [-Wstrict-prototypes]
5
OWIBitFunctions.h:47:1: warning: function declaration isn’t a prototype [-Wstrict-prototypes]
6
OWIBitFunctions.h:50:1: warning: function declaration isn’t a prototype [-Wstrict-prototypes]
7
OWIHighLevelFunctions.c: In function ‘OWI_SearchRom’:
8
OWIHighLevelFunctions.c:199:13: warning: ‘return’ with no value, in function returning non-void [enabled by default]

Aber das Teil scheint einfach nichts zu machen.

Habe ich etwas wichtiges übersehen?
Was hat es mit dem Makro BUSES auf sich?
Wenn ich das richig sehe liefert das derzeit die beiden UART-Pins, ist 
das so richtig?

Wie kriege ich raus ob der selbstgebaute open collector/drain-buffer 
richtig funktioniert? Ich habe ja nur 2 BS170 und 2 Widerstände so 
zusammengesteckt wie in der AppNote mit 2 BC547 gezeigt wird(das gab es 
woanders genauso, aber mit FETs).

von Andi M. (rootsquash)


Lesenswert?

Ich habe es jetzt so weit eingegrenzt:
1
unsigned char OWI_TouchBit(unsigned char outValue)
2
{
3
    // Place the output value in the UART transmit buffer, and wait
4
    // until it is received by the UART receiver.
5
    OWI_UART_DATA_REGISTER = outValue;
6
    lcd_setcursor(0,1);lcd_data('D');
7
    while(!(OWI_UART_STATCTRL_REG_A & (1 << OWI_RXC)))
8
    {
9
      lcd_setcursor(0,1);lcd_data('F');
10
    }
11
    lcd_setcursor(0,1);lcd_data('G');
12
    // Set the UART Baud Rate back to 115200kbps when finished.
13
    OWI_UART_BAUD_RATE_REG_L = OWI_UBRR_115200;
14
    return OWI_UART_DATA_REGISTER;
15
    lcd_setcursor(0,1);lcd_data('H');
16
}
Das Display zeigt "F"
OWI_UART_STATCTRL_REG_A wird aufgelöst zu UCSRA
OWI_RXC wird aufgelöst zu RXC

Das ist also alles so wie es sein soll,

Hier ist das nochmal mit Kommentar:
1
OWI_UART_WRITE1 = 0xff;
2
3
void OWI_WriteBit1()
4
{
5
    OWI_TouchBit(OWI_UART_WRITE1);
6
}
7
8
9
/*! \brief  Write and read one bit to/from the 1-Wire bus. (Polled UART driver)
10
 *
11
 *  Writes one bit to the bus and returns the value read from the bus.
12
 *
13
 *  \param  outValue    The value to transmit on the bus.
14
 *
15
 *  \return The value received by the UART from the bus.
16
 */
17
unsigned char OWI_TouchBit(unsigned char outValue)
18
{
19
    // Place the output value in the UART transmit buffer, and wait
20
    // until it is received by the UART receiver.
21
    OWI_UART_DATA_REGISTER = outValue;
22
    while(!(OWI_UART_STATCTRL_REG_A & (1 << OWI_RXC)))
23
    {
24
    }
25
    // Set the UART Baud Rate back to 115200kbps when finished.
26
    OWI_UART_BAUD_RATE_REG_L = OWI_UBRR_115200;
27
    return OWI_UART_DATA_REGISTER;
28
}

Kann es sein dass das einfach konzeptionell falsch ist?
Wenn ich ein Bit schreibe soll er beim 1wire-bus doch einfach eine Zeit 
lang warten, nicht bis er eine Rückmeldung bekommt, oder sehe ich das 
hier völlig falsch?

von Peter D. (peda)


Lesenswert?

Ich hätte ja einfach die einfache Lösung genommen (Hochsetzen des 
Interrupts auf 20ms).


Peter

von Andi M. (rootsquash)


Lesenswert?

Hallo Peter,

leider sehe ich noch nicht wie das mein Problem lösen würde.

Ich vermute du schlägst vor die Interrupts weiter auseinander zu ziehen 
damit ich eine reine Softwarelösung für die 1wire-Kommunikation nehmen 
kann, die nicht den UART benötigt sondern einfach irgendeinen I/O-Pin.
Aber 1 Bit dauert ungefähr 500 µs, dann passen in 20 ms doch maximal 40 
Bit, dann kommt wieder ein Interrupt. So weit ich weiß reicht das nicht, 
da ja schon die Geräteadressen 64Bit lang sind.

Die UART-Lösung finde ich im Prinzip ganz gut, ich könnte ja sogar 
sicherstellen dass ich nur jede Millisekunde (oder alle x Millisekunden) 
ein Bit schreibe/lese*, indem ich am Anfang der Schleife den µC in einen 
sleepmode schicke, dann arbeitet er ja den Rest der Schleife erst ab 
wenn die ISR durchgelaufen ist.


Grüße, Andi M



*auch die Bit-Übertragung vom Slave zum Master wird ja vom Master 
initialisiert

von Peter D. (peda)


Lesenswert?

Andi M. schrieb:
> Aber 1 Bit dauert ungefähr 500 µs, dann passen in 20 ms doch maximal 40
> Bit, dann kommt wieder ein Interrupt.

Nö.
Das Reset dauert 480µs, ein Bit aber nur 60µs.

Und man sperrt die Interrupts ja nicht für einen komplettes Datenpaket, 
sondern nur für einen Puls, also max für 480µs.

Die High-Zeit zwischen den Pulsen ist nicht begrenzt, die kann auch 
Stunden dauern. Daher stört dort ein Interrupt nicht.


Peter

von Frank K. (fchk)


Lesenswert?

Andi M. schrieb:
>
1
> OWI_UART_WRITE1 = 0xff;
2
> 
3
> void OWI_WriteBit1()
4
> {
5
>     OWI_TouchBit(OWI_UART_WRITE1);
6
> }
7
> 
8
> 
9
> /*! \brief  Write and read one bit to/from the 1-Wire bus. (Polled UART
10
> driver)
11
>  *
12
>  *  Writes one bit to the bus and returns the value read from the bus.
13
>  *
14
>  *  \param  outValue    The value to transmit on the bus.
15
>  *
16
>  *  \return The value received by the UART from the bus.
17
>  */
18
> unsigned char OWI_TouchBit(unsigned char outValue)
19
> {
20
>     // Place the output value in the UART transmit buffer, and wait
21
>     // until it is received by the UART receiver.
22
>     OWI_UART_DATA_REGISTER = outValue;
23
>     while(!(OWI_UART_STATCTRL_REG_A & (1 << OWI_RXC)))
24
>     {
25
>     }
26
>     // Set the UART Baud Rate back to 115200kbps when finished.
27
>     OWI_UART_BAUD_RATE_REG_L = OWI_UBRR_115200;
28
>     return OWI_UART_DATA_REGISTER;
29
> }
>
> Kann es sein dass das einfach konzeptionell falsch ist?
> Wenn ich ein Bit schreibe soll er beim 1wire-bus doch einfach eine Zeit
> lang warten, nicht bis er eine Rückmeldung bekommt, oder sehe ich das
> hier völlig falsch?

Der Trick ist, dass TXD und RXD über den OC-Treiber (Deine beiden 
Transistoren) und den Pullup auf dem 1W-Bus miteinander verbunden sind. 
Wenn Du also etwas sendest, und es es nichts weiter am Bus 
angeschlossen, dann solltest Du genau das gleiche wieder empfangen. Wenn 
nicht, dann ist an der Hardware etwas faul.

Das musst Du dann debuggen mit den üblichen Elektronik-Messmitteln...

fchk

von Andi M. (rootsquash)


Lesenswert?

Oh, das hört sich sinnvoll an. Dann muss ich heute Nachmittag mal drüber 
nachdenken wie sich der Ausgang verhalten soll und durchmessen.
Schnelltest: Temperatursensor abgezogen -> Funktion läuft durch.


Eine andere Sache: Ich habe ganz übersehen dass in der Application Note 
sogar Hinweise stehen wie man die Software ans Laufen kriegt rotwerd

Leider weiss ich nicht bei allen Punkten was sie damit meinen, ich habe 
das mal mit Fragezeichen an Stelle der Aufzählungszeichen markiert.
Achja: Ich nutze den AVR-GCC unter Linux.


To get started with the polled drivers, follow the steps below:
• Create a new project in IAR embedded workbench. Depending on the 
version, this
might require that a workspace is already created.
• Add all *.c files from the “polled” and “common_files” directories.
• Select the project from the project browser. Right click on the 
project and select
options to bring up the project options dialog.
? Under “General/Target”, make sure that the correct device and memory 
model(?) is
selected.
? Under “General/Library configuration”, check the “Enable bit 
definitions in I/O
include files” option. (#include <avr/io.h>?)
? Under “General/System”, set the Data stack (CSTACK) to 0x40 and the 
Return
stack (RSTACK) to 0x10. This is required to run the memory-intensive 
example
code. Smaller stack sizes may be sufficient for other application 
utilizing this driver.
• If AVRStudio is used for debugging, the output file format must be 
changed. Under
XLINK/Output, select Format/Other, and then select “ubrof 8 (forced)” 
from the
“Output format” drop-down box.
• Open the file “OWIPolled.h” for editing and locate the section named 
“User
defines”.
• Choose between software only or UART driver by uncommenting one of the 
lines
as described in the file.
• Move down to the section corresponding to the selected driver.
• Adjust the defines in the section according to the hardware setup as 
described in
the file.
• The project is now ready to be compiled.

von Andi M. (rootsquash)


Lesenswert?

Peter Dannegger schrieb:
> Andi M. schrieb:
>> Aber 1 Bit dauert ungefähr 500 µs, dann passen in 20 ms doch maximal 40
>> Bit, dann kommt wieder ein Interrupt.
>
> Nö.
> Das Reset dauert 480µs, ein Bit aber nur 60µs.
>
> Und man sperrt die Interrupts ja nicht für einen komplettes Datenpaket,
> sondern nur für einen Puls, also max für 480µs.
>
> Die High-Zeit zwischen den Pulsen ist nicht begrenzt, die kann auch
> Stunden dauern. Daher stört dort ein Interrupt nicht.
>
>
> Peter

Diesen Post habe ich ganz übersehen da Frank direkt danach geantwortet 
hat.
Mir ist eben eingefallen warum ich jede Millisekunde einen Interrupt 
haben möchte:
Ich möchte die Temperatur auslesen um sie zu regeln, das Regeln soll per 
Phasenanschnitt erfolgen. Da eine Halbwelle nur 50 ms dauert hätte ich 
mit 20 ms etwas wenig Auflösung:
Ich dachte daran den Nulldurchgang zu detektieren, entweder indem ich 
den Nulldurchgang zu einem Puls forme und als Interrupt annehme, sofern 
das nicht Konflikte mit dem Timer-Interrupt gibt oder den Nulldurchgang 
oder den Puls per Polling zu detektieren, dann einzustellen in welcher 
Millisekunde der TRIAC zünden soll und ihn dann in der ISR zur 
entsprechenden Millisekunde zu zünden.

Aber:
Wenn ich zwischen den Bits beliebig lang warten kann, kann ich ja 
einfach jedes Bit am Ende der ISR lesen/schreiben.
Ich weiß nicht exakt wie lang die ISR läuft, aber eine LED die ich zu 
Beginn der ISR anmache und am Ende wieder ausschalte leuchtet kaum, da 
sollte also genug Zeit sein, auch mit 1 Interrupt pro Millisekunde.

Deinen 1wire-Quelltext habe ich bereits, wenn ich das mit dem OC-Buffer 
nicht gefixt kriege probiere ich den nachher mal aus.

Kriegt man den DS18S20 kaputt indem man ihn falsch anschließt? Höhere 
Spannungen als 5 Volt habe ich auf dem Steckbrett nicht...

von Andi M. (rootsquash)


Angehängte Dateien:

Lesenswert?

Hallo.

Ich habe etwas weiter gebaut:
Ich habe Peters 1 wire-Code genommen und mit der Tempmeas.c aus diesem 
Post: Beitrag "Re: DS1820, DS18B20 in C" (das ist die 
Variante mit der Namenszuordnung) erweitert. Die Berechnung des 
Temperaturwerts habe ich neu gebaut, die kann jetzt 0,1°C-Schritte und 
negative Temperaturen.

Was noch nicht so recht klappen will ist die parallele Kommunikation per 
1-Wire und Auswertung des DCF-Signals wenn die ISR jede Millisekunde 
läuft.

Jetzt habe ich ein paar "Design"-Fragen:

- Sollte ich die ISR seltener laufenlassen? Peter hat das ja schon 
mehrfach vorgeschlagen, aber das würde die Genauigkeit der geplanten 
Temperaturregelung (über Triac) herabsetzen. Oder Kriegt man das "noch 
nebenbei" mit Timern hin?

- Ich finde die Main-Schleife schon jetzt nicht hübsch.
Kann da mal jemand draufgucken und mir einen Vorschlag machen wie ich 
das einfacher/übersichtlicher aufbauen könnte?

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.