Manche Anwendungen sind so komplex, dass die Entwicklung auf einem Microcontroller zu zeitaufwendig wird. Dann muss man oft wohl oder übel zu einem PC greifen, um rasch zu brauchbaren Ergebnissen zu gelangen. Doch wie bekommt man Echtzeit - Anwendungen auf einen PC, ohne auf den Komfort eines modernen Betriebssystems verzichten zu müssen? Diese Seite untersucht am Beispiel einer Schrittmotor - Steuerung, inwieweit RTLinux dafür geeignet ist, und ob es sich auch von 'Normalsterblichen' programmieren und einsetzen lässt. | ||||||||||||||||||
Warum RTLinux |
||||||||||||||||||
Nach einigen durchaus erfolgreichen Versuchen, meine
Fräsanlage mit einem Microcontroller zu steuern,
bleibt vor allem eines festzuhalten: es ist ohne weiteres
möglich, drei Schrittmotore mit einem uC synchron zu
steuern. Jedoch ist die Fehlersuche äusserst
schwierig, und man programmiert ewig daran, das
notwendige Drumherum aus Datenspeicher, manuelle und
automatische Steuerung und Synchronisation der
verschiedenen Controller zu realisieren.
Da man zur Datenspeicherung -- dafür ein Flash - ROM zu verwenden, ist auf Dauer unpraktisch -- ohnehin einen Rechner neben der Anlage braucht, kann dieser auch die komplette Schrittmotor - Steuerung übernehmen. Ganz so einfach ist das dann aber doch nicht: schließlich ist die Erzeugung von Schrittmotor - Takten eine 'harte' Echtzeitanwendung. Sind die generierten Takte nicht synchron, so ist an eine präzise Arbeit nicht mehr zu denken. Die Echtzeit - Fähigkeit hat übrigends nicht das geringste mit der Ausführungsgeschwindigkeit zu tun. Es geht keinesfalls um ein so schnell wie möglich, wie es die als "Realtime" bezeichneten Prioritäten diverser Multitasking - Betriebssysteme nahelegen. Vielmehr liegt das Ziel eines echtzeitfähigen Betriebssystems darin, eine Aufgabe genau rechtzeitig auszuführen, nicht früher und nicht später. Nicht echtzeitfähige Betriebssysteme können diese Rechtzeitigkeit nicht garantieren. |
Übliche kommerzielle Programme zur Steuerung von
Fräsanlagen verwenden DOS als Betriebssystem, das
zwar ebensowenig echtzeitfähig ist wie Linux oder
Windows, jedoch als Singletasking - Betriebssystem der
Anwendung die volle Kontrolle über die Maschine
gibt. Jedoch ist DOS reichlich angestaubt, und um darauf
eine Echtzeit - fähige Steuerung zu realisieren,
muss man tief in das Betriebssystem eingreifen und nahezu
alle benötigten Funktionen und Programme selbst
entwickeln.
An dieser Stelle kommt RTLinux in's Spiel: es ist eine Erweiterung für den Standard - Linuxkernel, die sich vollkommen transparent in's System integriert. Alle Linux - Anwendungen laufen weiterhin, ob es nun eine Oracle - Datenbank oder der Lieblings - Texteditor ist. Linux ist ein modernes Multitasking - Betriebssystem mit ausgezeichneten Netzwerkfähigkeiten und einer Unmenge an frei verfügbaren Entwicklungswerkzeugen und Programmbibliotheken. Inwieweit ist nun RTLinux in der Lage, zur Steuerung
von Schrittmotoren Verwendung zu finden? Und vor allem,
ist es auch von einem Nicht - Guru und Nicht -
Kernelhacker (wie mir ;-) sinnvoll
einzusetzen? Diesen Fragen will diese Seite auf den Grund
gehen. Dazu soll die Installation von RTLinux 3.1 auf
einem SuSE 7.2 System mit Kernel 2.4.4 durchgeführt
und ein einfaches Programm zur Steuerung eines
Schrittmotors über den Parallelport entwickelt
werden. |
|||||||||||||||||
Die Installation |
||||||||||||||||||
Grundsätzlich sollte man sich für Experimente
mit RTLinux einen Zweitrechner aufstellen. RTLinux -
Threads laufen im Kernelspace, sodass der Rechner bei
Fehlern im Programm öfters neu gebootet werden muss;
währenddessen kann man auf seinem Arbeitsrechner
weitermachen. Auf Monitor, Tastatur und Maus für den
Zweitrechner kann verzichtet werden, da man per
Displayumleitung auch sehr gut über's Netz arbeiten
kann.
Zunächst ist Linux auf dem Rechner - bei mir ein alter Pentium 133 mit 80 MB RAM, 1.2 GB Festplatte und 100MBit Netzwerkkarte - zu installieren. Bei den begrenzten Ressourcen auf dem Rechner ist es sinnvoll, bei der verwendeten SuSE 7.2 Distribution die Option Minimalsystem mit grafischer X11 - Oberfläche zu wählen, um nicht zuviel Plattenplatz für unnötige Programme zu verschwenden. Bei diesem Minimalsystem muss man hinterher allerdings noch die Netzwerk - Serverkomponenten (ftp-, telnet- rlogin - Deamon, xinetd etc.) hinzuinstallieren. Nun kann man das System konfigurieren, wie man es für richtig hält. Vor allem sind die Netzwerkdienste einzurichten, da man danach auf Monitor, Maus und Tastatur verzichten und den Rechner in einem Winkel unter dem Schreibtisch verstauen kann. Trägt der installierte Kernel nicht die Versionsnummer 2.4.4 (cat /proc/version), so ist er zu installieren. Jetzt geht es an die Installation von RTLinux. Zuerst sind die Quellen von RTLinux 3.1 sowie die 2.4.4er Kernel - Quellen herunterzuladen. Da RTLinux als Kernel - Patch ausgeliefert wird, ist unbedingt ein originaler, ungepatchter Kernel von www.kernel.org erforderlich, die Quellen des SuSE - Standardkernels patchen zu wollen ist aussichtslos. Nun werden die Quellen entpackt: Daraufhin werden die Kernel - Sourcen mit der RTLinux
- Erweiterung gepatcht. Die Kernel - Konfiguration ist der nächste
Schritt. Nach 4 gescheiterten Versuchen weiß ich es
genau: für einen 'Uneingeweihten' ist es nahezu
unmöglich, einen lauffähigen Kernel selbst
zusammenzustellen. Irgendetwas vergisst man immer, sei es
eine wichtige Komponente zum Ansprechen der Festplatte
oder ein Modul mit unwichtig klingendem Namen, das so
unwichtig dann doch nicht sein konnte. Es gibt aber einen
guten Trick, dennoch zu einem funktionierenden Kernel zu
gelangen. Bei der Einrichtung wurde darauf hingewiesen,
den 2.4.4er Kernel von SuSE zu installieren. Dieser ist
zwar von SuSE angepasst, aber die Konfigurationsdatei
scheint zum Originalkernel kompatibel zu sein. Diese ist
also als Vorlage zu kopieren: Mit dieser Vorlage braucht man nur diejenigen Module
abzuwählen, von denen man mit Sicherheit
ausschließen kann, dass man sie jemals braucht.
Dazu zählen Sound, Video, USB, SCSI, zahllose
Netzwerkkarten - Treiber etc. Auszuschalten sind auch
ACPI und der Parallelport - Support. Es ist auch ganz
praktisch, sämtliche wirklich benötigten Module
direkt in den Kernel unterzubringen, weil dann ein Aufruf
von lsmod nur noch die RTLinux - Module
anzeigt. Nun können der Kernel und die ausgewählten
Module übersetzt werden. Das dauert ein Weilchen,
wenn man bei der Abwahl unnötiger Module zu zaghaft
war. Als Ergebnis liegt nun ein Kernel - Image in
arch/i386/boot/bzImage und ein neues Module -
Verzeichnis in /lib/modules/2.4.4-rtl/. Um vom
neuen Kernel zu booten, ist dieser an die richtige
Position zu kopieren. Weiterhin ist ein Eintrag beim Bootloader -- hier am
Beispiel von lilo -- zu ergänzen. In die
Datei /etc/lilo.conf gehören diese Zeilen
unter Anpassung des Pfades zur Root - Partition:
Damit lilo diese Änderungen an seiner
Konfigurationsdatei auch wahrnimmt, ist er einmal
aufzurufen. Daraufhin kann gebootet werden. Hat alles
funktioniert, steht nun ein neuer Eintrag rtlinux
im Bootmenü, der den neu erstellten Kernel
startet. Wenn das System erfolgreich hochgefahren ist, kann man sich leicht davon überzeugen, dass der soeben kompilierte Kernel mit RTLinux - Erweiterungen läuft. Ein Aufruf von cat /proc/version sollte nun den Text "Linux version 2.4.4-rtl" ausgeben. Es bleibt noch das Kompilieren der RTLinux - eigenen
Module, die nicht in die Sourcen des Linux - Kernels
hineinkopiert wurden. Ein Link von den Linux -
Kernensourcen in das RTLinux - Verzeichnis dient dabei
zum Einbinden der Kernelquellen. Bei der Konfiguration
von RTLinux mit make xconfig sind die Vorgaben
sinnvoll, es genügt ein Mausclick auf "Save and
Exit". Die Installation ist nun erfolgreich abgeschlossen.
Mit diesen Kommandos (die man sich am besten gleich in
ein Makefile oder ein Shellscript packt) werden die
RTLinux - Module geladen, wovon man sich wieder mit
lsmod überzeugen kann: Alle Module stehen jetzt fertig kompiliert zur
Verfügung, und die in
/usr/src/rtlinux-3.1/examples stehenden
Beispiele sollten zur Zufriedenheit funktionieren.
Letztlich sollte jeder, der auch Linux selbst installiert
bekommt, mit RTLinux keine Schwierigkeiten haben. |
||||||||||||||||||
Entwicklung unter RTLinux |
||||||||||||||||||
RTLinux - Threads laufen grundsätzlich als Kernel -
Modul (die neue Echtzeit - Userspace Erweiterung habe ich
noch nicht getestet) ab. Sie werden also als
.o-File kompiliert, mit insmod modul.o
gestartet und rmmod modul gestoppt. Sie beginnen
darum auch nicht wie normale Applikationen mit einer
main() - Funktion, sondern werden über
spezielle Funktionen initialisiert und beendet:
int init_module(void) Meldungen werden nicht auf die Konsole ausgegeben -- wie auch, welche Konsole gehört dem Kernel? -- sondern in den Kernel Ring Buffer geschrieben, wo sie sich mit dmesg anzeigen lassen. Programmseitig steht für die Ausgabe solcher Nachrichten die Funktion rtl_printf() zur Verfügung, die ebenso wie das bekannte printf() parametrisiert wird. Da diese Kernel - Module mit Root - Rechten ablaufen, können sie auf alle Hardware direkt zugreifen, sind aber auch anfällig für Programmierfehler oder gar Angriffe von aussen. Die übliche Reaktion von RTLinux auf Fehler gleich welcher Art besteht darin, das System sofort anzuhalten. Sollte also Ihr System aus unerfindlichen Gründen stehenbleiben, so ist dies nicht auf Fehler im Linux - Kernel zurückzuführen, sondern Absicht. |
Im Unterschied zum normalen Linux gehört zu den
Fehlern, die zum Einfrieren des Kernels führen, auch
die Überlastung. Wenn Echtzeit - Threads nicht im
Rahmen der angegebenen Zeiten ausgeführt werden
können, können durchaus gefährliche
Situationen entstehen, beispielsweise wenn bei einer 3
Achsen - Fräsanlage nur für die Bewegung von 2
Achsen genug Rechenleistung bereitsteht und die dritte
nicht hinterherkommt. Das Anhalten des Systems ist dabei
eine sinnvolle Vorgehensweise zum Verhindern
größerer Schäden.
Dies ist sicher sinnvoll für Produktivumgebungen, da es besser ist, in einem definierten Zustand zu enden als in einem unvorhersehbaren Chaos aus laufenden und abgeschossenen Modulen und verspäteten Threads. Für die Entwicklung ist dieses Verhalten hingegen lästig und lässt sich über das Laden des debug - Moduls mittels insmod /usr/src/rtlinux-3.1/debugger/rtl_debug.o abstellen (Siehe README im debugger - Verzeichnis von RTlinux). Die Echtzeitfähigkeit der Threads muss man auch bei der Ein- und Ausgabe berücksichtigen. So ist es zum Beispiel ausgeschlossen, in Echtzeit - Threads Dateien zu lesen oder Netzwerkverbindungen zu öffnen, da deren Ein- und Ausgabefunktionen den Prozess unvorhersagbar lange blockieren. Die einfachste Art, Daten in einen Echtzeit - Thread zu bekommen oder von ihm auszulesen, besteht in den FIFOs (First In First Out), die bei der Installation als /dev/rtf0 ... /dev/rtfn angelegt wurden. Sie lassen sich von nicht echtzeitfähigen Programmen und Prozessen wie normale Dateien bzw. Geräte ansprechen und von den Echtzeit - Prozessen aus mit rtf_get() und rtf_put() leicht lesen und schreiben. Inzwischen wurde bereits oft von Echtzeit - Prozessen gesprochen -- doch wie werden diese erzeugt und verwaltet? Ein periodischer RT - Thread, wie er für die Erzeugung von Schrittmotor - Steuersignalen benötigt wird, wird mit pthread_create() erzeugt, mit pthread_make_periodic_np() als periodisch markiert und mit pthread_delete_np() vernichtet. Hat der Thread seine Aufgabe für die jeweilige Periode erfüllt und wartet auf die nächste, so legt er sich mit pthread_wait_np() schlafen. |
|||||||||||||||||
Ein einfaches Beispiel, dessen Ausgabe sich wie oben
erwähnt mit dmesg ansehen lässt, und
das wie ebenfalls erläutert mit insmod
test.o und rmmod test gestartet und
gestoppt wird, sieht so aus:
pthread_t t; |
||||||||||||||||||
Ansteuerung eines Schrittmotors |
||||||||||||||||||
Bipolare Schrittmotore sind sehr grob vereinfacht gesehen
'herumgedrehte' Gleichstrommotore: die Ankerwicklungen
bilden den Stator, und ein Permanentmagnet den Rotor. Da
der Schrittmotor somit ohne Kommutator (das Element am
Elektromotor, an dem die Kohleschleifer sitzen, und das
die Stromrichtung am Anker umschaltet) auskommen muss,
ist eine Elektronik oder Programmlogik dafür
zuständig, diese Umschaltung vorzunehmen.
Solange ein Muster an den Spulen anliegt, verharrt der Läufer in der aktuellen Position. Daher lässt sich die Drehzahl und die Position eines Schrittmotors sehr exakt bestimmen. Im einfachsten Falle erfolgt die Ansteuerung mit dem Vollschrittverfahren. Dabei wird die Spannung von Spule zu Spule mit wechselseitiger Polarität weitergeschaltet, wie unten abgebildet. Das ebenfalls abgebildete Halbschrittverfahren fügt zwischen die beiden Vollschritte noch einen weiteren Schritt ein, in dem beide Spulen stromdurchflossen sind. Dadurch lässt sich die Auflösung des Schrittmotors effektiv verdoppeln. Jedoch steigt der Stromverbrauch, und die Spannung muss ständig am Schrittmotor anliegen, weil der Rotor sonst bei einem halben Schritt in die letzte oder nächste Vollschrittstellung laufen würde. Bei der Microschritt - Ansteuerung wird das Halbschrittverfahren weiter verfeinert, indem durch Pulsweitenmodulation des Stromes beider Spulen zwischen zwei Vollschritte beliebig viele Zwischenschritte eingefügt werden. Diese Ansteuerung hat jedoch keine große Bedeutung, da die erreichbare theoretisch beliebig hohe Auflösung von der Mechanik des Schrittmotors oft nicht nachvollzogen werden kann. |
Schrittmotore können nicht unmittelbar vom Stand auf
die gewünschte Geschwindigkeit beschleunigt werden.
Auf Grund der Masseträgheit der rotierenden
Komponenten würden einige der ersten Schritte
übersprungen. Ebensowenig kann ein Schrittmotor von
einer hohen Geschwindigkeit abrupt bremsen, da er durch
die Trägheit etwas nachläuft. Ausserdem hat
jeder Schrittmotor eine Resonanzfrequenz, bei dem sich
die Vibrationen des Motors so stark 'aufschaukeln', dass
der Motor langfristig sogar zerstört werden kann.
Die Beschleunigungs- und Bremskurve sollte bei der
Resonanzfrequenz ihren maximalen Anstieg aufweisen.
Das Ziel der hier vorgestellten Schrittmotor - Ansteuerung ist der Einsatz des Halbschrittverfahrens. Die Beschleunigungs- und Bremskurve soll mit Hilfe einer quadratischen Gleichung zurück zum Anfang |
|||||||||||||||||
Halbschritt - Ansteuerung |
||||||||||||||||||
Die benötigte Hardware zum Testen der Schrittmotor - Funktionalität ist einfach: es genügt ein Brückentreiber wie der L293D an den Datenpins des Parallelports. Eine Schreiboperation auf den Port 0x378 oder 0x278 (LPT1 und 2) setzt diese Datenpins. Eine Warnung am Rande: wer oft mit selbstgebauter Elektronik am Parallelport experimentiert, sollte das unbedingt an einer Schnittstellenkarte und nicht mit dem auf dem Motherboard integrierten Port tun. | Wenn nicht die 'D'-Version des L293 mit integrierten Dioden zum Ableiten der Rückströme induktiver Lasten eingesetzt wird, sind diese Dioden zusätzlich einzubauen, da der Brückentreiber an sonsten schnell zerstört wird. Je nach Güte des Netzteils sind Pufferkondensatoren vorzusehen. Einige Parallelports benötigen Pullups an den Datenpins, da sie nicht genug Strom liefern können. In vielen Fällen kann darauf aber verzichtet werden. | |||||||||||||||||
Schaltplan und Aufbau des Testboards |
||||||||||||||||||
Das Programm |
||||||||||||||||||
Zur Entwicklung braucht man als erstes einmal ein
geeignetes Makefile, um die Compiler - Parameter
nicht ständig neu angeben zu müssen. Dieses
Makefile ist eine leichte Abwandlung der Makefiles, mit
denen die RTLinux - Beispiele im
examples-Verzeichnis erzeugt wurden. Der
CFLAGS-Parameter '-g' bindet Debug -
Symbole mit in den produzierten Binärcode ein und
und kann für die finale Version entfernt werden. Es
gibt drei Targets, die sich mit make, make
clean und make modinst aufrufen lassen. Was
diese Aufrufe produzieren, ist wohl
selbsterklärend:Nun zum Programm. Zunächst werden einige Header eingebunden, statische Definitionen definiert und globale Variablen festgelegt. Die Schrittmotor - Bewegung gliedert sich in 4 aufeinanderfolgende Zustände: bei STATUS_STOP bewegt sich nichts, bei STATUS_SPEEDUP wird beschleunigt, bei STATUS_RUNNING wird die Geschwindigkeit gehalten und bei STATUS_SPEEDDN wird abgebremst.RTL_DIR = /usr/src/rtlinux-3.1 RTLINUX_DIR = /usr/src/rtlinux-3.1/linux INCLUDE= -I/usr/src/rtlinux-3.1/linux/include -I/usr/src/rtlinux-3.1/include \ -I/usr/src/rtlinux-3.1/include/compat CFLAGS = -g -D__KERNEL__ -Wall -Wstrict-prototypes -fno-strict-aliasing -pipe \ -mpreferred-stack-boundary=2 -march=i586 -DMODULE -g -D__RTL__ \ -D_LOOSE_KERNEL_NAMES -O2 -I/usr/src/rtlinux-3.1/linux/include \ -I/usr/src/rtlinux-3.1/include -I/usr/src/rtlinux-3.1/include/compat \ -I/usr/src/rtlinux-3.1/include/posix ARCH = i386 CC = gcc CXXFLAGS = -D__KERNEL__ -Wall -Wstrict-prototypes -fno-strict-aliasing -pipe \ -mpreferred-stack-boundary=2 -march=i586 -DMODULE -g -D__RTL__ \ -D_LOOSE_KERNEL_NAMES -I/usr/src/rtlinux-3.1/linux/include \ -I/usr/src/rtlinux-3.1/include -I/usr/src/rtlinux-3.1/include/compat \ -I/usr/src/rtlinux-3.1/include/posix -fno-exceptions -fno-rtti all: clean \ stepper.o modinst: @echo "installiere Kernel-Module für RT-Linux" (cd /usr/src/rtlinux-3.1/; scripts/insrtl) clean: @echo "Entferne alte Objektdateien:" rm -f *.o Der nun folgende Thread hat die Aufgabe, Daten von /dev/rtf0 einzulesen und gemäß den übergebenen Anweisungen den Status weiterzusetzen und die Beschleunigungs- und Bremskurve zu errechnen. Die Kommandos werden einfach im Klartext an den FIFO geschickt, etwa in der Konsole mit "echo start > /dev/rtf0" Wer übrigens bei String- und überhaupt allen Operationen auf Arrays oder Puffern Funktionen ohne Angabe einer Maximallänge wie strcmp() statt strncmp() verwendet, braucht sich über Sicherheitslücken und bei unerwarteten Daten abstürzende Programme nicht zu wundern.#include <linux/module.h> #include <linux/kernel.h> #include <linux/version.h> #include <linux/cons.h> #include <asm/io.h> #include <rtl_sched.h> #include <rtl_fifo.h> #include <linux/string.h> // erster Parallelport: 0x378 // zweiter Parallelport: 0x278 #define LPT_PORT 0x278 // Enable-Signal liegt auf D7 des Parallelports #define ENABLE 0x0080 #define STATUS_STOP 0 #define STATUS_SPEEDUP 1 #define STATUS_RUNNING 2 #define STATUS_SPEEDDN 3 // Globale Variablen pthread_t controlthread; pthread_t stepperthread; int status = STATUS_STOP; long changespeed = 0; // Funktionsprototypen void* stepper_control(void* arg); void* stepper_out(void* arg); Die Veränderung der Geschwindigkeit des Schrittmotors geschieht indirekt über die globale Variable changespeed. Es ist zwar möglich, die Periodendauer des Ausgabe - Threads auch von diesem Steuerthread aus zu verändern, jedoch entstünden dadurch Unregelmäßigkeiten, da der Steuerthread ja nicht weiß, wieviel Zeit seit dem letzten Aufruf des Ausgabethreads vergangen ist. Dieser Thread hat die Aufgabe, das Bitmuster für die Bewegung des Schrittmotors auf den Parallelport auszugeben. Dazu wird ein Zähler verwaltet, der über eine Modulo 8 - Division als Index auf ein Datenfeld mit den Bitmustern dient. Steht in der Variable changespeed ein Wert > 0, so wird die Periodendauer des Ausgabethreads verändert und die Variable auf 0 zurückgesetzt.// Steuer-Thread void* stepper_control(void* arg) { char *buf[1024]; int count = 255; pthread_make_periodic_np (pthread_self(), gethrtime(), 10000000); while(1) { // Daten vom FIFO einlesen int l = rtf_get(0, buf, 1024); // Daten vom FIFO interpretieren if(l>0) { if(strncmp("start",(char *)buf,5)==0 && status == STATUS_STOP) { rtl_printf("starting\n"); // Thread starten pthread_wakeup_np(stepperthread); // Status weitersetzen status = STATUS_SPEEDUP; count = 255; } else if(strncmp("emerg",(char *)buf,5)==0 && status > STATUS_STOP) { rtl_printf("emergency stop\n"); // Status weitersetzen status = STATUS_STOP; } else if(strncmp("stop",(char *)buf,4)==0 && status > STATUS_STOP) { rtl_printf("stopping\n"); // Status weitersetzen status = STATUS_SPEEDDN; } } // Beschleunigungskurve berechnen (quadratische Gleichung) if(status == STATUS_SPEEDUP) { if(count == 0) { status = STATUS_RUNNING; } else { count=count-1; changespeed = (count*count*61)+1000000; } } else if(status == STATUS_SPEEDDN) { if(count == 255) { status = STATUS_STOP; } else { count=count+1; changespeed = (count*count*61)+1000000; } } // Warten bis zum nächsten Aufruf pthread_wait_np(); } return 0; } Beim Laden eines Kernel - Moduls mit insmod wird die init_module()-Funktion vom Modul - Loader aufgerufen. Daher ist dies die richtige Stelle, um die beiden Threads zu starten.// Ausgabe-Thread void* stepper_out(void* arg) { // Daten für die Ausgabe der Bitmuster für Halbschrittbetrieb int cnt = 0; const int val[] = {0x01,0x05,0x04,0x06,0x02,0x0A,0x08,0x09}; // Thread als periodisch markieren und schlafenlegen pthread_make_periodic_np (pthread_self(), gethrtime(), 5000000); pthread_suspend_np(pthread_self()); while(1) { // Wenn status auf STOP gesetzt, schlafen legen if(status == STATUS_STOP) { outb(0,LPT_PORT); pthread_suspend_np(pthread_self()); } // Auf Änderung der Geschwindigkeit reagieren if(changespeed>0) { pthread_make_periodic_np (pthread_self(), gethrtime(), changespeed); changespeed = 0; } // Bitmuster ausgeben, um den Stepper einen Schritt weiterzusetzen outb(val[cnt%8]|ENABLE,LPT_PORT); // Zähler auf das nächste Bitmuster cnt++; // Warten bis zur nächsten Ausgabe pthread_wait_np(); } return 0; } Beim Entladen eines Moduls mit rmmod wird diese Funktion aufgerufen. Sie hat die Aufgabe, die Threads zu stoppen und alle benutzten Ressourcen freizugeben.int init_module(void) { // Hello-Message ausgeben (dmesg) rtl_printf("Stepper Control is running!\n"); // FIFO 0 (/dev/rtf0) initialisieren rtf_create(0, 1024*1024); // Threads initialisieren pthread_create(&stepperthread, NULL, stepper_out, (void*) 0); pthread_create(&controlthread, NULL, stepper_control, (void*) 0); return 0; } Das war das vollständige Programm. Man sieht, dass sich die Komplexität in Grenzen hält - auch mit nur rudimentären C - Kenntnissen und ohne große Programmiererfahrung unter Linux kommt man leicht zu ansprechenden Ergebnissen. Die POSIX - kompatiblen C - Standardbibliotheken, zu denen sich im Internet Beispiele für fast jede denkbare Problemstellung finden lassen, sowie die sehr gut dokumentierten RTLinux - Funktionen machen eine Entwicklung mit diesem System zum Vergnügen. Damit ist RTLinux auch für größere Projekte geeignet, ich werde also meinen Fräsroboter damit ansteuern können. Mehr dazu demnächst...void cleanup_module(void) { rtl_printf("Stepper Control is shutting down!\n"); // Threads anhalten pthread_delete_np(stepperthread); pthread_delete_np(controlthread); // Enable zurücksetzen outb(0,LPT_PORT); // Eingabe-FIFO anhalten rtf_destroy(0); } zurück zum Anfang |
||||||||||||||||||
Bibliographie |
||||||||||||||||||
|