Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Serielle Schnittstelle AD-Wandler / Pascal oder Basic zu C oder Perl

11 views
Skip to first unread message

Ulli Drescher

unread,
Sep 3, 2001, 6:04:09 AM9/3/01
to
Hallo,

vorausschicken muss ich, dass ich ausser in Java fast keine
Programmiererfahrung habe. Da aber ein Freund behauptet hat, dass es nur
4 Zeilen braucht, um in Perl eine Schnittstelle anzusprechen, dachte ich
mir, dass das nicht so schwer sein kann. Entweder ich stell mich gerade
dumm an oder es ist doch komplizierter. Perl erzaehlt mir immer was von
"Can`t locate loadable object".

Das Problem:

Ich moechte gerne mit einem AD-Wandler (MAX186 des Interfaces SERAI812 8
Kanaele, 12 bit Aufloesung) ueber die serielle Schnittstelle ein paar
Geraete abfragen.

Ich habe auch fuer Windows die notwendigen (verblueffend kurze)
Programme bzw. Quellcodes in GW-Basic, Pascal und VBA da. Ich moechte
aber eigentlich das ganze unter Linux laufen lassen. (Das Pascalprogramm
laesst sich nicht unter Linux compilieren.)

Es scheint mit den Standardmodulen fuer die Schnittstelle, die es in
Perl gibt, nicht zu klappen. Soweit ich die mitgelieferten Programme
durchschaue, schicken sie jeweils ein Steuerbyte und erhalten zwei
Datenbytes zurueck. Dabei stellen sie irgendwas an der seriellen
Schnittstelle um.
Es scheint sich um keine RS-Standardsache zu handeln.

Meine Frage ist:

Gibt es einen Befehl fuer C oder Perl der dem OUT (Zeile 20, 550, 560,
570, 595, 640, 650) in Basic bzw. dem PORT in Pascal entspricht? Und
wenn ja, wie lauten die Werte, die ich dazu uebergeben muss? Bleibt der
Code fuer die Schnittstelle (&H2F8 bzw. $02F8) unter Linux gleich?

Ich waere Euch dankbar, wenn ich auf Windows verzichten koennte!

Ulli Drescher

Hier sind die Quellcodes in Basic und Pascal:

######################### BASIC ################################

10 BA=&H2F8 : REM COM2

20 OUT (BA+3), 64
30 CLS
40 PRINT " SERAI812 an COM2
100 REM Messung an 8 Kan„len
110 LOCATE 10,1

120 FOR N= 0 TO 7
130 SEL = 7-(N\2) -4*(N AND 1)

140 GOSUB 500

150 PRINT N,
160 PRINT USING "##.###"; U;
170 PRINT " V"
180 NEXT N
190 FOR T= 1 TO 10000 : NEXT T
200 LOCATE 10,1
210 GOTO 120

500 REM ************* Ansteuerung des MAX186 ******
510 CMD = 128 + 16 * SEL + 8 + 4 + 2
520 BIT = 128

530 FOR B= 1 TO 8
540 IF (CMD AND BIT)=BIT THEN RTS = 2 ELSE RTS=0
550 OUT (BA+4),RTS
560 OUT (BA+4),RTS+1
570 OUT (BA+4),RTS
580 BIT = BIT \ 2
590 NEXT B

595 OUT (BA+4),0
600 FOR T= 1 TO 10 : NEXT T

610 BIT = 2048 : AUS = 0
630 FOR B= 1 TO 16
640 OUT (BA+4),1
650 OUT (BA+4),0
660 IF ((INP(BA+6) AND 16)=16) THEN AUS = AUS + BIT
670 BIT = BIT \ 2
680 NEXT B

690 U = AUS / 1000
700 RETURN

####################### Pascal ##########################

Program MAX186;
Uses CRT;
var BA : Integer;
Offset: Real;

procedure Init;
begin
BA := $02F8; { COM2 }
Port[BA+3]:=$40; { Break, TXD=1, Betriebsspannung }
Port[BA+4]:=$00; { DTR(Sclk) = 0, RTS(Din) = 0 }
delay (100);
end;

function shift8 (Commando: Byte):Byte;
var Aus, Lesen, Bit, N: Byte;
i : Integer;
begin
Bit := 128;
Lesen := 0;
for n:=1 to 8 do begin
if (Commando AND Bit) = Bit then Aus := 2 else Aus := 0;
Port[BA+4]:=Aus; { Din }
for i:= 1 to 30 do;
Port[BA+4]:=Aus+1; { Din + Sclk }
for i:= 1 to 30 do;
Port[BA+4]:=Aus; { Din }
for i:= 1 to 30 do;
if (Port[BA+6] AND 16)= 16 then Lesen := Lesen + Bit;
Bit := Bit div 2;
end;
Shift8 := Lesen;
Port[BA+4]:=$00; { Din=0, Sclk=0 }
end;

function Messung (Steuerbyte: Byte): Real;
var Ausgabe: Byte;
Wert, i: Integer;
begin
Ausgabe := shift8(Steuerbyte); {Start}
{repeat until (Port[BA+6] AND 32)= 32;} {SSTRB, fertig}
for i:= 1 to 100 do;
{delay (10);}
Wert := 16 * shift8(0); {Highbyte}
Wert := Wert + shift8(0) div 16; {Lowbyte}
Messung := Wert/1000;
end;

procedure Achtkanal;
var n, Sel: Integer;
begin
GotoXY (10,3);
write ('Kanal Spannung');
for n := 0 to 7 do begin;
GotoXY (10,5+n); write (N);
Case N of
7: Sel := 0;
6: Sel := 4;
5: Sel := 1;
4: Sel := 5;
3: Sel := 2;
2: Sel := 6;
1: Sel := 3;
0: Sel := 7;
end;
GotoXY (20,5+n);
write (Messung(128+16*Sel+8+4+2):5:3,' V');
end;
delay (500)
end;

begin
Init;
ClrSCR;
writeln ('SERAI812 an COM2');
repeat Achtkanal until Keypressed;
end.


ulli.drescher.vcf

Jan Kandziora

unread,
Sep 3, 2001, 8:09:01 AM9/3/01
to
Ulli Drescher wrote:

>
> Gibt es einen Befehl fuer C oder Perl der dem OUT (Zeile 20, 550, 560,
> 570, 595, 640, 650) in Basic bzw. dem PORT in Pascal entspricht? Und
> wenn ja, wie lauten die Werte, die ich dazu uebergeben muss? Bleibt der
> Code fuer die Schnittstelle (&H2F8 bzw. $02F8) unter Linux gleich?
>

Du kannst dir in C mit der Funktion "iopl" Rechte auf die Schnittstelle
holen und sie dann von Hand mit "outb" und "inb" wie in deinen Vorlagen
programmieren. Wichtig: Das Programm muß mit -O kompiliert werden und läuft
nur als Root(oder suid-Root).

Jan

Ulli Drescher

unread,
Sep 5, 2001, 6:37:10 AM9/5/01
to
Jan Kandziora wrote:

Hallo Jan,

vielen Dank fuer die Tips, die mir sehr geholfen haben.

Prinzipiell funktioniert es jetzt auch. Das heisst das Programm liest die
Kanaele der Reihe nach aus und es bekommt auch Daten zurueck. Nur leider
addiert bzw. subtrahiert (?) es auf die vorgegeben Spannung noch bit-Werten
dazu. Z.B gebe ich die Spannung 2,5 Volt vor, so erhalte ich die Werte (mV)
2547 und 2555 (plus 8!)was ja noch OK ist. Doch ueberwiegend kommen folgende
Werte: 3579 (plus 1024) oder 3547 (plus 1024 minus 32).

Dieser Fehler taucht in den Windowsprogrammen nicht auf.

An was koennte das liegen? Muss ich irgendwo eine Zeitverzoegerung einbauen?
Oder liegt das irgendwo in den Tiefen des Betriebssystems?

Fuer Vorschlaege aller Art bin ich dankbar.

Tschuess Ulli

Hier der Quelltext der eigentlich dem BASIC-Quelltext entsprechen sollte
(Disclaimer: Ich bin kein Informatiker)

/********************************** GCC
*******************************************/

/* Programm zm Auslesen eines AD - Wandlers ueber die Serielle Schnittstelle.
* MAX186 des Interfaces SERAI812 8 Kanaele, 12 bit Aufloesung Firma
ak-modul-bus
*/

#include <stdio.h>
#include <sys/io.h> /* for glibc */
/* #include <unistd.h> /* for libc5 */

main()
{
int portsel = 0x2F8; // /dev/ttyS1/ entspricht in Windows COM2
int sel = 0; //dem jeweiligen Kanal entsprechender Wert, um das
Steuerbyte zu erzeugen
int kanal = 0; //8 Kanaele
int wert = 0;
int steuerbyte = 0;
int bit = 0;
int bitbit = 0;
int b = 0; //Laufzahl fuer das Steuerbyte
int bb = 0; //Laufzahl fuer die zwei Datenbytes
int i = 0; //Laufzahl fuer die Anzahl von Abfragen hier ev.
Endlosschleife einbauen
int rts = 0; //Ready To Send
int fehler = 0; //0 = OK, -1 = Fehler
int millivolt = 0;

/* Set the I/O privilege level to LEVEL. If LEVEL>3, permission to
access any I/O port is granted. This call requires root privileges. */

fehler = iopl (3); //siehe man iopl
printf ("%1i\n", fehler); //0 = OK, -1 = Fehler

outb (64, portsel + 3);

printf ("\n SERAI812 an dev/ttyS1/ \n");

for(i = 0; i<100; i++) //Der AD-Wandler wird 100 mal abgefragt
{
for(kanal = 0; kanal <= 7; kanal++) //Abfrage der einzelnen Kanaele
{
sel = 7-(kanal/2) - 4* (kanal & 1); //Kanaelen die passenden sel-Werte
zuordnen
steuerbyte = 128 + 16*sel + 8 + 4 + 2;

//Steuerbyte senden
bit = 128;
for(b = 1; b <= 8; b++)
{
if ((steuerbyte & bit) == bit)
rts = 2;
else
rts = 0;
outb (rts, portsel + 4);
outb (rts + 1, portsel + 4);
outb (rts, portsel + 4);
bit = bit / 2;
}

outb (0, portsel + 4);
//sleep(0.1); //Zeitverzoegerung

//2 Datenbytes empfangen
bitbit = 2048;
wert = 0;
for(bb = 1; bb <= 16; bb++)
{
outb (1, portsel + 4);
outb (0, portsel + 4);
if((inb (portsel + 6) & 16) == 16)
wert = wert + bitbit;
bitbit = bitbit / 2;
}

millivolt = wert ;
printf ("Kanal: %1i Spannung: %4i Millivolt\n", kanal, millivolt);
}
sleep(1);
printf("\n");
}
}

Jan Kandziora

unread,
Sep 6, 2001, 6:43:44 AM9/6/01
to
Ulli Drescher wrote:
>
----Schnipp----

>
> was ja noch OK ist. Doch
> ueberwiegend kommen folgende Werte: 3579 (plus 1024) oder 3547 (plus 1024
> minus 32).
>
Wahrscheinlichlich Übertragungsfehler.

>
> Dieser Fehler taucht in den Windowsprogrammen nicht auf.
>
> An was koennte das liegen? Muss ich irgendwo eine Zeitverzoegerung
> einbauen? Oder liegt das irgendwo in den Tiefen des Betriebssystems?
>

Es gibt eine Version der Funktionen mit eingebauter Verzögerung: outb_p und
inb_p. Die kannst du ja mal ausprobieren.

Jan

Ulli Drescher

unread,
Sep 6, 2001, 12:36:21 PM9/6/01
to
Jan Kandziora wrote:

Hallo

Mit diesen Befehlen klappt es. Ich hatte vorher ein paar Schleifen eingebaut,
die auch geholfen haben, bzw. habe ich es auf dem eigentlichen Messcomputer
(einem 486) laufen lassen, der langsam genug war, um den AD-Wandler nicht
durcheinander zu bringen und auf dem es auch ohne Verzoegerung gelaufen ist.

Vielen herzlichen Dank noch mal fuer die Hilfe

Ulli

0 new messages