Hallo zusammen Ich habe folgendes Problem ich bin dabei eine Steuerung für eine Maschine zu Programmieren inkl. Display. Die Maschiene hat folgende Funktionen: Pumpe - An / Aus Injektion von Flüssigkeiten - An / Aus Lufdruck - An/Aus/ Impulsverfahren nach gespeicherten Einstellungen (Imp-Dauer & Pause) Jetzt habe ich das Problem das wenn ich alles mit diesem Blöden Delay mache das Der Controller solange garnbicht mehr reargiert. Wie sieht es Mit Multitasking aus Ich will mit dem Keypad immer Einfluss haben können. z.B ich starte Mit der Impulsetaste Die IMP-Sequenz und will ausschalten aber nichts mehr reargiert. Folgend mal der Code: // include the library code: #include <Wire.h> #include <EEPROM.h> #include <LiquidCrystal_I2C.h> #include <Menu.h> #include <LCDMenu2.h> #include <Keypad.h> #define CONFIG_START 32 const byte ROWS = 4; //four rows const byte COLS = 3; //tree columns //define the cymbols on the buttons of the keypads char hexaKeys[ROWS][COLS] = { {'p','u','m'}, {'l','e','r'}, {'b','d','#'}, {'1','2','3'} }; //# Own Chars //# ================================== uint8_t arrow_up[8] = {0x4,0xE,0x15,0x4,0x4,0x4,0x0}; uint8_t arrow_down[8] = {0x0,0x4,0x4,0x4,0x15,0xE,0x4}; byte rowPins[ROWS] = {5, 4, 3, 2}; //connect to the row pinouts of the keypad byte colPins[COLS] = {6, 7, 8}; //connect to the column pinouts of the keypad boolean sysStatus = false; struct StoreStruct{ float impPause; float impDauer; } storage = { 0, 0 }; //initialize an instance of class NewKeypad Keypad keypad = Keypad( makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS); /*-----( Declare Constants )-----*/ /*-----( Declare objects )-----*/ LiquidCrystal_I2C lcd(0x27,20,4); // set the LCD address to 0x27 /*-----( Declare Variables )-----*/ const int pumpe = 9; const int injektor = 10; const int v_pneumatik = 12; const int v_leer = 11; const int startposX = 5; Menu top("Root"); // menu, lcd, rows, cols, arrow_up_pos, arrow_down_pos LCDMenu2 Root(top, lcd , 4, 20, 0, 1); Menu Item1("Jobs"); Menu Item11("Job 01"); Menu Item12("Job 02"); Menu Item13("Job 03"); Menu Item14("Job 04"); Menu Item15("Job 05"); Menu Item16("Job 06"); Menu Item17("Job 07"); Menu Item2("Einstellungen"); Menu Item21("Impulse"); Menu Item211("Pause"); Menu Item212("IMP-Dauer"); Menu Item22("Uhr"); Menu Item23("Auto-Aus"); Menu Item3("Geraeteinfo"); Menu Item31("Name:"); Menu Item32("Impulse-Cleaner"); Menu Item33("Hersteller:"); Menu Item34("Muster GmbH"); Menu Item35("Gewicht:"); Menu Item36("35 Kg"); String strPumpe = "PMP"; String strSanosil = "SAN"; String strPneumatik = "IMP"; String aktMenu = "main"; int menuPos = 0; int mAnzMain = 3; int mAnzSetup = 3; boolean tmpFF = false; void setup() { loadData(); // setup Relais pinMode(pumpe, OUTPUT); pinMode(injektor, OUTPUT); pinMode(v_pneumatik, OUTPUT); pinMode(v_leer, OUTPUT); delay(500); lcd.init(); // initialize the lcd //lcd.backlight(); lcd.createChar(0, arrow_up); lcd.createChar(1, arrow_down); menuinit(); keypad.addEventListener(keypadEvent); //add an event listener for this keypad } //## Menu Init void menuinit() { top.addChild(Item1); Item1.addChild(Item11); Item1.addChild(Item12); Item1.addChild(Item13); Item1.addChild(Item14); Item1.addChild(Item15); Item1.addChild(Item16); Item1.addChild(Item17); top.addChild(Item2); Item2.addChild(Item21); Item21.addChild(Item211); Item21.addChild(Item212); Item2.addChild(Item22); Item2.addChild(Item23); top.addChild(Item3); Item3.addChild(Item31); Item3.addChild(Item32); Item3.addChild(Item33); Item3.addChild(Item34); Item3.addChild(Item35); Item3.addChild(Item36); } void p_pulse(int ps, int dauer){ digitalWrite(v_pneumatik, HIGH); aktStatus(); delay(dauer); digitalWrite(v_pneumatik, LOW); aktStatus(); delay(ps); } void menu(){ lcd.clear(); Root.display(); } // Aktualisiert de Status in der linken Spalte void aktStatus(){ lcd.setCursor(0,0); if(digitalRead(pumpe)==HIGH) {lcd.print(strPumpe);} else {lcd.print(" ");}; lcd.setCursor(0,1); if(digitalRead(injektor)==HIGH) {lcd.print(strSanosil);} else {lcd.print(" ");}; lcd.setCursor(0,2); if(digitalRead(v_pneumatik)==HIGH) {lcd.print(strPneumatik);} else {lcd.print(" ");}; } // Steuert Jobablauf ohne Keypad interupt void job01(){ digitalWrite(pumpe, HIGH); aktStatus(); delay(7000); digitalWrite(injektor, HIGH); aktStatus(); delay(11000); int d = 500; int p = 200; p_pulse(p,d); p_pulse(p,d); p_pulse(p,d); p_pulse(p,d); p_pulse(p,d); p_pulse(p,d); p_pulse(p,d); p_pulse(p,d); p_pulse(p,d); p_pulse(p,d); p_pulse(p,d); p_pulse(p,d); p_pulse(p,d); p_pulse(p,d); delay(3000); digitalWrite(injektor, LOW); aktStatus(); delay(10000); digitalWrite(pumpe, LOW); aktStatus(); delay(3000); } //Loop schleife nur für Keypadabfrage void loop() { char key = keypad.getKey(); } void einschalten(){ loadData(); sysStatus = true; lcd.init(); // initialize the lcd lcd.backlight(); lcd.clear(); lcd.setCursor(startposX,0); lcd.print("IMP_Cleaner 1.0"); lcd.setCursor(startposX,1); lcd.print("Copyrigth by:"); lcd.setCursor(startposX,2); lcd.print("A.Frauenstein"); lcd.setCursor(startposX,3); lcd.print("Init...."); delay(500); menu(); } void loadData() { for (unsigned int t=0; t<sizeof(storage); t++) *((char*)&storage + t) = EEPROM.read(CONFIG_START + t); } void saveData() { for (unsigned int t=0; t<sizeof(storage); t++) EEPROM.write(CONFIG_START + t, *((char*)&storage + t)); } void ausschalten(){ saveData(); sysStatus = false; lcd.noBacklight(); } void aktPause() { lcd.clear(); lcd.print("Pause"); lcd.setCursor(0,1); lcd.print(storage.impPause); } void aktDauer() { lcd.clear(); lcd.print("Dauer"); lcd.setCursor(0,1); lcd.print(storage.impDauer); } //## Function Check boolean funccheck(int action) { tmpFF = false; if(Root.curfuncname == "Pause") { if (action==1) { aktPause(); }; tmpFF = true; } else if(Root.curfuncname == "IMP-Dauer") { if (action==1) { aktDauer(); }; tmpFF = true; } else if(Root.curfuncname == "Job 01") { if (action==1) { job01(); }; tmpFF = true; } return tmpFF; } //take care of some special events void keypadEvent(KeypadEvent key){ int mAnz; if (aktMenu == "main") { mAnz = mAnzMain; } else if(aktMenu == "Setup") { mAnz = mAnzSetup; }; switch (keypad.getState()){ case PRESSED: switch (key){ case 'p': if(sysStatus) {ausschalten();} else{einschalten();}; break; case 'u': if(tmpFF) { if (Root.curfuncname == "Pause") { storage.impPause = storage.impPause + 0.1; aktPause(); } else if (Root.curfuncname == "IMP-Dauer") { storage.impDauer = storage.impDauer + 0.1; aktDauer(); }; } else { Root.goUp(); aktStatus(); }; break; case 'd': if(tmpFF) { if (Root.curfuncname == "Pause") { storage.impPause = storage.impPause - 0.1; aktPause(); } else if (Root.curfuncname == "IMP-Dauer") { storage.impDauer = storage.impDauer - 0.1; aktDauer(); }; } else { Root.goDown(); aktStatus(); }; break; case 'm': Root.goMenu(top); aktStatus(); break; case '1': if(digitalRead(pumpe) == HIGH) {digitalWrite(pumpe, LOW);} else{digitalWrite(pumpe, HIGH);}; aktStatus(); break; case '2': if(digitalRead(injektor) == HIGH) {digitalWrite(injektor, LOW);} else{digitalWrite(injektor, HIGH);}; aktStatus(); break; case '3': if(digitalRead(v_pneumatik) == HIGH) {digitalWrite(v_pneumatik, LOW);} else{digitalWrite(v_pneumatik, HIGH);}; aktStatus(); break; case 'b': Root.goBack(); aktStatus(); break; case 'e': Root.goEnter(); aktStatus(); funccheck(1); break; } break; case RELEASED: switch (key){ case '*': break; } break; case HOLD: switch (key){ case '*': break; } break; } }
ohne deinen code gelesen zu haben (pack sowas bitte nächstes mal in den anhang) gehören delays generell nicht in solche programme rein! das ganze realisiert man mit timern und interrupts - schau dir hier im forum in der artikelsammlung einmal bitte die entsprechenden stellen an ;)
Sorry, aber Arduino kann ich nicht ernst nehmen.. Die Abstraktionsebene ist ja der Hammer, wenn ich den Code mal überfliege :-) Wenn du auf eine Eingabe reagieren willst, dann per Interrupt oder Polling. MIT Betriebssystem kannst du das in einen anderen Task packen. Ein Prozessor kann immer nur einen Befehl gleichzeitig ausführen. Gruß
Okay erstmal danke für die Antworten. Sorry wegen dem Langen Code Ich habe gehört das Interrupt nicht funktionieren wenn ein Delay abgearbeitet wird. Das heist das ich alles mit Interrupts und timern machen muss oder? Es gibt aber doch nur zwei Timer. - Ich dacht das Mit der Keypadlibary ist schon ein Interrupt ist dem so ? Dann habe ich noch eine Frage: Was meinst du mit Betriebssystem kann man auf den Arduino ein Betriebssystem laden oder wie ?
Nochmals. Schmeiss die Delays raus, die sind Schrott. Nimm einen Timer und eine Zustandsmaschine. In einer anderen Zustandsmaschine verarbeitest du die Tasten. interrupt timer { reload timer timercame=true } main { Zustand=0; while true { if timercame { timercame=false; switch zustand { 0: irgendwas; zustand=1; | 1: irgendwas; zustand=2; | 2: irgendwas; zustand=3; | 3: irgendwas; zustand=..; | .. } } }
Nein ich habe folgendes mit 7 Anschlüssen einer davon ist 5V http://www.voelkner.de/products/261525/Tastatur-3x4-M.Beschriftungsstr.-Ac3560.html Das Problem ich raffe diese keypadlibary nicht. Warum muss mann wen mann ein Keypadevent declariert: keypad.addEventListener(keypadEvent); //add an event listener for this noch in der Loop schleife den Folgenden Befehl ausführen? //Loop schleife nur für Keypadabfrage void loop() { char key = keypad.getKey(); } Und dann Diese Delays keine Idee Wie ich das mit dur Zwei Timern Umsetzten kan.
Andreas Frauenstein schrieb: > Das Problem ich raffe diese keypadlibary nicht. Kann man sich diese Lib irgendwo ansehen (Quellcode)? Zu ner Lib sollte es ja auch ein Manual geben, wo alle Funktionen beschrieben sind. Ne 3*4 Matrix einlesen, da gibt es haufenweise Quellcode. Man muß dazu keine spezielle Lib benutzen. Es schad auch nix, wenn man versteht, wie eine Matrix ausgelesen und entprellt wird (das sind 2 separate Aufgaben). Peter
>Und dann Diese Delays keine Idee Wie ich das mit dur Zwei Timern
Umsetzten kan.
Ein einziger Timer genuegt. Hab ich doch oben gezeigt.
>Habe sie von hier: >http://arduino.cc/playground/Code/Keypad > >Das ist aber nichts mit Interrups Dann ist ja auch gut...
Tja durch die hohe Abstraktionsebene vom Failduino weis man eben nicht was es wirklich macht und kanns nur qick n dirty hinhacken ;) Zum warten: Bastel dir nen Timer, der alle x ms nen Interrupt auslöst und in der ISR wird ne Variable hochgezählt. Die Warteprozedur guckt ob die Variable hoch genug gezählt wurde und löst dann aus. Richtiges Multitaskings ist auf AVRs dann doch SEHR aufwändig.
Okay aber was auslösen Tastaturabfrage oder Impulsechange. Ich brauche so etwas wie eine Blinklicht ohne die blöden delays Bsp. 2 sec an 1 sec aus und Paralles soll der Prozessor diese Folientastur abfragen damit ich die Impulse sequenz wieder ausschalten kann. Ich Brauche also sowas wie eine Delayprozedur mit Timer Und Ein Interrupt.
Andreas Frauenstein schrieb: > Okay aber was auslösen Tastaturabfrage oder Impulsechange. > > Ich brauche so etwas wie eine Blinklicht ohne die blöden delays > Bsp. 2 sec an 1 sec aus und Paralles soll der Prozessor diese > Folientastur abfragen damit ich die Impulse sequenz wieder ausschalten > kann. > > Ich Brauche also sowas wie eine Delayprozedur mit Timer > Und Ein Interrupt. Ganz genau. Und du brauchst keine 'Delayprozedur' sondern lediglich EINEN Timer, der dafür sorgt, dass in regelmässigen Zeitabständen eine bestimmte Funktion (die Timer-ISR) aufgerufen wird. Alles andere ist dann nur noch abzählen von Aufrufen. Wenn deine Timer-ISR alle (hausnummer) 10 Millisekunden aufgerufen wird, dann zählt man halt in dieser ISR einen Zähler bei jedem Aufruf um 1 hoch (oder runter) und wenn der Zähler bei 100 angelangt ist, ist eine Sekunde vergangen. Du musst nicht 10 Sekunden 'am Stück' auf etwas warten. Du kannst auch 10 mal 1 Sekunde auf etwas warten. Und wenn du eine Uhr hast, die jede Sekunde 1 mal tickt, dann zählst du eben 10 dieser Uhrenticks ab und hast auch wieder deine 10 Sekunden. Und ja: Es ist nicht verboten, dass ein und dieselbe Timer-ISR sich um mehrere Dinge kümmert. Und wenn du dich mit Timern und ISR noch nicht auskennst, dann wäre das jetzt ein guter Zeitpunkt, um dein Projekt erst mal zur Seite zu legen ein Testprojekt anzufangen, in dem du dich einfach nur mit Timern und wie man mit ihnen arbeitet vertraut machst. Wenn du da dann ein wenig experimentiert hast, schmeisst du dein Testprojekt weg und mit dem was du in diesem Testprojekt alles gelernt hast, gehst du dann erneut an dein eigentliches Projekt ran. So wie überall anders auch: Ehe man als Arbeitskraft in die Produktion übernommen wird, macht man erst mal in der Lehrwerkstatt ein paar Lehrstücke. Nur in der Programmierung glauben immer alle, man müsse nicht im Vorfeld seine Hausaufgaben machen und nicht üben.
Vielleicht war's zu kompliziert : interrupt timer { reload timer timercame=true } main { Delaytimer=100; timercame=false; while true { if timercame { timercame=false; if (delaytimer !=0) { delaytimer--; if delaytimer==0 { .. timer abgelaufen } } } }
Yep. Entweder so oder aber wenn die Aktion schnell durchführbar ist (wie zb eine LED ein/ausschalten, einen Motor ausschalten, die Uhrzeit hochzählen etc.), kann man die Aktion durchaus auch in die ISR selbst verlagern. interrupt timer { timercame=true delaytimer--; if delaytimer == 0 { LED umschalten; delaytimer = 100; } if motortimer > 0 { motortimer--; if motortimer == 0 Motor ausschalten; } } main { delaytimer =100; timercame=false; while true { if Taste gedrückt { Motor einschalten motortimer = 500; // nach einer Wartezeit von 500 * 100 // soll der Motor wieder abgeschaltet werden } } } So erfolgt das Blinken der LED komplett in der ISR. Und nach dem gleichen Muster und weiteren Zählvariablen, kann man dann auch mehrere zeitliche Abläufe quasi gleichzeitig bearbeiten lassen. Einzige Einschränkung: alle diese zeitlichen Abläufe müssen ganzzahlige VIelfache der Aufruffrequenz der Timer-ISR sein. Wird die ISR alle 10 Millisekunden aufgerufen, kann ich damit keine Verzögerung von 15 Millisekunden realisieren. Sorge ich aber dafür, dass die ISR alle 5 Millisekunden aufgerufen wird, gehts wieder.
Danke vielmals ich werde mich die Tage einarbeiten und erst dann das Projekt umschreiben.
Soweit so gut habe das prinzip verstanden aber es passt überhaupt nicht zum Arduino bzw. ind die IDE des Arduino Interrupts werden auch irgendwie anders declariert void Setup void Loop
Andreas Frauenstein schrieb: > Soweit so gut habe das prinzip verstanden aber es passt überhaupt nicht > zum Arduino bzw. ind die IDE des Arduino > > > Interrupts werden auch irgendwie anders declariert Nun ja. Obiges ist ja auch nur das Prinzip. Das das so ähnlich aussieht wie C-Code liegt einfach daran, dass sich so das Prinzip viel kompakter zeigen lässt als wie wenn man eine Prosa-Beschreibung dafür macht. Speziell für das Arduino-System wird dir hier keiner fertigen Code frei Haus liefern. Um das Studium, wie man das Prinzip mit den Mitteln der Arduino Bibliothek umsetzt, wirst du also nicht umhinkommen. Die meisten hier programmieren ohne eine derartige Hilfsbibliothek. Mehr oder weniger praktisch direkt auf der Hardware. Daher wäre dir so ein Code ebenfalls keine Hilfe. Wenn du das Prinzip verstanden hast, sollte es allerdings kein Problem sein, das mit deinr Arduino-Bibliothek zur realisieren. Die Fragen, die du beantworten musst, lauten: * wie aktiviere ich einen Timer * wie sorge ich für regelmässige Aufrufe einer Interrupt Routine und wie steuere ich den Zeitraum von einem Aufruf zum nächsten * wie muss ich diese Interrupt Routine vereinbaren Mit diesem Wissen und dem vorgestellten Implementierungsprinzip solltest du in der Lage sein, das alles umzusetzen. Das du dann allerdings dein eingangs vorgestelltes Programm heftig umbauen musst, liegt in der Natur der Sache. Wenn man mit dem falschen Verfahren angefangen hat, ist man oft weit weg von einer funktionierenden Lösung. Daher auch: Erst mal mit einem Testprogramm Erfahrung sammeln. Ich fang bei solchen Sachen normalerweise erst mal mit der zugrundeliegenden 'Maschine' an, die bei dir eben 'zeitliche Abläufe abarbeiten' lautet. Menüs und Einschaltmeldung und dergleichen, kommt erst viel später. Erst mal muss die arbeitende Maschinerie funktionieren.
Hallo ich muss Karl Heinz in allen Punkten Recht geben. Habe auch lange gebraucht, bis ich es richtig verstanden habe, doch jetzt geht es ohne Probleme. Kann bis zu 4 Tasten entprellen. Kann kurz oder land auswerten und kann noch viele andere Sachen fast gleichzeitig machen. Habe einen Timer laufen mit 10 ms und leite von diesem alles ab. Bin voll zufrieden. achim
Ja Karl Heinz hat Recht ich habe vorher auch nur mit folgender Reihenfolge programmiert: C64 hehehe Q- Quick- Basic Visualbasic Visual C++ C++ Microcontroller nur Oberflächlich Wobei Mit Microcontroller zu Programmieren was ganz anderes ist habe bemerkt Alleine schon die Byteoperationen sind ersteinmal zu verstehen g Habe meine Sachen jetzt mit eine Millis ISR gelöst klappt ganz gut: //Loop schleife nur für Keypadabfrage void loop() { char key = keypad.getKey(); if (state_imp) {pmp_isr();}; } void pmp_isr() { byte value = digitalRead(v_pneumatik); if (value == LOW) { intervall_imp = (storage.impPause * 1000); } else { intervall_imp = (storage.impDauer * 1000); } if (millis() - pMillis > intervall_imp) { pMillis = millis(); // aktuelle Zeit abspeichern // LED Zustand wecheln. if (value == LOW) value = HIGH; else value = LOW; // Wert auf den Ausgang schreiben digitalWrite(v_pneumatik, value); aktStatus(); } } Nur nach Job1 das jetztr statt Delay eine Millisfuction aufruft habe ich immernoch das Problem das er in dem Menu festhängt und ich danch nichtmehr im Menu nach unten kann. Nur die die Folgende Tastenkombination löst das wieder: Enter, Back
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.