\documentclass[11pt,a4paper]{article} % 2006-07-04 EW Adventures-1.tex % needs to be first for some reason \usepackage{epsfig} %\psfigurepath{./images} % language support \usepackage[german]{babel} %\usepackage[latin1]{inputenc} % can use Umlauts now ü instead of ü \usepackage{pslatex} % use native PostScript fonts \usepackage{url} % \url{} \path{} with correct "hyphenation" \usepackage{fancyvrb} % for code examples % \voffset-10mm % \pagestyle{empty} % \pagestyle{plain} % \pagestyle{headings} % \renewcommand{\baselinestretch}{1.08} \usepackage{xspace} \parindent=0pt %\newcommand{Forth}{\textsc{forth}\xspace} \begin{document} \title{Adventures in Forth} \author{Erich Wälde} \maketitle \begin{multicols}{2} Bevor ich vergesse, wie es am Anfang war, schreib ich mal ein bisschen auf, wie es mir ergangen ist, seit ich meine Nase in Forth gesteckt habe. Am Linuxtag 2006 in Wiesbaden hatte ich den Renesas r8c/13--Mikrokontroller in Forth--Aktion gesehen. Den Kontroller auf dem Elektor--Platinchen hatte ich noch zu Hause, und so hatte ich endlich eine sinnvolle Verwendung dafür. Allerdings habe ich das Entwicklungsboard (von Elektor, \ref{elektor}) und ein 16x2--LCDisplay dazugekauft. \section{Installation} Das Wiki von Bernd Paysan (\ref{wiki}) führte mich zu den nötigen Zutaten \begin{enumerate} \item \texttt{gforth} \item \texttt{libffcall} \item \texttt{m16c\_flasher} von Thomas Fischl \end{enumerate} Eine etwas ältere Version von gforth war auf meinem Rechner schon installiert: \begin{verbatim} $ dpkg -l gforth ii gforth 0.6.2-6 GNU Forth Language Environment \end{verbatim} % $ der Dollar ist nur um fontlock-mode zufriedenzustellen Die Installation der libffcall war zwar einfach, aber wie gforth beim Installieren davon Wind bekommt, das war nicht ganz offensichtlich, weil ich diese Dinge in meinem HOME--Verzeichnis installiert hatte. Mit ein paar zusätzlichen Umgebungsvariablen lässt sich das aber lösen ('\$' ist der shell prompt): \begin{verbatim} $ wget ftp://ftp.ilog.fr/pub/Users/haible/gnu/ ffcall-1.8.tar.gz $ tar xvf ffcall-1.8.tar.gz $ export CC=gcc-3.4 $ cd ffcall-1.8 $ ./configure --prefix=$HOME $ make $ make install $ cd .. \end{verbatim} \begin{verbatim} $ cvs -d :pserver:anonymous@c1.complang.tuwien. ac.at:/nfs/unsafe/cvs-repository/src-master co gforth $ export CFLAGS=-I$HOME/include $ export LDFLAGS=-L$HOME/lib $ cd gforth $ export GFORTH=/usr/bin/gforth $ export GFORTHPATH=$PWD:/usr/lib/gforth/0.6.2 $ ./BUILD-FROM-SCRATCH --prefix=$HOME $ ./build-ec r8c $ cd .. \end{verbatim} \begin{verbatim} $ wget http://www.fischl.de/thomas/elektronik/ r8c/m16c_r8c_flash.2005-11-20.tar.gz $ tar xzvf ~/Forth/m16c_r8c_flash.2005-11-20. tar.gz $ cd m16c_flash $ make clean $ make $ cd .. \end{verbatim} % $ \texttt{BUILD-FROM-SCRATCH} blieb bei mir irgendwann hängen, aber \texttt{gforth} wurde davor erzeugt, so dass \texttt{./build-ec r8c} erfolgreich läuft. Das frisch gebackene \texttt{rom-r8c.mot} muss jetzt auf den Kontroller. Dazu verbindet man den Kontroller entweder direkt mit der seriellen Schnittstelle (s. Elektor 01/2006) oder über das dazugehörige Entwicklungsboard. Eine Stromversorgung und das Ansteuern des MODE--Pins zum Programmieren gehört dazu, Details finden sich in den erwähnten Artikeln. Angenommen, die serielle Schnittstelle des Entwicklungsrechner wäre \texttt{/dev/ttyUSB0}, dann geht das Programmieren des Kontrollers so: \begin{verbatim} $ ./m16c_flash/flash /dev/ttyUSB0 R8C ./gforth/ rom-r8c.mot ff:ff:ff:ff:ff:ff:ff \end{verbatim} %$ über die gerade eben schon verwendete serielle Schnittstelle kann man sich jetzt mit dem Kontroller verbinden, z.B. mit minicom. Die Einstellungen sind dann \texttt{/dev/ttyUSB0}, 38400 baud, 8 Datenbits, kein Paritätsbit, 1 Stopbit (8N1). Wenn alles funktioniert, erhält man auf Drücken der Return--Taste \verb++ die Antwort "`\texttt{ok.}"' \begin{verbatim} minicom ... start message ... ok. \end{verbatim} %$ Siehe auch den Diskussionsthread unter \ref{thread_install} für Hinweise. % ---------------------------------------------------------------------- \section{Erste Versuche} Für die ersten Versuche (blinken mit den LEDs, etwas auf das Display schreiben) finden sich Beispiele im Wiki (\ref{wiki}). Über Forth selbst sind die Dokumentation von gforth sowie die Bücher ``Starting Forth'' und ``Thinking Forth'' (Leo Brodie) sehr gute Quellen. Zu beiden Büchern gibt es Webseiten (\ref{startingforth}, \ref{thinkingforth}). Auch der Wikipedia--Artikel zu Forth (\ref{wikipediaforth}) ist meiner Meinung nach recht gut. % ---------------------------------------------------------------------- \section{\texttt{rom} und \texttt{ram}} aus dem Wiki: \begin{quote} Das Forth \ldots legt selbstdefinierte Programme per Default im (sehr knappen) RAM ab. Umschalten zwischen RAM und ROM mit den Wörtern ram und rom. \end{quote} ROM ist das Flashrom des Kontrollers, es ist größer als das RAM. Daher kann man Forth--Programme ins ROM speichern: \begin{verbatim} rom ... hier kommt das programm hin ram savesystem \end{verbatim} \texttt{savesystem} speichert eine Kopie des RAM--Inhalts ins ROM. Wenn das Programm im ROM überschrieben werden soll, dann muss man das ROM erst mit dem Wort \texttt{empty} löschen. Wenn man das versäumt, oder wenn es nicht richtig funktioniert hat, dann erhält man beim nächsten Befehl etwas irreführende Fehlermeldungen, etwa so: \begin{verbatim} : foo <<< Undefined word \end{verbatim} %>>> \texttt{empty} und evtl. ein RESET hilft dann normalerweise. Den Erfolg kann man auch überprüfen mit dem Wort \texttt{dump}, welches den Speicher\-inhalt ausliest: \begin{verbatim} rom ... ein paar Befehle hier ram savesystem $2000 $800 dump ... empty $2000 $800 dump ... \end{verbatim} Nach dem \texttt{empty} stehen lauter \texttt{FF} im Speicher, vorher kann man mit etwas Phantasie das Programm wiederfinden. Das Dollarzeichen `\$' sagt Forth, dass die Zahl dahinter auf jeden Fall eine Hexadezimalzahl ist, egal welche Basis zur Eingabe gerade benutzt wird, z.B.\ \$10 = 16. Entsprechend sagt das Prozentzeichen `\%', dass die Zahl dahinter eine Binärzahl ist, z.B. \%10001010 = \$8a = 138. Auch für Dezimalzahlen gibt es ein Zeichen: `\&', welches in den Beispielen im Wiki benutzt wird. %---------------------------------------------------------------------- \section{Ein i2c--Device ansteuern} Als erstes Bastelprojekt, bei dem sich richtig was tut, wollte ich einen i2c--Baustein ansteuern, welcher 8 digitale IO--Pins besitzt (PCF8574). Der Bus benutzt 2 Drähte, SDA und SCL genannt. Die Details stehen im Datenblatt zum PCF8574 oder beispielsweise in dem Buch ``I2C Bus angewandt'' (\ref{i2cbus_angewandt}) Der R8C--Kontroller soll als ``i2c master'' funktionieren, d.h., nur er darf den Bus ungefragt belegen und er gibt bei der Datenübertragung den Takt vor. Als Erstes werden ein paar Konstanten definiert. Deren Namen sind aussagekräftiger als die blanken Werte. Sie machen das Programm besser lesbar. Pin 15 alias P1.0 des Kontrollers gehört zum ersten Bit von Port 1 und soll die SCL Leitung treiben: \begin{verbatim} 0 Constant PinSCL \end{verbatim} Pin 14 alias P1.1, also das zweite Bit von Port 1 soll die SDA Leitung treiben: \begin{verbatim} 1 Constant PinSDA \end{verbatim} Für den Port 1 gibt es schon ein Wort (\texttt{port1}), ansonsten hört der auch auf das Register mit der Adresse \$E1 \begin{verbatim} port1 Constant PortI2C \end{verbatim} Da ich nicht nur auf den Bus schreiben will, sondern auch davon lesen, muss ich gelegentlich das "`Data Direction Register"' von Port 1 beschreiben. Deshalb bekommt es ebenfalls einen Namen statt seiner Registeradresse (\$E3) \begin{verbatim} $E3 Constant PddrI2C \end{verbatim} %$ Die 7--Bit--Adresse des Portexpanders ist \%010\_0000 oder \$20 hexadezimal. Das Schreiben/Lesen--Bit--w wird hintendran gehängt: \%010\_0000\_w. Das ist \$20 um eins nach links verschoben + w, also \$40 + w. Zum Lesen vom Baustein wird diese Adresse um 1 erhöht (\$41). \begin{verbatim} $40 Constant i2c_addr_portexpander \end{verbatim} %$ Die einfachsten Funktionen (Worte) setzen je einen der beiden Pins auf 0 oder 1: \begin{verbatim} : sda0 PinSDA PortI2C bclr ; : sda1 PinSDA PortI2C bset ; : scl0 PinSCL PortI2C bclr ; : scl1 PinSCL PortI2C bset ; \end{verbatim} Diese Worte kann man jetzt schon ausprobieren. Da an diesen beiden Pins auf der Ergänzungsplatine schon LEDs angeschlossen sind, kann man sofort sehen, ob es funktioniert. Nach \texttt{scl0} geht die rechte der 4 LEDs aus, nach \texttt{sda0} die links daneben. Um ein Bit zu versenden, müssen wir das Datenbit setzen, ein bisschen warten, dann SCL auf 1 setzen, wieder ein bisschen warten und dann SCL zurück auf 0. Ich habe beschlossen, jeden Clock--Zyklus in 4 Teile zu zerlegen, Die kleinste Wartezeit nenne ich \texttt{tick} und sie soll eine Mikrosekunde betragen. Damit dauert ein Clock--Zyklus 4 Mikrosekunden, was lange genug sein sollte. \begin{verbatim} : tick 1 us ; : 2tick tick tick ; \end{verbatim} Man kann tick anfangs auch sehr viel länger wählen, z.B.\ \texttt{250 ms} (Millisekunden), dann kann man den Datenaustausch an den LEDs \textit{sehen}. Um ein Bit zu verschicken, erwarten wir das Bit (0 oder 1) auf dem Stack, IF nimmt es vom Stapel und inspiziert es. Ist es 1 (true), dann wird die Datenleitung ebenfalls auf 1 gesetzt, andernfalls wird die Datenleitung auf 0 gesetzt. \begin{verbatim} IF sda1 ELSE sda0 ENDIF \end{verbatim} Danach muss ich den Clock--Impuls erzeugen, und das vollständige Wort soll \verb+bit>i2c+ heißen: \begin{verbatim} \ sende 1 Bit per Clock-Zyklus : bit>i2c ( bit -- ) IF sda1 ELSE sda0 ENDIF tick scl1 2tick scl0 tick ; \end{verbatim} Um ein bestimmtes Bit aus einem gegebenen Byte zu verschicken, muss ich dieses Bit aus dem Byte extrahieren. Um das Bit Nr.\ i aus dem Byte x zu erhalten, muss ich das Byte um i Stellen nach rechts verschieben (\texttt{x i rshift}) und evtl. vorhandene höherwertige Bits löschen (\texttt{\$01 and}). \begin{verbatim} : getBit ( x i -- bit ) rshift $01 and ; \end{verbatim} %$ Damit kann ich jedes Bit aus dem Byte einzeln gewinnen. Das lässt sich schön überprüfen mit \begin{verbatim} %00001010 dup . 0 getBit . 10 0 ok %00001010 dup . 1 getBit . 10 1 ok %00001010 dup . 2 getBit . 10 0 ok %00001010 dup . 3 getBit . 10 1 ok %00001010 dup . 4 getBit . 10 0 ok \end{verbatim} Um ein ganzes Byte zu verschicken, muss ich eine Schleife schreiben, die 8 mal durchlaufen wird. \begin{verbatim} 8 0 DO ... LOOP \end{verbatim} Dabei ist 8 der Grenzwert, 0 der Startwert, und das Wort \texttt{I} legt den aktuellen Zählerstand auf den Stapel. \texttt{I} produziert nacheinander die Werte 0 bis 7: \begin{verbatim} : 8mal 8 0 DO I . LOOP ; ok 8mal 0 1 2 3 4 5 6 7 ok \end{verbatim} Allerdings muss das höchstwertige Bit zuerst verschickt werden. Ich muß also statt $I$ den Wert $8 - (I + 1)$ benutzen: \begin{verbatim} : 8mal 8 0 DO 8 I 1+ - . LOOP ; redefined 8mal ok 8mal 7 6 5 4 3 2 1 0 ok \end{verbatim} Damit hätte ich alles beisammen, um ein ganzes Byte mit dem höchstwertigen Bit zuerst zu versenden. Beachte, dass das zu versendende Byte immer erst dupliziert werden muss, weil es sonst nach dem ersten Schleifendurchgang verloren ist. Am Ende der Schleife muss man dann das übriggebliebene Byte mit \texttt{drop} vom Stapel nehmen. \begin{verbatim} \ sende 1 Byte (8 Bit) MSB zuerst : >i2c ( x -- ) 8 0 DO dup 8 I 1+ - getBit bit>i2c LOOP drop ; \end{verbatim} Wenn man statt \verb+bit>i2c+ das Bit lediglich ausgibt mit \texttt{.}, dann erhält man folgende Ausgaben: \begin{verbatim} 10 >i2c 0 0 0 0 1 0 1 0 ok 11 >i2c 0 0 0 0 1 0 1 1 ok 12 >i2c 0 0 0 0 1 1 0 0 ok 64 >i2c 0 1 0 0 0 0 0 0 ok \end{verbatim} Mit diesen Worten kann ich 1 Byte auf dem Bus verschicken. Soweit so gut. Davor brauchen wir noch eine Startbedingung, und am Ende eine Stopbedingung. \begin{verbatim} \ sende START, STOP : i2c_start ( -- ) tick sda0 2tick scl0 tick ; : i2c_stop ( -- ) tick scl1 2tick sda1 tick ; \end{verbatim} Jetzt fehlt lediglich noch eine Kleinigkeit, nämlich, nach dem Versenden der Adresse zu überprüfen, ob sich der adressierte Baustein auch angesprochen fühlt. Dies tut er kund, indem er beim 9.\ Clock--Impuls die Datenleitung auf low zieht. Ich muss also die Datenrichtung an SDA umkehren, einen Clock--Impuls erzeugen und die Leitung lesen, während SCL high ist: \textit{ (Bei manchen Kontrollern muss man vorher SDA auf 1 setzen, bei diesem anscheinend nicht.)} \begin{verbatim} \ setze Pin SDA als Eingang / Ausgang : sdaInput ( -- ) PinSDA PddrI2C bclr ; : sdaOutput ( -- ) PinSDA PddrI2C bset ; \ lies SDA : readSDA ( -- bit ) PinSDA PortI2C btst IF 1 ELSE 0 ENDIF ; \ lies ACK oder NACK vom Empfänger : ackportexpander ( x -- ) i2c_start \ START i2c_addr_portexander >i2c \ Adresse schreiben acki2c \ Datenbyte schreiben ackportexpander ok \end{verbatim} Jetzt sollten 4 von den 8 LEDs am PCF8574 leuchten. Wenn man genau hinschaut, dann stellt man fest, dass die LEDs der 4 höherwertigen Bits leuchten. Das ist richtig, weil die LEDs gegen +5V geschaltet sind, und ein Pin mit einer Null den Strom durch die LEDs einschaltet. Oft will man das aber anders sehen, dafür muss man die Bits des zu verschickenden Bytes invertieren. Dafür gibt es auch ein Forth--Wort: \begin{verbatim} 15 invert >portexpander ok \end{verbatim} Jetzt ist alles so, wie's sein soll. Um länger in den Genuss blinkender LEDs zu kommen, hilft eine Schleife, in der eine Variable (\texttt{N}) jede Sekunde um 1 erhöht und dann invertiert auf dem i2c--Portexpander ausgegeben wird. Die Schleife soll unterbrochen werden, wenn ich eine beliebige Taste drücke. Die Forth--Worte \texttt{Variable}, \texttt{!} (store), \texttt{@} (fetch), \texttt{BEGIN \dots{} UNTIL} (Schleife) und \texttt{key?} (ist eine Taste gedrückt worden?) kommen mir zu Hilfe: \begin{verbatim} Variable N 0 N ! : run 0 >portexpander 1000 ms BEGIN N @ dup invert >portexpander 1+ N ! 1000 ms key? UNTIL ; \end{verbatim} Nach der Eingabe von \texttt{run} sollten auf den LEDs alle Sekunde ein neuer Wert erscheinen! Das Programm beendet sich, wenn man eine Taste drückt. Natürlich kann man das alles von Hand eintippen, aber nach einem Reset ist erst mal alles verloren. Deshalb schreibe ich eine Datei \texttt{adv\_01.fs}, in der alle Anweisungen stehen, eingeklammert mit den Worten \texttt{rom} und \texttt{ram}. Die Datei kann ich im terminal--Programm mit \texttt{include} an den Kontroller übertragen und danach die darin definierten Worte benutzen: \begin{verbatim} $ gforth terminal.fs include adv_01.fs run \end{verbatim} %$ and watch the show! Das Programm zu diesem Teil befindet sich in der Datei \texttt{adv\_01.fs}. %---------------------------------------------------------------------- \section{Verbesserungen} Einen i2c--Baustein in etwa 60 kurzen Zeilen Code anzusprechen, das finde ich schon bemerkenswert --- auch wenn es bislang ganz ohne Fehlerbehandlung ist. \subsection{Adressierung} Der erste Schritt ist gemacht, ein i2c--Baustein lässt sich zum Schreiben ansprechen. Ein anderer Baustein lässt sich durch Auswechseln der Adresse ebenfalls addressieren. Allerdings würde ich dazu eine Kopie von \texttt{>portexpander} anlegen, in der nur die Adresse anders ist. Schön ist das nicht. Daher soll das Wort \texttt{>portexpander} so geändert werden, dass sich die Adresse auf dem Stapel befindet. \begin{verbatim} : send1byte>i2c ( x addr -- ) i2c_start \ START >i2c \ Adresse 'addr' senden acki2c \ DatenByte 'x' senden acki2c \end{verbatim} \subsection{Schreiben/Lesen} Bislang schreibe ich Daten an den i2c--Baustein. Um zu lesen, brauchen wir analog zu \verb+>i2c+ ein Wort \verb+i2c \ ADRESSE acki2c \ NACK _senden_ i2c_stop ; \ STOP \end{verbatim} Allerdings muss man fast immer nach der Adresse erst einmal ein Byte schreiben: Das kann ein \textit{Controlbyte} sein, oder die Adresse im Speicher des Bausteins, von der man die Daten will, oder die Kanalnummer bei einem AD--Wandler etc. Sogar bei dem simplen Portexpander muss ich erst mal eine \texttt{1} auf alle Pins schreiben und dann lesen, damit das Ergebnis zuverlässig ist. Die Folge ist dann eben Start, Adresse senden, ACK lesen, das Controlbyte senden, ACK lesen, danach wird eine repeated--start--Bedingung gesendet, dann ein oder mehrere Datenbytes gelesen und nach jedem gelesenen Byte ein ACK \textit{gesendet}. Nach dem letzten gelesenen Byte verschickt der i2c--Master ein NACK, also eine 1 statt einer 0. Damit wird dem adressierten Baustein mitgeteilt, dass keine weiteren Bytes gelesen werden. Und zum Abschluss wie immer eine Stopp--Bedingung. \begin{verbatim} \ Sende "repeated start" : i2c_rstart ( -- ) sda1 tick scl1 tick sda0 tick scl0 tick ; \end{verbatim} \subsection{Variable Anzahl von Bytes lesen/schreiben} Ein Lesevorgang auf dem i2c--Bus besteht also normalerweise aus dem Verschicken von mindestens einem Controlbyte an die Adresse, dem Lesen von einem oder mehreren Datenbytes, jeweils gefolgt von ACK oder NACK. Um das besser programmieren zu können, ändere ich die Worte \verb+>i2c+ und \verb+i2c ( x1 .. xN.msB N addr -- ) i2c_start \ START >i2c acki2c acki2c ack IF \ Schleife über N-1 Byte 0 DO \ Datenbyte = 0 (initialisieren) i2c \ DATA_BYTE lesen, ACK schicken LOOP \ Ende Schleife ENDIF i2c \ letztes Byte lesen, NACK schicken i2c_stop \ STOP ; \end{verbatim} Die Schleife geht hier über $n-1$ Byte, nicht $n$ Byte, weil nur $n-1$ ACK verschickt werden. Man hätte das auch anders lösen können, aber mir gefällt es so. Ich hätte auch das Versenden von ACK und NACK getrennt definieren können: \begin{verbatim} : ack>i2c ( -- ) 0 bit>i2c ; : nack>i2c ( -- ) 1 bit>i2c ; \end{verbatim} Aber da diese Stelle nur in \texttt{NBi2c 1 i2c_addr_portexpander NB 255 ok \end{verbatim} %$ Jetzt ist es nett und übersichtlich. Zwar muss ich die LEDs durch eine Schalterleiste auswechseln, sonst kommt immer das gleiche Ergebnis (255), aber das ist kein Programmierproblem. Das Programm zu diesem Teil befindet sich in der Datei \texttt{adv\_02.fs}. %---------------------------------------------------------------------- \section{Thermometer} In diesem Teil kommt ein Thermometer mit i2c--Schnittstelle an den i2c--Bus, welches vom R8C--Kontroller gelesen wird. Das Ergebnis wird auf dem LCDisplay ausgegeben. Etwa 4 Messungen pro Sekunde sollen es werden. Der Temperatursensor ist ein LM75, die Auflösung beträgt 0.5$^{\circ}$C, die Genauigkeit etwa $\pm 2^{\circ}$C. Der Baustein hat die 7--Bit--Adresse \$48, wenn alle Adressbits auf low sind, und \$4f, wenn alle Adressbits gesetzt sind. \verb,$4f << 1 == $9e,. \begin{verbatim} $9e Constant i2c_addr_lm75 \end{verbatim} %$ Der LM75 liefert das Ergebnis in 2 Bytes, das höherwertige Byte (xh) wird zuerst übertragen. Im niederwertigen Byte (xl) ist nur noch ein Bit gültig, nämlich das höchste. (Beim LM75\textbf{A} sind es die \textit{drei} höchsten Bits, was einer Auflösung von 0.125$^{\circ}$C entspricht) Um die Temperatur zu lesen, ist eine \$00 zu verschicken (pointer register, s.\ Datenblatt), das entspricht unserem Controlbyte. Mit den oben erarbeiteten Worten ist das Auslesen des LM75 ein Kinderspiel: \begin{verbatim} : get.T ( -- xh xl ) $00 \ ControlByte 1 i2c_addr_lm75 NB>i2c \ verschicken 2 i2c_addr_lm75 NB <2> 24 255 245 ok \end{verbatim} Das sind $24.5^{\circ}$C, soweit so schön. Um die Zahl mit Nachkommastelle auf das LCDisplay zu schreiben, muss man im Forth--Buch oder in der Dokumentation von gforth nachlesen. Hier das Ergebnis ohne große Erklärungen: \begin{verbatim} \ _immer_ das Vorzeichen anzeigen, '+' or '-' : sign! 0 < IF 45 ELSE 43 ENDIF hold ; \ formatiere T zur Ausgabe mit type or lcdtype : format.T ( T*10 -- ) dup >R \ Kopie fuer das Vorzeichen aufheben abs s>d \ Betrag, single in double umwandeln \ 1 Ziffer, "." Dezimalpunkt, 2 Ziffern, \ Vorzeichen \ Zahlen >= 1000 werden VORNE abgeschnitten! <# # 46 hold # # R> sign! #> \ == "%+5.1f" ; \end{verbatim} Ausprobieren mit \begin{verbatim} lcdpage get.T decode.T format.T lcdtype \end{verbatim} Das Thermometer soll ständig laufen, braucht also wieder eine Schleife. Eine Messung soll 4-mal pro Sekunde sein: \begin{verbatim} : thermometer BEGIN lcdpage get.T decode.T format.T lcdtype 250 ms key? UNTIL ; thermometer \end{verbatim} \begin{figure} \includegraphics[width=1\hsize]{2006-03/img_thermometer1} \caption{Thermometer--Aufbau} \end{figure} Auffällig ist, dass das LCDisplay recht unruhig {\em flimmert}. Das kommt durch die häufigen Aufrufe von \texttt{lcdpage}. Besser ist es, ein Wort \texttt{lcdpos} zu schreiben, welches den Cursor an eine bestimmte Stelle setzt. \begin{verbatim} : lcdpos ( row col -- ) swap $40 * + $80 + lcdctrl! &1 ms ; \end{verbatim} Damit kann man \texttt{thermometer} aufbessern: \begin{verbatim} : thermometer lcdpage BEGIN 0 5 lcdpos get.T decode.T format.T lcdtype 250 ms key? UNTIL ; thermometer \end{verbatim} Den Finger auf den LM75 \dots{} \includegraphics[width=1\hsize]{2006-03/img_thermometer2} \dots{} and watch the show! Das Programm zu diesem Teil befindet sich in der Datei \texttt{adv\_03.fs}. %---------------------------------------------------------------------- \section{Referenzen} \begin{enumerate} \item \label{elektor} Elektor--Hefte 12/2005, 01/2006, 02/2006 \url{http://www.elektor.de} \item \label{wiki} \href{http://www.forth-ev.de/wiki/doku.php/projects:r8c:r8c_forth}{\tt http://www.forth-ev.de/wiki/doku.php/pro jects:r8c:r8c\_forth} \item \label{thread_install} \href{http://groups.google.com/group/de.comp.lang.forth/browse_thread/thread/038d092aab9c558c/80aa79ab4b8624cd#80aa79ab4b8624cd}{\tt http://groups.google.com/group/de.comp.lang. forth/browse\_thread/thread/038d092aab9c558c/ 80aa79ab4b8624cd\#80aa79ab4b8624cd} (thread zur Installation) % \item \label{startingforth} \url{http://home.iae.nl/users/mhx/sf.html} Starting Forth Online Transkript \item \label{thinkingforth} \url{http://thinking-forth.sourceforge.net/} Thinking Forth Online \item \label{i2cbus_angewandt} I2C--Bus angewandt (Elektor--Verlag, ISBN \mbox{3928051717}) \item \label{wikipediaforth} \href{http://en.wikipedia.org/wiki/Forth_programming_language}{\tt http://en.wikipedia.org/wiki/Forth\_program ming\_language} \end{enumerate} \end{multicols} \section{Listings} \begin{quote} \begin{small} \listinginput[1]{1}{2006-03/SMBus.fs} \listinginput[1]{1}{2006-03/adv_01.fs} \listinginput[1]{1}{2006-03/adv_02.fs} \listinginput[1]{1}{2006-03/adv_03.fs} \end{small} \end{quote} \end{document}