Go Down

Topic: count ch button presses without overlap (Read 173 times) previous topic - next topic

BKK

I am trying to use the CH button on an IR remote to increment a variable by 1, count to 4 then reset to 0

the count needs to happen inside of an ISR, so I tried "delay(#)" and I also found millis does not work inside an ISR

the problem is that the system is dynamic, so delaying the button from incrementing cant really be done with a timer

when I push the button, no matter how quickly I try to do it, it increments at least 17 counts, I assume the program is looping through that fast.

here is a solution I got to work, but it is a little obtuse since it takes a while to begin, then it increments but not as predictably as I would like.

I think I am going to add a LED flash to tell the status (number) of the variable "CHButtonCounter" but is there a more sure way so the feedback is not necessarily needed?

thanx in advance, BKK

Code: [Select]

///Libraries///
#include <IRremote.h>                   // insert IRremote.h library

// IR pin connection
#define IRPin 2 // D2 IR Receiver output on D2 interrupt 1 pin

//interrupt set up
const byte interruptPin = 2;

//Blue position LED's
#define BlueLed1 A0  // blue LED in position A2 pin
#define BlueLed3 A3  // blue LED in position A3 pin
#define BlueLed5 3  // blue LED in position D3 pin
#define BlueLed7 A4  // blue LED in position A4 pin
#define BlueLed9 A5  // blue LED in position A5 pin on 6 pin header

//IR Remote button codes
#define IRButtonCH 16736925
#define IRButton1 16724175
#define IRButton3 16743045
#define IRButton5 16726215
#define IRButton7 16728765
#define IRButton9 16732845
#define RepeatValue 4294967295  //value broadcast by remote when button is held down


// IR Remote
IRrecv irrecv(IRPin);                 //define IR PIN for infrared receiver
volatile decode_results results;                  //define variable results to save the result of infrared receiver added volatile because it is interrupt routine
volatile int CHButtonCounter = 0 ;   // was 1 counter for the number of ch button presses volatile because it is in interrupt routine
volatile long LastButtonValue = 0;     // previous state of the button, holds value so it can compare if the remote button is held down volatile because it is in interrupt routine


//baud rate
#define BaudRate 9800  //was 115200

volatile char LedID = BlueLed5;
volatile int SkipCHcount = 0;

void setup()
{
  //IR receiver
  irrecv.enableIRIn();                      //Boot infrared decoding
  pinMode(IRPin, INPUT);                    // set pin to receive

  Serial.begin(BaudRate);

  //interupt setup
  attachInterrupt(digitalPinToInterrupt(interruptPin), IRinput, CHANGE);
}  //end setup

void loop() {

  Serial.println(CHButtonCounter);     // turn off and on to print value for trouble shooting, plot output to see representation of control

}//loop end

////////////////////////Functions//////////////////

//get IR input
void IRinput() {
  if (irrecv.decode(&results)) {
    if (results.value == RepeatValue)
      LastButtonValue = LastButtonValue;
    else
      LastButtonValue = results.value;
    irrecv.resume(); // Receive the next value
  }
  SkipCHcount = SkipCHcount + 1;
  if (SkipCHcount > 75) SkipCHcount = 1;
  if (SkipCHcount == 1) {
    //if CH is pressed, increment up until 5 which doesnt exist so resets to 1
    if (LastButtonValue == IRButtonCH) {  // if CH is pushed
      CHButtonCounter = CHButtonCounter + 1; //Ch button counter is incremented
    } //end if
    if (CHButtonCounter > 4) CHButtonCounter = 0;
  } //end if
}


larryd

#1
Nov 25, 2017, 03:19 am Last Edit: Nov 25, 2017, 03:19 am by larryd
It is seldom necessary to use interrupts for slow events, suggest you avoid using one.

ISRs should be simple and the code small.
Set a flag then handle things outside the routine.

Most remotes send repeat codes with buttons held.


.
No technical PMs.
The last thing you did is where you should start looking.

BKK

#2
Nov 25, 2017, 03:56 am Last Edit: Nov 25, 2017, 04:03 am by BKK
I am handling the repeat code with a different method which is working since I just want the value of the button, even if it enters that value 17 times it doesn't matter because it is still correct. My guess is the button push duration even for a single send from the remote is spanning 17 iterations through the loop and considering them different events

I tried to get the IR to read without the ISR, and it ignored the ir. I see what you're saying to move the if's outside the ISR, but how can I handle the button repeat I am seeing without a timer? If I use a timer won't that also affect the balancing routine?

this is just a segment of the full code, where the print command is in the code above, there is a PID balancing routine that balances a steel ball on a flat plate. sorry that wasn't clear.

here is where it will reside in the full program

Code: [Select]
void loop() {
  while (Stable < 125) //REGULATION LOOP
  {
    TSPoint p = ts.getPoint();   //measure pressure on plate
    if (p.z > ts.pressureThreshhold) //ball is on plate
    {
      servo1.attach(ServoX); //connect servos
      servo2.attach(ServoY);
      setTrajectory();
      noTouchCount = 0;  //timer value for ball not present
      TSPoint p = ts.getPoint(); // measure actual position
      Input = (p.x * convertX); // read and convert X coordinate
      Input1 = (p.y * convertY); // read and convert Y coordinate
      if ((Input > Setpoint - 2 && Input < Setpoint + 2 && Input1 > Setpoint1 - 2 && Input1 < Setpoint1 + 2)) //if ball is close to setpoint
      {
        Stable = Stable + 1; //increment STABLE
        digitalWrite(LedID, HIGH); // if its stable lights led 9
      }
      else
      {
        digitalWrite(LedID, LOW);  //if not stable turns off led 9
      }
      myPID.Compute();  //action control X compute
      myPID1.Compute(); //   action control  Y compute
    }
    else //if there is no ball on plate
    {
      noTouchCount++; //increment no touch count
      if (noTouchCount == 75)
      {
        noTouchCount++;
        Output = 95; //make plate flat
        Output = 95;
        servo1.write(Output + AdjustXservo);
        servo2.write(Output1 + AdjustYservo);
        digitalWrite(LedID, HIGH);
      }
      if (noTouchCount == 150) //if there is no ball on plate longer
      {
        servo1.detach(); //detach servos
        servo2.detach();
      }
    }
    servo1.write(Output + AdjustXservo);//control
    servo2.write(Output1 + AdjustYservo);//control
    //  Serial.print(Setpoint);   Serial.print(",");  Serial.print(Setpoint1);  Serial.print(",");  Serial.print(Input);Serial.print(","); Serial.println(Input1);
    //Serial.println(CHButtonCounter);     // turn off and on to print value for trouble shooting, plot output to see representation of control
  }
  ////END OF REGULATION LOOP///

  servo1.detach();//detach servos
  servo2.detach();
  ///KONTROLA STABILITY////
  while (Stable == 125) //if is stable
  { //still measure actual postiion
    setTrajectory();
    TSPoint p = ts.getPoint();
    Input = (p.x * convertX); //read X
    Input1 = (p.y * convertY); //read Y
    if (Input < Setpoint - 2 || Input > Setpoint + 2 || Input1 > Setpoint1 + 2 || Input1 < Setpoint1 - 2  ) //if ball isnt close to setpoint
    {
      servo1.attach(ServoX); //again attach servos/     
      servo2.attach(ServoY);
      digitalWrite(LedID, LOW);
      Stable = 0; //change STABLE state
    }
  }//end of STABLE LOOP
}//loop end

////////////////////////Functions//////////////////

//get IR input
void IRinput() {
   if (irrecv.decode(&results)) {
    if (results.value == RepeatValue)
      LastButtonValue = LastButtonValue;
    else
      LastButtonValue = results.value;
    irrecv.resume(); // Receive the next value
  }
  SkipCHcount = SkipCHcount + 1;
  if (SkipCHcount > 75) SkipCHcount = 1;
  if (SkipCHcount == 1) {
    //if CH is pressed, increment up until 5 which doesnt exist so resets to 1
    if (LastButtonValue == IRButtonCH) {  // if CH is pushed
      CHButtonCounter = CHButtonCounter + 1; //Ch button counter is incremented
    } //end if
    if (CHButtonCounter > 4) CHButtonCounter = 0;
  } //end if
[code/]

larryd

#3
Nov 25, 2017, 04:42 am Last Edit: Nov 25, 2017, 04:53 am by larryd
Review the attach sketch.
Obviously, it is not what you need but it presents some ideas that may help you in your project.

Code: [Select]

//**********************************************************************
 
#include "IRremote.h"
//LarryD

//Sketch to demonstrate using an IR hand remote to control Arduino outputs.
//The remote used here uses the NEC protocol.
//This remote sends the button code (example 0xFF629D) then a repeat code 0xFFFFFFFF
//The repeat code is re-sent as long as an IR remote button is pressed.
//The IR receiver used is the TSOP4838
 
/*  17 IR button remote layout   http://i.imgur.com/X1KIdqI.png
 
   ^
< OK  > 
   v
1  2  3
4  5  6
7  8  9
*  0  #
 
*/
 
 
const byte RECV_PIN = 7;   //IR receive pin
 
IRrecv irrecv(RECV_PIN);   //create instance of 'IRrecv'
decode_results results;    //create instance of 'decode_results'
 
unsigned long   TimerUp;   //UP arrow on the remote
boolean         TimerUpFlag = false;
 
unsigned long   TimerDown; //DOWN arrow on the remote
boolean         TimerDownFlag    = false;
 
unsigned long   TimerIntensity;
unsigned long   TimerIncDec;
boolean         intesityUpFlag   = false;
boolean         intesityDownFlag = false;
int             brightness;
 
unsigned long   dummy;
unsigned long * TimerPtr = &dummy; //pointer to the current timer
 
const byte upLED        = 13;  //turns on as long as the UP button is pressed
const byte downLED      = 12;  //turns on as long as the DOWN button is pressed
const byte leftLED      = 11;  //toggles on/off
const byte rightLED     = 10;  //toggles on/off
const byte intensityLED =  9;  //a LED which can have its intensity adjusted
 
 
//                           s e t u p ( )
//**********************************************************************
void setup()
{
  Serial.begin(9600);
  irrecv.enableIRIn(); //start receive
 
  pinMode(upLED,   OUTPUT);
  pinMode(downLED, OUTPUT);
  pinMode(leftLED, OUTPUT);
  pinMode(rightLED, OUTPUT);
  pinMode(intensityLED, OUTPUT); //this is a PWM output pin
 
} //                    E N D  O F  s e t u p ( )
 
 
 
//                            l o o p ( )
//**********************************************************************
void loop()
{
  if (irrecv.decode(&results)) //is there IR remote button code
  {
    //Serial.println(results.value);
    processButton(); //process button press
    irrecv.resume(); //restart for next button press
  }
 
  //**********************                                //Turn off upLED
  //if timing is enabled, is it time to stop
  if (TimerUpFlag && millis() - TimerUp >= 250ul)
  {
    TimerUpFlag = false; //disable timing
    TimerPtr = &dummy;   //pointer to dummy timer
    digitalWrite(upLED, LOW);
  }
 
  //**********************                                //Turn off downLED
  //if timing is enabled, is it time to stop
  if (TimerDownFlag && millis() - TimerDown >= 250ul)
  {
    TimerDownFlag = false; //disable timing
    TimerPtr = &dummy;     //pointer to dummy timer
    digitalWrite(downLED, LOW);
  }
 
  //**********************                                //LED intensity
  //are we still within the adjustment time
  if (millis() - TimerIntensity <= 300ul)
  {
    //is it time to increase/decrease the intensity
    if (millis() - TimerIncDec >= 200ul)
    {
      TimerIncDec = millis();
 
      if (intesityUpFlag == true) //Increase
      {
        brightness += 5;
        if (brightness > 255)
        {
          brightness = 255;
        }
      }
      else if (intesityDownFlag == true) //Decrease
      {
        brightness -= 5;
        if (brightness < 0)
        {
          brightness = 0;
        }
      }
 
      analogWrite(intensityLED, brightness);
      //Serial.println(brightness); //debug
    }
  }
  //stop increasing/decreasing intensity
  else
  {
    intesityUpFlag = false;
    intesityDownFlag = false;
  }
 
  //************************************
  //Other non blocking code goes here
  //************************************
 
} //                   E N D  O F  l o o p ( )
 
 
 
//======================================================================
//                       F U N C T I O N S
//======================================================================
 
//                   p r o c e s s B u t t o n ( )
//**********************************************************************
//process IR remote button presses
void processButton()
{
  switch (results.value)
  {
    //**********************
    case 0xFF629D:                                           //UP Arrow
      {
        Serial.println("UP");
        TimerPtr = &TimerUp;  //point to this timer
        TimerUpFlag = true;   //enable timing
        digitalWrite(upLED, HIGH);
        TimerUp = millis();
      }
      break;
 
    //**********************
    case 0xFFA857:                                           //DOWN Arrow
      {
        Serial.println("DOWN");
        TimerPtr = &TimerDown;  //point to this timer
        TimerDownFlag = true;   //enable timing
        digitalWrite(downLED, HIGH);
        TimerDown = millis();
      }
      break;
 
    //**********************
    case 0xFF22DD:                                           //LEFT Arrow
      {
        Serial.println("LEFT");
        digitalWrite(leftLED, !digitalRead(leftLED));   //Toggle LED
      }
      break;
 
    //**********************
    case 0xFFC23D:                                           //RIGHT Arrow
      {
        Serial.println("RIGHT");
        digitalWrite(rightLED, !digitalRead(rightLED)); //Toggle LED
      }
      break;
 
    //**********************
    case 0xFF42BD:                                           // * button
      {
        Serial.println("*");
        TimerPtr = &TimerIntensity;  //point to this timer
        intesityUpFlag = true;       //enable intensity up adjustment
        intesityDownFlag = false;
        TimerIncDec = millis();
        TimerIntensity = millis();
      }
      break;
 
    //**********************
   case 0xFF52AD:                                           // # button
      {
        Serial.println("#");
        TimerPtr = &TimerIntensity;  //point to this timer
        intesityDownFlag = true;     //enable intensity down adjustment
        intesityUpFlag = false;
        TimerIncDec = millis();
        TimerIntensity = millis();
      }
      break;
 
    //**********************
    case 0xFF02FD:
      Serial.println("OK");
      break;
 
    //**********************
    case 0xFF6897:
      Serial.println("1");
      break;
 
    //**********************
    case 0xFF9867:
      Serial.println("2");
      break;
 
    //**********************
    case 0xFFB04F:
      Serial.println("3");
      break;
 
    //**********************
    case 0xFF30CF:
      Serial.println("4");
      break;
 
    //**********************
    case 0xFF18E7:
      Serial.println("5");
      break;
 
    //**********************
    case 0xFF7A85:
      Serial.println("6");
      break;
 
    //**********************
    case 0xFF10EF:
      Serial.println("7");
      break;
 
    //**********************
    case 0xFF38C7:
      Serial.println("8");
      break;
 
    //**********************
    case 0xFF5AA5:
      Serial.println("9");
      break;
 
    //**********************
    case 0xFF4AB5:
      Serial.println("0");
      break;
 
    //**********************
    case 0xFFFFFFFF: //Repeat code
      {
        Serial.println("REPEAT");
        *TimerPtr = millis();       //reset the current timer
      }
      break;
 
  } // END switch case
 
} //             E N D  o f  p r o c e s s B u t t o n ( )
 
//**********************************************************************
 
//======================================================================
//                        E N D  O F  C O D E
//======================================================================
   







No technical PMs.
The last thing you did is where you should start looking.

BKK

#4
Nov 25, 2017, 04:56 am Last Edit: Nov 25, 2017, 05:03 am by BKK
Thanx I will look it over. here is what I found works. the trouble I was having was that the span of the button press allows the "LastButtonValue" to act 2 times, so no matter what it would increment 2

I added a LastButtonValue = 0, at the end of the CHButtonCounter loop and that solves it. I sometimes have to try 2-3 times to get it to take the CH button from the IR, but it is predictable.

I added lights to show the CHButtonCounter value so it is easier to follow as well.

Code: [Select]
void IRinput() {
  if (irrecv.decode(&results)) {
    if (results.value == RepeatValue)
      LastButtonValue = LastButtonValue;
    else
      LastButtonValue = results.value;
    irrecv.resume(); // Receive the next value
  }
  SkipCHcount = SkipCHcount + 1;
  if (SkipCHcount > 50) SkipCHcount = 1;
  if (SkipCHcount = 1) {
    //if CH is pressed, increment up until 4 which doesnt exist so resets to 1
    if (LastButtonValue == IRButtonCH) {  // if CH is pushed
      CHButtonCounter = CHButtonCounter + 1; //Ch button counter is incremented
      LastButtonValue = 0;
    } //end if
    if (CHButtonCounter > 4) CHButtonCounter = 1;
  } //end if
  switch (LastButtonValue) {
    case IRButton1: //remote button 1
      Setpoint = 109;
      Setpoint1 = 38;
      CHButtonCounter = 0;
      LedID = BlueLed1;
      digitalWrite(BlueLed3, LOW);
      digitalWrite(BlueLed5, LOW);
      digitalWrite(BlueLed7, LOW);
      digitalWrite(BlueLed9, LOW);
      LastButtonValue = 0;
      break;
    case IRButton3: //remote button 3
      Setpoint = 54;
      Setpoint1 = 38;
      CHButtonCounter = 0;
      LedID = BlueLed3;
      digitalWrite(BlueLed1, LOW);
      digitalWrite(BlueLed5, LOW);
      digitalWrite(BlueLed7, LOW);
      digitalWrite(BlueLed9, LOW);
      LastButtonValue = 0;
      break;
    case IRButton5: //remote button 5
      Setpoint = 84;
      Setpoint1 = 53;
      CHButtonCounter = 0;
      LedID = BlueLed5;
      digitalWrite(BlueLed3, LOW);
      digitalWrite(BlueLed1, LOW);
      digitalWrite(BlueLed7, LOW);
      digitalWrite(BlueLed9, LOW);
      LastButtonValue = 0;
      break;
    case IRButton7: //remote button 7
      Setpoint = 109;
      Setpoint1 = 63;
      CHButtonCounter = 0;
      LedID = BlueLed7;
      digitalWrite(BlueLed3, LOW);
      digitalWrite(BlueLed5, LOW);
      digitalWrite(BlueLed1, LOW);
      digitalWrite(BlueLed9, LOW);
      LastButtonValue = 0;
      break;
    case IRButton9: //remote button 9
      Setpoint = 54;
      Setpoint1 = 63;
      CHButtonCounter = 0;
      LedID = BlueLed9;
      digitalWrite(BlueLed3, LOW);
      digitalWrite(BlueLed5, LOW);
      digitalWrite(BlueLed7, LOW);
      digitalWrite(BlueLed1, LOW);
      LastButtonValue = 0;
      break;
  }
}
///// DESIRED POSITION
void setTrajectory() {
  // shape trajectories using channel button

  switch (CHButtonCounter) {
    case 1: //LEMNISCATE (figure 8) TRAJECTORY
      Setpoint = 84 + (35 * cos(k)) / (1 + sin(k) * sin(k));
      Setpoint1 = 53 + (35 * sin(k) * cos(k)) / (1 + sin(k) * sin(k));
      k = k + 0.008;
      digitalWrite(BlueLed3, LOW);
      digitalWrite(BlueLed5, HIGH);
      digitalWrite(BlueLed7, LOW);
      digitalWrite(BlueLed9, LOW);
      digitalWrite(BlueLed1, HIGH);
      break;
    case 2: // CIRCLE TRAJECTORY
      Setpoint = 84 + 50 * cos(k); //BIGGER SMALLER
      Setpoint1 = 53 + 50 * sin(k);
      k = k - 0.028; //WAS 0.012  //FASTER SLOWER
      digitalWrite(BlueLed5, HIGH);
      digitalWrite(BlueLed7, LOW);
      digitalWrite(BlueLed9, LOW);
      digitalWrite(BlueLed1, HIGH);
      digitalWrite(BlueLed3, HIGH);
      break;
    case 3: // ELLIPSE TRAJECORY
      Setpoint = 84 + 40 * cos(k);
      Setpoint1 = 53 + 25 * sin(k);
      k = k - 0.02;
      digitalWrite(BlueLed5, HIGH);
      digitalWrite(BlueLed9, LOW);
      digitalWrite(BlueLed1, HIGH);
      digitalWrite(BlueLed3, HIGH);
      digitalWrite(BlueLed7, HIGH);
      break;
    case 4: //PENTAGRAM TRAJECOTRY
      Setpoint = 84 +  18 * cos(k) + 12 * cos(k * 150); //
      Setpoint1 = 53 + 18 * sin(k) - 12 * sin(k * 150); //
      k = k + 0.01;
      digitalWrite(BlueLed5, HIGH);
      digitalWrite(BlueLed1, HIGH);
      digitalWrite(BlueLed3, HIGH);
      digitalWrite(BlueLed7, HIGH);
      digitalWrite(BlueLed9, HIGH);
      break;
      LastButtonValue = 0;
  }
}

BKK

I am using this remote:

larryd

#6
Nov 25, 2017, 05:31 am Last Edit: Nov 25, 2017, 05:32 am by larryd


I use those also.

.
No technical PMs.
The last thing you did is where you should start looking.

larryd

If you don't need the repeat code capability, here is a library that doesn't use timers.

https://forum.arduino.cc/index.php?topic=317625.0   


.
No technical PMs.
The last thing you did is where you should start looking.

BKK

here is the final CH button code. I added lights to see when the button is activated and counted. When in point mode it lights the LED for the desired point when it reaches the exact point. For the CH button trajectories it will light the middle light to show it is trajectory mode and then the corners to show which trajectory

BKK Ball and Plate with trajectories

larryd

No technical PMs.
The last thing you did is where you should start looking.

Go Up