4 Zeitlicher Arbeitsablauf

4.3 Kommunikation mit der vorhandenen Schrittmotorsteuerung

4.3.1 Befehle senden

Im nächsten Schritt geht es darum, Befehle an die Schrittmotorkarte zu versenden. Da es nicht möglich ist, für jeden Befehl eine eigene Taste zu verwenden, wird eine menübasierte Steuerung mittels des LC-Displays verwendet. Im Menü lässt sich mit den Tasten Hoch, Runter, Ok, und Zurück, navigieren.
Analog wie beim LC-Display und bei den Tastern wird hier eine vorhandene Bibliothek genutzt. Um die Bibliothek verwenden zu können musste die Menüstruktur den Bedürfnissen des Projekts angepasst werden und die Funktionen zum Ausgeben von Text auf dem LC-Display und zum Versenden von Befehlen über die RS-232-Schnittstelle, aus den vorangegangen Kapiteln, bekannt gemacht werden. Dies geschieht in der Datei tinymenu/tinymenu.h.
Die Zeilen 1–6 des Codelisting 6 dienen zum Einbinden der benötigten Bibliotheken. Die Zeilen 8–20 zeigen eine vereinfachte Struktur des Hauptprogramms. Wird ein Taster gedrückt, wird dies durch die get_key_press()-Funktion, bekannt aus Kapitel 4.1.1, erkannt und die entsprechende Menü Funktion aufgerufen.

Listing 6: Menü
1 define MCU_CLK F_CPU
2 keywordstyle include "tinymenu/spin_delay.h"
3 define CONFIG_TINYMENU_USE_CLEAR
4 keywordstyle include "tinymenu/tinymenu.h"
5 keywordstyle include "tinymenu/tinymenu_hw.h"
6 keywordstyle include "mymenu.h"
7 // Gekuerzte Main-Funktion
8 int main(void) {
9         while (1) {  // In Endlosschleife wechseln
10                 wdt_reset();     // Watchdog zuruecksetzen
11                 if (get_key_press(1 << KEY1))      // 1 - Zurueck
12                         menu_exit(&menu_context);
13                 if( get_key_press(1 << KEY2))      // 2 - Hoch
14                         menu_prev_entry(&menu_context);
15                 if (get_key_press(1 << KEY3))      // 3 - Runter
16                         menu_next_entry(&menu_context);
17                 if (get_key_press(1 << KEY4))      // 4 - Ok
18                         menu_select(&menu_context);
19         }
20 }
21 // Funktion zum senden der Menuepunkte ueber die serielle Schnittstelle
22 void        menu_puts                (void *arg, char *name) { // Menu/Sende Funktion
23         uart_put_string(arg, D_Stepper);   // Uebergebenen String an Stepper senden
24         // Befehl auf Display ausgeben
25         lcd_clrscr();
26         lcd_puts("Sent: ");
27         lcd_puts(arg);
28         lcd_puts("\n");
29         ms_spin(100);
30         //if ((UCSR1A & (1 << RXC1)))
31         uart_rx(D_Stepper);     // Antwort des Stepper empfangen
32         ms_spin(1000);         // Antwort noch eine weile Anzeigen
33 }

Folgende Menüpunkte wurden realisiert:

Listing 7: Menü Baum
1 Main Menu
2   Bewegen - Rotation
3     +90
4     -90
5     +10.000 Schritte
6     -10.000 Schritte
7     Gehe zum Uhrsprung
8   Bewegen - Hoehe
9     +500000
10     -500000
11     +1000000
12     -1000000
13     Gehe zum Ursprung
14   Konfigurieren
15     Motorstatus
16     Setze Ursprung
17     Write to EEPROM
18     Newline 1
19     Parameter Auslesen

Wird einer der Menüpunkte aufgerufen, wird die im Menüpunkt hinterlegte Funktion mit dem hinterlegten Parameter aufgerufen. Wird beispielsweise der Befehl +90 ausgewählt, wird die hinterlegte Funktion menu_puts(arg, name)(Codelisting 6 Zeile 18-28) mit dem hinterlegten Wert aufgerufen. Diese sendet dann mit der aus Kapitel 4.1.4 bekannten Funktion uart_puts(arg, dir) einen Befehl an die Schrittmotorsteuerung.
Es ist somit nun möglich mit Tastern vordefinierte Befehle aus dem Menü auszuwählen und an die Schrittmotorsteuerung zu senden.

4.3.2 Antworten empfangen und speichern

Die Schrittmotorsteuerung antwortet auf Befehle mit einem String. In diesem Arbeitsschritt wird die Funktionalität zum Empfangen von Antworten der Schrittmotorsteuerung auf Befehle des Mikrocontrollers hergestellt. Diese Antworten sollen in einem String gespeichert und im nächsten Schritt an eine Auswerte-Funktion weiter gegeben werden.
Dazu wird in der Hauptschleife des Programms ständig das Eingangsregister der ersten seriellen Schnittstelle abgefragt (siehe Codelisting 8 Zeile 10–13). Dieses Vorgehen bezeichnet man als Polling. Sind Daten im Register vorhanden, wird LED3 eingeschaltet und die Funktion uart_rx(int dir) mit dem Parameter D_Stepper aufgerufen. Der übergebene Parameter gibt an, dass der Befehl von der für die Schrittmotorkarte zuständigen Schnittstelle empfangen wurde. Dadurch wird sichergestellt, dass der empfangene String aus dem richtigen Datenempfangsregister ausgelesen wird und festgelegt wie er weiterverarbeitet wird. Die Funktion uart_rx(dir) liest dann das Empfangsregister mit der aus Kapitel 4.1.4 bekannten Funktion uart_get_string(str_rx, dir) aus und schreibt den empfangenen String in die Variable str_rx(Codelisting 8, Zeile 7). In einer if-Abfrage wird entschieden von welcher Schnittstelle der empfangene Befehl kam. Da D_Stepper übergeben wurde, wird der if-Teil der Abfrage ausgeführt. In dieser wird der empfangene String an die Auswerte-Funktion für die Schrittmotorkarte (Codelisting 8, Zeile 15-45) übergeben. Durch diesen Teil des Programms ist es nun möglich Antworten der Schrittmotorkarte zu empfangen, in dem String str_rx zu speichern und an die Auswerte-Funktion switch_Stepper(str_rx) zu übergeben.

Listing 8: RS-232 Empfang
1 if ((UCSR1A & (1 << RXC1))){                // Stepper Polling
2         LED_PORT &= ( 1 << LED3 );          // LED einschalten
3         uart_rx(D_Stepper);                     // Register auslesen
4 }
5 // UART Empfangsregister auslesen
6 void        uart_rx                                (int dir) {
7         uart_get_string(str_rx, dir);   // String aus Empfangsregister auslesen
8         if (dir == D_Stepper)         // Empfangsregister Stepper
9                 switch_Stepper(str_rx);     // Uebersetzungsfunktion fuer Stepper aufrufen
10         else{                               // Empfangsregister RapidForm
11                 // Wird spaeter erklaert
12         }
13 }

4.3.3 Antworten auswerten

Die Funktion zum Auswerten empfangener Strings spielt eine zentrale Rolle im Projekt. Diese Funktion ermöglicht es, ankommende Strings im Mikrocontroller gegen die bekannten Antworten zu prüfen und eine entsprechende Reaktion auszuführen.
In der Auswerte-Funktion wird der übergebene String mittels der Funktion
FindStringInArray(str_rx, pOptions, length)(Codelisting 9) gegen ein Array (Codelisting 10, Zeile 3) mit bekannten Befehlen geprüft. Ist der String in diesem Array vorhanden, wird die Position des Strings im Array zurückgegeben, ansonsten wird ’’99’’ zurückgegeben. In einer anschließenden switch/case-Struktur wird dann der Position im Array ein bestimmtes Verhalten des Mikrocontrollers zugeordnet. Wird beispielsweise der String # empfangen, wird Position 0 zurück gegeben und auf dem LC-Display wird Erfolgreich ausgegeben.
Durch diese Funktion kann nun auf Strings reagiert werden und eine entsprechende Reaktion seitens des Mikrocontrollers erfolgen.

Listing 9: FindStringInArray()
1 int        FindStringInArray        (const char* pInput, const char* pOptions[], int cmp_length) {
2         int n = -1;
3         while (pOptions[++n]) {       //Array durchlaufen bis 0 terminiert
4                 //Wenn pInput == pOptions dann gib Array Position zurueck
5                 if (!strncmp(pInput, pOptions[n], cmp_length))    return n;
6         }
7         return 99; // Wenn keine uebereinstimmung, gib 99 zurueck
8 }
Listing 10: switchStepper()
1 // Uebersetzung Schrittmotorkarte
2 void        switch_Stepper                (char * str_rx) {
3         const char* pOptions[] = {       // Array mit bekannten Befehlen
4                         "#",    // 0 - Stepper Karte hat Befehl erkannt
5                         "E",    // 1 - Stepper Karte meldet Error
6                         "!CLS", // 2 - Clear Screen (Debugging)
7                         "Test", // 3 - Test (Debugging)
8                         0 };
9         switch (FindStringInArray(str_rx, pOptions, 1)) { // String gegen bekannte Antworten pruefen
10         case 0:                     // 0 - Stepper Karte hat Befehl erkannt
11                 lcd_puts("Erfolgreich\n");
12                 break;
13         case 1:                     // 1 - Stepper Karte meldet Error
14                 lcd_puts("Error\n");
15                 uart_put_string("1\r\n", D_RapidForm);
16                 break;
17         case 2:                     // 2 - Clear Screen (Debugging)
18                 lcd_clrscr();
19                 break;
20         case 3:                     // 3 - Test (Debugging)
21                 lcd_puts("Test bestanden\n");
22                 break;
23         default:
24                 ms_spin(10);
25         }
26 }