Code um einen Takt auszugeben

Hallo,
ich will mit dem Ardunio Uni einen Schrittmotor ansteuern.
Der Motortreiber (L297) ist schon fertig vorhanden. Das heißt ich brauch nur noch einen Befehl der an einem Ausgang z.B. 1000 mal alle 2 Sekunden ein High Signal anlegt.

Ich habe an folgenden Code gedacht, allerdings fehlt mir der Befehl wie ich eben so einen Takt machen kann.
Hoffe ihr könnt mir da Helfen.

int Motor = 13;
int Taster1 = 10;
int Taster2 = 9;
int Taster3 = 8;
int Zeit1 = 1000;
int Zeit2 = 2000;

void setup(){
  pinMode(Motor, OUTPUT);
  pinMode(Taster1, INPUT);
  pinMode(Taster2, INPUT);
  pinMode(Taster3, INPUT);
}
  
void loop (){
  if (digitalRead(Taster1)==HIGH) {
    Hier soll dann 100mal HIGH Signale mit einer verzögerung von Zeit 1 an den Ausgang Motor kommen.
    
  if (digitalRead(Taster2)==HIGH) {
    Das gleiche dann aber mit der "Zeit2"
    
    Mit dem Taster3 soll man das ganze Stoppen können und zum loop zurückkehren. Denke das kann man mit einem Interrupt machen oder?

Da steht, wie man das mit einer Led macht. musst du ein bisschen abändern, damit die Frequenz stimmt. Ich würde es allerdings so machen, dass du den dritten Schalter weglässt, dann kannst du es mit
if (digitalRead(Taster1) == HIGH)
machen. Denn dann wird das ganze nur ausgeführt, wenn du einen der beiden Taster drückst. Wenn du aber willst, dass man einmal einen Taster drückt, und dann immer weiter gedreht wird, bis der dritte Taster gedrückt wird, dann würde ich eine while-Schleife nehmen:
void loop(){
if (digitalRead(Taster1) == HIGH){
while (Taster3 != HIGH){
hier dein an aus machen vom pin (also der Takt)
}
} else if (digitalRead(Taster2) == HIGH){
wieder eine while Schleife
} else {
vllt. fällt dir irgendetwas ein, was du sonst machen willst. Zum beispiel auf einem Display "warten" anzeigen, oder so was...

Also die billig Version ist das hier:

1.) Ausgang HIGH
2.) Zeit warten
3.) Ausgang LOW
4.) Zeit warten

Kannst halt dann sonst nichts machen. Du hättest dann die Möglichkeit die Taster per Interrupt abzufragen. Die beste Lösung, ist wie oben beschrieben wahrscheinlich "BlinkWithoutDelay". Dann kannst du während der Zeit noch andere Sachen machen.

Da du zweimal das gleiche tun willst schreib vielleicht deine Takterzeugung in einer eigene Methode, der du die Zeit als Parameter übergibst.

Interrupt für den dritten Taster ist das sauberste. Wenn du den jedesmal in der Schleife per Hand abfrägst bekommst du das Ereignis eventuell nicht mit. Du kannst dann z.B. in der IRS einen bool auf true setzen und dann sowas machen:

while(1)
{
    (if buttonPressed == true)
        break;
}

Das beendet die while-schleife

oder einfach

while(buttonPressed == false)
{
}

Und dann nicht vergessen die Variable zurückzusetzen

Du kannst auch mal schauen ob dir die PWM Frequenz passt:

Duty Cycle von 50% ist was du willst und die PWM Frequenz ist fest eingestellt 500 Hz laut der Seite. Das wären "1000 mal alle zwei Sekunden", wenn ich da nichts falsch verstehe. Normalerweise rechnet man da mit "Schritten/Takte pro 1 Sekunde" aka Hertz. Damit müsstet du nur einmal den PWM-Ausgang einschalten und dann nichts mehr manuell setzten bis du ihn abschaltest und das kann in der ISR passieren.

Das geht aber nur für eine deiner Zeiten, da die Frequenz nicht variabel ist.

Soo danke für eure Antworten, ich habe mir das Beispiel der LED genommen und bissel umgeschrieben.
Der Motor ist für eine Sonnenachführung. Darum wollte ich das der Motor sich 180° dreht und wenn er die 180° erreicht hat, sich wieder zurück dreht.
Mit den beiden Tastern steuert man die Geschwindigkeit (falls man was sehen will und nicht 24h warten will^^)

Hier der Code, vllt hat ja jemand Verbesserungsvorschläge.

int Motor = 13;
int Taster1 = 10;
int Taster2 = 9;
int Taster3 = 8;
int Winkel = 0;
int Winkel180 = 450;
int Winkel360 = 900;
int Drehung = 12;
long Zeit = 500;
int MotorState = LOW;
int DrehungState = LOW;
long previousMillis = 0;

void setup(){
  pinMode(Motor, OUTPUT);
  pinMode(Taster1, INPUT);
  pinMode(Taster2, INPUT);
  pinMode(Taster3, INPUT);
  pinMode(Drehung, OUTPUT);
}

void loop(){
  if (digitalRead(Taster1) == HIGH){
    Zeit= 1000; 
  }
  if (digitalRead(Taster2) == HIGH){
    Zeit= 100;
  }
  
  // Schaltet den Takt      
      unsigned long currentMillis = millis();
  if(currentMillis - previousMillis > Zeit) {
    previousMillis = currentMillis;
    
   
   if (MotorState == LOW)
       MotorState = HIGH;
       else
       MotorState = LOW;
       Winkel+=1;
    
     digitalWrite(Motor, MotorState); }
  if (Winkel >= Winkel180){
    Winkel = 0;
     if (DrehungState == LOW)
     DrehungState = HIGH;
    else
     DrehungState = LOW;
    digitalWrite(Drehung, DrehungState);
  }
 }

Kleinigkeit:
Du fragst beide Taster hintereinander ab. Wenn beide gedrückt werden überschreibt dir der zweiten den ersten. Das kannst du mit "else if" verhindern. Du solltest die Taster vielleicht auch mit Deounce entprellen. Funktioniert hier wahrscheinlich auch ohne, aber sicher ist sicher:

Wenn du beim Drücken merkwürdiges Verhalten hast und Dinge mehrmals ausgeführt werden liegt es daran. Aber da du ja gleich mit dem Motorschalten beginnst macht es wahrscheinlich nichts.

MotorState zu invertieren geht viel einfacher:
MotorState = !MotorState;

Das liegt daran wie die defines für HIGH/LOW gesetzt sind. Es geht wahrscheinlich weil man true/false auch als 1/0 schreiben kann

Hallo Serenifly,

Serenifly:
Kleinigkeit:
Du fragst beide Taster hintereinander ab. Wenn beide gedrückt werden überschreibt dir der zweiten den ersten. Das kannst du mit "else if" verhindern.

Worin siehst Du den Vorteil ?
Fall 1: der zweite Taster überschreibt den ersten, Aktion 2 wird ausgeführt
Fall 2 ( else if ): der zweite Taster wird nicht beachtet, Aktion 1 wird ausgeführt

je nach weiterem Programm ist das doch völlig gleichwertig, oder ?

Gruss
Kurti

Ich denk auch, dass das nicht wirklich einen Unterschied macht, aber ich gehe mal davon aus, dass alphatierchen es einfach lassen kann, zwei Taster gleichzeitig zu drücken, es wird ja kein kommerzielles Gerät, was direkt nicht funktioniert, wenn man die beiden Knöppe gleichzeitig drückt. zumal ist es doch vllt. ganz gut, die Sache dem Zufall überlassen zu können! Wenn das nicht der Fall ist müsste man auf dem Brett vielleicht irgendeine Schaltung einbauen, die verhindert, das von Taster2 ein Signal an den Arduino kommt, wenn Taster1 schon gedrückt ist, damit der Arduino nicht eins zufällig nimmt, wobei das natürlich fast das selbe ist, nur mit ein bisschen mehr Verzögerung, aber egal.

Also bisher funktioniert es ganz gut. Es gibt noch paar Feinheiten die ich noch ausbügeln muss.

Das eine hat mit der Drehung zu tun.
der Schrittmotor macht 0,8° pro Signal. Darauf folgt eine Untersetzung von 1:96.
Das heißt das ich für eine Umdrehung am Ende (eine Umdrehung am Tag= Sonne nachgeführt) 43200 Signale brauche.
(43200 Signale x 0,8°)/96 = 360° (eine umdrehung pro Tag)
Da der Tag 86400 sekunden hat muss der Motor alle 2 Sec ein Signal bekommen damit er genau gedreht wird.

Ich habe den Code so geschrieben das er Anfängt zu zählen mit jedem High Signal. Wenn er dann den Wert [long Winkel180 = 21600;] läst er den Motor in die andere Richtung drehen so das ich 2x 180° Drehungen habe.
Taster 1 --> Speed mit 1 Signal alle 2 Sec
Taster 2 --> Turbo 10ms pro Signal damit man etwas sieht, braucht trozdem 7 min für 360° :stuck_out_tongue:
Taster 3 --> setzt den Zähler auf 10800 (12 Uhr mittags) damit man den einstellen kann.

ich hatte am Anfang probleme da ich nicht beachtet habe das ich mit [long] und nicht mit [int] arbeiten kann.
Kann ich [long] mit[int] vergleichen? bzw addieren etc?
Dann eine technische Frage. Bei meinem Aufbau habe ich die Taster nicht mit Ground verbunden. Die + 5V gehen vom Taster direkt in den Arduino rein. Hab jetzt gelesen das man am Ausgang des Tasters noch einen 10.000 Ohm Widerstand auf Ground legen soll um Störungen zu vermeiden. Ist das richtig?
Bei mir war es zum teil so das es gereicht hat in die nähe eines Taster zu kommen und der wurde aktiviert ohne ihn zu drücken.

long und int sind kompatibel. Der führt da implizierte Konversionen durch. Solange du das Ergebnis wieder in einen long schreibst passt alles. Wenn nicht würde der Compiler meckern und du weißt was los ist. Überlaufe zur Runtime kann er natürlich nicht feststellen und das war dein Problem.

Der Widerstand ist dazu da um einen definierten Pegel zu bekommen und den Strom zu begrenzen. Sonst hängt er eventuell in der Luft. Das ist so ne Sache. Die meisten Mikrokontroller haben interne Pullups. Die sind aber auch schaltbar (und nicht unbedingt automatisch ein) und manche Pins haben je nach Controller keine, da sie noch andere Funktionen haben (z.B. DAC). Also sicher ist sicher.

Du hängt den Eingang normalerweise mit dem Widerstand gegen Plus und den anderen Kontakt des Tasters gegen Masse. Dann liegt normal Plus an und wenn der Taster gedrückt wird Masse. Es geht aber auch anders herum mit Pull-Downs.

Hier ist die Pull-Down Version:

Wurde da wohl gewählt, da man dann im gedrückten Zustand HIGH hat, was vielleicht etwas logischer ist wenn man das nicht gewöhnt ist.

Hier ist das mit den Internen Pullups erklärt: