Perl Win32 Arduino

Hello Group!

I've been using an Arduino Uno for over a year now and I've been a Perl programmer since highschool and I've recently starting to incorporate my Arduino and my Perl scripts together with some amazing results. I usually try and work on a project until it is completed with out asking for any help however that is why I am now a registered forum member. So here goes nothing. I can successfully send commands to my Arduino from my Perl script however I am trying to read information being sent from the Arduino and using that information to execute other commands in the Perl script. I am stuck. I know the information is being sent as I open the serial monitor on the Arduino software and issue a command and based on that command I see the result. The result is not being parsed correctly by my Perl script. I've posted code of both the Ardiuno Sketch as well as the Perl code. Thanks in advanced for the help!

Arduino Code:

int buttonPin   = 2;     // the number of the pushbutton pin
int ledPin      = 13;    // the number of the LED pin
int buttonState = 0;     // variable for reading the pushbutton status

int sigoneRed      = 12;
int sigoneYellow   = 11;
int sigoneGreen    = 10;
int sigtwoRed      = 9;
int sigtwoYellow   = 8;
int sigtwoGreen    = 7;
int sigthreeRed    = 6;
int sigthreeYellow = 5;
int sigthreeGreen  = 4;

void setup() {
  
Serial.begin(9600);

pinMode(sigoneRed,      OUTPUT);
pinMode(sigoneYellow,   OUTPUT);
pinMode(sigoneGreen,    OUTPUT);
pinMode(sigtwoRed,      OUTPUT);
pinMode(sigtwoYellow,   OUTPUT);
pinMode(sigtwoGreen,    OUTPUT);
pinMode(sigthreeRed,    OUTPUT);
pinMode(sigthreeYellow, OUTPUT);
pinMode(sigthreeGreen,  OUTPUT);

// initialize the LED pin as an output:
  pinMode(ledPin, OUTPUT);   
  
// initialize the pushbutton pin as an input:
  pinMode(buttonPin, INPUT); 

}
 
char in;
 
void loop() {

buttonState = digitalRead(buttonPin);

if (buttonState == HIGH) {    
   
// TEST ALL SIGNAL LEDS ON: 

digitalWrite(ledPin,         HIGH); 
digitalWrite(sigoneRed,      HIGH);
digitalWrite(sigtwoRed,      HIGH);
digitalWrite(sigthreeRed,    HIGH);
digitalWrite(sigoneYellow,   HIGH);
digitalWrite(sigtwoYellow,   HIGH);
digitalWrite(sigthreeYellow, HIGH);
digitalWrite(sigoneGreen,    HIGH);
digitalWrite(sigtwoGreen,    HIGH);
digitalWrite(sigthreeGreen,  HIGH);
Serial.println("TEST ALL SIGNAL LEDS ON");

delay(10000);

digitalWrite(ledPin,         LOW); 
digitalWrite(sigoneRed,      LOW);
digitalWrite(sigtwoRed,      LOW);
digitalWrite(sigthreeRed,    LOW);
digitalWrite(sigoneYellow,   LOW);
digitalWrite(sigtwoYellow,   LOW);
digitalWrite(sigthreeYellow, LOW);
digitalWrite(sigoneGreen,    LOW);
digitalWrite(sigtwoGreen,    LOW);
digitalWrite(sigthreeGreen,  LOW);
Serial.println("TEST ALL SIGNAL LEDS OFF");
} 
  
if(Serial.available() > 0) {
int in = Serial.read();
 
switch(in) {
case 't':
digitalWrite(ledPin,         HIGH); 
digitalWrite(sigoneRed,      HIGH);
digitalWrite(sigtwoRed,      HIGH);
digitalWrite(sigthreeRed,    HIGH);
digitalWrite(sigoneYellow,   HIGH);
digitalWrite(sigtwoYellow,   HIGH);
digitalWrite(sigthreeYellow, HIGH);
digitalWrite(sigoneGreen,    HIGH);
digitalWrite(sigtwoGreen,    HIGH);
digitalWrite(sigthreeGreen,  HIGH);
Serial.println("ON");
delay(8000);
digitalWrite(ledPin,         LOW); 
digitalWrite(sigoneRed,      LOW);
digitalWrite(sigtwoRed,      LOW);
digitalWrite(sigthreeRed,    LOW);
digitalWrite(sigoneYellow,   LOW);
digitalWrite(sigtwoYellow,   LOW);
digitalWrite(sigthreeYellow, LOW);
digitalWrite(sigoneGreen,    LOW);
digitalWrite(sigtwoGreen,    LOW);
digitalWrite(sigthreeGreen,  LOW);
Serial.println("OFF");
break;

default:
Serial.println("Invalid Character");
break;

}
}
}

Perl Code:

use strict;
use warnings;
use Win32::SerialPort;

my $port = Win32::SerialPort->new("COM7") or die "Open Port Failed. $!\n";
$port->is_rs232;

# SET UP THE SERIAL PORT 9600, 81N ON THE USB FTDI DRIVER

$port->initialize();
$port->baudrate(9600);
$port->databits(8);
$port->parity("none");
$port->stopbits(1);
$port->write_settings || undef $port;
#$port->are_match("\r\n");

sleep(3);

print STDOUT "\n$time Signal Driver Starting....\n";

my $testall = "t";
$port->write($testall);

my $data;

$port->lookclear;

while(1) {

$data = $port->lookfor();

if ($data) {
print STDOUT "$time Signal Driver Message Received: (" . $data . ")\n";
return;
}


if ($data =~ /OFF/) {
print STDOUT "$time Signal Driver Message Received: (" . $data . ")\n";
return; 
}

}     

return;

What I expect to see is when OFF is received I can have the perl script execute another command. So far it has not. Thanks again for pointing me in the right direction.

Looks to me like you're looking for a string that contains ONLY "OFF", but what you're sending is "TEST ALL SIGNAL LEDS OFF". You RegEx should account for the extra characters, even if it ignores them.

Have you printed what is in $data before doing the RegEx?

Regards,
Ray L.

Hello Ray,

Thanks for the quick reply. The area of concentration is: case "t" and the perl code is looking for the word OFF as the key to trigger another command...turning a Perl/Tk button on a GUI app a shaded color when the LEDs go Off....when the Green LEDs are on the Button is Shaded Green...this part works....when the LEDs turn OFF the Green Shaded Button goes "gray" or "dark"....or it should. This is the area I am having trouble with.

How are you ever going to reach the test for "OFF", when you have a return in the first if, which I assume will be executed any time $data is not null?

Regards,
Ray L.

I removed the return and the script hangs during the while(1) statement....it does read the word OFF and makes the changes....however this IS after the time delay of when the LEDs go LOW and not simultaneously...if that makes sense

The only place I see in the loop that could possibly hang is in the $port->lookfor(). Add print statements that give you a "trace of what's happening, perhaps adding a delay in the while(1) to keep the console from getting over-whelmed.

Personally, I would not use lookfor - I would simply read characters, using whatever non-blocking character read function SerialPort provides, and gather the string myself. That way, you can parse on-the-fly, add a timeout, etc. lookfor() may simply block until it receives a terminator.

Regards,
Ray L.

I think I found the problem. When the delay(8000) of 8 seconds takes place it does not transmit anything out of the Arduino to the Perl script that is waiting to receive a transmission from the Arduino. In other words when I press a GUI button on the Perl script both the TX and RX lights on the Arduino board flash. When the delay(8000) has reached its time nothing is being transmitted. However when I press the button again the second If statement in the Perl script is invoked. This function needs to take place after the delay(8000) automatically. Suggestions on how to accomplish this?

Ok so what I need is to figure out how to keep "polling" and to clear the "buffer" the Arduino with the Perl code in order to find "OFF" and issue a command based on that trigger and that is where I am stuck at. Any ideas? I cannot find if there is such a command using Win32::SerialPort.