Serial Communication between PC E-Prime and Arduino Nano.

Hi,

I am building an experiment within E-Prime, which is a psychology program, where I intend to have primates touch specific shapes. Certain shapes are considered the correct response and upon this they are rewarded with a pellet. The way I have this set up is once a correct response is given E-Prime has been instructed via in-line script to send (Serial.WriteByte 255) to the Arduino, which is listening. Once received the Arduino will pulse a relay that is connected to the pellet feeder. I have tried different things, but can't seem to formulate a sketch to properly do what I want. Any help or suggestions would be greatly appreciated.

Thanks!

Can E-Prime write to a serial port?

What is your Arduino code for reading its serial port?

Which relay are you using?

.

From everything I have search you can write to a serial port in E-Prime 3.0 via in-line script or through "Task Events".

The relay I'm using is one I bought from Amazon: ELEGOO 8 Channel Relay Module 5VDC.

The base sketch I have is the following:

int incomingByte = 0;
int Relay8 = 13;

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

pinMode(Relay8, OUTPUT);

digitalWrite(Relay8, HIGH);
}

void loop() {
if(Serial.available()>0) {
incomingByte = Serial.read();

It is after that point that I can't figure out what is needed. Basically I'm trying to get the Arduino to read for a specific integer such as 1. If its 1 that comes through the serial port then the relay is switched on, but if anything else comes through basically nothing happens.

I am not sure why you need E-Prime.

You should be able to use some sort of touch capacitive sensor Touch sensors: What it is, How it works, Arduino Guide - Latest open tech from seeed studio with the Arduino and then have the Arduino close a relay.

.

E-Prime is the software suite we are using to design and run cognitive experiments in primates. A PCAP touchscreen monitor is placed in front of a primate, which acts as a duplicate screen for a laptop running E-Prime. The experiment in Prime is an SD/SDR program where the primate has to choose the correct image out of three. The correct response is rewarded with a pellet dispensed by the pellet feeder. An incorrect response isn't rewarded and met with a 15sec timeout period where the screen goes dark. What I am trying to do is implement the pellet feeder via relay and an Arduino Nano where the Nano is listening for a correct response from E-Prime. When that happens the Nano pulses the relay causing the pellet feeder to dispense a pellet. This will again and again for a total of 10-15 trials. What I am having trouble doing is writing a sketch in the Arduino IDE to have the Nano listening for serial output from Prime.

The very basics below.

After reading the incoming byte, test its value with an if statement. If it matches the desired value, take action.

int incomingByte = 0;
int Relay8 = 13;

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

  pinMode(Relay8, OUTPUT);
  digitalWrite(Relay8, HIGH);
}

void loop()
{
  if (Serial.available() > 0)
  {
    incomingByte = Serial.read();
    if(incomingByte == 255)
    {
      // activate the relay
      digitalWrite(Relay8, LOW);
      // delay a bit
      delay(500);
      // de-activate relay
      digitalWrite(Relay8, HIGH);
    }
  }
}

The above assumes a relay that is activated when the pin is LOW; I base this on the fact that you set it HIGH in setup() which will de-activate it. If that's the wrong conclusing, swap HIGH and LOW in loop().

Please note that the delay causes blocking code; you can basically not send faster than one byte every 500ms from E-prime.

Please be aware that the Nano might/will reset when you open the serial port; it depends how E-prime handles that. This reset will result in a delay between sending the command and the actual activation of the relay.

You are correct that when HIGH it is deactivated.

Also, the delay shouldn't be a problem since there is roughly a 5-10sec timeout period after a pellet is dispensed, so it should have plenty of time to reset itself before the primate is allowed to proceed to the next trial.

I tested it with my program and it works great, but I do have a question regarding start up. When I start the program it causes the Arduino to switch the relay from HIGH - LOW - HIGH where the relay finally is deactivated waiting for a response. Is there any way to handle that or it is simply a matter of the program opening the serial port upon experiment start?

Swap the pinMode and digitalWrite lines in setup().

Ah thank you! Took a couple resets for it to actually work, but does so now. I appreciate the help!!

Do have another question. Currently with it set to sending a byte is there a way to send a char such as a or b? Basically with how its currently coded I can't test using the serial monitor on Arduino's site. All I can do now is to boot up E-Prime and run an experiment to test.

Why can't you test using Serial Monitor?

Anyway, the below line tests the received byte

if(incomingByte == 255)

Change it to e.g.

if(incomingByte == 'a')

to test for the lowercase letter a

Note on your code
incomingByte can be declared as a byte or char; it doesn't need be an int. Serial.read() returns an int, possible values 0..255 and -1. The -1 indicates that there was nothing to read. But you already check that with Serial.available() so no need for the int.

Some reason when I send 255 through on the serial monitor nothing happens. I know it works because when I run it with the experiment everything operates as it should. So I'm not sure why that its happening and why I had asked the previous question.

I also only made incomingByte an int because Arduino was showing it as such on an example from their site. I wasn't sure why they did that, but thought I would include it. I'm new to doing things like this and am learning as I go so I appreciate any and all feedback. I will get rid of that to free up space.

255 in serial monitor is text; 255 in E-prime is a number (see below from your opening post). You can't type binary numbers in Serial Monitor.

E-Prime has been instructed via in-line script to send (Serial.WriteByte 255) to the Arduino

I do not know what you can do in E-prime; if there is something like Serial.print to print a text, you could use Serial.print("255") which will send the text 255 from E-prime and will equally not work.

You can use a terminal program that can send binary numbers (e.g. RealTerm under Windows) instead of Serial Monitor for testing purposes.

There are solutions at the Arduino side to convert text to number if you need that.

int incomingByte = 0;
int Relay8 = 13;

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

  pinMode(Relay8, OUTPUT);
  digitalWrite(Relay8, HIGH);
}

void loop()
{
  if (Serial.available() > 0)
  {
    incomingByte = Serial.read();
    if(incomingByte == 255)
    {
      // activate the relay
      digitalWrite(Relay8, LOW);
      // delay a bit
      delay(500);
      // de-activate relay
      digitalWrite(Relay8, HIGH);
    }
  }
}

The code above works, but I am having issues. When I have the pellet feeder attached to the relay and the Arduino sends a pulse I am getting two pellets instead of one. It appears to be triggered when the relay switches LOW as well as when it goes back to HIGH. Is there a way to handle this?

To eliminate E-prem as a possible cause, use serial monitor and modify the code to e.g. react on an ‘a’. If the behaviour is the same, keep using serial monitor for debugging purposes.

In setup(), add a print statement to indicate that your code is started; if you see the message after sending an ‘a’, it indicates that the Arduino resets; this is not a code issue.

Which relay / relay module are you using? Please provide a wiring diagram (photo of hand drawn one is OK).

I modified the code to accept ‘a’ and when I tested in serial monitor I still get the double feed.

I also put the Serial.print line indicating “Start” within setup() and after sending ‘a’ nothing else appears, so I assume from your statement that it is not resetting.

The relay module I am using is 8 Channel Relay Module by ELEGOO from Amazon. It has the SONGLE SRD-05VDC-SL-C mechanical relays which have NO,C,NC.

Not my area so excuse the diagram for being crude. Hopefully its understandable.

Diagram.png

Relays do bounce, so maybe that's the cause of the double feeding.

I don't know whose image this is, but below shows how to wire the relay using an external power supply; it's posted on the forum somewhere.

A relay draws quite a bit of current so feeding it from the Arduino can have a side effect as the Arduino can't supply much; it's not my area of expertise but I know that it is the better way of wiring it.

Although it might not be the cause of the problem, it's worth a shot to use an external power supply.

I can def try, but I forgot to mention that I will only be using 1 relay out of the 8. I don't know if that would make a difference for what you are referencing since the draw from just 1 relay should be well within the Arduino's capability.

From my (minimal) testing experience with a double relay board (smaller version of yours) in a setup with a LCD on an Arduino, the LCD dims a little when one relay is activated and quite a bit when both are activated.

I agree that it will probably not help, but not tried is always missed (or whatever the exact English saying is).

After that I'm probably out of here as I don't know a solution.

I appreciate the help and what I have will work to get us started, but would eventually like to work the kinks out.

You had mentioned something about bounce and I know there is a “Debounce” example under “02.Digital” and was wondering if implementing something like this would help? If so how would I go about doing that. The example is using a pushbutton so I’m not really sure how to translate it over to my situation.

/*
  Debounce

  Each time the input pin goes from LOW to HIGH (e.g. because of a push-button
  press), the output pin is toggled from LOW to HIGH or HIGH to LOW. There's a
  minimum delay between toggles to debounce the circuit (i.e. to ignore noise).

  The circuit:
  - LED attached from pin 13 to ground
  - pushbutton attached from pin 2 to +5V
  - 10 kilohm resistor attached from pin 2 to ground

  - Note: On most Arduino boards, there is already an LED on the board connected
    to pin 13, so you don't need any extra components for this example.

  created 21 Nov 2006
  by David A. Mellis
  modified 30 Aug 2011
  by Limor Fried
  modified 28 Dec 2012
  by Mike Walters
  modified 30 Aug 2016
  by Arturo Guadalupi

  This example code is in the public domain.

  http://www.arduino.cc/en/Tutorial/Debounce
*/

// constants won't change. They're used here to set pin numbers:
const int buttonPin = 2;    // the number of the pushbutton pin
const int ledPin = 13;      // the number of the LED pin

// Variables will change:
int ledState = HIGH;         // the current state of the output pin
int buttonState;             // the current reading from the input pin
int lastButtonState = LOW;   // the previous reading from the input pin

// the following variables are unsigned longs because the time, measured in
// milliseconds, will quickly become a bigger number than can be stored in an int.
unsigned long lastDebounceTime = 0;  // the last time the output pin was toggled
unsigned long debounceDelay = 50;    // the debounce time; increase if the output flickers

void setup() {
  pinMode(buttonPin, INPUT);
  pinMode(ledPin, OUTPUT);

  // set initial LED state
  digitalWrite(ledPin, ledState);
}

void loop() {
  // read the state of the switch into a local variable:
  int reading = digitalRead(buttonPin);

  // check to see if you just pressed the button
  // (i.e. the input went from LOW to HIGH), and you've waited long enough
  // since the last press to ignore any noise:

  // If the switch changed, due to noise or pressing:
  if (reading != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }

  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer than the debounce
    // delay, so take it as the actual current state:

    // if the button state has changed:
    if (reading != buttonState) {
      buttonState = reading;

      // only toggle the LED if the new button state is HIGH
      if (buttonState == HIGH) {
        ledState = !ledState;
      }
    }
  }

  // set the LED:
  digitalWrite(ledPin, ledState);

  // save the reading. Next time through the loop, it'll be the lastButtonState:
  lastButtonState = reading;
}