Hallo zusammen, ich suche eine Möglichkeit ein Menü zu schreiben, das beim warten auf eine Eingabe den uC nicht komplett blockiert. Genauer: Ich arbeite an einer Funkfernbedienung für einen hausbus. Da die Fernbedienung gleichzeitig der Master im single Master- Multi Slave System ist, muss ich dafür sorgen das andere Prozesse auch aufgerufen werden während sich ein Benutzer durch das Menü bewegt. Ich bin nicht ganz sicher wie ich das am Besten mache. Ich dachte mir allerdings schon das es evt. möglich sei, das sobald das Menu seine punkte ausgegeben hat, wieder in die main loop zu springen, und sobald ein neuer Satz Befehle für das menü eingegeben wurde, sollte wieder ins menu gesprungen werden. Was ja schon mal bedeutet das ich feste punkte für Unterbrechung setzen kann. Das schien mir theoretisch bisher am einfachsten, allerdings weiß ich nicht wie man einen solchen Sprung realisieren könnte. Wobei das Menu ja seine Arbeit Transparent wieder aufnehmen können muss. Ich wäre für hinweise Bezüglich der Umsetzung sehr dankbar, und auch offen für weitere Vorschläge. Grüße Felix
Hi, (RT)OS / Scheduler: Das einfachste, da mehrere while(1) { ... } Flags, pollen / ISR: Menuanzeige aktualisieren, mit Flags letzten Zustand merken und gleich wieder nach main() oder so zurück. Dort die Eingabe mit pollen oder per ISR.
Da kannst du auch mein OS nano OS verwenden, das hier im Forum weiterentwickelt wird und ebenfalls multitaskingfähig ist. Thread dazu Beitrag "NeuesOS für AVR Mikrocontroller" Code auf Sourceforge http://sourceforge.net/projects/nanoos/ gruß tobi
Einfach zu lösen mit einer State-Machine. ohne den Overhead und die Einarbeitungszeit in ein RTOS .... Deine Software, und dein Menu genau durchdesignen und dann in einer State-Machine abbilden. innerhalb der States "NIEMALS!" while() oder do{}while() verwenden, sonder immer mit Rückgabewerten arbeiten die den State beeinflussen. BSP: switch(state) { case state_1 : { state = functioncall_state_1(); break; } case state_2 : { state = functioncall_state_2(); break; } default : { state = functioncall_state_init() //falls was schief läuft ... } } gruss SoundSo
Am einfachsten machst Du es mit einer Statemachine (switch/case). Die Menüfunktion macht eine Aktion, setzt bei Erfolg den nächsten State und geht wieder zum Main. Ein RTOS klingt erstmal nett, macht aber dafür nen Haufen zusätzlicher Probleme. Aus Funktionssicht wird nämlich alles gleichzeitig ausgeführt, die Funktion weiß nicht, wann sie von welcher anderen unterbrochen wird. Ressourcen (LCD, UART, I2C) können belegt sein, Variablen können sich mitten im Zugriff ändern usw. Ein RTOS erfordert sehr viel Disziplin beim Programmieren. Es macht Fehler leicht und verzeiht sie nicht. Und beim Debuggen mit einem RTOS rauft man sich eh die Haare. Peter
Wow, das ging ziemlich schnell! Also an Flags habe ich natürlich auch schon gedacht, nur bin ich nicht sicher wie das realisieren soll, da mein Programm ziemlich komplex ist, es gibt Profile programmierbare Knöpfe bei den slaves, am master, unzählige Sensoren und kurz tausende von Einstellungs Möglichkeiten. Programmierbare Displays... Etc... Kurz es ist ziemlich komplex, und irgendwie weiß ich nicht wie ich das mit anhand von flags merken soll wo genau ich gerade im menü bin. Bis auf ich würde es bei jeder eingabe wieder durchrechnen lassen. An Multitasking habe ich auch schon gedacht, das ist ja eigentlich auch mehr oder weniger was ich vor habe, nur halt in einer sehr simplen Form... Es soll halt nur an eine stelle springen können und bei bedarf wieder zurück... Wie heißt den so ein Sprung blos? Ein komplettes OS scheint mir bis auf weiteres ein wenig overkill, da ich bisher auch alle anderen Aufgaben anders lösen konnte... Aber ich werde es mir trotzdem mal ansehen Tobi, da es mich interessiert. Bevor ihr euch allzu viel mühe mit den antworten gebt, werde ich noch einmal probieren ein normales Menü zu programmieren, habe es noch nie gemacht, und vielleicht fällt mir ja auch selber etwas ein wenn ich die Praxis erst mal soweit drauf habe... Allso nochmal ein paar Details die vielleicht helfen helfen, ich habe eine Zügig durchlaufende main loop, und die Eingabe von zeichen geschieht mittels Interrupt. Im Moment mache ich noch alles über ein selbst implementiertes comandline interface, das ist toll und macht spaß... Aber ist wohl nicht praxis taglich für eine Fernbedienung :( Ich schaue mir auch nochmal das multitasking genauer an, im code beispielen müssen ja eigentlich irgendwo beispiele für solche sprünge zu finden sein. Grüße und danke Felix
Hi, ich habe sowas mal für das Aquarium meines Sohnes gemacht, eine Steuerung die Temperatur regelt (mit einstellbarer Hysterese und Nachtabsenkung), zum Füttern die Pumpe abstellt und enstprechend vieler Schaltpunkte der Zeitschaltuhr. In der main-Schleife wird sich der aktuelle Menupunkt gemerkt, der wird auch von der Menu-Funktion zurückgegeben, alle anderen zyklischen arbeiten werden normal ausgeführt, das Menu blockiert also nicht. Hauptsächlich läuft das im main so:
1 | // Endlosschleife
|
2 | while (1) |
3 | {
|
4 | /*
|
5 | ** Timer handling, as long as there is a tick...
|
6 | */
|
7 | while ((millis() - ms_old) > 10) |
8 | {
|
9 | ms_old += 10; |
10 | |
11 | /*
|
12 | ** now call all the regular functionality...
|
13 | */
|
14 | |
15 | ......
|
16 | |
17 | // check for user interaction...
|
18 | key = get_key(); |
19 | |
20 | if (active_menu == NO_MENU) |
21 | {
|
22 | switch (key) |
23 | {
|
24 | case KEY_FWD: |
25 | menu_timeout = 45; |
26 | active_menu = START_MENU; |
27 | |
28 | // here we enter the menu, so copy all data to
|
29 | // menu-space for editing
|
30 | menu_print (active_menu); |
31 | break; |
32 | ......
|
33 | }
|
34 | }
|
35 | else
|
36 | {
|
37 | if (key == NO_KEY) |
38 | {
|
39 | if (menu_timeout == 0) |
40 | {
|
41 | menu_exit (); |
42 | lcd_clear (); |
43 | active_menu = NO_MENU; |
44 | }
|
45 | }
|
46 | else
|
47 | {
|
48 | menu_timeout = 45; |
49 | |
50 | active_menu = menu_action (active_menu, key); |
51 | |
52 | if (active_menu == NO_MENU) |
53 | {
|
54 | // here we left the menu, so save all data
|
55 | lcd_clear(); |
56 | ee_write ((void *)&eedata, (void *)&setup, sizeof (struct eep_setup)); |
57 | ee_write ((void *)&eework, (void *)&work, sizeof (struct eep_work)); |
58 | |
59 | ....
|
60 | }
|
61 | else
|
62 | menu_print (active_menu); |
63 | }
|
64 | }
|
65 | }
|
66 | sleep_mode(); |
67 | }
|
es wird im Prinzip im main gemerkt, in welchem Menupunkt man ist (active_menu) und es ist wichtig, ob man in einem Menu ist, denn dann darf das main nicht ins Display schreiben... Das Menusystem selbst kommt immer mit dem aktuellen Menu als Rückgabewert zurück, es wird immer aufgerufen mit:
1 | active_menu = menu_action (active_menu, key); |
es macht selbst keine Displayausgabe innerhalb dieser Routinen, das passiert in
1 | menu_print (active_menu); |
Das Menu-Konzept ist ursprünglich basierend auf einem Artikel hier im Wiki (find ich jetzt nicht), allerdings stark angepasst. Wenn Interesse besteht kann ich heute abend mal das Projekt hier hochladen, die aktuellen sourcen habe ich momentan nicht hier. Gruß, Bernhard
Hi, Ladyada z.B. implementiert bei deren IceTubeClock auch ein Menü, welches aber z.B. per Interrupt unterbrochen werden kann, und selbbsttätig nach einer gewissen Zeit zurückspringt. Ich habe den code vor ewigkeiten mal etwas modifiziert. Zu finden hier Beitrag "Alternative Firmware für LadyAda IceCubeClock"
@Peter: "Ein RTOS klingt erstmal nett, macht aber dafür nen Haufen zusätzlicher Probleme. Aus Funktionssicht wird nämlich alles gleichzeitig ausgeführt, die Funktion weiß nicht, wann sie von welcher anderen unterbrochen wird." Im Prinzip ja, aber dafür gibt es die Möglichkeit, das Multitasking zu unterbrechen. In Nano_OS z.B. mit TASK_DISABLE_MULTITASKING() und TASK_ENABLE_MULTITASKING(). "Ressourcen (LCD, UART, I2C) können belegt sein, Variablen können sich mitten im Zugriff ändern usw." Dafür gibt es Semaphore. "Ein RTOS erfordert sehr viel Disziplin beim Programmieren. Es macht Fehler leicht und verzeiht sie nicht. Und beim Debuggen mit einem RTOS rauft man sich eh die Haare." Das ist bahr. Allerdings hängt es sehr vom RTOS ab, wie sehr man sich disziplinieren muss. gruß tobi
Felix H. schrieb: > es gibt Profile programmierbare Knöpfe bei den slaves, am master, > unzählige Sensoren und kurz tausende von Einstellungs Möglichkeiten. Dann ist es umso wichtiger, sich erstmal alle Menüpunkte und Einstellungen aufzuschreiben. Und dann versuchen, das in möglichst allgemeinen Funktionen zu beschreiben. Und nur die Unterschiede in einer Struktur anzulegen, z.B.: - Menüname - Parametername, Anzeigeformat, Korrekturfaktor, Adresse, Max-/Minwert - Aktionen (nur Rücklesen, einstellbar, Einstelldigit). Eine durchdachte Menüstruktur macht nicht nur das Programmieren leichter, sondern auch die Bedienung. Peter
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.