Guten Tag.
Ich versuche eine Gartensprengeranlage zu programmieren.
Es gibt 12 Ausgänge (Magnetventile für Rasensprenger) die jeweils 6, 8
oder 10 Minuten aktiv sind.
Es gibt eine binäre Ausgabe der verbleibenden Zeit.
Bedingt durch den niedrigen Wasserdruck kann immer nur ein Ausgang
( Magentventil der Rasensprenger) aktiv sein.
Um den Wasserschlag der schließenden Magnetventile zu verhindern wird
immer erst der zeitlich folgende Ausgang aktiv gesetzt, 10 Sekunden
gewartet und dann der vorherige Ausgang inaktiv gesetzt.
Das Programm soll über das Einschalten der Betriebsspannung selbst
starten und
nach Beendigung des Programmablaufes die Betriebsspannung selbstständig
ausschalten.
Dazu wird am Programmanfang der Port PB2 auf 1 gesetzt wodurch eine
Halteschaltung aktiv wird.
Am Ende des Programm wird PB2 auf 0 gesetzt, somit ist keine
Betriebsspannung mehr vorhanden.
Das Programm, mit meinen Programmierkenntnissen, ufert nun aus.
Ich habe 10 Zeitschleifen für einen Rasensprenger.
Deshalb hoffe ich das mir jemand Tips gibt wie ich das Programm
einfacher schreiben kann.
Bisher habe ich einen Ausschnitt Programmanfang/ Ende eingestellt, kann
aber gerne das ganze Programm in Textformat einstellen.
Gruß Ritschel
Ritschel schrieb:> Das Programm, mit meinen Programmierkenntnissen, ufert nun aus.
Umsteigen. Ob jetzt BASIC oder C oder sonstwas ist eigentlich egal.
Irgendwann kann die Assembler-Masochisten-Zeit auch mal vorbei sein.
Hi
>Umsteigen. Ob jetzt BASIC oder C oder sonstwas ist eigentlich egal.>Irgendwann kann die Assembler-Masochisten-Zeit auch mal vorbei sein.
Bei der Wahl der falschen Mittel ist die Programmiersprache egal.
MfG Spess
spess53 schrieb:> Bei der Wahl der falschen Mittel ist die Programmiersprache egal.
Hmm. Könnte sein. Mit einer anderen Programmiersprache ist es aber
(vielleicht) übersichtlicher. Möglicherweise ist es dann immer noch
schlecht programmiert, aber es würde laufen.
Heinz K. schrieb:> Warum verwendest du keine Timer?>> Und warum Assembler und nicht C?
Und warum um alles in der Welt postet man Sourcecode als PNG-Datei? :-(
Ritschel schrieb:> Das Programm, mit meinen Programmierkenntnissen, ufert nun aus.> Ich habe 10 Zeitschleifen für einen Rasensprenger.
Klopp den Warteschleifengenerator in die Tonne.
Wenn man etwas mehrmals braucht, schreibt man ein Macro oder eine
Funktion, der man z.B. die Wartezeit als Argument übergibt.
Man kann dann sogar die Zeit in s oder ms als Klartext übergeben und den
Assembler/Compiler anhand der CPU-Frequenz die nötigen Variablen
ausrechnen lassen. Der AVR-Assembler kann intern bis 64Bit Ganzzahl und
der C-Compiler double float rechnen.
Mark B. schrieb:> Heinz K. schrieb:>> Warum verwendest du keine Timer?>>>> Und warum Assembler und nicht C?>> Und warum um alles in der Welt postet man Sourcecode als PNG-Datei? :-(
Hey, es ist immerhin kein JPEG!
Ritschel schrieb:> Deshalb hoffe ich das mir jemand Tips gibt wie ich das Programm> einfacher schreiben kann.
Wenn du schon nicht mit Timer arbeiten willst, dann folgendes:
Zeitschleifen als Routinen schreiben die mit rcall aufgerufen werden,
in eine gesonderte Datei schreiben und mit .include einbinden.
So etwas untereinander zu schreiben ist grauenhaft.
Statemachine in mainloop, die regelmässig Zustände von Flags prüft
und entsprechende Aktionen unternimmt.
Kann sogar ziemlich übersichtlich werden.
Ritschel schrieb:> Nun hochgeladen als Text.
Hänge die Quelltext-Datei doch bitte als .asm an, so wie sie eben heißt.
Die Verwendung eines einzelnen Timers wurde ja schon genannt.
Ansonsten mache doch eine Tabelle wie eine LUT:
2 Bytes für die zu schaltenden Ausgänge + 2 Bytes für die Zeit in
Sekunden.
In der letzten Zeile stehen dann 4 Nullen. Die kann man leicht abprüfen
und so erkennen dass die Tabelle nun zu Ende ist und zum Anfang
zurückspringen.
Ritschel schrieb:> Nun hochgeladen als Text.
Zeilen in deiner Datei: 456
Zeilen mit nur einer Zeitschleife und 12 x rcall mit
Parameterübergabe: 230
Das ganze ohne Kommentare mit 12 x rcall und auch ohne
Statemachine, einfach durchfallen: <= 98 Zeilen.
Ist dir schon aufgefallen, dass der Warteschleifengenerator für alle
Verzögerungen ≥ 60 s den gleichen Code generiert?
Müssen die Verzögerungen tatsächlich taktzyklengenau eingehalten werden,
d.h. ist es ein Problem, wenn der Rasensprenger statt 10 m 00.000000 s
nur 9 m 59.999999s eingeschaltet wird?
Um diese hohe Genauigkeit zu erreichen, erzeugt der Generator recht
komplizierten Code, der zudem noch umständlicher ist, als er eigentlich
sein müsste.
Schreib dir selber eine Warteschleife mit einer Auflösung von bspw. 1 s,
die du als Unterprogramm mit einem Registerargument beliebig oft in
deinem Code aufrufen kannst.
Auch eine Lösung mit Timer-Interrupt wird nicht einfacher, hat aber den
Vorteil, dass der Controller nebenher noch andere Dinge erledigen oder
alternativ sich die meiste Zeit schlafen legen kann.
Ritschel schrieb:> Nun hochgeladen als Text.
Probiere es mal mit angehängten Dateien.
EDIT:
Zeiten im ZH-reg.
Wird nicht auf 0 geprüft, ZH = 0 ergibt 256 Durchläufe.
Marc V. schrieb:> Probiere es mal mit angehängten Dateien.
Edit ging nicht mehr, hab erst jetzt gesehen, dass du einfach
runterzählst, hier ist komplettes Programm.
P.S.
84 Zeilen.
PORTC=(PORTC&0x0f)|i;// Ausgabe von i auf PORTC[0..3]
15
delay_s(60);// 60s warten
16
}
17
PORTD|=1<<1;// Rasensprenger 2 an
18
delay_s(10);// 10s warten (Druckstoßreduzierung
19
PORTD&=~(1<<0);// Rasensprenger 1 aus
20
PORTB&=~(1<<2);// Strom aus
21
}
Die Pinnummern könnte man noch durch aussagekräftigere Symbole
(RASENSPRENGER_0, RASENSPRENGER_1 usw.) ersetzen.
Der GCC generiert daraus folgenden Assemblercode:
1
delay_s:
2
.L2:
3
tst r24
4
breq .L5
5
ldi r18,lo8(199999)
6
ldi r19,hi8(199999)
7
ldi r25,hlo8(199999)
8
1: subi r18,1
9
sbci r19,0
10
sbci r25,0
11
brne 1b
12
rjmp .
13
nop
14
subi r24,lo8(-(-1))
15
rjmp .L2
16
.L5:
17
ret
18
main:
19
push r28
20
sbi 0x18,2
21
sbi 0x12,0
22
sbic 0x13,4
23
rjmp .L9
24
ldi r28,lo8(8)
25
rjmp .L8
26
.L9:
27
ldi r28,lo8(10)
28
.L8:
29
in r24,0x15
30
andi r24,lo8(15)
31
or r24,r28
32
out 0x15,r24
33
ldi r24,lo8(60)
34
rcall delay_s
35
subi r28,lo8(-(-1))
36
sbrs r28,7
37
rjmp .L8
38
sbi 0x12,1
39
ldi r24,lo8(10)
40
rcall delay_s
41
cbi 0x12,0
42
cbi 0x18,2
43
ldi r24,0
44
ldi r25,0
45
pop r28
46
ret
Dazu kommt ggf. noch der CRT0-Startcode aus der C-Bibliothek.
Die Warteschleife in delay_s() ist etwas komplizierte als nötig, da
delay_ms(1000) zyklengenau 1 Sekunde wartet, was hier nicht wichtig ist.
Die Zeilen
Marc V. schrieb:> Yalu X. schrieb:>> Dazu kommt ggf. noch der CRT0-Startcode aus der C-Bibliothek.>> Muss ja, wegen Stack.
Nur bei den Uralt-AVRs, die beim Reset den Stack-Pointer mit 0
initialisieren. Die neueren setzen ihn stattdessen auf RAMEND.
> PORTC = (PORTC & 0x0f) | i; // Ausgabe von i auf PORTC[0..3]>> Die unteren 4 bits sollen ausgeblendet werden, oder ?>> PORTC = (PORTC & 0xf0) | i; // Ausgabe von i auf PORTC[0..3]
Ja, da habe ich mich vertan. Danke für die Korrektur.
> Aber:>> subi r28,lo8(-(-1))> sbrs r28,7>> LOL, das mit 7-tem bit habe ich lange nicht gesehen und gerade heute> in einem anderen Thread daruber diskutiert.
Statt dem SBRS mit dem nachfolgende RJMP hätte der Compiler auch einfach
einen BRPL nehmen können.
Ich habe jetzt auch mal ein Programm für Deine Anwendung geschrieben.
Leider auch in Assembler. Aber für ein paar Portbits setzen und warten
reicht das auch, auch wenn es scheinbar uncool ist.
Das ist jetzt eine Ablaufsteuerung, die Du frei programmieren kannst.
-------------------------------------------------
/* ***Anleitung Zeitablauf ***
Befehle hintereinander in Tabelle schreiben:
.dw xxx,xxx,xxx,xxx,xxx,xxx ...
.dw xxx,xxx,xxx,xxx,xxx,xxx ... ,ENDE
RSx_AN/AUS , Wartezeit Minuten <=255, Wartezeit Sekunden <=255
WARTEN , Wartezeit Minuten <=255, Wartezeit Sekunden <=255
ENDE (Programm Ende und Abschaltung)
zB:
ZeitAblauf: .dw RS1_AN ,7,50, RS2_AN ,0,10, RS1_AUS,9,50, RS3_AN,0,10
.dw RS2_AUS,9,50, RS3_AUS,0,0
.dw WARTEN,240,00,WARTEN,240,00, ENDE
(00m00s) RS1_AN ,7,50 = Rasenspr. 1 AN und 7min 50sek warten (RS1 an)
(07m50s) RS2_AN ,0,10 = RS2 anschalten und 10sek warten (RS1+RS2 an)
(08m00s) RS1_AUS,9,50= RS1 AUS und 9min 50sek warten (RS2 an)
(17m50s) RS3_AN ,0,10 = RS3 anschalten und 10sek warten (RS2+RS3 an)
(18m00s) RS2_AUS,9,50= ... (RS3 an)
(27m50s) RS3_AUS,0,0 = RS3 aus, nicht warten (alle aus)
(27m50s) WARTEN,240,00, WARTEN,240,00 = nichts schalten - nur warten
(8h28m00s) ENDE = Ende des Programms
*/
-------------------------------------------------
Was Du mit den Eingängen C4 C5 gemeint hast, ist mir nicht klar. Kann
man dann noch einbauen.
Vielleicht bringt es Dir was. Hat auf jeden Fall Spass gemacht. Sowas
kann man vielleicht auch für andere Sachen brauchen.
gruss
HerrMueller
Danke erstmal für euere Bereitschaft mir zu helfen.
Die Idee mit den Warteschleifen habe ich aufgegeben.
Danke noch für den Tip die Datei.txt zu Assembler zu konvertieren.
Ich hatte immer die gleiche Schleife ( Beschreibung) angegeben. Das
funktioniert nicht.
Bei Weiterführung der Schleifentechnik hätte ich über 130 Schleifen
generiert.
Zum Programm.
Ich möchte das die verbleibende Sprengerzeit in binär angezeigt wird.
Ausgabe über PC0 bis PC3.
ca 10,9,8,7,6,5,4,3,2,1 Minuten .
PC4 und PC5
Darüber wollte ich die Sprengerzeiten beeinflussen.
Standart sollte 8 Minuten pro Rasensprenger sein.
Es wird nicht lange dauern, dann wird behauptet der Rasen ist zu viel
gegossen oder der Rasen ist zu trocken.
Deshalb die Idee über die beiden Eingänge eine Veränderung der
Sprengerzeiten realisieren. 6,8 oder 10 Minuten.
Gruß Ritschel
Nun versuche ich die für mich von euren Lösungen einfachste umzusetzen.
Sicherlich habe ich noch einige Fragen zum Programmierverständnis.
hallo
Ich habe jetzt die beiden Schalter C4/C5 noch mit berücksichtigt.
Schalter gegen GND.
Bei einer Zeitprogrammierung ab 5 Minuten wird mit Schalter C4 2 Minuten
addiert - Schalter C5 +4 Minuten - beide +6 Minuten.
Das heisst: Du programmierst 6 Min - Mit Schalter C4 = 8 Min - Schalter
C5 10 Min - beide 12 Min.
Bei Zeiten von 0 bis 4 Min werden die Schalter ignoriert, um die
Überschneidung der Sprengerzeit programmieren zu können, ohne dass zu
den 10 Sek. x Minuten addiert werden.
Das Programm sollte so direkt lauffähig sein (natürlich noch die Zeiten
eingeben)
gruss
HerrMueller
Danke erstmal Herr Müller.
Ich werde das Program ausprobieren.
Die Platine wird heute erstellt.
Ich verstehe im Beispiel Deinen Zeitablauf .
Nur im Test mit 4 LED verstehe ich den Zeitablauf nicht.
Du setzt in Zeile 3 und Zeile 4 RS3 _aus ,XX,XX und RS4_aus, XX,XX.
Warum schaltest du erneut in Zeile 4 aus aus wenn beide bereits aus
Zeile 3 aus sind ?
Oder verstehe ich den Zeitablauf noch nicht.
Gruß Ritschel
Hallo HerrMüller
Ich habe das Programm weiter vervollständigt.
Leider habe ich noch Probleme die ich auf meine Unwissenheit
zurückführe.
Ich stelle die Datei hier einmal ein.
Problem 1.
Der Wechsel von RS1_an zu RS2_AN funktioniert nicht.
Es ist entweder Port D0 oder D1 an.
Beide sind nicht zur gleichen Zeit an.
Das psssiert nur bei Port D0 und D1 ,bei Port D1 und D2 etc funktioniert
es.
************************************************************************
*
Ich habe deshalb versucht Port D0 bis D4 nacheinander einzuschalten.
.dw RS1_AN ,0,30, RS2_AN ,0,30, RS3_AN ,0,30, RS4_AN 0,30.
Port D0 ist sofort an, dann passiert nichts dann sind Ports D1,D2,D3
zeitgleich an.
Die Datei mit dem Testversuch habe ich nicht angehängt.
************************************************************************
*
Wird C4 nach Masse gezogen, scheint die Zeit ins unendliche zu gehen.
Gruß Ritschel
Kuckuck!
Ritschel schrieb:> Nur im Test mit 4 LED verstehe ich den Zeitablauf nicht.>> Du setzt in Zeile 3 und Zeile 4 RS3 _aus ,XX,XX und RS4_aus, XX,XX.>> Warum schaltest du erneut in Zeile 4 aus aus wenn beide bereits aus> Zeile 3 aus sind ?
Da hast Du recht, den hätte ich nicht nochmal abschalten müssen. Ich
habe die Zeilen aus Faulheit mit Copy/Paste kopiert und verändert, da
ist es mir nicht aufgefallen. Nochmal Abschalten hat ja auf den Ablauf
keinen Einfluss.
Eigentlich könnte man sich den Befehl WARTEN sparen, indem man einfach
den letzten Befehl mit einer weiteren Wartezeit wiederholt. (Ausser und
Anner geht ja nicht ;-) ).
>Ich habe deshalb versucht Port D0 bis D4 nacheinander einzuschalten.>.dw RS1_AN ,0,30, RS2_AN ,0,30, RS3_AN ,0,30, RS4_AN 0,30.>>Port D0 ist sofort an, dann passiert nichts dann sind Ports D1,D2,D3>zeitgleich an.
Das kann ich leider nicht nachvollziehen. Ich habe Deine Version geladen
und bei mir funktioniert es einwandfrei. Das muss dann an der Hardware
liegen. Schau nochmal, ob an den Pins was falsch - oder noch was anderes
angeschlossen ist. (Siehe Video - Deine Daten (7.50, 0.10 ...) mit 80
facher Geschwindigkeit. Die Leds sind invers, dh. Led AN = 0 , Led AUS =
1 )
Die 10sek kann man nur schwach erkennen 0.125s, aber sie sind da.
>Wird C4 nach Masse gezogen, scheint die Zeit ins unendliche zu gehen.
Da hast Du recht, das war ein Fehler von mir. Ich habe die Abfrage in
die Verzögerungsschleife gesetzt, deshalb hat er zu jeder Minute 2min
dazu gezählt. (Leider nur mit 1 Min getestet, da hat es ja gestimmt.)
Jetzt steht sie davor und es stimmt. Diesmal getestet mit 8Mhz (8 fach
Geschw.). Anzeit 1min, C4 1m15s, C5 1m30s, C4+C5 1m45s .
Wenn Du an den Fuses nicht rumspielen willst, kannst Du zum Testen auch
die Warteschleife Delay1s am Ende des Prg. verändern. 10 fach Werte
einsetzen
ldi XH, $D9 ; 1 Takt (10 fach = $1b)
ldi XL, $03 ; 1 Takt (10 fach = $63) X =55555
gruss
HerrMueller
Hallo
HerrMüller
Danke für die schnelle Antwort.
Zu den Fuses.
Die hatte ich im Test geändert, damit der Ablauf schneller voran geht.
C4 und die Zeiten.
Jetzt funktioniert das herunterzählen.
Die beiden anderen Zeiteinstellungen habe ich moch nicht ausprobiert.
Zu dem Port D0 und D1
Da habe ich mich selbst überlistet.
Die Ausgangsports des Atmega werden über einen ULN 2003 A in der
Leistung verstärkt.
Zur optischen Darstellung habe ich jedem Ausgangsport des ULN eine LED
zugeordnet.
Allerdings habe ich nur einen gemeinsamen Widerstand für die LED`s
genommen.
Solange die LED`s identisch sind geht das.
Ich mußte jedoch eine LED (blau) (Port D0) wegen einem defekt ersetzen.
Blaue LED war nicht mehr vorhanden deshalb eine zum Test in rot
genommen.
Blau hat 3,3 Volt, Rot hat 2 Volt. Somit konnte keine weitere LED
leuchten solange Port D0 aktiv war.
Gruß Ritschel
Juhu!
Das freut mich, dass es nun klappt.
Du kannst das Programm ja noch ein bisschen ausbauen, zB. 2 stellige
Minutenanzeige oder Anschluss von Bewegungsmeldern, die bei
Rasenbenutzung die Sprenger deaktivieren - oder gegen Einbrecher
aktivieren ...
Nach SmartHome kommt SmartGarden.
Jetzt hoffe ich nur noch, dass das Wetter den Einsatz nötig werden
lässt.
Im Moment kanst Du es ja mit 12 Heizlüftern zum Trocknen des Rasens
betreiben ;-) .
Viel Spass noch mit dem Hobby
und
... Assembler ist gar nicht so schlecht
HerrMueller
...wäre das nicht mal ein Projekt für unseren Assemblerkönig Moby?
Ich wette, von seiner Seite wird da nix kommen. Dabei wäre das doch n
Klacks für ihn...
Hallo HerrMüller
Nicht übertreiben sonst wird es zu kompliziert im Fehlerfall.
Jetzt kam schon der Wunsch die 4 LED gegen eine Minutenanzeige
auszutauschen.
Klar kein Problem gab doch LED Anzeige mit binaeren Eingang.
Anschliessen, fertig.
Irgendwie kann ich die LED Anzeig mit Binaereingang nicht mehr finden.
Ich überlege die Sprengersteuerung später mit dem Mähroboter zu
koppeln.
Deshalb auch die Eintastensteuerung.
Wenn der Mähroboter seine Arbeit erledigt hat, kann die
Sprengersteuerung arbeiten.
Der Vorteil, fährt der Mähroboter wegen Regen nicht los , wird auch
nicht der Rasen gesprengt.
Eine Austaste hatte ich vergessen. Muß ich noch einbauen.
Dann kann bald das Gehäuse erstellen.
Zum Schluß ..... Erstmal danke für eure Unterstützung.
Wenn gewünscht kann ich den Schaltplan hier einstellen.
Im allgemeinen kann man in den Foren einen kleinen Betrag spenden.
Gibt es hier auch solch einen Link ?
Gruß Ritschel
Ikke schrieb:> ...wäre das nicht mal ein Projekt für unseren Assemblerkönig Moby?> Ich wette, von seiner Seite wird da nix kommen. Dabei wäre das doch n> Klacks für ihn...
Der hat längst auf Raspberry umgeschwenkt und kann nun nur noch kein
Linux.
Aber noch nicht so gut wie früher Assembler.
Hallo nochmals.
Der Schaltplan ist nun fertig.
Der erste Test (mit Rasensprenger ) war erfolgreich.
Allerdings folgen bereits die ersten kleinen Einwände.
Aus der Ferne soll die Anlage ein und ausgeschaltet werden.
Berücksichtigt war , einschalten und ausschalten nach Programmende.
Ich werde mir noch eine Lösung einfallen lassen.
Gruß Ritschel
Es gibt noch eine Änderung .
Der Strom für die Elektromagenten der Rasensprenger soll laut Datenblatt
230 mA im Betrieb betragen.
Gemessen 300 mA . Die ULN2003A fanden bei geschlossenen Gehäuse den
Wärmetot.
Ursachse ist der Hohe UCE (ca 1,5 Volt) der ULN 2003A.
1,5 V *300 mA = 0,45 Watt.
Deshalb habe ich 2 Ausgangstreiber paralell geschaltet.
Zur Bedienung
Grün zum einschalten ,
Rot zum vorzeitigen beenden,
Drehschalter für die Zeiterweiterung, sowie Sonderfunktioneines
seperaten Rasensprenger.
Die Verkabelung gefällt mir noch nicht