Hallo Freunde der Unendlichkeit.
Für ein neues Projekt will ich einen Mikrocontroller so programmieren,
so dass er zusammen mit einem Drehschalter einen Motor zeitlich steuert.
Der Drehschalter hat 12 Positionen, davon verwende ich aber nur 10.
Einer dieser 10 Pole ist ein OFF bzw. Standby mode. Die anderen sollen
verschiedene zeitliche Pausen einstellen. "Warum Pausen?" Ja der Mototr
soll wiederum an einem Eingang des Mikrocontrollers über ein Relais
geschalten werden. Dafür habe ich 3 Laufzeiten herausgesucht diese dann
beliebig eingestellt werden(durch Lötbrücken ). Jetzt sollen die
Schaltpausen zwischen den Laufzeiten des Motors mit Hilfe des
Drehschalter eingestellt werden.
Wie soll ich das ganze am besten lösen? Wie stelle ich einen Timer
prezise ein bzw. was für ein Quarz sollte ich da am besten verwenden(so
klein wie möglich)? Das ganze sollte am besten in C gelöst werden. Kann
ich die internen Pull-up widerstände ohne großen Aufwand in der Software
in C aktivieren, oder ist einer externe Beschaltung besser?
DANKE
Warum überhaupt einen Quarz?
Wie schlimm ist es, wenn der Motor 1% länger läuft als eingestellt?
Einstellung 1 Minute, läuft nur 59 sekunden => Katastrophe oder egal?
Welche Einstellungs-Möglichkeiten hattest du im Sinn?
wenige ms? => schnell takten.
viele Monate oder Jahre => Lieber extern die Zeit beziehen,
DCF77-Empfänger z.B..
Dazwischen ist die Quarz-Frequenz egal. Ich würde dir als Anfänger aber
eine vorschlagen, die nicht einer der internen RC-Frequenzen
entspricht, z.B. 16 MHz, sonst merkst du evtl. nicht wenn wegen falscher
Fuses der Quarz garnicht verwendet wird.
Und ja, Pullups kann man auch in C aktivieren.
Erstmal danke für deinen Einwand. ist für mich auch sehr
entgegenkommend, da mir eine externes Quarz auch was kostet :-).
Laufzeiten bei Motor sind 1-3 min. Was ich vergessen habe bzw. falsch
erklärt habe: An einem Eingang muss eingestellt werden wie die Laufzeit
des Motors ist (Lötbrücke auf GND), Softwaremäßig muss der jetzt z.B
3min laufen, dann wird die pause durch Drehschalter eingestellt(9
Möglichkeiten und 1 x Off) . Motor soll dementsprechend über einen
Ausgang und einem Relais angesteuert werden. :-D
Grüße
Faisal Alam schrieb:> Laufzeiten bei Motor sind 1-3 min. Was ich vergessen habe bzw. falsch> erklärt habe: An einem Eingang muss eingestellt werden wie die Laufzeit> des Motors ist (Lötbrücke auf GND), Softwaremäßig muss der jetzt z.B> 3min laufen, dann wird die pause durch Drehschalter eingestellt(9> Möglichkeiten und 1 x Off) . Motor soll dementsprechend über einen> Ausgang und einem Relais angesteuert werden. :-D
Ja und.
Wenn wir uns den Motor (bzw. das Relais) durch eine LED ersetzt denken
und anstatt des Drehschalters eine entsprechende Latte von 10 Tastern,
dann hat diese 'Transformation' (die ja nichts an der Funktionalität
ändert) die Aufgabenstellung in einen Bereich gebracht, der in so
ziemlich jedem Tutorial in den ersten 2 oder 3 'Unterrichtseinheiten'
besprochen wird (von 25).
AVR-TutorialAVR-GCC-Tutorial
Wegen dem Quarz:
Klar kostet der was. Im Vergleich zum Rest ist das aber verschwindend.
Die Frage ist: wie genau müssen die Zeiten sein? Wenn es egal ist, ob 1
Minute auch mal 1 oder 2 Millisekunden kürzer oder länger sind, und um
recht viel mehr wird es sich nicht reissen, dann brauchst du keinen
Quarz, sondern kannst dein Timeing auch ganz simpel mit _delay_ms
erreichen. Solange der µC nicht mehr zu tun hat, als diese einfache
Aufgabenstellung bringt es nichts, da komplexere Methoden, wie zb einen
Timeransatz, anzuwenden.
Die eigentlich spannenden Fragen wurden ja noch gar nicht angesprochen:
Wie soll vorgegangen werden, wenn während der Pausezeit jemand am
Drehschalter eine andere Zeit einstellt? Ab wann gilt dann diese Zeit.
Zum Beispiel: Die Pausenzeit ist auf 4 Minuten eingestellt. Die Pause
läuft gerade und es sind bereits 2 Minuten 40 Sekunden vergangen. Genau
zu diesem Zeitpunkt dreht jemand am Drehschalter: 3:30, 3:00, 2:30,
2:00, 1:30 Und nu? Soll der Motor jetzt sofort gestartet werden? Oder
gilt für diese Pause noch die Zeit von 4:00 von vorher?
Was soll passieren, wenn der Motor gerade in seiner 2 Minuten Laufzeit
steckt und jemand dreht den Drehsschalter auf 'OFF'. Stoppt der Motor
dann sofort oder bringt er seinen Zyklus noch hinter sich?
Was ist wenn der Drehschalter auf 'OFF' steht (der Motor steht
ebenfalls) und jemand beginnt den Schalter zu drehen? Was kommt zuerst?
Der Motorzyklus oder die Pause?
Die Antwort auf diese Fragen hat unmittelbare Auswirkungen wie man das
Programm (so simpel es auch ist) aufziehen wird. Daher müssen diese
Fragen im Vorfeld geklärt werden.
Mal wieder danke Karl. Die 1% Fehler können vernachlässigt werden.
Ja du hast recht, das ganze befindet sich eigentlich net in einem hohen
Niveau.
Im Grunde kann ich dass doch so Programmieren.
1. Eingänge und Ausgänge deklarieren:
- Drehschalter Pole als Eingänge
- Motorlaufzeit als EIngang
- Relais mit Logikverschaltung als Ausgang
2. Zur eigentlichen MAIN:
- Motorlaufzeit,eingänge(3 Möglichekeiten sind geplant:1Min,2min,3mIn):
Falls der Pin auf Low gezogen ist(durch lötbrücke einstellbar):
Motorausgang auf High (mit delay als timer?)
(If schleife?switch/case?)
-Wenn ein Pin durch den Schalter auf LoW(Gnd) gezogen wird-> delay um
irgendwas im Sinne von Pause am Ausgang und damit den Pin wieder auf
LOW(Für jede Drehschalter Position)
So sollte es doch funktionieren, oder?
Eine Frage noch? Der Drehschalter funktioniert ja nicht ganz wie taster,
da ja bei einem Drehvorgang auch andere Positionen durchgegangen werden
können. Wie muss ich das in meiner Software mit einplanen? Oder ist das
vernachlässigbar?
Grüße
hast die Einwände von Karl Heinz aber geschickt übergangen.
Überleg dir wann was passieren darf und kann, so musst du dein Programm
gestallten.
Entweder du ließt die Stellungen deiner Drehschaltungen zu Beginn ein
und akzeptierst das keine Änderungen mehr oder du musst halt
schwissendurch nochmal nach den Stellungen schauen und festlegen wie und
ob du darauf reagierst.
Karl Heinz schrieb:> Die eigentlich spannenden Fragen wurden ja noch gar nicht angesprochen:> Wie soll vorgegangen werden, wenn während der Pausezeit jemand am> Drehschalter eine andere Zeit einstellt? Ab wann gilt dann diese Zeit.> Zum Beispiel: Die Pausenzeit ist auf 4 Minuten eingestellt. Die Pause> läuft gerade und es sind bereits 2 Minuten 40 Sekunden vergangen. Genau> zu diesem Zeitpunkt dreht jemand am Drehschalter: 3:30, 3:00, 2:30,> 2:00, 1:30 Und nu? Soll der Motor jetzt sofort gestartet werden? Oder> gilt für diese Pause noch die Zeit von 4:00 von vorher?>> Was soll passieren, wenn der Motor gerade in seiner 2 Minuten Laufzeit> steckt und jemand dreht den Drehsschalter auf 'OFF'. Stoppt der Motor> dann sofort oder bringt er seinen Zyklus noch hinter sich?>> Was ist wenn der Drehschalter auf 'OFF' steht (der Motor steht> ebenfalls) und jemand beginnt den Schalter zu drehen? Was kommt zuerst?> Der Motorzyklus oder die Pause?>> Die Antwort auf diese Fragen hat unmittelbare Auswirkungen wie man das> Programm (so simpel es auch ist) aufziehen wird. Daher müssen diese> Fragen im Vorfeld geklärt werden.
Super Fragen. Hab ich mir auch zum Teil überlegt, und will es wie folgt
lösen:
Also wenn der Drehschalter währrend einem Zyklus umgelegt wird, soll der
neuer Pausevorgang eingeleitet werde( Vereinfacht das ganze.)
Der Motor soll immer auf OFF gestellt werden,wenn der SChalter auf OFF
ist. Der Motorzyklus ist immer als erstes: ---_______----___ in dem
Sinne ungefähr:-)
Grüße
Faisal Alam schrieb:> - Motorlaufzeit,eingänge(3 Möglichekeiten sind geplant:1Min,2min,3mIn):> Falls der Pin auf Low gezogen ist(durch lötbrücke einstellbar):> Motorausgang auf High (mit delay als timer?)
Nein.
> -Wenn ein Pin durch den Schalter auf LoW(Gnd) gezogen wird-> delay um> irgendwas im Sinne von Pause am Ausgang und damit den Pin wieder auf> LOW(Für jede Drehschalter Position)
Würde ich auch nicht machen.
Ich würde es angehen
Der Kern der Sache besteht darin, dass ich die Durchlaufzeit durch die
while Schleife auf ungefähr 1 Millisekunde einstelle (durch das
'Beiwerk' wird es etwas länger sein).
Und dann greift das Prinzip: Um 1 Sekunde zu warten, kann man auch 1000
mal 1 Millisekunde warten. D.h. Wenn du die Pausenzeit auf zb 1200
stellst, dann dauert es 1200 Durchläufe durch die while Schleife (die
jedesmal 1 Millisekunde daueren) ehe aktuelle Zeit auf 1200 erhöht
wurde. Ab 1201 ist die aktuelle Zeit dann größer als die Pausenzeit
(oder mit anderen Worten: die Pause ist vorbei) und der Motor wird
eingeschaltet. Irgendwann ist dann auch noch die gewollte Laufzeit des
Motors abgelaufen und der Motor wird wieder ausgeschaltet. Der nächste
Zyklus beginnt, indem aktuelleZeit wieder bei 0 zu zählen anfängt.
So ein Ansatz scheint mir am geeignetsten um auch auf Änderungen an den
Einstellungen zu reagieren, während gerade eine Zeit abgezählt wird.
Faisal Alam schrieb:> Der Motorzyklus ist immer als erstes
OK.
Auch kein Problem. Dann dreht sich eben einfach die Zyklenreihenfolge
um.
1
...
2
if(aktuelleZeit<MotorLaufzeit)
3
Motoreinschalten
4
5
elseif(aktuelleZeit<PausenZeit+MotorLaufzeit){
6
Motorausschalten
7
}
8
9
else
10
aktuelleZeit=0;
11
...
Alles nur eine Frage dessen, welche Millisekunden-'Zahl' welchen Zyklus
(Pause oder Motor) bedeuten soll.
Steht der Drehschalter auf OFF, dann wird einfach ständig bei der
Auswertung des Drehschalters die Motorlaufzeit und die aktuelle Zeit auf
0 gezwungen (einfach 0 zuweisen). Dadurch wird
1
if(aktuelleZeit<MotorLaufzeit)
nie true und in Folge wird der Motor nicht eingeschaltet. Dadurch, dass
auch die aktuelle Zeit auf 0 gesetzt wird, wird erreicht, dass erst bei
wegdrehen aus 'OFF' die aktuelleZeit wieder hochzählen kann. Voila: der
erste Motorzyklus läuft die festgelegte Zeit und der Motor wird
eingeschaltet (weil ja dann MotorLaufzeit nicht mehr 0 ist)
Es ist eigentlich die ganz normale Sichtweise, wie man meistens an ein
µC Programm rangeht.
Weg von der Betrachtung von 'Zeiträumen', sondern hin zu:
Alle x Zeiteinheiten 'erwacht' das Programm, sieht sich um und bestimmt
anhand der aktuellen Situation und irgendwelcher Variablen, was zu tun
ist.
Bei dir ist das dann eben: Wenn das Programm zb alle 1 Millisekunden
erwacht, dann muss es eben mitzählen, wie oft es erwacht ist und nach
dem 1000-ten erwachen ist 1 Sekunde vergangen. Jetzt brauchst du halt
nur noch anstatt der 1000 eine Zahl, die die von dir gewählte Zeit
repräsentiert.
PS: Ich merke gerade, dass sich das so mit den Zeiten nicht ausgehen
wird. Du hast ja Zeiten im Minutenbereich. Ein uint16_t kann aber nicht
größer als 65565 werden. D.h. das wären maximal 65 Sekunden, was zu
wenig ist.
OK, dann legst du eben die Durchlaufzeit auf 10 Millisekunden, wodurch
ein uint16_t für 650 Sekunden reicht, oder eben knapp 10 Minuten. An der
Bedienbarkeit ändert das nichts. Als Mensch kannst du eine Reaktion auf
einen Schaltvorgang nach 10 Millisekunden nicht wirklich von einer
Reaktion nach 1 Millisekunde unterscheiden.
Ich habe sogar vor, Positionen am Schalter mit viel höhehren Pauszeiten
zu implementieren. Als die letzte stufe sollte so 60 Minuten Pause
haben. Hmm wird das trotzdem so funktionieren ?
Grüße
Faisal Alam schrieb:> Ich habe sogar vor, Positionen am Schalter mit viel höhehren Pauszeiten> zu implementieren. Als die letzte stufe sollte so 60 Minuten Pause> haben. Hmm wird das trotzdem so funktionieren ?
Was solls. Dann nimmst du eben uint32_t anstatt der uin16_t. Mit einem
uin32_t kannst du bis 4294967295 zählen. Bei 1 Millisekunde Auflösung
wären das dann 4294967 Sekunden oder 71582 Minuten oder 1193 Stunden
oder 49 Tage.
Das dürfte ja dann doch für so ziemlich alles reichen.
Und ob der Tiny mit 32 Bit rummachen muss anstatt mit 16 Bit, ist auch
schon egal. Er hat ja sonst ohnehin nichts zu tun. Zur Not muss man eben
den
1
_delay_ms(1.0);
gegen ein
1
_delay_ms(0.9);
austauschen, um den Zeitanteil der restlichen Teile in der Schleife zu
'berücksichtigen'. (Wobei ich die 0.9 jetzt geschätzt habe)
Auch wenn ich damit vermutlich nichts zur Lösung beitrage, so frage ich
mich bei solchen Fragen jedes mal, warum Menschen die sich vorgenommen
haben ein Steuerungsproblem mit einem µC zu lösen -besonders wenn es
sich um so etwas einfaches und banales wie hier handelt- sich nicht
vorher ein wenig mit der Materie beschäftigen. So etwas kann vermutlich
ein 10 Jähriger nach der Lektüre eines Anfängerbuches lösen. Was ich
sagen will: Mit der Technologie die an benutzen möchte sollte man sich
ein wenig auseinander setzen und sich nicht alles von anderem Vorkauen
lassen.
Thomas Holmes schrieb:> Auch wenn ich damit vermutlich nichts zur Lösung beitrage,
Ein Ruf aus der Unendlichkeit - der 13. Apostel ist gefunden! Ostern
kann kommen ... :-)
Karl Heinz schrieb:> Faisal Alam schrieb:>> Ich habe sogar vor, Positionen am Schalter mit viel höhehren Pauszeiten>> zu implementieren. Als die letzte stufe sollte so 60 Minuten Pause>> haben. Hmm wird das trotzdem so funktionieren ?>> Was solls. Dann nimmst du eben uint32_t anstatt der uin16_t. Mit einem> uin32_t kannst du bis 4294967295 zählen. Bei 1 Millisekunde Auflösung> wären das dann 4294967 Sekunden oder 71582 Minuten oder 1193 Stunden> oder 49 Tage.>> Das dürfte ja dann doch für so ziemlich alles reichen.>> Und ob der Tiny mit 32 Bit rummachen muss anstatt mit 16 Bit, ist auch> schon egal. Er hat ja sonst ohnehin nichts zu tun. Zur Not muss man eben> den>
1
>_delay_ms(1.0);
2
>
> gegen ein>
1
>_delay_ms(0.9);
2
>
> austauschen, um den Zeitanteil der restlichen Teile in der Schleife zu> 'berücksichtigen'. (Wobei ich die 0.9 jetzt geschätzt habe)
So ich habe mittlerweile mal wieder was für dieses Projekt getan, und
den code so wie empfohlen geschrieben. @Karl meintest du das so?
1
#include<avr/io.h>
2
#include<util/delay.h>
3
4
uint32_tMotorLaufzeit;
5
uint32_tPausenZeit;
6
uint32_taktuelleZeit;
7
8
9
intmain(void)
10
{//Eingänge konfigurieren
11
DDRB&=~(1<<PB0);//Brücke2(Laufzeit Mot2)3Min
12
DDRB&=~(1<<PB1);//Brücke 3(Laufzeit Mot3)2Min
13
DDRB&=~(1<<PB5);//Brücke 1(Laufzeit Mot1)1Min
14
15
16
17
DDRB&=~(1<<PB2);// Schalterstufe 8( 3 Min Pause)
18
DDRB&=~(1<<PB3);// Schalterstufe 9( 2 Min Pause)
19
DDRB&=~(1<<PB4);// Schalterstufe 10( 1 Min Pause)
20
DDRD&=~(1<<PD0);// Schalterstufe 1 (Standby)
21
DDRD&=~(1<<PD1);// Schalterstufe 2( 60 Min Pause)
22
DDRD&=~(1<<PD2);// Schalterstufe 3( 40 Min Pause)
23
DDRD&=~(1<<PD3);// Schalterstufe 4( 20 Min Pause)
24
DDRD&=~(1<<PD4);// Schalterstufe 5( 10 Min Pause)
25
DDRD&=~(1<<PD5);// Schalterstufe 6( 8 Min Pause)
26
DDRD&=~(1<<PD6);// Schalterstufe 7( 5 Min Pause)
27
28
//Ausgänge konfigurieren
29
DDRB|=(1<<PB6);// Ausgang zum Relais bzw. zum Transistor
Testen musst du schon selber.
Tip fürs nächste mal: nicht gleich alles auf einmal.
Für deine Erstversion braucht es die ganzen 48
Konfigurationsmöglichkeiten alle nicht. Du willst in der Erstversion
wissen, ob die Motorsteuerung an sich funktioniert. Dazu willst du kein
Programm, dass sich über 27 Bildschirmseiten hinzieht, sondern das
überschaubar sich auf einer Bildschirmseite abspielt. Frei nach dem
Motto: Wenn das Prinzip stimmt ... um mehr Möglichkeiten erweitern kann
ich es immer noch. Aber erst mal will ich wissen, ob das Prinzip stimmt.
Funktioniert es denn?
Karl Heinz schrieb:> Testen musst du schon selber.>> Tip fürs nächste mal: nicht gleich alles auf einmal.> Für deine Erstversion braucht es die ganzen 48> Konfigurationsmöglichkeiten alle nicht. Du willst in der Erstversion> wissen, ob die Motorsteuerung an sich funktioniert. Dazu willst du kein> Programm, dass sich über 27 Bildschirmseiten hinzieht, sondern das> überschaubar sich auf einer Bildschirmseite abspielt. Frei nach dem> Motto: Wenn das Prinzip stimmt ... um mehr Möglichkeiten erweitern kann> ich es immer noch. Aber erst mal will ich wissen, ob das Prinzip stimmt.>> Funktioniert es denn?
Ich muss leider noch mit dem Test warten, habe die Platine mit der es
arbeiten soll erst bestellt :-).
man darf sich ruhig Programmtext durch die Verwendung von Leerzeichen
ein bischen lesbar gestalten. Seit du 6 Jahre als bist, hast du dein
Gehirn darauf trainiert, dass zwischen 'Wörtern' in einem Text ein
Leerraum steht. Benutze doch diese Konditionierung um dir das Lesen des
Programms leichter zu machen. Die paar Sekunden, die du dazu brauchst um
die Leerezeichen einnzufügen, sind gut investierte Zeit. Programmtext
schreibt man einmal und ändert ihn manchmal noch ein paar mal. Aber man
liest ihn viel öfter als man mit Schreiben an ihm verbringt.
1
elseif(aktuelleZeit<(PausenZeit+MotorLaufzeit))
(ob man die rechte Seite in eine Klammer setzt um aus 2 Meter Entfernung
erkennbar zu machen, dass hier ein Ausdruck steht, ist Ansichtssache.
Notwendig wäre es nicht. Aber bei der Formatierung von Quelltext geht es
nicht nur primär darum, was laut Sprachregeln notwendig wäre, sondern
auch darum, welche 'Lesefehler' ich vermeiden will bzw. welche
'Leseführung' ich meinem Code-Leser geben will.)