PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Serielle Schnittstelle



LSSuper2004
29-09-2005, 17:11
Hallo,

in meinem C++-Buch habe ich von den Möglichkeiten der Programmierung des COM-Ports gelesen und es hat mein Interesse geweckt. Dort war auch so ein Anwendungsbeispiel (die Betonung liegt auf Beispiel) mit einer kleinen Ampel, also aus den drei Pins TxD, DTR und RTS Strom ziehen und zurück alles wieder in GND. Die Pinbelegung wurde da alles sehr gut erklärt, und Beispielcode für DOS und Windows war dort abgedruckt. Leider gibt's unter Linux die conio.h nicht (und ich würde sagen, das ist auch besser so - weiß nicht, wa<rum ich das meine) und der Code nützt mir nichts.

Also auf die harte Tour (nachdem ich durch die Kernelroutinen nicht durchblicke). Wollte per Assemblercode an die 0x3F8 schreiben (COM1) bzw. 0x2F8 (COM2). Dort war alles schön beschrieben mit den Registern, und wollte erst mal zum Test den Strom an DTR legen. Also den Wert 0x1 an die Adresse PORT+4 schreiben (PORT habe ich mit dem COM1-Wert getestet), später könnte ich dann auch immer erst den alten Wert auslesen und dann maskieren, um das RTS beizubehalten, aber das ist jetzt erst mal egal.

Meine Quelltextdatei sieht so aus:


/* penma's Serial I/O - Licensed under the GNU General Public License */

#include <stdio.h>

int main()
{
printf("Serial I/O IOIOI\n\n");
fflush(stdout);
asm("mov dx,1020");
asm("out dx, 0x1");
return 0;
}


(ich liebe es, meine Programme unter die GPL zu stellen - für Besserwisser: später kann ich den "Original"-Kommentar dorthin setzen)

Hier die Ausgabe:


lars@Lars-72QAJJS5MR:~/Documents/KDevelop/COM1> g++ -save-temps main.cpp
main.s: Assembler messages:
main.s:34: Error: too many memory references for `mov'
main.s:35: Error: too many memory references for `out'
lars@Lars-72QAJJS5MR:~/Documents/KDevelop/COM1>

und ich mache ihm extra das Leben (noch) leichter mit der dezimalen Adresse, nichtsdestoweniger weist mein treuer GNU-Compiler den Code zurück und zwar mit einer Meldung, aus der ich nicht schlau werde. Muss man vielleicht die Speicheradressen erst per Geheimbefehl freischalten???

Oder mir nennt jemand eine andere Möglichkeit, am besten (muss aber nicht sein) eine, wo ich die Spannung auch variieren kann. Der Dirk Louis meinte, man könnte die Ausgangsspannung zwischen -10 Volt und +10 Volt verändern --- fürxs Erste reicht mir auch die Tatsache, überhaupt Strom dranzubekommen.

Fakt ist, unabhängig davon, welche Wege genommen werden: Ich möchte Routinen der folgenden Art benutzen können (Header-Definitionen):


void TxD(int state);
void DTR(int state);
void RTS(int state);

wobei int 0 oder 1 für an oder aus sein darf oder, bei der Spannung, soll int Werte von -10 bis +10 aufnehmen, die die Spannung regeln. Die Funktionen sollen die jeweiligen Pins ansteuern. (Also TxD für Pin 3, DTR für Pin 4, RTS für Pin 7 und an Pin 5 oder GND wird alles wieder angelötet.) Um drei separate Anschlüsse zu haben (Pins 3, 4, 7) die in Pin 5 wieder zusammengeführt werden. (Sozusagen 3 Pluspole und ein Minuspol)

Hoffe, das hat euch nicht allzusehr verwirrt ( :confused: ), aber mir geht es nicht darum, irgendwelche Daten über den Anschluss zu übertragen, sondern Strom an die Pins zu legen und das natürlich kontrolliert.

-- penma --

Joghurt
29-09-2005, 17:52
asm("mov dx,1020");
asm("out dx, 0x1");
Das ist Intel-Syntax. GCC nutzt aber den AT&T Syntax.
Es müsste so lauten

asm("mov $1020,%dx");
asm("mov $1,%al");
asm("out %al,%dx");

Kurze Auflistung der Unterschiede (google für mehr)
Erst Quelle, dann Ziel => mov dx,2 => mov $2,%dx
Registernamen beginnen mit %
1234 in AT&T Syntax bedeutet [1234] in Intel-Syntax, also den Inhalt der Speicherstelle 1234. Wenn du den Wert 1234 meinst, musst du $1234 schreiben.
[edx] => (%edx)
mov dword ptr => movd etc. Ich hätte also eigentlich
"movw $1020,%dx" schreiben müssen, as macht das aber von selbst.

LSSuper2004
29-09-2005, 18:06
Jo, geht

na ja, jetzt noch irgendwoher ein Messgerät nehmen und dan ran an die Arbeit und was nützliches damit anstellen-... aber kompiliert bekomme ich's, und das muss ja was heißen! ;) :) THX THX THX THX THX THX THX THX THX

-- penma --

LSSuper2004
29-09-2005, 18:12
Schon mal ne Frage im Voraus:

Also, das Ansteuern (scheint) zu gehen (ich hatte halt noch mein Messgerät, aber lassen wir das) aber die weniger wichtige Frage wäre, was man der seriellen Schnittstelle "sagen" muss, damit sie die Spannung runterschaltet?

+Ist aber nicht so wichtig. Nur so ne kleine Frage am Rande des großen weiten Universums. :D

-- penma --

LSSuper2004
29-09-2005, 18:22
An den kleinen Assemblerprofi ;-) :

Könntest du mir vielleicht den Fehler im Ausschnitt sagen (die asm-Anweisungen stehen aber da):

mov $1020,%dx
in %cx,%dx
or $1,%cx
mov %cx,%al
out %al,%dx

Zweck der Aktion ist, per IN-befehl den Wert aus 0x3FC den Wert nach %cx zu schreiben, über OR mit 0x1 verknüpfen, und anschließend das ganze per OUT wieder zurück.

-- penma -- :o (peinlich)

RapidMax
29-09-2005, 20:49
Soll es ohne Assembler gehen, schaltet man mit ioperm() (sys/io.h) den gewünschten Port frei und betreibt mit inb/outb (bzw. -w -l) I/O. Ist allerdings mehr für private Bastelprojekte als für ernsthafte Programme. Soll es etwas professioneller sein, gibt es auch Projekte, die Kernelmodule für I/O-Missbrauch zur Verfügung stellen (zumindest für den Parallelport).

Gruss, Andy

LSSuper2004
30-09-2005, 11:37
Nein, Assembler nach Möglichkeit. Außer, jemand indet etwas für die Spannung raus... bis dahin: Warten aufs Messgerät. :D

-- penma --

LSSuper2004
30-09-2005, 11:54
Soll es ohne Assembler gehen, schaltet man mit ioperm() (sys/io.h) den gewünschten Port frei und betreibt mit inb/outb (bzw. -w -l) I/O. Ist allerdings mehr für private Bastelprojekte als für ernsthafte Programme. Soll es etwas professioneller sein, gibt es auch Projekte, die Kernelmodule für I/O-Missbrauch zur Verfügung stellen (zumindest für den Parallelport).

Gruss, Andy

Wie, durch Ansteuerung der parallelen Schnittstelle über Kernelmodule Eingabe/Ausgabe missbrauchen? :confused:

-- penma --

Joghurt
30-09-2005, 13:21
in %cx,%dxDas liest den Port in CX aus und schreibt es in DX! Erst Quelle, dann Ziel! Außerdem kannst du die Register nicht beliebig kombinieren. In kann nur in ax lesen. Also

in %dx,%ax
or $1,%ax
out %al,%dx

LSSuper2004
30-09-2005, 13:24
Danke, Joghurt (ich lerne es wohl nie) DANKE DANKE

THX THX THX THX THX THX THX THX THX THX THX THX THX THX THX THX THX THX THX THX

DANKE DANKE sehr

-- penma --

LSSuper2004
30-09-2005, 13:45
Frage an alle:

Habe jetzt mal etwas genauer getestet und finde raus, dass er jetzt sagt:
Speicherzugriffsfehler
(nach den Ausführen der ersten Assembleranweisung, die printf-Anweisungen davon funzen)

als root getestet (Systemabsturz wäre mir dann auch egal gewesen), und was ist? nix! printf-Anweisungen danach werden einfach nicht mehr ausgeführt (speicherzugriffsfehler sagt er aber nicht), jedenfalls: "in" führt er nicht mehr aus.

Warum? Wird wohl weniger wichtig sein, als dass ich jetzt eine andere Lösung brauche. Und die soll nicht für Datenübertragung, sondern für Strom gut sein. Vielleicht könnte mir jemand die Funktionen aus linux/serial.h und linux/serial_core.h näher erklären... vielleicht dann auch, um mal so eben eines der Empfangspins zu überprüfen, also vielleicht so mit einem Schalter Strom anlegen oder sowas...

...wichtiger ist mir aber erst mal das Anlegen von Strom. Natürlich möglichst so, dass es bis zum nächsten Ändern gilt. Wie zuvor, wichtig sind TxD DTR RTS.

-- penma --

(ich weiß ich mach euch hier alle verrückt)

RapidMax
30-09-2005, 22:44
Wie, durch Ansteuerung der parallelen Schnittstelle über Kernelmodule Eingabe/Ausgabe missbrauchen? :confused:
Missbrauch der Schnittstelle als I/O (Dafür war sie nicht gedacht).

Für den Parallelport gibt es dieses Projekt hier: http://parapin.sourceforge.net/
Für die Serielle Schnittstelle wird es vermutlich ähnliche Ansätze geben.

Gruss, Andy