Schrift
[thread]7306[/thread]

Lesen von serieller Schnittstelle: Events unter Win nutzen



<< >> 2 Einträge, 1 Seite
Hellmaker
 2005-09-23 13:23
#58378 #58378
User since
2005-08-05
16 Artikel
BenutzerIn
[default_avatar]
Hallo liebe Perl Gemeinde,

mein Problem ist eigentlich ganz schnell genannt: Ich kann auf die serielle Schnittstelle schreiben (Funkmodul, Daten kommen auch wunderbar auf der anderen Seite an), aber lesen klappt einfach mal garnicht! :(

Erklärt ist es leider nicht so einfach:
Das schreiben klappt mit verschiedenen Modulen (z.B. Win32API::CommPort, Win32::API) und verschiedenen Funktionen (z.B. $PortObj->write() oder WriteFile() der kernel32.dll).
Der Code für das Schreiben sieht dann z.B. so aus:
Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
use strict;
require 5.003;
use Win32API::CommPort;
use Win32::SerialPort qw( :STAT 0.19);
use Win32;

my $quiet = 1; # Einschränkung bei Fehlermeldung
my $PortName = 'COM3';
my $configFile = 'ER400TRS.cfg';

my $PortObj = new Win32::SerialPort( $PortName, $quiet )
   or die "Can't open $PortName: $^E\n";

## initialize
$PortObj->user_msg( 'ON' );
$PortObj->baudrate( 19200 );
$PortObj->databits( 8 );
$PortObj->parity( "none" );
$PortObj->stopbits( 1 );

$PortObj->handshake( "none" );
my @ar=$PortObj->buffers( 128, 128 ); ## read buffer, write buffer

## write settings to com port
$PortObj->write_settings or undef $PortObj;
unless( $PortObj ){ print "can't change device control block: $^E\n"; }
## save settings in configuration file
$PortObj->save( $configFile ) or warn "can't save $configFile: $^E\n";

## close all stuff
$PortObj->close or die "failed to close";
undef $PortObj; ## frees memory back to perl

## open again with tie (needed for some functions)
$PortObj = tie( *COMFH, 'Win32::SerialPort', $configFile )
or die "can't tie using $configFile: ^E\n";

### ready to communicate
##get current status

my $BlockingFlags;
my ( $InBytes, $OutBytes, $LatchErrorFlags );
( $BlockingFlags, $InBytes, $OutBytes, $LatchErrorFlags ) = $PortObj->status
       || warn "could not get port status\n";

if ( $BlockingFlags ) { warn "Port is blocked"; }
if ( $BlockingFlags & BM_fCtsHold ) { warn "Waiting for CTS (clear to send)"; }
if ( $LatchErrorFlags & CE_FRAME ) { warn "Framing Error"; }


#######write to serial port###################
my ( $count_out, $output_string );
$output_string = "Hallo ";

my $i = 10;
while( $i > 0 ) {
  $count_out = $PortObj->write( $output_string );
  warn "write failed\n"         unless ( $count_out );
  warn "write incomplete\n"     if ( $count_out != length( $output_string ) );
  $i--;
}

## close all stuff
$PortObj->close or die "failed to close";
undef $PortObj; ## frees memory back to perl

bis zum eigentlich write-Abschnitt werden einige Werte gesetzt und überprüft (möglich, dass sich hier schon Fehler eingeschlichen haben). Diese Initialisierungssequenz gilt auch für die entsprechende read-Anweisung.

Für das Lesen von der seriellen Schnittstelle gibts in den einzelnen Modulen/dlls natürlich auch jede Menge Funktionen, wie read() oder ReadFile. Das entsprechende read()-Beispiel zum oberen write()-File sieht dann folgendermaßen aus (Init. und close() hier weggelassen):
Code: (dl )
1
2
3
4
5
6
## read
$InBytes = 1;
my ( $count_in, $string_in );
( $count_in, $string_in ) = $PortObj->read( $InBytes );
print "count: $count_in\nin: $string_in\n";
warn "read unsuccessful\n" unless ( $count_in == $InBytes );


Wie schon gesagt funktioniert das leider nicht. Auch die anderen Read-Funktionen, der unterschiedlichen Module bringen keine Ergebnisse. write und read Funktionen werden in einem Beispiel auch nur aus dem selben Modul verwendet, kein MischMasch!
Ich denke ich muss vor dem lesen bestimmte Event-Flags abwarten, wie z.B InputBuffer80%Full.
Leider habe ich da keine Beispiele gefunden, die das Auslesen der seriellen Schnittstelle oder das Nutzen der Events in diesem Zusammenhang behandlen oder gar gut dokumentieren.

Hat das schon mal jemand gemacht?! Wie nutz ich die Flags, wie kann ich die Schnittstelle auslesen, damit ich auch wirklichen das Zeichen reinkrieg, welches gerade an der Schnittstelle aufläuft?
kristian
 2005-09-24 13:35
#58379 #58379
User since
2005-04-14
684 Artikel
BenutzerIn
[Homepage] [default_avatar]
Hallo
Versuchs mal mit:
Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
while(1){
$ca++;
($BlockingFlags,$InBytes,$OutBytes,$ErrorFlags) = $PortObj->status;
die "lost port\n" unless defined $ErrorFlags;
unless($InBytes){
last if($ca > 25);
select(undef,undef,undef,0.01);
next;
}
if($string_in = $PortObj->read($InBytes)){
# hat geklappt mach was
last;
}
}

Du darfst nicht erwarten dass die Hardware am Port so schnell ist, wie du sie gerne hättest. Daher die 25 Wiederholungen in dem Beispiel. mit select() wird hier gebremst. Das ist manchmal eine Geduldsprobe, bis man den Speed abgeglichen hat.
Gruß Kristian
<< >> 2 Einträge, 1 Seite



View all threads created 2005-09-23 13:23.