http://qs321.pair.com?node_id=11130992

mastertone has asked for the wisdom of the Perl Monks concerning the following question:

I am communicating with equipment on a USB COM port using USB-RS485 serial port adapter using Win32::SerialPort A CMD message of six bytes is sent to Equipment, which responds with ACK message.

However, I have trouble reading the ACK messsage returned from Equipment from the COM port. I have used  $PortObj->input; $PortObj->lookfor();  $PortObj->read() to retrieve the string from COM port, but it does not show up.

Port characteristics are: Datarate = 115200 bps, 1 start bit, 8 databits, 1 stop bit, odd parity. 1 Byte = 11 bits. Each 11-bit byte has duration 11/115200 = 95.49 us. Timing is approx: 0.5msec: CMD message six bytes duration, 2 msec later ACK message, 2msec ACK message duration. 20 msec between successive CMD messages.

Nearly any combinations of values on  $PortObj->read_interval(), $PortObj->read_char_time(), $PortObj->read_const_time() times, but it does not read the the COM port. I tried these methods and they do not read COM port, and gives in Error messages,

: CMD 01 61 00 00 01 61 Second Read attempted before First is done at serial_io.pl line 20. Use of uninitialized value $got in numeric ne (!=) at C:/appl/strawber +ry64/perl/site/lib/Win32/SerialPort.pm line 1560. : ACK
Also, is the command 20 millisec between port writes sleep( 0.020 ) a problem? Any advice how to read COM port? - Mastertone "Longtime Reader, First time poster"

#!C:\appl\strawberry64\perl\bin use strict; use warnings 'all'; use Win32::SerialPort; use Time::HiRes qw (time sleep); use Data::Dumper; my $PortObj_r = &com_port_initialize() ; my @byte = (0x01, 0x61, 0x00, 0x00, 0x01, 0x61 ); my $str = ": CMD "; foreach ( @byte ) { $str .= sprintf(" %02X", $_)}; my $string_in; my $count_in; while () { my $PortObj_r = &get_PortObj; # Call Port Obj # my $PortObj = $$PortObj_r; print "$str \n"; foreach my $num ( @byte ) { $PortObj->transmit_char($num) } $string_in = $PortObj->input; # Error: Line 20 ** # # $string_in = $PortObj->lookfor(); # Error: Line 21 ** # # ($count_in, $string_in) = $PortObj->read(1); # Error: Line 22 # print ": ACK "; print $string_in; print "\n"; sleep( 0.020 ); # 20 millisec between writes undef $PortObj; } # ----------------------------------------- sub get_PortObj { $PortObj_r; } # -------------------------------------------------------- # PortObject Definiton # -------------------------------------------------------- sub com_port_initialize { my $quiet = 1; $| = 1; my $PortName = "COM10"; my $PortObj = new Win32::SerialPort ($PortName, $quiet) || die "Error: Can't open $PortName: $^E\n"; print "> PortName = ", $PortObj->alias, "\n"; my $dataRate = 115200; my $read_bufferSize = 4096; my $write_bufferSize = 4096; my $char11_t = (11/$dataRate) ; # 95.49 us = 0.095 msec my $readChar_t = 1 ; # in millisec; char11_t my $readConst_t = 2; # read_const_time my $readInterval_t = 10; my $writeCharTime = 1; my $writeConstTime = 0; $PortObj->handshake("none"); $PortObj->user_msg("ON"); $PortObj->baudrate($dataRate); $PortObj->databits(8); $PortObj->parity("odd"); $PortObj->stopbits(1); $PortObj->binary('T'); $PortObj->parity_enable('T'); $PortObj->debug(0); $PortObj->buffers($read_bufferSize, $write_bufferSize); $PortObj->read_interval($readInterval_t ); $PortObj->read_char_time($readChar_t ); $PortObj->read_const_time($readConst_t); $PortObj->write_char_time($writeCharTime); $PortObj->write_const_time($writeConstTime); $PortObj->write_settings || undef $PortObj; my $ModemStatus = $PortObj->modemlines; if ($ModemStatus & $PortObj->MS_RLSD_ON) { print "> Carrier Detect +ed"; } open OUTFILE, ">portObj.txt" or die "Error: Cannot open portObj.txt $!\n"; print OUTFILE "> PortObj = ", Dumper \\$PortObj; close OUTFILE; \$PortObj; # return reference to $PortObj }

Replies are listed 'Best First'.
Re: How to read serial port with Win32::SerialPort?
by Discipulus (Canon) on Apr 08, 2021 at 06:18 UTC
    Hello mastertone and welcome to (the number of writers in) the monastery!

    Maybe unrelated but as you are on Windows and using a 64bit perl (assuming this from the path name) you might be interested in Win32::SerialPort finally fixed for 64 bit Perl leading to this fix.

    Also show the Win32::SerialPort version you are using, even if the last version in CPAN is 6 years holder than the above mentioned fix, so.. :)

    L*

    There are no rules, there are no thumbs..
    Reinvent the wheel, then learn The Wheel; may be one day you reinvent one of THE WHEELS.
      Maybe unrelated but as you are on Windows and using a 64bit perl (assuming this from the path name) you might be interested in Win32::SerialPort finally fixed for 64 bit Perl leading to this fix.

      I can confirm that I can reproduce the bug using the OP's code with the $PortObj->read(1) method on a 64-bit Strawberry Perl, but the same code does not produce the error on a 32-bit version.

Re: How to read serial port with WIN32:SerialPort?
by xiaoyafeng (Deacon) on Apr 12, 2021 at 02:48 UTC

    Hi mastertone,

    Several years ago, I did some work to connect terminal server on windows by this module. mostly Win32::SerialPort workds well, except 2 issues:
    1. on 64bit windows box, the structure of serial port changes, if you use the modules on win64, you have to apply a patch on cpan( sorry I can't reach metacpan.)
    2. when com port number larger than 9, you have to specify the name as this format" \\.\COM10". since I note you use COM10 in your script. Please refer to this node

    BTW:this module does work done, but the author use old Win32::API which has been buggy and itself unmaintained for long time, anyone want to pick it up? I think serial port is still used widely.





    I am trying to improve my English skills, if you see a mistake please feel free to reply or /msg me a correction

Re: How to read serial port with WIN32:SerialPort?
by jmlynesjr (Deacon) on Apr 09, 2021 at 02:54 UTC

    I've only used Device::SerialPort under Linux, but, your stated data format looks funny. 1 start bit is ok. 1 stop bit is ok. 8 data bits dictates no parity, not odd parity. Serial data bytes are 8 bits, not 11.

    Sample code:

    # Perl Polling Test # Title: Perl to chipKIT Serial Poll Test # Author: James M. Lynes, Jr. # Version: 1.0 # Creation Date: June 10, 2012 # Modification Date: June 10, 2012 use strict; use warnings; # Initialize the serial port - creates the serial port object $Arduino use Device::SerialPort::Arduino; my $Arduino = Device::SerialPort::Arduino->new( port => '/dev/ttyUSB0', baudrate => 9600, databits => 8, parity => 'none', ); while(1) { $Arduino->communicate('P'); # Send a poll print ($Arduino->receive(), "\n"); # Print poll respons +e sleep(1); # Delay until next p +oll }
    package Device::SerialPort::Arduino; use strict; use warnings; use Time::HiRes; use Carp; use Device::SerialPort; use vars qw($VERSION); our $VERSION = '0.07'; sub new { my $class = shift; my $self = bless {}, $class; my %init = @_; # Sets many parameters for Device::SerialPort usage $self->{'port'} = $init{'port'}; $self->{'baudrate'} = $init{'baudrate'}; $self->{'databits'} = $init{'databits'}; $self->{'parity'} = $init{'parity'}; $self->{'stopbits'} = $init{'stopbits'}; $self->initialize(); return $self; } sub initialize { my $self = shift; $self->{'DSP'} = Device::SerialPort->new( $self->{'port'} ) or croak "Can't open " . $self->{'port'} . " - $!\n";

    James

    There's never enough time to do it right, but always enough time to do it over...

      your stated data format looks funny. 1 start bit is ok. 1 stop bit is ok. 8 data bits dictates no parity, not odd parity. Serial data bytes are 8 bits, not 11.

      That's not quite correct. With a PC-standard serial port (i.e. 8250, 16450, 16550, and generations of clones embedded in various chipsets), you can freely choose any combination of 5 to 8 data bits, 1 or 2 stop bits, and None, Even, or Odd parity. There is always only one start bit. Combined, the minimum number of bits in one serial frame is used in 5N1, i.e. one start bit, 5 data bits, No parity bit, 1 stop bit, for a total of only 7 bit. The maximum number is 8E2 or 8O2, i.e. one start bit, 8 data bits, 1 parity bit (even or odd), 2 stop bits, for a total of 12 bit. (Note: Nobody uses the total number of bits. Only the number of data and stop bits are specified.)

      5 data bits are nearly exclusively used for old teletypes, I've never seen anything using 6 data bits, 7 and 8 data bits are quite common for general communication. 7 data bits are often used with parity, 8 data bits are often used without parity, but as I wrote: data bits and parity bits can be used in any combination.

      When using other serial ports (e.g. on embedded systems), you can often also select mark or space in place of the parity bit (i.e. fixed 0 or fixed 1). Some UARTs also support 9 data bits, just to confuse you further. Also, 1.5 stop bits are possible, but rare.

      See also Serial port.

      Update: Mark and Space in place of the parity bit is supported by PC-standard serial ports, so you can choose from None, Even, Odd, Mark, Space for the parity bit. Some embedded controllers do not support mark and space for the parity bit.

      Alexander

      --
      Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)

        Alexander:

        Thanks for the response. It prompted me to do a lot of reading.

        Showing my age, parity was always the MSB of an 8-bit byte. There also appears to be an unfortunate reuse of the term "parity". In some implementations of RS-485 systems, the 9th "parity" bit is used to key the end nodes that the current byte is an address(see MAX 3140 datasheet). This allows the end node to quickly determine if the message is for it without having to decode the packet.

        This 9th bit is generated internally by the UART based on the value of the parity bit. So, which parity bit is the Perl modules dealing with? And do the modules allow this definition to be changed at will to drive the address function out onto the RS-485 bus?

        Interesting topic.

        James

        There's never enough time to do it right, but always enough time to do it over...