nanoBasic

von Günther Zivny

Elektronik-Labor  Projekte  Mikrocontroller  TLScript  




Download: nanoBasic.zip

NanoBasic ist eine Erweiterung von PicoBasic bzw. TLScript. NanoBasic ist mit den Vorgängerversionen weitgehend kompatibel, bietet aber mehr Möglichkeiten. Es handelt sich bei der Version 0.0 um eine Testversion, die möglicherweise noch Fehler enthält.

Was ist anders?

-1. Auf der Bedienungsoberfläche befinden sich nun in der ersten Reihe mehr Variablen, die direkt gesetzt werden können. Aus „B“ ist „B0“ geworden. In den Verknüpfungen wurde „B“ durch „Bm“ ersetzt, also z. B. A = A + Bm statt A = A + B. Das sind nicht nur Namensänderungen. Hinter „B“ verbirgt sich ein Array mit den indizierten Variablen B0 … B15. Es gibt jetzt also genügend Speicherplätze. Der Index wird mit „m =“ gesetzt.

Beispiel: Füllen und Auslesen von B5 mit dem Wert 24:
A = 24
m = 5
Bm = A
A = Bm

Außer B0 kann Bm nicht direkt gesetzt werden, man muss also über A gehen.

-2. B+ heißt jetzt Bn+. Der Index von „Bn+“ ist nicht mehr „B“, sondern „n“. Dadurch wird der Index nicht überschrieben, wenn B anderweitig verwendet wird. Mit „n=“ wird der Startindex gesetzt. Mit jedem weiteren Aufruf wird n um 1 erhöht.

Beispiel:
n = 2
Bn+ = A        B2 = A
Bn+ = A        B3 = A

Hier unterscheidet sich nanoBasic von picoBasic. Wenn in einem bestehenden Programm „B=“ zur Angabe der Startposition von B+ verwendet wird, muss dies auf „n =“ geändert werden.

-3. Es können jetzt auch einzelne Pins angesprochen werden, nicht nur der ganze Port.

Beispiel: Pin D3 auf HIGH setzen, Pin D4 einlesen:

Pdir = 15 = 0000 1111    die hinteren 4 Bits auf Ausgang stellen
A = 1
out 3 = A    wenn A>0 ist, dann wird D3 auf HIGH gesetzt, wenn A = 0 ist, dann auf LOW
A = in 4        A erhält den Bit-Wert von D4, also 8, wenn der Pegel HIGH ist.

-4. Mit A shr x und A shl x wird um die angegebene Anzahl Stellen nach rechts bzw. links geschoben werden. Aus Kompatibilitätsgründen gibt es weithin A = A shr 1 und A = A shl 1.

-5. Mit On L-H Goto  kann der Programmablauf von außen beeinflusst werden. Ist der Pegel an D0=HIGH, wird mit der nächsten Zeile weitergemacht. Ist der Pegel D0=LOW, wird auf den Wechsel nach HIGH gewartet und nach Goto gesprungen. Mit On H-L Goto wird bei einem Pegel D0=LOW weitergemacht und bei einem Wechsel von HIGH nach LOW nach Goto gesprungen. Während auf den Pegelwechsel gewartet wird, ist der Arduino blockiert.

Beispiel für Pegelwechsel:

        <<<
0x09FE  Pdir = 254
0x01DE  A = 222
0x1905  Delay ms = 5
0x4200  Print A
0x1E06  On lo-hi Goto L1:
0x4900  End
              L1:
0x0101  A = 1
0x1905  Delay ms = 5
0x4200  Print A
0x1A02  Delay s = 2
0x1F0A  On hi-lo Goto L2:
              L2:
0x016F  A = 111
0x1905  Delay ms = 5
0x4200  Print A
0x4900  End

NanoBasic ist ohne das TestLab, aber mit dem Simulator.

Allgemeines Beispielprogramm in nanoBasic

Hier nun ein Beispielprogramm, das zeigt, wie man die zusätzlichen Möglichkeiten von nanoBasic nutzen kann. Zunächst die Aufgabe in Pseudosprache:

L1:
A = analogRead AD0
If A>50 OR A<200 then
digitalPin0 = HIGH
else
digitalPin0 = LOW
delay 1 s
Goto L1
END

In nanoBasic:
<<<
0x09FF  Pdir = 255
0x0232  B0 = 50
0x5001  m = 1
0x01C8  A = 200
0x5600  Bm = A
0x0B00  display A, Pos: 0    das Display starten
              L1:
0x1A01  Delay s = 1
0x3C00  A = AD0
0x0B05  display A, Pos: 5    den gemessenen Wert am Display anzeigen
0x4200  Print A            den gemessenen Wert drucken
0x5000  m = 0
0x230F  If A>Bm Goto L2:
0x0100  A = 0
0x5900  A = out  0        Pin D0 auf LOW setzen
0x2006  Goto L1:
              L2:
0x5001  m = 1
0x2414  If A<Bm Goto L3:
0x0100  A = 0
0x5900  A = out  0        Pin D0 auf LOW setzen
0x2006  Goto L1:
              L3:
0x0101  A = 1
0x5900  A = out  0        Pin D0 auf HIGH setzen
0x2006  Goto L1:
0x4900  End




Arduino-Firmware

NanoBasic erfordert eine entsprechende Erweiterung der Firmware im Arduino: nanoBasic0_3 .ino. Diese erweiterte Firmware hat darüber hinaus zusätzliche Features. Damit das Programm auch mit einem OLED läuft, muss aber die Treiberdatei schon jetzt installiert werden. Hierzu muss man in der Arduino-IDE in der Bibliotheksverwaltung U8g2 suchen und installieren. U8X8 ist darin enthalten und wird im Sketch mit #include <U8x8lib.h> eingebunden.



Ein weiteres Feature ist die Programmierung ohne PC. Es ist aber sehr wichtig, schon jetzt den Digitalpin 12 mit GND (Masse) zu verbinden, weil der Arduino sonst unkontrolliert in den Programmiermodus geht und blockiert ist! Außerdem muss Analoganschluss A3 während des Laufs auf +5 V gehalten werden.



Das Foto zeigt den Betrieb ohne TPS und ohne OLED. Der Draht oben linhs verbindet D12 mit GND, und A3 wird hier mit einem Widersatnd an +5V gezogen.

Impulslängenmessung:

Mit der Anweisung „gosub L247“ ( bzw. call L247) wird ein spezielles Unterprogramm aufgerufen, mit dem man die Länge positiver Impulse am Arduino Pin D2 (nanoBasic D0) messen kann. Das Ergebnis ist in A.
1. Arduino wartet, bis das Signal an Pin 2 LOW ist.
2. Dann wartet er, bis das Signal HIGH wird (Beginn des Pulses).
3. Jetzt startet die Messung.
4. Er misst, wie lange das Signal HIGH bleibt.
5. Sobald das Signal wieder LOW wird, ist die gemessene Zeit in Millisekunden in Speicher A.
6. Wenn innerhalb von TIMEOUT kein Puls erkannt wird, gibt die Funktion A = 0 zurück.
Der TIMEOUT ist in der Firmware fix auf 1,5 Sekunden gestellt.

Im Simulator wird das auch nachgebildet, selbstverständlich nicht in Echtzeit. Wenn das Programm an die Anweisung „Gosub L 247“ kommt, stoppt es. Wenn man die CheckBox D0 auf TRUE stellt, läuft in der unteren Zeile „A =“. Wenn man die CheckBox dann auf FALSE stellt, wird der nächste Programmschritt ausgeführt.

Ein Beispiel für die Verwendung der  Impulslängenmessung findet man unten in der Funkuhr-Anwendung.

Betrieb mit OLED



Mit der erweiterten Firmware kann ein OLED-Display SSD1306 128x64 mit TLScript / picoBasic / nanoBasic angesprochen werden. Der Bildschirm ist in 9 Felder aufgeteilt, in die Zahlen mit der Anweisung „Pulldown =“ geschrieben werden können. Pulldown = x bezeichnet das Feld. Der Button „Pulldown =“ wurde gewählt, weil dieser beim Arduino keine Funktion hat. Auf der nanoBasic-Bedienungsoberfläche heißt der Button „display A Pos x“. Nach dem Einschalten bleibt das Display zunächst dunkel, es muss erst aktiviert werden. Der Arduino kann auch ohne das Display betrieben werden. In jedem Fall muss aber der Pin D12 an GND gelegt werden, damit das Programm nicht in den Programmiermodus geht.


Anschluss des Displays an den Arduino. In Feld 5 wird „102“ angezeigt. Wichtig ist, dass D12 an GND gelegt wird, sonst geht das Programm unkontrolliert in den Programmiermodus.

Beispiel für ein OLED-Programm in nanoBasic:

(In picoBasic und TLScript heißt es pulldown = x statt display A,  aber der Code ist der gleiche).
Die am Anschluss A0 anliegende Spannung wird fortlaufend im Sekundentakt angezeigt (0…255 entspricht 0…5 V).

0x0B00  display A, Pos: 0    Rem: Display starten und löschen
              L1:
0x3C00  A = AD0
0x0B05  display A, Pos: 5
0x1A01  Delay s = 1
0x2001  Goto L1:
0x4900  End

Wenn man ein offenes Leitungsstück an A0 anschließt, wird der elektrische Störnebel in unserem Haus angezeigt und führt zu wechselnden Anzeigen. Die Zahlen werden normalerweise im Dezimalcode angezeigt. Man kann sie aber auch im Hexadezimalcode anzeigen lassen, wenn man an die Feldkennziffer eine „1“ anhängt, also z. B. „51“ statt „5“ . Kommazahlen erhält man, wenn man an die Feldkennziffer eine „2“ anhängt, also z. B. „52“ statt „5“. Es werden dann Spannungen von 0.00 bis 5.00 V angezeigt.

Anwendung: nanoBasic-Programm >>Funkuhr<<

Das folgende Programm ist ein Anwendungsbeispiel für nanoBasic. Es handelt sich um eine Funkuhr, die Stunden, Minuten und Sekunden auf dem OLED-Display anzeigt. Die genaue Uhrzeit wird von dem Langwellensender DCF77 ausgestrahlt (siehe Wikipedia, Stichwort DCF77). Der Sender sendet ein Dauersignal, das zu Beginn einer jeden Sekunde für 0,1 Sekunden oder 0,2 Sekunden abgesenkt wird. Eine Absenkung von 0,1 s entspricht einer logischen 0, eine Absenkung von 0,2 Sekunden entspricht einer logischen 1. Auf diese Weise werden in einer Minute 58 Bits übertragen, die im BCD-Code Datum und Uhrzeit codieren. Die 59. Sekundenabsenkung fehlt, sodass die nachfolgende Absenkung den Beginn einer neuen Minute markiert. Details siehe Wikipedia.



Zum Empfang des Signals verwendet man am besten ein fertiges Empfangsmodul. Das Modul liefert bereits saubere positive Impulse der entsprechenden Dauer. Die Dekodierung erfolgt durch das Programm. Kern des Programms ist die Impulslängen-Messfunktion, die mit Gosub L247 aufgerufen wird. Die gemessenen Zeiten werden in „0“ und „1“ klassifiziert. Diese Bitfolge wird in Bn+ fortlaufend gespeichert. Die time out-Zeit wurde in der Arduino-Firmware auf 1,5 Sekunden gestellt sodass nach dieser Zeit zur Dekodierung gesprungen wird (also wenn der Sekundenimpuls länger als 1,5 Sekunden ausbleibt). Das Signal kann zeitweise gestört sein, sodass es zu Falschanzeigen kommt.

Der Empfänger wird bei mir über Pin D7 mit „+ 5 V“ versorgt. Nach dem Anlegen der Betriebsspannung braucht der Empfänger etwa 20 Sekunden, bis er sich auf das Signal abgestimmt hat. Das Programm nutzt in seiner Länge fast den gesamten Speicherplatz von 128 Zeilen aus. Die im Prinzip mögliche Datumsanzeige hätte keinen Platz mehr. Wenn man hinter Gosub L247 „Print A“ einfügt, werden die gemessenen Zeiten auf dem Bildschirm angezeigt. Sie liegen nicht exakt bei 100 ms bzw. 200 ms.

Wenn man das Programm im EEPROM speichern möchte, zuerst STOP drücken. Ebenso vor RUN immer STOP drücken.


Programm Funkuhr:

0x09FE  Pdir = 254
0x0880  Pout = 128
0x0B00  display A, Pos: 0
0x5800  n = 0
0x5003  m = 3
0x018C  A = 140
0x5600  Bm = A
              L1:
              Rem Sekunden
0x5001  m = 1
0x5500  A = Bm
0x2800  A = A + 1
0x5600  Bm = A
0x0B06  display A, Pos: 6
0x21F7  Gosub L247:
0x0200  B0 = 0
0x5000  m = 0
0x2218  If A=Bm Goto L2:
0x5003  m = 3
0x2415  If A<Bm Goto L3:
0x0101  A = 1
0x3B00  [Bn+] = A
0x2007  Goto L1:
              L3:
0x0100  A = 0
0x3B00  [Bn+] = A
0x2007  Goto L1:
              Rem Min-Einer
              L2:
0x5815  n = 21
0x5000  m = 0
0x3A00  A = [B+]
0x5600  Bm = A
0x3A00  A = [B+]
0x3100  A = A Shl 1
0x2A00  A = A + Bm
0x5600  Bm = A
0x3A00  A = [B+]
0x5B02  A = A shl  2
0x2A00  A = A + Bm
0x5600  Bm = A
0x3A00  A = [B+]
0x5B03  A = A shl  3
0x2A00  A = A + Bm
0x5600  Bm = A
              Rem Min-Zehner
0x5001  m = 1
0x5819  n = 25
0x3A00  A = [Bn+]
0x5600  Bm = A
0x3A00  A = [Bn+]
0x3100  A = A Shl 1
0x2A00  A = A + Bm
0x5600  Bm = A
0x3A00  A = [Bn+]
0x5B02  A = A shl  2
0x2A00  A = A + Bm
0x5600  Bm = A
0x5002  m = 2
0x010A  A = 10
0x5600  Bm = A
0x5001  m = 1
0x5500  A = Bm
0x5002  m = 2
0x2C00  A = A * Bm
0x5000  m = 0
0x2A00  A = A + Bm
0x0B05  display A, Pos: 5
         Rem Std-Einer
0x581D  n = 29
0x5000  m = 0
0x3A00  A = [B+]
0x5600  Bm = A
0x3A00  A = [B+]
0x3100  A = A Shl 1
0x2A00  A = A + Bm
0x5600  Bm = A
0x3A00  A = [B+]
0x5B02  A = A shl  2
0x2A00  A = A + Bm
0x5600  Bm = A
0x3A00  A = [B+]
0x5B03  A = A shl  3
0x2A00  A = A + Bm
0x5600  Bm = A
              Rem Std-Zehner
0x5001  m = 1
0x5821  n = 33
0x3A00  A = [Bn+]
0x5600  Bm = A
0x3A00  A = [Bn+]
0x3100  A = A Shl 1
0x2A00  A = A + Bm
0x5600  Bm = A
0x5002  m = 2
0x010A  A = 10
0x5600  Bm = A
0x5001  m = 1
0x5500  A = Bm
0x5002  m = 2
0x2C00  A = A * Bm
0x5000  m = 0
0x2A00  A = A + Bm
0x0B04  display A, Pos: 4
0x5800  n = 0
0x0100  A = 0
0x5001  m = 1
0x5600  Bm = A
0x2007  Goto L1:
0x4900  End



Programmieren ohne PC

Wer dieses Feature nicht nutzen möchte, muss den Digitalanschluss D12 an GND legen, wie im Schaltplan oben gezeigt, damit das Programm nicht ungewollt in den Programmiermodus geht. Auch wenn die Programmierung abgeschlossen ist, empfiehlt es sich, D12 an GND zu legen, also den 100k-Widerstand zu überbrücken. Die Software sortiert zwar Spikes normalerweise aus, aber das benötigt Zeit und stört den Programmablauf.

Damit man Daten eingeben kann, ist etwas Peripherie nötig. Schaltplan:


 
Der Code von TLScript: Zur Vorbereitung muss man das Script von Hand in den Programmcode umschlüsseln. Der Programmcode ist eine vierstellige Hexadezimalzahl. Die vorderen zwei Ziffern codieren den Befehl, die hinteren beiden den Wert.
Beispiel:    09 FF        Pdir = 255
Manche Befehle haben keinen Wert, dann sind die beiden hinteren Ziffern 00.
Beispiel:    28 00        A = A + 1

Der Programmcode kann hier heruntergeladen werden: Zettel-IDE.pdf


Programmieren:
Die Eingabe des Codes erfolgt über analoge Spannungen, die von einer Widerstandskette abgenommen werden. Fehlerquellen sind hier schlechte Kontaktgabe oder zu kurzes Antippen der Kontaktpunkte. Man verwendet am besten eine Tastspitze und drückt diese solange auf den Kontakt, bis am Display der gewünschte Wert angezeigt wird, was etwas verzögert geschieht. Wenn es nicht geklappt hat, kann man die Eingabe wiederholen. Erst wenn man den Kontakt „S“ mit der Tastspitze berührt, wird das, was angezeigt wird, übernommen. Zum Start der Programmierung berührt man den Kontakt „S“ mit der Tastspitze. Das Display startet mit einer kurzen Verzögerung und zeigt die erste Programmzeile an, also Adresse 00. Bei der nächsten Berührung von „S“ wird zusätzlich COM (Befehl) angezeigt und bei der nächsten Berührung DAT (Wert), dann folgt die nächste Adresse usw. Die Zahl, neben der der Text neu erscheint, kann geändert werden, indem man die entsprechenden Kontaktpunkte berührt. Bestätigung jeweils mit „S“:

 

Verlassen des Programmiermodus:
Man drückt solange auf „S“, bis „main“ angezeigt wird. Das dauert einige Sekunden. Das Programm befindet sich dann in der main-Schleife und läuft ab. Die maximale Anzahl von Zeilen ist 128. Wird eine Adresse über 127 erreicht, wird „adr overflow“ angezeigt. In diesem Fall erfolgt am besten ein Neustart.

 
Vorschlag für ein Eingabegerät. Die Widerstände sind auf der Rückseite verlötet.

Dauerhaftes Speichern des Programms:
Das Programm ist zunächst nur im flüchtigen Speicher abgelegt und kann getestet werden. Um es dauerhaft im EEPROM zu speichern, während des Programmlaufs, also wenn „main“ angezeigt wird, die „0“ der Widerstandskette berühren. Am Display wird „stored“ angezeigt.
Das Programm ermittelt während des Laufs die letzte Programmzeile. Gespeichert werden also die Zeilen 0 bis max. Damit das Programm vollständig gespeichert wird, muss man sicherstellen, dass die letzte Zeile auch tatsächlich erreicht wird. Danach kann man den Arduino ausschalten. Beim Wiedereinschalten startet das Programm automatisch.

Zusätzliche Möglichkeiten:
Neben den beschriebenen Grundfunktionen gibt es zusätzliche Möglichkeiten.

Zeile Anspringen:
Wenn ADR angezeigt wird, gibt man die Zeilennummer an, zu der gesprungen werden soll.

Zeile löschen:
Die angezeigte Adresse auf „DD“ (wie delete) ändern. Da Adressen im Zehnersystem angezeigt werden, wird 1313 angezeigt. Dann „S“ berühren.
Die Zeile wird nicht gelöscht, sondern durch den Code 4A 00 Nop (nichts machen) ersetzt, das Programm muss also nicht neu durchnummeriert werden.

Zeile einfügen:
Man scrollt bis zu der Zeile, vor der eine Zeile eingefügt werden soll und gibt als Adresse „EE“ (wie Einfügen) an, es wird 1414 angezeigt. Dann kann man COM und DAT wie gewohnt eingeben Nach Bestätigung mit „S“ ist die Zeile eingefügt und die Sprungbefehle sind korrigiert. Im Script muss man jetzt die Zeilennummern korrigieren. Wenn der gewünschte Einfügeort nicht durch Scrollen, sondern Springen erreicht wird, muss man auf eine Zeile vorher springen und dann zur nächsten Zeile scrollen. Wenn beispielsweise zwischen Zeile 3 und Zeile 4 eine Zeile eingefügt werden soll, auf Zeile 3 springen und auf Zeile 4 scrollen.



Elektronik-Labor  Projekte  Mikrocontroller  TLScript