1

My project is very complicated, but here is a visual synthesis

enter image description here

The input actually comes from a kinect, that detects a person position through Processing, which I connected via Serial to Arduino. Whenever my trigger is activated, a character is sent to arduino. What I need to make everything work properly is, upon the said input, some lines of code have to be executed once and for a specific amount of time. And upon repeated input, these lines must not be executed until the input changes.

A semplified version would be: I press a button, led turns on for one second and then turns off (even if i'm still pressing it). led doesn't turn on again until i stop pressing and press again. Obviously in my project the input is the character received via serial and the output is the motor to turn on for some time, and then turn off.

I wanted to make the serial thing specific because i think it makes the thing a little bit trickier than the led example.

1
  • Your button analogy falls apart immediately when you try to convert it to serial. Could you delete it, please, and explain exactly how you want it to behave, considering that characters being received on the serial port are discrete events?
    – Mark Smith
    Feb 12, 2017 at 10:07

2 Answers 2

1

Well, te problem is actually the same provided that you write correctly the first program.

How did you solve the button problem? My suggestion is to use a simple state machine:

const byte ledPin = 13;
const byte buttonPin = 2;

const int onTimeMs = 1000; // The time the led should be on

// In this state the board waits
// for the user input
#define STATE_WAITING 0
// In this state the button was
// pressed (so the led is on)
#define STATE_PRESSED 1
// In this state the board is waiting
// for the button to be released
#define STATE_WAITREL 2

byte currState;
unsigned long pressTime;

void setup() {
  pinMode(ledPin, OUTPUT);
  pinMode(buttonPin, INPUT_PULLUP);
  currState = STATE_WAITING;
}

void loop() {
    switch (currState)
    {
    case STATE_WAITING:
        if (digitalRead(buttonPin) == LOW)
        {
            digitalWrite(ledPin, HIGH);
            pressTime = millis();
            currState = STATE_PRESSED;
        }
        break;
    case STATE_PRESSED:
        if ((millis() - pressTime) > onTimeMs)
        {
            digitalWrite(ledPin, LOW);
            currState = STATE_WAITREL;
        }
        break;
    case STATE_WAITREL:
        if (digitalRead(buttonPin) == HIGH)
            currState = STATE_WAITING;
        break;
    }
}

In this case you can be in three states: waiting for the button press, waiting for the led to turn off (after one second) and waiting for the user to release the button.

So... The states remain the same even for the serial input, you just have to trigger the transitions in another way. The only problem is that the serial input is not continuous, so you have to determine what you mean by "stop sending". In my opinion, you can just set a timeout. The simplest way to achieve this is with this code, IMHO:

const byte ledPin = 13;
const char cmdChar = 'x';

const int onTimeMs = 1000; // The time the led should be on
const int timeoutCmdChar = 50; // The time the char should be off

// In this state the board waits
// for the user input
#define STATE_WAITING 0
// In this state the character was
// received (so the led is on)
#define STATE_RECEIVED 1
// In this state the board is waiting
// for the char to be absent
#define STATE_WAITABS 2

byte currState;
unsigned long recvTime;

unsigned long lastTimeCmdChar;

void setup() {
    pinMode(ledPin, OUTPUT);
    Serial.begin(9600);
    currState = STATE_WAITING;
}

void loop() {
    bool cmdCharReceived = false;
    while (Serial.available())
    {
        if (Serial.read() == cmdChar)
        { // Received the character
            cmdCharReceived = true;
            lastTimeCmdChar = millis();
        }
    }

    switch (currState)
    {
    case STATE_WAITING:
        if (cmdCharReceived)
        {
            digitalWrite(ledPin, HIGH);
            recvTime = millis();
            currState = STATE_RECEIVED;
        }
        break;
    case STATE_RECEIVED:
        if ((millis() - recvTime) > onTimeMs)
        {
            digitalWrite(ledPin, LOW);
            currState = STATE_WAITABS;
        }
        break;
    case STATE_WAITABS:
        if ((millis() - lastTimeCmdChar) > timeoutCmdChar)
            currState = STATE_WAITING;
        break;
    }
}
1

you want something along the lines:

bool continuing;
#define trigger 't'
void loop(){
  if( Serial.avaiable()) { 
    char c;
    c=Serial.read();
    if (continuing) { 
       if (c==trigger) { //do nothing, ignore it
       } else { 
       continuing=False; }
   } else { 
     continuing=True;
     motors.start();
     the_time=milis();
   }
 };
 if (the_time+timespan>milis()) {motors.stop();};
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.