Go Down

Topic: Motor bei erreichtem Wert einer Variable nur einmal kurz ansteuern (Read 732 times) previous topic - next topic

berni576

Hallo Leute!

Ich hab da einen Code geschrieben, welcher, auch mit kleinen Macken, soweit funktioniert und macht was er soll.
Jetzt folgt meine Bitte an euch:
Ich möchte sobald die Variable anzahl den wert 3 und 4 hat und die LED somit leuchtet, einen (Linear-)Motor einmalig für 2sec ansteuern, sobald die Variable den Wert 1,2,5,6 hat den Motor umpolen, sodass er den daran angebauten Schieber wieder schließt. Bzw. so:
anzahl = 1 Der Schieber soll geschlossen sein
anzahl = 2 der Schieber soll geschlossen sein
anzahl = 3 kurzer Impuls (2 Sekunden) + - am Motor - Schieber offen
anzahl = 4 Schieber offen
anzahl = 5 kurzer Impuls (2 Sekunden) - + am Motor - Schieber zu
anzahl = 6 der Schieber soll geschlossen sein


Die LED ledPin blinkt auch immer wieder, genauso wie die Anzeige am LED. Das müsste sich eigentlich auch nicht immer aktualisieren, nur bei Änderung.

Ich bitte um Hilfe! Bin Neuling im Bereich Arduino und Programmieren!


Hier der Code:

Code: [Select]
//OUTPUTS
const int ledPin = 9;
const int pauseLed = 10;

//INPUTS
const int buttonPin = 8;
const int pausePin = 7;

//Variablen
int anzahl;
int buttonState = LOW;
int buttonread = 0;
int pauseState = LOW;
int pauseread = 0;

//Display
#include <LiquidCrystal.h>
LiquidCrystal lcd(12,11,5,4,3,2);

void setup()
{
  //OUTPUTS
  pinMode(ledPin, OUTPUT);
  pinMode(pauseLed, OUTPUT);


  //INPUTS
  pinMode(buttonPin, INPUT);
  pinMode(pausePin, INPUT);


  //Serielle Verbindung
  Serial.begin(9600);
  Serial.println("Serial port opened");

  //Display
  lcd.begin(16,2);

  lcd.setCursor(0,0);
  lcd.print("Schieber-");
  lcd.setCursor(0,1);
  lcd.print("schaltung 1.0");
  delay(3500);
  lcd.clear();

  if(anzahl == 0)
  {
    lcd.setCursor(2,1);
    lcd.print("START");
  }
}


void loop()
{
    pauseread = digitalRead(pausePin);
    buttonread = digitalRead(buttonPin);
  //Entprellen
//Display
    lcd.setCursor(0,0);
    lcd.print("ANZAHL");
    lcd.setCursor(0,1);
    lcd.print(anzahl);

    if (anzahl >0)
    {
      lcd.setCursor(2,1);
      lcd.print("     ");
    }
   

 
  if (pauseread == LOW)
  {
    if (buttonread == HIGH)
    {
      delay(20);
      if (digitalRead(buttonPin))
      {
        if (buttonState == LOW)
        {
          if (digitalRead(buttonPin))
          {
            anzahl = anzahl + 1;
            buttonState = HIGH;
            Serial.print("ANZAHL ");
            Serial.print(anzahl);
            Serial.println("");

          }
        }
      }
    }
    else
    {
      if (buttonState == HIGH)
      {
        anzahl = anzahl;
        buttonState = LOW;
      }
    }

    if (anzahl == 3 || anzahl == 4)
    {

      digitalWrite(ledPin, HIGH);
      Serial.println("Schieber offen");
      lcd.setCursor(5,1);
      lcd.print("SCHIEBER ON");
      delay(100);
    }

    if (anzahl >= 7)
    {
      anzahl = 1;
    }
    else
    {
      digitalWrite(ledPin, LOW);
      lcd.setCursor(7,1);
      lcd.print("         ");
    }
    pauseread = LOW;
    digitalWrite(pauseLed, LOW);

    lcd.setCursor(9,0);
    lcd.print("     ");
  }
  else if (pauseread == HIGH)
  {

    digitalWrite(pauseLed, HIGH);
    lcd.setCursor(9,0);
    lcd.print("PAUSE");
   

  }
}

ElEspanol

Du solltest dich mit "endlicher Automat" etwas beschäftigen

berni576

Du solltest dich mit "endlicher Automat" etwas beschäftigen
Danke ElEspanol!

Ich hab mich da jetzt ein wenig im Netz umgesehen. Ich finde jedoch nicht so wirklich wie ich zählen soll bzw. die Taster abfrage machen soll.
Mit if(digitalRead(taster, HIGH); komme ich leider nicht weiter.

kannst du mir da vielleicht ein paar tipps geben? :D

LG

agmue

Mit if(digitalRead(taster, HIGH); komme ich leider nicht weiter.
Da stimme ich Dir zu. Anstelle den Status abzufragen, solltest Du die Veränderung auswerten. Also wenn alter Zustand LOW und neuer Zustand HIGH, dann mache was.

Code: [Select]
if(!alt_buttonread && akt_buttonread) {}
Zum Entprellen reicht es, alle ca. 30 ms die Taster abzufragen.

Vergesse delay(), verwende stattdessen millis()!

Wenn Du im Forum nach "agmue anleitung" suchst, findest Du mein Geschreibsel und weiterführende Links.

Max_Beginner

Mahlzeit,

hatte zu Beginn die selben Schwierigkeiten.
Kannst ja mal in mein "Zähler" Progrämmchen reinschauen.
Das beinhaltet die Tasterentprellung sowie "delay" ohne delay().  :)
Code: [Select]

//BCD_7SEG Zaehler v1.4             (Max B. 26.09.2017)
//Zaehler +/-/reset, Ausgabe auf BCD 7-Segment 2 Digits
//min.=0; max.=99
//wenn +/- >=1s = +/- 1Hz Takt

//(UnoArduSim) #include <pgmspace.h>

//Ein-/Ausgaenge (const uint8_t / byte)
const uint8_t S0_CU = 2; bool plus = 0;
const uint8_t S1_CD = 3; bool minus = 0;
const uint8_t S2_CR = 4; bool reset = 0;
//------------BCD_Einer------------------BCD_Zehner----
const uint8_t BCD_1_1 = 5; const uint8_t BCD_1_10 = 9;
const uint8_t BCD_2_1 = 6; const uint8_t BCD_2_10 = 10;
const uint8_t BCD_4_1 = 7; const uint8_t BCD_4_10 = 11;
const uint8_t BCD_8_1 = 8; const uint8_t BCD_8_10 = 12;
const uint8_t alarm = 13;
//Variablen
bool s_x = 0; //Merker fuer Eingabe
bool m_reset = 0; //Merker fuer Reset
byte zaehler_dec = 0; //DEC Zaehler 0-100
word zaehler_bcd = 0; //BCD Zaehler 0-160(byte)
const uint16_t M_1s = 1000; //1 Sekunde
unsigned long j_ms = 0; //Zeitpunkt "jetzt"
unsigned long l_ms = 0; //Zeitpunkt "zuletzt"
unsigned long alarm_ms = 0; //Zeitpunkt "alarm"


void setup() //(OB100)
{//Start setup
Serial.begin(19200);
pinMode(S0_CU, INPUT); pinMode(S1_CD, INPUT); pinMode(S2_CR, INPUT);
pinMode(BCD_1_1, OUTPUT); pinMode(BCD_1_10, OUTPUT);
pinMode(BCD_2_1, OUTPUT); pinMode(BCD_2_10, OUTPUT);
pinMode(BCD_4_1, OUTPUT); pinMode(BCD_4_10, OUTPUT);
pinMode(BCD_8_1, OUTPUT); pinMode(BCD_8_10, OUTPUT);
pinMode(alarm, OUTPUT);

while (!Serial) {/*NICHTS*/} //auf serielle Uebertragung warten
Serial.println(F("\nEingabe Pin: 2=plus, 3=minus, 4=reset"));
Serial.println(F("Ausgabe Pin: BCD_1=5-8, BCD_10=9-12"));
Serial.println(F("\nBetriebsbereit..."));
DEC_zu_BCD();
}//Ende setup


void loop() //(OB1)
{//Start loop
//Eingaenge einlesen (erspart Platz)
plus  = digitalRead(S0_CU);
minus = digitalRead(S1_CD);
reset = digitalRead(S2_CR);

j_ms = millis();
//Freigabe fuer weitere Eingabe, sobald keine Taste gedrueckt ist.
if (plus == 0 && minus == 0 && reset == 0)
{
s_x = 0;
l_ms = millis(); //1Hz zaehler blockieren
}
//Taster reset
if (reset == 1 && s_x == 0 && m_reset == 0)
{
Serial.println(F("\nReset..."));
zaehler_dec = 0;
zaehler_bcd = 0;
s_x = 1;
m_reset = 1;
Bit_lesen();
}
//Taster plus
if (plus == 1 && minus == 0 && reset == 0 && s_x == 0 && zaehler_dec < 99)
{
zaehler_dec += 1;
s_x = 1;
m_reset = 0;
DEC_zu_BCD();
Bit_lesen();
}
//Taster minus
if (minus == 1 && plus == 0 && reset == 0 && s_x == 0 && zaehler_dec > 0)
{
zaehler_dec -= 1;
s_x = 1;
m_reset = 0;
DEC_zu_BCD();
Bit_lesen();
}
//zaehlen mit 1Hz
if ((j_ms - l_ms >= M_1s) && ((plus == 1 && zaehler_dec < 99) || (minus == 1 && zaehler_dec > 0)))
{
s_x = 0; //weiteres zaehlen freigeben
l_ms = millis();
}
//Alarm ab 99 oder ab 0 wenn minus aktiv
if ((zaehler_dec >= 99 || (zaehler_dec < 1 && minus == 1)) && (j_ms - alarm_ms >= M_1s))
{
digitalWrite(alarm, digitalRead(alarm) ^ 1);
alarm_ms = millis();
}
else if ((zaehler_dec < 99 && minus == 0) || (zaehler_dec > 0 && minus == 1))
{
digitalWrite(alarm, LOW);
}
return;
}//Ende loop

void DEC_zu_BCD() //(FC1)
{//Start DEC_zu_BCD()
//|-BCD-----=--------DEC-------HEX----+-------MOD(10)-|
zaehler_bcd = (zaehler_dec / 10 * 16) + (zaehler_dec % 10);
Serial.print(F("Zaehlerstand = "));
Serial.print(zaehler_dec);
Serial.print(F(" | BCD = "));
Serial.println(zaehler_bcd, BIN);
}//Ende DEC_zu_BCD()

void Bit_lesen() //(FC2)
{//Start Bit_lesen()
//erste 4Bit "Einer"
digitalWrite(BCD_1_1, bitRead(zaehler_bcd, 0));
digitalWrite(BCD_2_1, bitRead(zaehler_bcd, 1));
digitalWrite(BCD_4_1, bitRead(zaehler_bcd, 2));
digitalWrite(BCD_8_1, bitRead(zaehler_bcd, 3));
//letzte 4Bit "Zehner"
digitalWrite(BCD_1_10, bitRead(zaehler_bcd, 4));
digitalWrite(BCD_2_10, bitRead(zaehler_bcd, 5));
digitalWrite(BCD_4_10, bitRead(zaehler_bcd, 6));
digitalWrite(BCD_8_10, bitRead(zaehler_bcd, 7));
}//Ende Bit_lesen()

agmue


berni576

Danke für eure schnellen Antworten!

@agmue:
Ich habe mir jetzt mal dein Programm mit dem Kran angesehen. Das läuft auch nach Zeit ab & nicht wenn ein Taster z.B. 4 mal betätigt wurde, jedoch denke ich, dass das Programm genau das wäre, was ich brauche:
Das mit dem zeitlichen Ablauf würde ich gerne durch eine Variable ersetzen, welche ihren Wert nach Tastendruck um eins erhöht. Wenn die Variable den Wert 3 erreicht hat, soll der Schieber auf gehen und nach Wert 4, also bei 5 soll er wieder zu gehen. Den Linearmotor zum Schieben ( http://www.ebay.at/itm/Linearmotor-Verstellantrieb-Toroffner-Linear-Actuator-Motor-12V-1500N-50mm-/112151431966?hash=item1a1cbf0b1e:g:8t0AAOSwZQRYgC4I ) habe ich jetzt schon bei mir liegen, er benötigt ca. 2 sec. bis zur gewünschten Position - diese 2 Sekunden soll der jeweilige +Pin und der -Pin  also bei Wert 3 dann High bzw. LOW sein, bei Wert 5 soll er für 2 Sek gewechselt +Pin LOW und -Pin HIGH geschalten werden um per H-Brücke den Motor anzusteuern. Dann soll 2 Mal dazugezählt werden und nach Rücksetzen des Wertes auf 0 (bzw. 1), das Ganze von vorne anfangen.

Das Wäre mein Konzept, nur happerts da leider an der Umsetzung.
Ich hab mir mal deinen Code vom Kran in die IDE Kopiert und probier ein wenig um, denke jedoch nicht, dass ich da alleine etwas richtiges rausbekomme.

Vielen Dank nochmals!


--------

Kurzer Nachruf dazu:

Dein Programm läuft ja eh mit "Tastern", ich Idiot!
Aber trotzdem hätt ich eine Frage dazu, wo müsste ich meinen "Zähler" hinpacken?
Den hier:
Code: [Select]

if (buttonread == HIGH)
    {
      delay(20);
      if (digitalRead(buttonPin))
      {
        if (buttonState == LOW)
        {
          if (digitalRead(buttonPin))
          {
            anzahl = anzahl + 1;
            buttonState = HIGH;
            Serial.print("ANZAHL ");
            Serial.print(anzahl);
            Serial.println("");

          }
        }
      }

Max_Beginner

Was soll das return bewirken?
wird für UnoArduSim benötigt, da es sonst die Funktionen DEC_zu...
usw. von alleine aufrufen würde.

agmue

Der Kran läuft rein zeitgesteuert, Du brauchst eine Mischung von Zeit- und Tastensteuerung. Die findest Du eher bei der Fußgängerampel.

Etwas abgewandelt könnte das so aussehen:

Code: [Select]
#include <LCD.h>                //NewliquidCrystal
#include <LiquidCrystal_I2C.h>  //NewliquidCrystal
#include <Wire.h>

#define I2C_ADDR     0x27
#define BACKLIGHT_PIN     3
#define En_pin  2
#define Rw_pin  1
#define Rs_pin  0
#define D4_pin  4
#define D5_pin  5
#define D6_pin  6
#define D7_pin  7

LiquidCrystal_I2C  lcd(I2C_ADDR, En_pin, Rw_pin, Rs_pin, D4_pin, D5_pin, D6_pin, D7_pin, BACKLIGHT_PIN, POSITIVE);

//OUTPUTS
const int ledPin = 13;

//INPUTS
const int buttonPin = 8;

//Variablen
enum {ZU, OEFFNEN, OFFEN, SCHLIESSEN};
byte zustand = ZU;
bool aktButton, altButton;
const uint32_t buttonIntervall = 30, schieberIntervall = 2000;
uint32_t aktMillis, buttonMillis, schieberMillis;

void setup() {
  //OUTPUTS
  pinMode(ledPin, OUTPUT);

  //INPUTS
  pinMode(buttonPin, INPUT_PULLUP);

  //Serielle Verbindung
  Serial.begin(9600);
  Serial.println("Serial port opened");

  //Display
  lcd.begin(16, 2);                     // initialize the lcd
  lcd.setCursor(0, 0);
  lcd.print("Schieber-");
  lcd.setCursor(0, 1);
  lcd.print("schaltung 0.2");
  delay(3500);
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Geschlossen     ");
}

void loop()
{
  aktMillis = millis();
  altButton = aktButton;
  if (aktMillis - buttonMillis >= buttonIntervall) {  //Entprellen
    buttonMillis = aktMillis;
    aktButton = digitalRead(buttonPin);
  }
  switch (zustand) {
    case ZU:
      if (!altButton && aktButton) {
        lcd.setCursor(0, 0);
        lcd.print("Oeffnen         ");
        digitalWrite(ledPin, HIGH);
        schieberMillis = aktMillis;
        zustand = OEFFNEN;
      }
      break;
    case OEFFNEN:
      if (aktMillis - schieberMillis >= schieberIntervall) {
        lcd.setCursor(0, 0);
        lcd.print("Offen           ");
        digitalWrite(ledPin, LOW);
        zustand = OFFEN;
      }
      break;
    case OFFEN:
      if (!altButton && aktButton) {
        lcd.setCursor(0, 0);
        lcd.print("Schliessen      ");
        digitalWrite(ledPin, HIGH);
        schieberMillis = aktMillis;
        zustand = SCHLIESSEN;
      }
      break;
    case SCHLIESSEN:
      if (aktMillis - schieberMillis >= schieberIntervall) {
        lcd.setCursor(0, 0);
        lcd.print("Geschlossen     ");
        digitalWrite(ledPin, LOW);
        zustand = ZU;
      }
      break;
  }
}

Um Pins zu sparen, nutze ich ein LCD mit I2C-Schnittstelle.

Wegen des endlichen Automaten und den darin enthaltenen Verzögerungen, ist eine Tastenentprellung verzichtbar. Um mal zu zeigen, was ich meinte, habe ich sie mit reingeschrieben.

berni576

Vielen Dank Agmue!

Per Tastendruck öffnet und schließt sich der Schieber! :)

Wenn ich da jetzt noch den Zähler in void loop () von meinem ersten code reinsetze, und die Verschiedenen  case's per Variablenwert ändere sollte das passen oder? bin gerade leider nicht daheim, dass ich da umschreiben und probieren kann :(

Vielen Dank nochmal!

agmue

Wenn ich da jetzt noch den Zähler in void loop () von meinem ersten code reinsetze, und die Verschiedenen  case's per Variablenwert ändere sollte das passen oder?
Das wäre doppelt, da eigentlich zustand == zähler. Ich habe nur weniger Zustände, da mir nicht klar ist, wozu die anderen gut sein sollen:

Quote
anzahl = 1 Der Schieber soll geschlossen sein
anzahl = 2 der Schieber soll geschlossen sein
...
anzahl = 6 der Schieber soll geschlossen sein
Das enum kannst Du aber beliebig erweitern :)

berni576

...Ich habe nur weniger Zustände, da mir nicht klar ist, wozu die anderen gut sein sollen:
Das enum kannst Du aber beliebig erweitern :)
Ich brauche die Zustände 1: ZU 2: ZU 3: OFFEN 4: OFFEN 5: ZU 6: ZU da der Schieber durch einen Lichtschranken "angesteuert" wird und bei Zustand 3 öffnen und nach Zustand 4 schließen soll und bei 1,2,5 und 6 zu sein soll.

Ich werde das enum erweitern & probiers nochmal! Sag dir dann bescheid! :)
Danke!

agmue

Bei enum müssen die Begriffe eindeutig sein, als ZU1,ZU2,OFFEN1,OFFEN2,ZU3,ZU4 oder besser sinnvollere Bezeichnungen.

berni576

@ agmue:

Jetzt hab ich mein Projekt wieder aufgegriffen und Aufgebaut. Funktioniert ganz gut :D
Jetzt hab ich noch das Problem, dass ich für den Zustand ZU1 einen Taster drücken muss um den "Programmablauf" zu Starten. --> lieber wär mir: Strom am Arduino, Starte in Zustand ZU1... ohne Tastendruck, jeder weitere Wechsel startet per Lichtschranke...

Ich bin einfach zu blöd dazu, probier heute schon den ganzen Tag.. :(

LG

agmue


Go Up