{"id":766,"date":"2017-11-27T00:44:25","date_gmt":"2017-11-26T23:44:25","guid":{"rendered":"http:\/\/mikrocontroller.bplaced.net\/wordpress\/?page_id=766"},"modified":"2018-02-11T21:57:31","modified_gmt":"2018-02-11T20:57:31","slug":"16-uplay-basic-interpreter-per-xmc2go","status":"publish","type":"page","link":"https:\/\/mikrocontroller.bplaced.net\/wordpress\/?page_id=766","title":{"rendered":"16-Show (UPlay Basic Interpreter per XMC2Go)"},"content":{"rendered":"<p><div id=\"nav-below\" class=\"navigation\"><div class=\"nav-previous\"><a href=\"https:\/\/mikrocontroller.bplaced.net\/wordpress\/?page_id=764\" title=\"15-Show (Scope-Clock per STM32F4)\"><span class=\"meta-nav\">\u2190<\/span> 15-Show (Scope-Clock per STM32F4)<\/a><\/div><\/div><!-- #nav-below --><div id=\"nav-below\" class=\"navigation\"><div class=\"nav-next\"><a href=\"https:\/\/mikrocontroller.bplaced.net\/wordpress\/?page_id=770\" title=\"17-Show (Logic-Analyzer per STM32F429)\">17-Show (Logic-Analyzer per STM32F429) <span class=\"meta-nav\">&rarr;<\/span><\/a><\/div><\/div><!-- #nav-below --><br \/>\nLaut Wikipedia gibt es die Programmiersprache &#8222;BASIC&#8220; jetzt \u00fcber 50 Jahre. Dem einfachen Syntaxaufbau mag es geschuldet sein, dass auch heute noch neue Projekte damit realisiert werden.<\/p>\n<p>Auch ich habe mit Basic ein paar Jahre programmiert und obwohl h\u00f6here Programmiersprachen viele Vorteile besitzen, kann man dennoch auch mit Basic einiges anfangen.<\/p>\n<p>Dieses Projekt zeigt einen Basic-Interpreter, der auf einem 32Bit ARM-M0 System von Infineon l\u00e4uft und mit dem der User, mit Hilfe von ein paar Buttons und einem Graphic-LCD, einfache Spiele und Anwendungen selbst erstellen kann.<\/p>\n<p>Das ganze habe ich &#8222;<strong>uPlay<\/strong>&#8220; getauft&#8230;abgeleitet von dem benutzten Basic-Interpreter &#8222;uBasic&#8220; und als batteriebetriebenen kleinen &#8222;Handheld&#8220; designed.<\/p>\n<div class=\"center\"><a class=\"image\" href=\"http:\/\/mikrocontroller.bplaced.net\/wordpress\/wp-content\/uploads\/2017\/12\/UPlay.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"thumbimage\" src=\"http:\/\/mikrocontroller.bplaced.net\/wordpress\/wp-content\/uploads\/2017\/12\/300px-UPlay.jpg\" alt=\"\" width=\"300\" height=\"501\" \/><\/a><br \/>\nFertig aufgebautes uPlay<\/div>\n<p><strong>Inhaltsverzeichnis<\/strong><\/p>\n<ol>\n<li><a href=\"#Einleitung\">Einleitung<\/a><\/li>\n<li><a href=\"#Hardware\">Hardware<\/a>\n<ol>\n<li><a href=\"#CPU.BOARD\">CPU\/BOARD<\/a><\/li>\n<li><a href=\"#DISPLAY\">DISPLAY<\/a><\/li>\n<li><a href=\"#Break-Button\">Break-Button<\/a><\/li>\n<li><a href=\"#ADC\">ADC<\/a><\/li>\n<li><a href=\"#GPIOs\">GPIOs<\/a><\/li>\n<li><a href=\"#UART\">UART<\/a><\/li>\n<li><a href=\"#Spannung.2FStrom\">Spannung\/Strom<\/a><\/li>\n<\/ol>\n<\/li>\n<li><a href=\"#Entwicklungsumgebung\">Entwicklungsumgebung<\/a><\/li>\n<li><a href=\"#uPlay\">uPlay<\/a>\n<ol>\n<li><a href=\"#Startmenu.2FKommunikation\">Startmenu\/Kommunikation<\/a><\/li>\n<li><a href=\"#Basic-Programm_download\">Basic-Programm download<\/a><\/li>\n<li><a href=\"#Status-LEDs\">Status-LEDs<\/a><\/li>\n<li><a href=\"#DISPLAY_2\">DISPLAY<\/a><\/li>\n<li><a href=\"#ADC_2\">ADC<\/a><\/li>\n<li><a href=\"#GPIOs_2\">GPIOs<\/a><\/li>\n<li><a href=\"#UART_2\">UART<\/a><\/li>\n<\/ol>\n<\/li>\n<li><a href=\"#uBasic\">uBasic<\/a>\n<ol>\n<li><a href=\"#Anpassungen\">Anpassungen<\/a><\/li>\n<li><a href=\"#Verbesserungen\">Verbesserungen<\/a><\/li>\n<li><a href=\"#Syntax\">Syntax<\/a><\/li>\n<li><a href=\"#Befehlsbeschreibungen\">Befehlsbeschreibungen<\/a><\/li>\n<li><a href=\"#Standalone_Version\">Standalone Version<\/a><\/li>\n<li><a href=\"#Einschr.C3.A4nkungen\">Einschr\u00e4nkungen<\/a><\/li>\n<\/ol>\n<\/li>\n<li><a href=\"#Nachbau\">Nachbau<\/a>\n<ol>\n<li><a href=\"#Gr.C3.B6.C3.9Fe\">Gr\u00f6\u00dfe<\/a><\/li>\n<li><a href=\"#Platzierung\">Platzierung<\/a><\/li>\n<li><a href=\"#XMC-2Go\">XMC-2Go<\/a><\/li>\n<li><a href=\"#Display_3\">Display<\/a><\/li>\n<li><a href=\"#Funktionstest\">Funktionstest<\/a><\/li>\n<li><a href=\"#SNAKE\">SNAKE<\/a><\/li>\n<\/ol>\n<\/li>\n<li><a href=\"#Ausblick\">Ausblick<\/a><\/li>\n<li><a href=\"#Anmerkungen\">Anmerkungen<\/a><\/li>\n<li><a href=\"#Downloads\">Downloads<\/a><\/li>\n<\/ol>\n<h2 id=\"Einleitung\">Einleitung<\/h2>\n<p>Das &#8222;<strong>uPlay<\/strong>&#8220; basiert auf dem Basic-Interpreter &#8222;<strong>uBasic<\/strong>&#8220; von <strong>Adam Dunkels<\/strong> der von mir etwas &#8222;erweitert&#8220; wurde. Als CPU-Board kommt ein <strong>XMC-2Go<\/strong> von Infineon mit dem XMC1100 Prozessor zum Einsatz. Als Display habe ich ein 84&#215;48 Pixel Grafik-Display benutzt und zur Eingabe gibt es 5 Buttons. Die Hardwarekosten f\u00fcr einen Nachbau belaufen sich auf etwa 15 EUR. Der Aufbau der Hardware sollte an einem regnerischen Wochenende erledigt sein.<\/p>\n<ul>\n<li>Kosteng\u00fcnstiges CPU Board (ca. 6 EUR)<\/li>\n<li>Kosteng\u00fcnstiges Grafik-Display (ca. 5 EUR)<\/li>\n<li>Einfacher Hardwareaufbau<\/li>\n<li>Eigene Basic-Programme k\u00f6nnen als Ascii-File per UART vom PC geladen werden<\/li>\n<li>Kleine Abmessungen<\/li>\n<li>Batteriebetrieb m\u00f6glich<\/li>\n<\/ul>\n<h2 id=\"Hardware\">Hardware<\/h2>\n<p>Als Minimalhardware wird eigentlich nur eine CPU ben\u00f6tigt, wenn das Basic-Programm im Flash vorhanden ist und man kein Display zur Ausgabe ben\u00f6tigt.<\/p>\n<p>Mehr &#8222;Spa\u00df&#8220; bringt es nat\u00fcrlich, wenn man ein Display benutzen kann und zur Eingabe ein paar Buttons vorhanden sind. In dieser Beschreibung gehe ich davon aus, das die Hardware so aufgebaut wird, wie im Schaltplan beschrieben. Es kann aber auch eine andere Kombination gew\u00e4hlt werden, wenn die Software entsprechend angepasst wird.<\/p>\n<h3 id=\"CPU-BOARD\">CPU\/BOARD<\/h3>\n<p>Wie schon geschrieben habe ich das ganze f\u00fcr das XMC2-2Go Board von Infineon und die XMC1100 CPU programmiert. Prinzipiell kann hier auch jede andere CPU benutzt werden, solange genug RAM f\u00fcr das Basic-Programm vorhanden ist und sie schnell genug ist um die Anwendung auch in einer vern\u00fcnftigen Zykluszeit abzuarbeiten.<\/p>\n<p>Hier ein paar Eckdaten der XMC1100 :<\/p>\n<ul>\n<li>CPU : 32bit ARM-M0<\/li>\n<li>Clock : 32 MHz<\/li>\n<li>Flash : 64 kByte<\/li>\n<li>Ram : 16 kByte<\/li>\n<\/ul>\n<p>Mit dieser CPU liegt die Zykluszeit von einer Basic-Zeile (je nach Umfang) bei ca. 500 us.<\/p>\n<p>Am XMC-2Go Board sind nur 14 GPIO-Pins an Pfostenleisten zug\u00e4nglich, was den Einsatz der restlichen Hardware nat\u00fcrlich einschr\u00e4nkt. Aber wie an dem Projekt zu sehen ist, reicht es trotzdem f\u00fcr alle Funktionen.<\/p>\n<ul>\n<li>Manual vom XMC-2Go<sup id=\"cite_ref-1\" class=\"reference\"><a href=\"http:\/\/www.infineon.com\/dgdl\/Board_Users_Manual_XMC_2Go_Kit_with_XMC1100_R1.0.pdf?folderId=db3a30433580b3710135a47f3eb76c98&amp;fileId=db3a3043444ee5dc014453d6c75078c6&amp;ack=t\" target=\"_blank\" rel=\"noopener\">[1]<\/a><\/sup><\/li>\n<li>Datenblatt vom XMC1100<sup id=\"cite_ref-2\" class=\"reference\"><a href=\"http:\/\/www.infineon.com\/dgdl\/xmc1100_ds_v1.2_2013_12.pdf?folderId=db3a30433580b3710135a47f3eb76c98&amp;fileId=db3a30433d1d0bbe013d256b60160b7f&amp;ack=t\" target=\"_blank\" rel=\"noopener\">[2]<\/a><\/sup><\/li>\n<li>RefManual vom XMC1100<sup id=\"cite_ref-3\" class=\"reference\"><a href=\"http:\/\/www.infineon.com\/dgdl\/xmc1100_rm_v1+0_2013_03.pdf?folderId=db3a30433580b3710135a47f3eb76c98&amp;fileId=db3a30433cfb5caa013d1600856033eb&amp;ack=t\" target=\"_blank\" rel=\"noopener\">[3]<\/a><\/sup><\/li>\n<\/ul>\n<h3 id=\"DISPLAY\">DISPLAY<\/h3>\n<p>Als Display habe ich das vom <strong>Nokia Handy 5110<\/strong> benutzt. Das ist g\u00fcnstig zu bekommen, hat eine Aufl\u00f6sung von 84&#215;48 Pixel und wird per SPI-Schnittstelle betrieben. Als LCD-Controller ist ein <strong>PCD8544<\/strong> verbaut.<\/p>\n<p>Ein weiterer Vorteil von dem Display ist, das f\u00fcr einen kompletten Refresh vom Grafik-Inhalt nur 504 Bytes Daten \u00fcbertragen werden m\u00fcssen. Bei der max SPI-Frq die das Display mitmacht (4MHz), dauert das rechnerisch nur 1ms.<\/p>\n<p>Zum Betrieb des Displays werden 5 GPIO Pins ben\u00f6tigt\u00a0:<\/p>\n<ul>\n<li>MOSI = P0.7<\/li>\n<li>CLK = P0.8<\/li>\n<li>CS = P0.9<\/li>\n<li>D\/C = P0.14<\/li>\n<li>RESET = P0.15<\/li>\n<\/ul>\n<p>Um Strom zu sparen, habe ich die Hintergrundbeleuchtung per Jumper abschaltbar gemacht.<\/p>\n<ul>\n<li>Datenblatt vom PCD8544\u00a0<sup id=\"cite_ref-4\" class=\"reference\"><a href=\"https:\/\/www.sparkfun.com\/datasheets\/LCD\/Monochrome\/Nokia5110.pdf\" target=\"_blank\" rel=\"noopener\">[4]<\/a><\/sup><\/li>\n<li>Bezugsquelle vom Nokia5110 Display\u00a0<sup id=\"cite_ref-5\" class=\"reference\"><a href=\"https:\/\/www.sparkfun.com\/products\/10168\" target=\"_blank\" rel=\"noopener\">[5]<\/a><\/sup><\/li>\n<\/ul>\n<h3 id=\"Break-Button\">Break-Button<\/h3>\n<p>Der MISO Pin der SPI-Schnittstelle wird f\u00fcr das Display nicht ben\u00f6tigt. Damit dieser PIN nicht unbenutzt bleibt, habe ich daran einen &#8222;Break-Button&#8220; angeschlossen mit dem man ein laufendes Basic-Programm abbrechen kann.<\/p>\n<p>Der Pin hat einen internen PullUp, es reicht also einen Taster gegen GND einzubauen.<\/p>\n<p>Der Status vom Button wird automatisch bei jedem refresh vom Display abgefragt. Falls er nicht bet\u00e4tigt ist, ist der R\u00fcckgabewert 0xFF. Falls er bet\u00e4tigt ist, wird eine 0x00 zur\u00fcckgeliefert.<\/p>\n<ul>\n<li>Break-Button = P0.6<\/li>\n<\/ul>\n<h3 id=\"ADC\">ADC<\/h3>\n<p>Einen Pin der CPU habe ich als 10bit ADC-Eingang initialisiert. Dieser kann vom Basic-Programm aus abgefragt werden. In wie weit man das in seiner Anwendung benutzen will, bleibt jedem selbst \u00fcberlassen.<\/p>\n<p>Im\u00a0<b>&#8222;uPlay&#8220;<\/b>\u00a0wird der ADC nicht benutzt und ist nur im Schaltplan vorhanden.<\/p>\n<p>Beim abfragen vom Basic-Programm aus wird ein Integer Wert von 0&#8230;1023 zur\u00fcckgeliefert, was einer Spannung von 0 bis 3,3V entspricht.<\/p>\n<p>Die Umrechnungsformel &#8222;ADC-&gt;VOLT&#8220; lautet demnach\u00a0: Spannung = 3,3V \/ 1023 x ADC_WERT<\/p>\n<ul>\n<li>ADC-0 = P2.6<\/li>\n<\/ul>\n<h3 id=\"GPIOs\">GPIOs<\/h3>\n<p>Von den 14 Pins des XMC-2Go sind 7 vom Display und ADC belegt, bleiben also noch 7 GPIOs \u00fcbrig. Um Spiele zu realisieren braucht man mindestens 5 Buttons &#8222;Steuerkreuz + Enter&#8220; als Eingabe.<\/p>\n<p>Ich habe das\u00a0<b>&#8222;uPlay&#8220;<\/b>\u00a0also mit 5 Inputs und 2 Outputs designed. Wer das ganze Projekt f\u00fcr andere Zwecke benutzen will, kann das nat\u00fcrlich ab\u00e4ndern wie er lustig ist.<\/p>\n<p>Beachtet werden muss nur, das nicht jeder Pin vom XMC-2Go als Ausgang geschaltet werden kann\u00a0:<\/p>\n<ul>\n<li>P0.0 = STD_IN \/ STD_OUT<\/li>\n<li>P0.5 = STD_IN \/ STD_OUT<\/li>\n<li>P2.0 = STD_IN \/ STD_OUT \/ ADC_IN<\/li>\n<li>P2.7 = STD_IN \/ ADC_IN<\/li>\n<li>P2.9 = STD_IN \/ ADC_IN<\/li>\n<li>P2.10 = STD_IN \/ STD_OUT \/ ADC_IN<\/li>\n<li>P2.11 = STD_IN \/ STD_OUT \/ ADC_IN<\/li>\n<\/ul>\n<h4 id=\"INPUTS\">INPUTS<\/h4>\n<p>Damit User-Eingaben ausgewertet werden k\u00f6nnen, habe ich 5 Buttons angeschlossen. 4 als &#8222;Steuerkreuz&#8220; und 1 &#8222;Enter&#8220;.<\/p>\n<p>Per Software sind die PullUps der CPU aktiviert also reichen Taster gegen GND zum schalten. Daraus folgt, das ein nicht bet\u00e4tigter Button eine &#8222;1&#8220; beim einlesen vom Basic-Programm zur\u00fcckliefert und ein gedr\u00fcckter Button eine &#8222;0&#8220;.<\/p>\n<ul>\n<li>Button-0 (UP) = P2.10<\/li>\n<li>Button-1 (DOWN) = P0.0<\/li>\n<li>Button-2 (LEFT) = P2.9<\/li>\n<li>Button-3 (RIGHT) = P2.11<\/li>\n<li>Button-4 (ENTER) = P2.7<\/li>\n<\/ul>\n<h4 id=\"OUTPUTS\">OUTPUTS<\/h4>\n<p>Zwei der GPIO-Pins habe ich als Digital-Ausgang initialisiert, um z.B. eine LED oder ein Piepser anzuschlie\u00dfen.<\/p>\n<p>Die Outputs sind als PushPull geschaltet. Im\u00a0<b>&#8222;uPlay&#8220;<\/b>\u00a0werden die Outputs nicht benutzt und sind nur im Schaltplan vorhanden. (laut Datenblatt sind die PortPins nur bis max 10mA belastbar)<\/p>\n<ul>\n<li>Output-0 = P0.5<\/li>\n<li>Output-1 = P2.0<\/li>\n<\/ul>\n<h3 id=\"UART\">UART<\/h3>\n<p>Die UART vom XMX-2Go Board wird ben\u00f6tigt um Basic-Programme nachzuladen. Sie wird auch im laufenden Basic-Programm als Standardausgabe der &#8222;PRINT&#8220; Befehle benutzt.<\/p>\n<p>Die Schnittstelle wird mit 115200 Baud initialisiert mit dem Frame-Parameter &#8222;8N1&#8220;.<\/p>\n<ul>\n<li>TXD = P2.1<\/li>\n<li>RXD = P2.2<\/li>\n<\/ul>\n<h3 id=\"Spannung.2FStrom\">Spannung\/Strom<\/h3>\n<p>Als Spannungsversorgung ist eine 3V Lithium Knopfzelle mit 550mAh vorgesehen (CR-2450). Wenn der USB Stecker an den PC angeschlossen ist, wird das Board per USB versorgt.<\/p>\n<p>Eigentlich sollte man am Board, wenn es per USB versorgt wird, keine externe Spannung an die Stiftleiste anlegen. Ich habe aus dem Grund zum Schutz eine Diode vor der Batterie vorgesehen. Ein Jumper zum trennen der Batterie ist auch vorhanden (weil diese trotz Diode leergesaugt wird).<\/p>\n<p>Die Stromaufnahme vom Board+Display (ohne Hintergrundbeleuchtung) betr\u00e4gt ca. 9 mA.<\/p>\n<h2 id=\"Entwicklungsumgebung\">Entwicklungsumgebung<\/h2>\n<p>Als Entwicklungsumgebung habe ich <strong>KEIL uVision5<\/strong> benutzt. Davon gibt es eine kostenlose Version zum download die auch das XMC-2Go Board unterst\u00fctzt. Die max. 32k Flash Einschr\u00e4nkung ist f\u00fcr dieses Projekt nicht relevant.<\/p>\n<p>Unter dem gleichen Link wie uVision gibt es auch den USB-Treiber f\u00fcr das Debug-Interface von Segger &#8222;JLink&#8220;<\/p>\n<ul>\n<li>KEIL uVision5\u00a0<sup id=\"cite_ref-6\" class=\"reference\"><a href=\"http:\/\/www2.keil.com\/infineon\/mdk\/\" target=\"_blank\" rel=\"noopener\">[6]<\/a><\/sup><\/li>\n<li>Installationsanleitung\u00a0<sup id=\"cite_ref-7\" class=\"reference\"><a href=\"http:\/\/mikrocontroller.bplaced.net\/wordpress\/?page_id=580\">[7]<\/a><\/sup><\/li>\n<\/ul>\n<h2 id=\"uPlay\">uPlay<\/h2>\n<p>Die Software besteht im Prinzip aus zwei Teilen\u00a0:<\/p>\n<p>1. Dem\u00a0<b>&#8222;uPlay&#8220;<\/b>\u00a0System das die angeschlossene Hardware kontrolliert (LCD, Buttons, UART usw). \u00dcber dieses System kann ein Basic-Programm per UART nachgeladen werden und dieses startet dann auch den Basic-Interpreter.<\/p>\n<p>2. Dem Basic-Interpreter &#8222;uBasic&#8220; der ein Basic-Program das im RAM liegt \u00fcbersetzt und abarbeitet.<\/p>\n<h3 id=\"Startmenu.2FKommunikation\">Startmenu\/Kommunikation<\/h3>\n<p>Nach dem PowerOn vom\u00a0<b>&#8222;uPlay&#8220;<\/b>\u00a0steht das System im &#8222;Standby-Mode&#8220; und es wird ein Menu auf dem Display angezeigt.<\/p>\n<p>Man kann hier entweder ein Basic-Programm aus dem internen Flash der CPU starten oder ein schon geladenes Programm aus dem RAM. Die Auswahl erfolgt durch die Buttons &#8222;Left\/Right\/Enter&#8220;.<\/p>\n<p>Zur Demo habe ich eine Version von dem Spiel &#8222;Snake&#8220; programmiert und als Basic-Programm ins Flash gepackt. Das Programm liegt als Quellcode in der Datei\u00a0: &#8222;bas_snake.h&#8220;.<\/p>\n<p>Alternativ kann auch eine UART Verbindung aufgebaut werden. Mit dem UART-Befehl &#8222;HELP&#8220; kann man die Versions-Nummer vom &#8222;uPlay&#8220; und vom &#8222;uBasic&#8220; auslesen.<\/p>\n<h3 id=\"Basic-Programm_download\">Basic-Programm download<\/h3>\n<p>Um ein Basic-Programm zum\u00a0<b>&#8222;uPlay&#8220;<\/b>\u00a0zu senden, muss dieses zuerst im &#8222;Standby-Mode&#8220; stehen. Danach kann mit dem UART-Befehl &#8222;LOAD&#8220; in den &#8222;Load-Mode&#8220; gewechselt werden. (Es wird jetzt auf die \u00dcbertragung von einem Basic-Programm gewartet)<\/p>\n<p>W\u00e4hrend der \u00dcbertragung wird die Anzahl der empfangenen Zeilen auf dem Display angezeigt. Um das Ende der \u00dcbertragung zu signalisieren muss ein &#8222;END&#8220; \u00fcbertragen werden. Damit wird wieder in den &#8222;Standby-Mode&#8220; gewechselt.<\/p>\n<p>Das Programm steht jetzt im RAM und kann entweder mit dem UART-Befehl &#8222;RUN&#8220; oder \u00fcber die Buttons gestartet werden.<\/p>\n<p>Hinweis\u00a0: das Basic-Programm wird solange abgearbeitet, bis es zu dem Basic-Befehl &#8222;END&#8220; kommt oder der &#8222;Break-Button&#8220; bet\u00e4tigt wird.<\/p>\n<p>Hier ein Bild wie ein Download per UART und die Ausgabe dazu aussieht. Das ganze funktioniert auch nur mit dem reinen XMC-2Go (also auch ohne Display und Buttons).<\/p>\n<div class=\"center\"><a class=\"image\" href=\"http:\/\/mikrocontroller.bplaced.net\/wordpress\/wp-content\/uploads\/2017\/12\/Terminal_Test.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"thumbimage\" src=\"http:\/\/mikrocontroller.bplaced.net\/wordpress\/wp-content\/uploads\/2017\/12\/300px-Terminal_Test.jpg\" alt=\"\" width=\"300\" height=\"253\" \/><\/a><br \/>\nTest per Terminal-Programm<\/div>\n<h3 id=\"Status-LEDs\">Status-LEDs<\/h3>\n<p>Die beiden LEDs auf dem XMC-2Go zeigen den aktuellen Status vom System an\u00a0:<\/p>\n<ul>\n<li>LED1 blinkt zyklisch einmal pro Sekunde (Heartbeat)<\/li>\n<li>LED2 blinkt 3mal pro Sekunde wenn ein Basic-Programm abgearbeitet wird<\/li>\n<\/ul>\n<h3 id=\"DISPLAY_2\">DISPLAY<\/h3>\n<p>F\u00fcr das Display gibt es einen 504 Byte gro\u00dfen Graphic-Puffer im RAM (84 x 48 Pixel). Die Befehle aus dem Basic-Programm schreiben\/lesen in diesen Puffer und alle 100ms wird der komplette Inhalt vom Puffer zum Display gesendet.<\/p>\n<p>Im Moment ist nur eine Schriftart implementiert in der Gr\u00f6\u00dfe 6&#215;8 Pixel. Damit passen 6 Zeilen auf das Display mit je 14 Zeichen.<\/p>\n<h3 id=\"ADC_2\">ADC<\/h3>\n<p>Der ADC wird im Single-Conversation-Mode betrieben, wird also bei jedem Aufruf vom Basic-Programm aus neu gestartet.<\/p>\n<h3 id=\"GPIOs_2\">GPIOs<\/h3>\n<p>Die Basic-Befehle f\u00fcr Digital-IN, Digital-OUT werden direkt an die entsprechenden GPIOs weitergegeben.<\/p>\n<p>Durch die relativ langsame Zykluszeit vom Basic-Programm ist ein entprellen der Eing\u00e4nge nicht notwendig. (zumindest denke ich das\u00a0\ud83d\ude42<\/p>\n<h3 id=\"UART_2\">UART<\/h3>\n<p>Die UART ist die standard Ausgabe der &#8222;PRINT&#8220;-Befehle vom Basic-Programm aus.<\/p>\n<p>Ein &#8222;10 PRINT 123&#8220; sendet also den String &#8222;123&#8220; \u00fcber die UART. Als Stringendekennung wird ein CarriageReturn+Linefeed (0x0D,0x0A) angeh\u00e4ngt.<\/p>\n<p>Beim senden von Daten vom PC an das\u00a0<b>&#8222;uPlay&#8220;<\/b>\u00a0muss der PC ein CarriageReturn (0x0D) am Ende von jedem String anh\u00e4ngen.<\/p>\n<h2 id=\"uBasic\">uBasic<\/h2>\n<p>Der Basic-Interpreter von Adam Dunkels ist sehr einfach aufgebaut und die Funktionsweise ist auch ohne Dokumentation leicht per Debugger zu verstehen.<\/p>\n<ul>\n<li>uBascic von Adam Dunkels<sup id=\"cite_ref-8\" class=\"reference\"><a href=\"http:\/\/dunkels.com\/adam\/ubasic\/\" target=\"_blank\" rel=\"noopener\">[8]<\/a><\/sup><\/li>\n<\/ul>\n<p>Dieser Interpreter wurde schon von vielen als Basis benutzt. Bekannt aus diesem Forum sind z.B. die Portierungen f\u00fcr den AVR von Rene Boellhoff und Uwe Berger.<\/p>\n<ul>\n<li>AVR-Basic<sup id=\"cite_ref-9\" class=\"reference\"><a href=\"http:\/\/www.mikrocontroller.net\/svnbrowser\/avr-basic\/\" target=\"_blank\" rel=\"noopener\">[9]<\/a><\/sup><\/li>\n<\/ul>\n<p>Ich selbst habe nur mit der original Version von Adam Dunkels gearbeitet und wollte diese so wenig wie m\u00f6glich ab\u00e4ndern um den einfachen Aufbau nicht zu verlieren.<\/p>\n<p>Der Interpreter besteht nur aus 4 Files\u00a0: Dem &#8222;uBasic.c.+h&#8220; File und dem &#8222;Tokenizer.c+h&#8220; File.<\/p>\n<p>Im &#8222;Tokenizer&#8220; sind alle Basic-Sprachbefehle hinterlegt. Dieser liefert beim Aufruf der Funktion &#8222;get_next_token&#8220; zur\u00fcck, um welchen Befehl oder welches Zeichen es sich im geladenen Basic-Programm gerade handelt. Der R\u00fcckgabewert besteht aus einem einzelnen Bytewert, dem &#8222;Token&#8220;.<\/p>\n<p>Um z.B. die Basic-Zeile &#8222;10 PRINT a&#8220; zu zerlegen, m\u00fcsste man den Tokenizer 3mal aufrufen und dieser w\u00fcrde 3 Tokens zur\u00fcckliefert mit den Namen\u00a0: &#8222;LINENUM&#8220; , &#8222;PRINT&#8220; , &#8222;VARIABLE&#8220;<\/p>\n<p>Das &#8222;uBasic&#8220; k\u00fcmmert sich um das aufrufen vom Tokenizer und entscheidet je nach empfangenen Token was daraufhin gemacht werden soll. Hier sind die Funktionen aller Basic-Befehle &#8222;ausprogrammiert&#8220; das bedeutet in unserem Beispiel w\u00fcrde die Funktion &#8222;print&#8220; angesprungen werden, der Inhalt der Variable &#8222;a&#8220; w\u00fcrde ausgelesen und per UART versendet werden.<\/p>\n<p>Das ganze ist recht simpel gestrickt und kann dementsprechend leicht ge\u00e4ndert und angepasst werden.<\/p>\n<h3 id=\"Anpassungen\">Anpassungen<\/h3>\n<p>Die ersten \u00c4nderungen die ich am uBasic gemacht habe, waren reine Bugfixes\u00a0:<\/p>\n<ul>\n<li>Der Variablen Name &#8222;a&#8220; konnte nicht benutzt werden<\/li>\n<li>Die Funktion &#8222;IF\/THEN\/ELSE&#8220; hat nicht richtig gearbeitet<\/li>\n<\/ul>\n<p>Als zweiten Schritt habe ich das uBasic etwas &#8222;erweitert&#8220;\u00a0:<\/p>\n<ul>\n<li>Keine Unterscheidung zwischen Gro\u00df- und Kleinschreibung der Basic-Befehle (z.B. &#8222;10 IF a&gt;5 Then goto 100 else GoSub 200&#8220;)<\/li>\n<li>Bei der IF-Anweisung kann das THEN entfallen (z.B. &#8222;10 IF a&gt;5 GOTO 100&#8220;)<\/li>\n<li>Variablen und Ausdr\u00fccke k\u00f6nnen negativ sein (z.B. &#8222;10 a = -5&#8220;)<\/li>\n<li>Den Wertebereich der Variabeln von char auf int vergr\u00f6\u00dfert<\/li>\n<li>Die FOR\/NEXT-Schleife so angepasst, das sie auch decrementieren kann (z.B. &#8222;10 FOR a=8 TO 2&#8220;)<\/li>\n<li>Die FOR\/NEXT-Schleife um &#8222;STEP&#8220; erweitert. (z.B. &#8222;10 FOR a=2 TO 13 STEP 3&#8220;)<\/li>\n<li>Den Befehl &#8222;REM&#8220; hinzugef\u00fcgt f\u00fcr Bemerkungstexte (z.B. &#8222;10 REM -BEISPIELPROGRAMM-&#8222;)<\/li>\n<\/ul>\n<p>Der dritte Schritt war das vergr\u00f6\u00dfern vom Basic-Sprachumfang um die angeschlossene Hardware zu steuern. Dazu geh\u00f6ren folgende Punkte\u00a0:<\/p>\n<ul>\n<li>System-Befehle\u00a0: PAUSE \/ CLRTIC \/ GETTIC<\/li>\n<li>LCD-Befehle\u00a0: INVERSE \/ CLS \/ LCD \/ SETPX \/ CLRPX \/ GETPX \/ LINE \/ RECT \/ FILL \/ CIRCLE \/ CLRCOLL \/ GETCOLL<\/li>\n<li>GPIO-Befehle\u00a0: IN \/ OUT<\/li>\n<li>ADC-Befehle\u00a0: ADC<\/li>\n<\/ul>\n<h3 id=\"Verbesserungen\">Verbesserungen<\/h3>\n<p>Hier w\u00e4re eigentlich die Arbeit am Basic-Interpreter fertig gewesen (und hat auch soweit funktioniert) wenn nicht die Durchlaufzeit der Basic-Programme erb\u00e4rmlich langsam gewesen w\u00e4re.<\/p>\n<p>Der Tokenizer der das Basic-Ascii-Programm durchackert muss jedes einzelne Zeichen untersuchen um aus dem String &#8222;print&#8220; (in allen m\u00f6glichen Schreibweisen) das Token &#8222;PRINT&#8220; zu ermitteln. Und das bei jedem Durchlauf obwohl sich der Befehl nie mehr \u00e4ndert.<\/p>\n<p>Auch das Suchen der Zeilen-Nummern bei &#8222;GOTO\/GOSUB\/NEXT\/RETURN&#8220; verbraucht immens viel zeit, weil jedes Mal von der ersten Zeile des Basic-Programmes aus gesucht wird.<\/p>\n<p>Ich habe mich darauf hin entschlossen diese zwei Sachen zu verbessern und einen &#8222;Pre-Parser&#8220; einzubauen, der vor dem eigentlichen Programmstart einmal abgearbeitet wird. Dieser Eingriff \u00e4ndert die Original-Version nur minimal aber das Ergebnis ist um ein vielfaches besser.<\/p>\n<p>Der Pre-Parser ist 3 Teilig aufgebaut und hat folgende Aufgaben\u00a0:<\/p>\n<h4 id=\"1._Schritt_:_Ersetzung_aller_Basic-Keywords\">1. Schritt\u00a0: Ersetzung aller Basic-Keywords<\/h4>\n<p>Zuerst wird das komplette Basic-Programm nach Ascii-Keywords durchsucht (z.B. &#8222;PRINT&#8220; oder &#8222;GOTO&#8220;) und durch einen zwei Byte Hex-Code ersetzt. Da jedes Keyword mindestens zwei Zeichen lang sein muss, ist das kein Problem. Das erste Byte ist eine Kennungs-ID mit dem Wert 0x01. An dieser Kennung erkennt der Parser sp\u00e4ter das es sich um eine Ersetzung handelt. Das zweite Byte ist direkt die Array-Nummer vom gefundenen Keyword. Das bedeutet der Parser muss sp\u00e4ter nicht mit einer For-Schleife das passende Keyword suchen, sondern kann direkt mit der Array-Nummer arbeiten. (damit es zu keiner Verwechslung mit anderen Ascii-Zeichen kommt, wird zus\u00e4tzlich das Bit7 gesetzt)<\/p>\n<h4 id=\"2._Schritt_:_Speichern_der_Sprungziele\">2. Schritt\u00a0: Speichern der Sprungziele<\/h4>\n<p>In diesem Schritt wird das Basic-Programm nach Keywords durchsucht, die ein Sprung zur folge haben (also &#8222;GOTO&#8220;,&#8220;GOSUB&#8220;,&#8220;FOR&#8220;). Bei so einem Keyword, wird das Sprungziel (bzw. R\u00fccksprungziel) als Zeilen-Nummer in einem Array gespeichert. Doppelte Eintr\u00e4ge werden abgefangen.<\/p>\n<h4 id=\"3._Schritt_:_Suchen_der_Pointer-Adressen_der_Sprungziele\">3. Schritt\u00a0: Suchen der Pointer-Adressen der Sprungziele<\/h4>\n<p>Hier wird das Programm noch mal durchsucht und zwar um rauszufinden welche Programm-Adresse welchem Sprungziel entspricht. Es werden also zu allen gefundenen Sprungzielen die passenden Einsprungadressen gespeichert. Sp\u00e4ter im eigentlichen Programmlauf wird dann z.B. bei einem &#8222;GOTO 100&#8220; im Array nachgesehen welche Pointeradresse die Zeilen-Nummer 100 hat und es wird direkt dort mit dem Programmlauf weitergemacht.<\/p>\n<h4 id=\"Ergebnis\">Ergebnis<\/h4>\n<p>Das Ergebnis vom Pre-Parsing ist eine enorme Geschwindigkeitsverbesserung im Vergleich zur Ur-Version von Adam Dunkels. hier eine Vergleichsmessung mit zwei For-Schleifen die 1000 mal eine Subroutine mit einer Print-Anweisung aufrufen\u00a0:<\/p>\n<pre lang=\"gwbasic\" line=\"0\">10 REM =============\r\n15 REM Speed-Test\r\n20 REM =============\r\n25 PRINT \"Start\"\r\n30 CLRTIC\r\n35 FOR n = 0 to 10\r\n40 FOR m = 0 to 100\r\n45 GOSUB 100\r\n50 NEXT m\r\n55 NEXT n\r\n60 GETTIC a\r\n65 PRINT \"Stop\"\r\n70 PRINT a,\"ms\"\r\n75 END\r\n80 REM --------------\r\n100 PRINT n,m\r\n110 RETURN\r\n<\/pre>\n<p>Dieses Programm dauert ohne Pre-Parser 45 Sekunden und mit Pre-Parser nur noch 1,8 Sekunden\u00a0! Das ist 25 mal so schnell. Mit dieser Geschwindigkeit lassen sich auch kleine Spiele realisieren.<\/p>\n<h3 id=\"Syntax\">Syntax<\/h3>\n<p>Hier eine kurz Zusammenfassung \u00fcber die Syntax vom uBasic\u00a0:<\/p>\n<ul>\n<li>Jede Zeile muss mit einer eindeutigen Zeilen-Nummer beginnen<\/li>\n<li>In jeder Zeile darf nur ein Befehl stehen (Ausnahme\u00a0: IF\/ELSE)<\/li>\n<li>Variabeln-Namen bestehen aus einem einzelnen Kleinbuchstaben<\/li>\n<li>Es d\u00fcrfen nur Ganzzahlen verwendet werden (-99999 bis 99999)<\/li>\n<li>Sprungziele m\u00fcssen aus reinen Zahlen bestehen (keine Variablen oder Rechnungen)<\/li>\n<li>Strings werden in Anf\u00fchrungszeichen gefasst (z.B. 10 PRINT &#8222;Hallo&#8220;)<\/li>\n<li>Rechenoperatoren\u00a0: -,+,*,\/,%<\/li>\n<li>Vergleichsoperatoren\u00a0: =,&lt;,&gt;<\/li>\n<li>Logik-Operationen\u00a0: &amp;,|<\/li>\n<li>Klammern\u00a0: (,)<\/li>\n<\/ul>\n<p>Es folgt eine Liste aller im Moment unterst\u00fctzten Basic-Keywords\u00a0:<\/p>\n<table class=\"wikitable\">\n<caption><b>uBasic-Keywords<\/b><\/caption>\n<tbody>\n<tr>\n<th>Grundbefehle<\/th>\n<th>Bedeutung<\/th>\n<th>Beispiel<\/th>\n<\/tr>\n<tr>\n<td>REM<\/td>\n<td>Kommentar<\/td>\n<td>10 REM Testprogramm<\/td>\n<\/tr>\n<tr>\n<td>LET<\/td>\n<td>Variablenzuweisung<br \/>\n(optional)<\/td>\n<td>10 LET a=5<br \/>\n20 b = -4<\/td>\n<\/tr>\n<tr>\n<td>PRINT<\/td>\n<td>Ausgabe per UART<\/td>\n<td>10 PRINT &#8222;Hallo&#8220;<br \/>\n20 PRINT 123<\/td>\n<\/tr>\n<tr>\n<td>IF\/THEN\/ELSE<\/td>\n<td>Bedingung<br \/>\n(THEN ist optional)<\/td>\n<td>10 IF a&gt;3 THEN PRINT b<br \/>\n20 IF a&gt;5 PRINT &#8222;NEIN&#8220; ELSE GOTO 100<\/td>\n<\/tr>\n<tr>\n<td>FOR\/TO\/STEP\/NEXT<\/td>\n<td>Schleife<br \/>\n(STEP ist optional)<\/td>\n<td>10 FOR i=2 TO 20 STEP 5<br \/>\n20 PRINT i<br \/>\n30 NEXT i<\/td>\n<\/tr>\n<tr>\n<td>GOTO<\/td>\n<td>Sprung<\/td>\n<td>10 GOTO 100<\/td>\n<\/tr>\n<tr>\n<td>GOSUB\/RETURN<\/td>\n<td>Sprung mit<br \/>\nR\u00fccksprung<\/td>\n<td>10 IF a&gt;3 GOSUB 1000<br \/>\n20 PRINT &#8222;nach Return&#8220;<br \/>\n30 END<br \/>\n1000 PRINT &#8222;Subroutine&#8220;<br \/>\n1010 RETURN<\/td>\n<\/tr>\n<tr>\n<td>END<\/td>\n<td>Ende vom Basic Programm<\/td>\n<td>10 PRINT a<br \/>\n20 END<\/td>\n<\/tr>\n<tr>\n<th>System-Befehle<\/th>\n<th>Bedeutung<\/th>\n<th>Beispiel<\/th>\n<\/tr>\n<tr>\n<td>PAUSE<\/td>\n<td>Pause<br \/>\n(Zeit in ms)<\/td>\n<td>10 PAUSE 100<\/td>\n<\/tr>\n<tr>\n<td>CLRTIC<\/td>\n<td>l\u00f6schen vom Timer<\/td>\n<td>10 CLRTIC<\/td>\n<\/tr>\n<tr>\n<td>GETTIC<\/td>\n<td>auslesen vom Timer<br \/>\n(Zeit in ms)<\/td>\n<td>10 GETTIC a<br \/>\n20 PRINT a<\/td>\n<\/tr>\n<tr>\n<th>LCD-Befehle<\/th>\n<th>Bedeutung<\/th>\n<th>Beispiel<\/th>\n<\/tr>\n<tr>\n<td>INVERSE<\/td>\n<td>Mode der Ausgabe<br \/>\n0=normal<br \/>\n1=invers<\/td>\n<td>10 INVERS 0<\/td>\n<\/tr>\n<tr>\n<td>CLS<\/td>\n<td>ClearScreen<\/td>\n<td>10 CLS<\/td>\n<\/tr>\n<tr>\n<td>LCD<\/td>\n<td>Ausgabe auf LCD<br \/>\n(an x,y Position)<\/td>\n<td>10 LCD x,y,&#8220;Hallo&#8220;<br \/>\n20 LCD 0,0,123<\/td>\n<\/tr>\n<tr>\n<td>SETPX<\/td>\n<td>setzen eines Pixels<br \/>\n(an x,y Position)<\/td>\n<td>10 SETPX x,y<\/td>\n<\/tr>\n<tr>\n<td>CLRPX<\/td>\n<td>l\u00f6schen eines Pixels<br \/>\n(an x,y Position)<\/td>\n<td>10 CLRPX x,y<\/td>\n<\/tr>\n<tr>\n<td>GETPX<\/td>\n<td>auslesen eines Pixels<br \/>\n(an x,y Position, Wert=[0,1])<\/td>\n<td>10 GETPX a=x,y<br \/>\n20 PRINT a<\/td>\n<\/tr>\n<tr>\n<td>LINE<\/td>\n<td>zeichnen einer Line<br \/>\n(von x,y nach a,b)<\/td>\n<td>10 LINE x,y,a,b<\/td>\n<\/tr>\n<tr>\n<td>RECT<\/td>\n<td>zeichnen eines Rechtecks<br \/>\n(von x,y nach a,b)<\/td>\n<td>10 RECT x,y,a,b<\/td>\n<\/tr>\n<tr>\n<td>FILL<\/td>\n<td>f\u00fcllen eines Rechtecks<br \/>\n(von x,y nach a,b)<\/td>\n<td>10 FILL x,y,a,b<\/td>\n<\/tr>\n<tr>\n<td>CIRCLE<\/td>\n<td>zeichnen eines Kreises<br \/>\n(an x,y mit Radius r)<\/td>\n<td>10 CIRCLE x,y,r<\/td>\n<\/tr>\n<tr>\n<td>CLRCOLL<\/td>\n<td>loeschen vom Kollisions Ergebnis<br \/>\nvor einer Zeichenoperation<\/td>\n<td>10 CLRCOLL<br \/>\n20 SETPX 5,6<\/td>\n<\/tr>\n<tr>\n<td>GETCOLL<\/td>\n<td>auslesen vom Kollisions Ergebnis<br \/>\nnach einer Zeichenoperation<br \/>\n(1=kollision)<\/td>\n<td>10 CLRCOLL<br \/>\n20 SETPX 5,6<br \/>\n30 GETCOLL a<br \/>\n40 PRINT a<\/td>\n<\/tr>\n<tr>\n<th>GPIO-Befehle<\/th>\n<th>Bedeutung<\/th>\n<th>Beispiel<\/th>\n<\/tr>\n<tr>\n<td>IN<\/td>\n<td>einlesen eines Input-Kanals<br \/>\n(c=Channel [0&#8230;4], Wert=[0,1])<\/td>\n<td>10 IN a=c<br \/>\n20 PRINT a<\/td>\n<\/tr>\n<tr>\n<td>OUT<\/td>\n<td>setzen eines Output-Kanals<br \/>\n(c=Channel [0&#8230;1], Wert=[0,1,2])<\/td>\n<td>10 OUT c,1<\/td>\n<\/tr>\n<tr>\n<th>ADC-Befehle<\/th>\n<th>Bedeutung<\/th>\n<th>Beispiel<\/th>\n<\/tr>\n<tr>\n<td>ADC<\/td>\n<td>einlesen eines ADC-Kanals<br \/>\n(c=Channel [0], Wert=[0&#8230;1023])<\/td>\n<td>10 ADC a=c<br \/>\n20 PRINT a<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h3 id=\"Befehlsbeschreibungen\">Befehlsbeschreibungen<\/h3>\n<p>Die meisten Befehle sollten man auch ohne Beschreibung verstehen. Hier ein paar Hinweise f\u00fcr Befehle die ich mir selbst ausgedacht habe und deren Funktionsweise nicht so offensichtlich sind\u00a0:<\/p>\n<h4 id=\".22PRINT.22\">&#8222;PRINT&#8220;<\/h4>\n<p>Beim &#8222;PRINT&#8220; k\u00f6nnen mehrere Ausgaben hintereinander geh\u00e4ngt werden z.B. &lt;10 PRINT &#8222;Zeit=&#8220; a &#8222;ms&#8220;&gt; ergibt &#8222;Zeit=123ms&#8220;. Mit einem &#8222;,&#8220; kann ein Space als Trennzeichen eingef\u00fcgt werden &lt;10 PRINT &#8222;Zeit=&#8220;,a,&#8220;ms&#8220;&gt; ergibt &#8222;Zeit = 123ms&#8220;. Ein &#8222;;&#8220; am Zeilenende verhindert das senden vom Linefeed.<\/p>\n<h4 id=\".22CLRTIC.22.2C.22GETTIC.22\">&#8222;CLRTIC&#8220;,&#8220;GETTIC&#8220;<\/h4>\n<p>Der Befehl &#8222;GETTIC&#8220; liefert die Zeit in ms die seit dem letzten &#8222;CLRTIC&#8220; vergangen ist. Die Zeitmessung ist nicht besonders genau, weil der interne Quarz der CPU nicht sehr exakt l\u00e4uft.<\/p>\n<p>Dieser Befehl kann auch als &#8222;Zufallsgenerator&#8220; missbraucht werden. z.B. durch Auswertung vom niederwertigsten Bit beim einlesen von GETTIC (da die Umlaufzeit nie 100% gleich ist.<\/p>\n<h4 id=\".22IN.22\">&#8222;IN&#8220;<\/h4>\n<p>Der Befehl &#8222;IN&#8220; erwartet eine Kanal-Nummer, um die 5 verschiedenen INPUT-Pins zu unterscheiden. Ein &#8222;10 IN a=0&#8220; lie\u00dft also den INPUT-Pin mit der Kanal-Nr &#8222;0&#8220; ein.<\/p>\n<h4 id=\".22OUT.22\">&#8222;OUT&#8220;<\/h4>\n<p>Der Befehlt &#8222;OUT&#8220; erwartet wie &#8222;IN&#8220; eine Kanal-Nummer und zus\u00e4tzlich den Pegel auf den geschaltet werden soll. Wobei &#8222;0=Lo_Pegel&#8220;, &#8222;1=Hi_Pegel&#8220;, &#8222;2=Pegel_toggeln&#8220; entspricht<\/p>\n<h4 id=\".22CRLCOLL.22.2C.22GETCOLL.22\">&#8222;CRLCOLL&#8220;,&#8220;GETCOLL&#8220;<\/h4>\n<p>Um eine Kollision beim zeichnen zu erkennen, muss der Kollisionsmerker zuerst gel\u00f6scht werden mit &#8222;CLRCOLL&#8220; und nach dem zeichnen kann dann das Ergebnis per &#8222;GETCOLL&#8220; ausgelesen werden. Eine Kollision hat dann stattgefunden, wenn ein Pixel auf dem LCD gesetzt wurde, das vorher schon gesetzt war.<\/p>\n<h3 id=\"Standalone_Version\">Standalone Version<\/h3>\n<p>Wer den reinen Basic-Interpreter benutzen will (z.B. auf einer anderen CPU) kann das relativ einfach machen.<\/p>\n<h4 id=\"1._Einbinden_der_Files\">1. Einbinden der Files<\/h4>\n<p>Man braucht die 4 Files (uBasic.c+h, Tokenizer.c+h) die man in sein Projekt einbinden muss. Diese befinden sich im uPlay-Projekt im Unterordner &#8222;uBasic&#8220;.<\/p>\n<h4 id=\"2._RAM-Puffer\">2. RAM-Puffer<\/h4>\n<p>Dann wird zum speichern von einem Basic-Programm ein RAM-Buffer ben\u00f6tigt<\/p>\n<pre lang=\"c\" line=\"0\">char ram_buffer[1024]; \/\/ 1k Puffer fuer Basic-Programm\r\n<\/pre>\n<p>In diesen RAM-Buffer muss man irgendwie das Basic-Programm bekommen (z.B. durch kopieren aus dem Flash, oder per UART von einem PC usw)<\/p>\n<h4 id=\"3._Notwendige_Funktionen\">3. Notwendige Funktionen<\/h4>\n<p>Was jetzt noch fehlt sind die Funktionen die vom Basic-Programm aus aufgerufen werden k\u00f6nnen und die Hardware betreffen.<\/p>\n<p>Dazu sind diese Prototypen (und die entsprechenden Funktionen) notwendig\u00a0:<\/p>\n<pre lang=\"c\" line=\"0\">void XMC2GO_Systic_Pause_ms(uint32_t ms);\r\nvoid XMC2GO_Systic_ClrTic(void);\r\nuint16_t XMC2GO_Systic_GetTic(void);\r\nvoid XMC2GO_LCD_Inverse(uint8_t mode);\r\nvoid XMC2GO_LCD_Clear(void);\r\nvoid XMC2GO_LCD_SetPixel(uint8_t xpos, uint8_t ypos);\r\nvoid XMC2GO_LCD_ClearPixel(uint8_t xpos, uint8_t ypos);\r\nuint8_t XMC2GO_LCD_ReadPixel(uint8_t xpos, uint8_t ypos);\r\nvoid XMC2GO_LCD_DrawLine(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2);\r\nvoid XMC2GO_LCD_DrawRect(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2);\r\nvoid XMC2GO_LCD_DrawFill(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2);\r\nvoid XMC2GO_LCD_DrawCircle(uint8_t x0, uint8_t y0, uint8_t radius);\r\nvoid XMC2GO_LCD_DrawString(uint8_t x, uint8_t y,char *ptr, UB_Font *font);\r\nvoid XMC2GO_LCD_ClearCollision(void);\r\nuint8_t XMC2GO_LCD_GetCollision(void);\r\nuint8_t XMC2GO_DIn_Read(uint8_t din_name);\r\nvoid XMC2GO_DOut_Lo(uint8_t dout_name);\r\nvoid XMC2GO_DOut_Hi(uint8_t dout_name);\r\nvoid XMC2GO_DOut_Toggle(uint8_t dout_name);\r\nuint16_t XMC2GO_Adc_Read(uint8_t adc_nr);\r\n<\/pre>\n<p>Nat\u00fcrlich m\u00fcssen nicht alle Funktionen benutzt werden. Wer z.B. gar kein LCD anschlie\u00dfen will, kann alle Befehle die das LCD betreffen aus dem Quellcode l\u00f6schen.<\/p>\n<h4 id=\"4._Interpreter_starten\">4. Interpreter starten<\/h4>\n<p>Zum Schluss muss der Interpreter gestartet werden, dazu sind eigentlich nur 5 Zeilen Code notwendig\u00a0:<\/p>\n<pre lang=\"c\" line=\"0\">\/\/ init vom Basic-Programm (und start vom Pre-Compiler)\r\nubasic_init(ram_buffer);\r\n\r\nif(!ubasic_failed()) {\r\n  \/\/ abarbeiten vom Basic-Programm\r\n  do {\r\n    ubasic_run();\r\n  } while(!ubasic_finished()); \r\n}\r\n<\/pre>\n<p>F\u00fcr den Fall eines Endlosprogrammes z.B. (&#8222;10 GOTO 10&#8220;) sollte man noch eine M\u00f6glichkeit finden die DO-WHILE zu beenden.<\/p>\n<h3 id=\"Einschr.C3.A4nkungen\">Einschr\u00e4nkungen<\/h3>\n<p>Nat\u00fcrlich gibt es bei einer so einfachen Umsetzung eines Basic-Interpreters einige Einschr\u00e4nkungen\u00a0:<\/p>\n<ul>\n<li>Wegen dem Pre-Parser muss das Basic-Programm im RAM liegen<\/li>\n<li>Nur 26 Variabeln nutzbar (a&#8230;z)<\/li>\n<li>Keine &#8222;Float&#8220; Unterst\u00fctzung<\/li>\n<li>Systembedingt keine sehr hohe Abarbeitungsgeschwindigkeit<\/li>\n<\/ul>\n<h2 id=\"Nachbau\">Nachbau<\/h2>\n<p>Mit Hilfe vom Schaltplan sollte ein Nachbau eigentlich keine Probleme machen, so viele Bauteile sind es ja nicht.<\/p>\n<p>Hier ein paar Bilder von meinem Aufbau\u00a0:<\/p>\n<h3 id=\"Gr.C3.B6.C3.9Fe\">Gr\u00f6\u00dfe<\/h3>\n<p>Die Platine hat die Abmessungen\u00a0: 42mm x 70mm.<\/p>\n<h3 id=\"Platzierung\">Platzierung<\/h3>\n<p>Die obere H\u00e4lfte nimmt das Display ein. Dadurch das es gesockelt ist, bleibt unter dem Display genug Platz f\u00fcr das XMC-2Go und der Batterie bzw dem Batteriehalter.<\/p>\n<p>Auf der unteren H\u00e4lfte sind die 6 Buttons verteilt. Rechts habe ich (liegend) die zwei Jumper f\u00fcr die Hintergrundbeleuchtung und die Batterie angebracht.<\/p>\n<p>Die Kondensatoren und die Pins f\u00fcr die 3 nicht ben\u00f6tigten GPIOs (2xOUT, 1xADC) habe ich der einfachheit halber gar nicht best\u00fcckt.<\/p>\n<div class=\"center\"><a class=\"image\" href=\"http:\/\/mikrocontroller.bplaced.net\/wordpress\/wp-content\/uploads\/2017\/12\/UPlay_Aufbau.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"thumbimage\" src=\"http:\/\/mikrocontroller.bplaced.net\/wordpress\/wp-content\/uploads\/2017\/12\/300px-UPlay_Aufbau.jpg\" alt=\"\" width=\"300\" height=\"501\" \/><\/a><br \/>\nPlatzierung der Bauteile<\/div>\n<h3 id=\"XMC-2Go\">XMC-2Go<\/h3>\n<p>Die freie H\u00f6he unter dem Display ist begrenzt. Man kann das XMC-2Go entweder direkt auf die Platine l\u00f6ten oder (wie ich) die Leisten von IC-Sockeln benutzen um das Board trennbar zu halten.<\/p>\n<p>Da ich die Sockel vor dem Aufbau vom\u00a0<b>&#8222;uPlay&#8220;<\/b>\u00a0schon in das XMC-2Go gel\u00f6tet hatte und ich die nicht mehr rausl\u00f6ten wollte, hab ich in meiner Version das ganze &#8222;\u00fcber Kopf&#8220; montiert. Das sieht zwar etwas komisch aus aber funktioniert genauso.<\/p>\n<div class=\"center\"><a class=\"image\" href=\"http:\/\/mikrocontroller.bplaced.net\/wordpress\/wp-content\/uploads\/2017\/12\/Xmc2go.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"thumbimage\" src=\"http:\/\/mikrocontroller.bplaced.net\/wordpress\/wp-content\/uploads\/2017\/12\/300px-Xmc2go.jpg\" alt=\"\" width=\"300\" height=\"180\" \/><\/a><br \/>\nXMC 2Go<\/div>\n<div class=\"center\"><a class=\"image\" href=\"http:\/\/mikrocontroller.bplaced.net\/wordpress\/wp-content\/uploads\/2017\/12\/Xmc2go_montiert.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"thumbimage\" src=\"http:\/\/mikrocontroller.bplaced.net\/wordpress\/wp-content\/uploads\/2017\/12\/300px-Xmc2go_montiert.jpg\" alt=\"\" width=\"300\" height=\"501\" \/><\/a><br \/>\nuPlay mit XMC 2Go<\/div>\n<h3 id=\"Display_3\">Display<\/h3>\n<p>Das Display verdeckt, nach dem es aufgesteckt ist, das XMC-2Go und die Batterie.<\/p>\n<div class=\"center\"><a class=\"image\" href=\"http:\/\/mikrocontroller.bplaced.net\/wordpress\/wp-content\/uploads\/2017\/12\/UPlay_komplett.jpg\"><img loading=\"lazy\" decoding=\"async\" class=\"thumbimage\" src=\"http:\/\/mikrocontroller.bplaced.net\/wordpress\/wp-content\/uploads\/2017\/12\/300px-UPlay_komplett.jpg\" alt=\"\" width=\"300\" height=\"501\" \/><\/a><br \/>\nDas fertige uPlay<\/div>\n<h3 id=\"Funktionstest\">Funktionstest<\/h3>\n<p>Hier ein Basic-Programm, das die Funktion aller 5 Buttons testet.<\/p>\n<pre lang=\"gwbasic\" line=\"0\">10 REM =================\r\n15 REM uPlay Button-Test\r\n20 REM =================\r\n30 CLS\r\n35 INVERSE 1\r\n40 LCD 6,0, \"   uPlay   \"\r\n45 LCD 6,10,\"Button-Test\"\r\n50 INVERSE 0\r\n100 IN a=0\r\n110 IF a=0 LCD 15,30,\"U\" ELSE LCD 15,30,\"-\"\r\n120 IN a=1\r\n130 IF a=0 LCD 25,30,\"D\" ELSE LCD 25,30,\"-\"\r\n140 IN a=2\r\n150 IF a=0 LCD 35,30,\"L\" ELSE LCD 35,30,\"-\"\r\n160 IN a=3\r\n170 IF a=0 LCD 45,30,\"R\" ELSE LCD 45,30,\"-\"\r\n180 IN a=4\r\n190 IF a=0 LCD 55,30,\"E\" ELSE LCD 55,30,\"-\"\r\n200 GOTO 100\r\n210 END\r\n<\/pre>\n<h3 id=\"SNAKE\">SNAKE<\/h3>\n<p>Hier das Basic-Programm zum bekannten SNAKE Spiel.<\/p>\n<pre lang=\"gwbasic\" line=\"0\">10 REM == SNAKE ==\r\n20 REM ==  V : 1.0  UB ==\r\n30 REM ==============\r\n41 REM  Info :\r\n42 REM  s = speed\r\n43 REM  x,y = Player position\r\n44 REM  r = Player direction\r\n45 REM  a,b = Computer position\r\n46 REM  c = computer direction\r\n47 REM  l = distance of wall check\r\n48 REM  i = local variable\r\n49 REM ==============\r\n50 s=50\r\n99 REM ==============\r\n100 x=10\r\n110 y=24\r\n120 r=2\r\n130 a=74\r\n140 b=24\r\n150 c=4\r\n160 l=5\r\n197 REM ==============\r\n198 REM startscreen\r\n199 REM ==============\r\n200 CLS\r\n210 RECT 0,0,83,47\r\n215 LCD 10,10,\"-SNAKE-\"\r\n220 LCD 10,20,\"SPEED=\"\r\n230 LCD 50,20,s\r\n240 PAUSE 1000\r\n245 CLS\r\n250 RECT 0,0,83,47\r\n497 REM ==============\r\n498 REM game\r\n499 REM ==============\r\n500 GOSUB 1000\r\n510 PAUSE s\r\n520 GOSUB 2000\r\n530 GOSUB 3000\r\n540 GOSUB 5000\r\n550 GOTO 500\r\n997 REM ==============\r\n998 REM zeichnen\r\n999 REM ==============\r\n1000 CLRCOLL\r\n1010 SETPX x,y\r\n1020 GETCOLL i\r\n1030 IF i=1 GOTO 4000\r\n1040 SETPX a,b\r\n1050 GETCOLL i\r\n1060 IF i=1 GOTO 6000\r\n1070 RETURN\r\n1997 REM ==============\r\n1998 REM bewegen\r\n1999 REM ==============\r\n2000 IF r=2 x=x+1\r\n2010 IF r=4 x=x-1\r\n2020 IF r=1 y=y-1\r\n2030 IF r=3 y=y+1\r\n2040 IF c=2 a=a+1\r\n2050 IF c=4 a=a-1\r\n2060 IF c=1 b=b-1\r\n2070 IF c=3 b=b+1\r\n2080 RETURN\r\n2997 REM ==============\r\n2998 REM tastatur\r\n2999 REM ==============\r\n3000 IN i=1\r\n3010 IF i=0 GOTO 3100\r\n3020 IN i=0\r\n3030 IF i=0 GOTO 3200\r\n3040 IN i=3\r\n3050 IF i=0 GOTO 3300\r\n3060 IN i=2\r\n3070 IF i=0 GOTO 3400\r\n3090 RETURN\r\n3100 IF r=1 RETURN ELSE r=3\r\n3110 RETURN\r\n3200 IF r=3 RETURN ELSE r=1\r\n3210 RETURN\r\n3300 IF r=4 RETURN ELSE r=2\r\n3310 RETURN\r\n3400 IF r=2 RETURN ELSE r=4\r\n3410 RETURN\r\n3997 REM ==============\r\n3998 REM verloren\r\n3999 REM ==============\r\n4000 LCD 0,0,\"LOOSE\"\r\n4030 PAUSE 2000\r\n4040 END\r\n4997 REM ==============\r\n4998 REM computer move\r\n4999 REM ==============\r\n5000 IF c=4 GOTO 5100\r\n5010 IF c=2 GOTO 5200\r\n5020 IF c=1 GOTO 5300\r\n5030 IF c=3 GOTO 5400\r\n5090 RETURN\r\n5100 GETPX i=a-l,b\r\n5110 IF i=0 RETURN\r\n5115 GETTIC i\r\n5120 i=i&amp;1\r\n5125 IF i=0 c=1 ELSE c=3\r\n5130 RETURN\r\n5200 GETPX i=a+l,b\r\n5210 IF i=0 RETURN\r\n5215 GETTIC i\r\n5220 i=i&amp;1\r\n5225 IF i=0 c=3 ELSE c=1\r\n5230 RETURN\r\n5300 GETPX i=a,b-l\r\n5310 IF i=0 RETURN\r\n5315 GETTIC i\r\n5320 i=i&amp;1\r\n5325 IF i=0 c=2 ELSE c=4\r\n5330 RETURN\r\n5400 GETPX i=a,b+l\r\n5410 IF i=0 RETURN\r\n5415 GETTIC i\r\n5220 i=i&amp;1\r\n5425 IF i=0 c=4 ELSE c=2\r\n5430 RETURN\r\n5997 REM ==============\r\n5998 REM gewonnen\r\n5999 REM ==============\r\n6000 LCD 0,0,\"WIN\"\r\n6030 PAUSE 2000\r\n6040 IF s&gt;5 s=s-5\r\n6050 GOTO 100\r\n<\/pre>\n<h2 id=\"Ausblick\">Ausblick<\/h2>\n<p>Weil mir das ganze Projekt so viel Spa\u00df gemacht hat, und es nicht sehr viel mehr Aufwand ist, habe ich das ganze noch auf die <strong>STM32F4, STM429<\/strong> und <strong>STM32F7<\/strong> CPU portiert:<\/p>\n<ul>\n<li><a href=\"http:\/\/mikrocontroller.bplaced.net\/wordpress\/?page_id=535\">95-uBasic-Library<\/a> (STM32F4)<\/li>\n<li><a href=\"http:\/\/mikrocontroller.bplaced.net\/wordpress\/?page_id=2001\">28-uBasic-Library<\/a> (STM32F429)<\/li>\n<li><a href=\"http:\/\/mikrocontroller.bplaced.net\/wordpress\/?page_id=1410\">12-uBasic-Library<\/a> (STM32F746)<\/li>\n<\/ul>\n<h2 id=\"Anmerkungen\">Anmerkungen<\/h2>\n<p>Wie immer bei &#8222;Bastelprojekten&#8220; k\u00f6nnen Fehler in der Hardware und Software nicht ausgeschlossen werden. Ich habe zwar viele Testprogramme geschrieben um das uBasic zu \u00fcberpr\u00fcfen aber es sind mit Sicherheit noch BUGs vorhanden.<\/p>\n<p>Wer Fehler findet (egal welcher Art) oder wem Verbesserungen einfallen kann mir ja eine EMail schreiben (oder per PN eine Nachricht schicken)<\/p>\n<p>Ich w\u00fcrde mich auch \u00fcber Feedback freuen, wenn jemand das\u00a0<b>&#8222;uPlay&#8220;<\/b>\u00a0erfolgreich nachgebaut und ein eigenes Basic-Programm damit realisiert hat.<\/p>\n<p>Gru\u00df und viel Spa\u00df mit dem Projekt.<\/p>\n<p>-Uwe-<\/p>\n<h2 id=\"Downloads\">Downloads<\/h2>\n<ul>\n<li>Schaltplan\u00a0<a title=\"Datei:UPlay v100.pdf\" href=\"http:\/\/mikrocontroller.bplaced.net\/wordpress\/wp-content\/uploads\/2017\/12\/UPlay_v100.pdf\">Datei:UPlay v100.pdf<\/a><\/li>\n<li>Projektfiles\u00a0<a title=\"Datei:Xmc2go uPlay v100.zip\" href=\"http:\/\/mikrocontroller.bplaced.net\/wordpress\/wp-content\/uploads\/2017\/12\/Xmc2go_uPlay_v100.zip\">Datei:Xmc2go uPlay v100.zip<\/a><\/li>\n<\/ul>\n<h2>Web Ressourcen\/Einzelnachweise<\/h2>\n<ol>\n<li><a href=\"http:\/\/www.infineon.com\/dgdl\/Board_Users_Manual_XMC_2Go_Kit_with_XMC1100_R1.0.pdf?folderId=db3a30433580b3710135a47f3eb76c98&amp;fileId=db3a3043444ee5dc014453d6c75078c6\" target=\"_blank\" rel=\"noopener\">http:\/\/www.infineon.com\/dgdl\/Board_Users_Manual_XMC_2Go_Kit_with_XMC1100_R1.0.pdf?folderId=db3a30433580b3710135a47f3eb76c98&amp;fileId=db3a3043444ee5dc014453d6c75078c6<\/a><\/li>\n<li><a href=\"http:\/\/www.infineon.com\/dgdl\/xmc1100_ds_v1.2_2013_12.pdf?folderId=db3a30433580b3710135a47f3eb76c98&amp;fileId=db3a30433d1d0bbe013d256b60160b7f\" target=\"_blank\" rel=\"noopener\">http:\/\/www.infineon.com\/dgdl\/xmc1100_ds_v1.2_2013_12.pdf?folderId=db3a30433580b3710135a47f3eb76c98&amp;fileId=db3a30433d1d0bbe013d256b60160b7f<\/a><\/li>\n<li><a href=\"http:\/\/www.infineon.com\/dgdl\/xmc1100_rm_v1+0_2013_03.pdf?folderId=db3a30433580b3710135a47f3eb76c98&amp;fileId=db3a30433cfb5caa013d1600856033eb\" target=\"_blank\" rel=\"noopener\">http:\/\/www.infineon.com\/dgdl\/xmc1100_rm_v1+0_2013_03.pdf?folderId=db3a30433580b3710135a47f3eb76c98&amp;fileId=db3a30433cfb5caa013d1600856033eb<\/a><\/li>\n<li><a href=\"https:\/\/www.sparkfun.com\/datasheets\/LCD\/Monochrome\/Nokia5110.pdf\" target=\"_blank\" rel=\"noopener\">https:\/\/www.sparkfun.com\/datasheets\/LCD\/Monochrome\/Nokia5110.pdf<\/a><\/li>\n<li><a href=\"https:\/\/www.sparkfun.com\/products\/10168\" target=\"_blank\" rel=\"noopener\">https:\/\/www.sparkfun.com\/products\/10168<\/a><\/li>\n<li><a href=\"http:\/\/www2.keil.com\/infineon\/mdk\/\" target=\"_blank\" rel=\"noopener\">http:\/\/www2.keil.com\/infineon\/mdk\/<\/a><\/li>\n<li><a href=\"http:\/\/mikrocontroller.bplaced.net\/wordpress\/?page_id=580\">http:\/\/mikrocontroller.bplaced.net\/wordpress\/?page_id=580<\/a><\/li>\n<li><a href=\"http:\/\/dunkels.com\/adam\/ubasic\/\" target=\"_blank\" rel=\"noopener\">http:\/\/dunkels.com\/adam\/ubasic\/<\/a><\/li>\n<li><a href=\"http:\/\/www.mikrocontroller.net\/svnbrowser\/avr-basic\/\" target=\"_blank\" rel=\"noopener\">http:\/\/www.mikrocontroller.net\/svnbrowser\/avr-basic\/<\/a><\/li>\n<\/ol>\n<hr \/>\n<p>Hinweis: Dieses Projekt habe ich als Artikel bei\u00a0Mikrocontroller.net ver\u00f6ffentlicht:<br \/>\n<a href=\"https:\/\/www.mikrocontroller.net\/articles\/UPlay_Basic_Interpreter_per_XMC2Go\" target=\"_blank\" rel=\"noopener\">UPlay Basic Interpreter per XMC2Go<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Laut Wikipedia gibt es die Programmiersprache &#8222;BASIC&#8220; jetzt \u00fcber 50 Jahre. Dem einfachen Syntaxaufbau mag es geschuldet sein, dass auch heute noch neue Projekte damit realisiert werden. Auch ich habe mit Basic ein paar Jahre programmiert und obwohl h\u00f6here Programmiersprachen &hellip; <a href=\"https:\/\/mikrocontroller.bplaced.net\/wordpress\/?page_id=766\">Weiterlesen <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"parent":591,"menu_order":16,"comment_status":"open","ping_status":"closed","template":"","meta":{"footnotes":""},"categories":[134,132],"tags":[207,258,167,156,108],"class_list":["post-766","page","type-page","status-publish","hentry","category-show-projekte","category-xmc2go","tag-nokia-5110","tag-pcd8544","tag-projekt","tag-ubasic","tag-xmc2go"],"_links":{"self":[{"href":"https:\/\/mikrocontroller.bplaced.net\/wordpress\/index.php?rest_route=\/wp\/v2\/pages\/766","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/mikrocontroller.bplaced.net\/wordpress\/index.php?rest_route=\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/mikrocontroller.bplaced.net\/wordpress\/index.php?rest_route=\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/mikrocontroller.bplaced.net\/wordpress\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/mikrocontroller.bplaced.net\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=766"}],"version-history":[{"count":23,"href":"https:\/\/mikrocontroller.bplaced.net\/wordpress\/index.php?rest_route=\/wp\/v2\/pages\/766\/revisions"}],"predecessor-version":[{"id":2050,"href":"https:\/\/mikrocontroller.bplaced.net\/wordpress\/index.php?rest_route=\/wp\/v2\/pages\/766\/revisions\/2050"}],"up":[{"embeddable":true,"href":"https:\/\/mikrocontroller.bplaced.net\/wordpress\/index.php?rest_route=\/wp\/v2\/pages\/591"}],"wp:attachment":[{"href":"https:\/\/mikrocontroller.bplaced.net\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=766"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mikrocontroller.bplaced.net\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=766"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mikrocontroller.bplaced.net\/wordpress\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=766"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}