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.
| 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:
| 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.
| 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.
| 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 | } |
| 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 | } |