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
Hi
>Ich habe 10 Zeitschleifen für einen Rasensprenger.
TIMER
MfG Spess
Warum verwendest du keine Timer? Und warum Assembler und nicht C?
:
Bearbeitet durch User
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.
Sven B. schrieb: > Hey, es ist immerhin kein JPEG! Ich hätte da noch DOCX und BMP als absolutes No-Go anzubieten.
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.
:
Bearbeitet durch User
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.
:
Bearbeitet durch User
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.
:
Bearbeitet durch User
Oder in C:
1 | #include <stdint.h> |
2 | #include <avr/io.h> |
3 | #include <util/delay.h> |
4 | |
5 | void delay_s(uint8_t secs) { |
6 | while(secs--) // secs Mal |
7 | _delay_ms(1000); // 1 Sekunde warten |
8 | }
|
9 | |
10 | int main(void) { |
11 | PORTB |= 1<<2; // Stromhaltung |
12 | PORTD |= 1<<0; // Rasensprenger 1 an |
13 | for(int8_t i = PIN4 & 1<<4 ? 10 : 8; i>=0; i--) { |
14 | 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
1 | rjmp . |
2 | nop |
könnten deswegen entfallen.
:
Bearbeitet durch Moderator
Yalu X. schrieb: > Dazu kommt ggf. noch der CRT0-Startcode aus der C-Bibliothek. Muss ja, wegen Stack.
1 | PORTC = (PORTC & 0x0f) | i; // Ausgabe von i auf PORTC[0..3] |
Die unteren 4 bits sollen ausgeblendet werden, oder ?
1 | PORTC = (PORTC & 0xf0) | i; // Ausgabe von i auf PORTC[0..3] |
Aber:
1 | subi r28,lo8(-(-1)) |
2 | sbrs r28,7 |
LOL, das mit 7-tem bit habe ich lange nicht gesehen und gerade heute in einem anderen Thread daruber diskutiert.
:
Bearbeitet durch User
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.