Arduino Megajoy isolating a pin to manipulate its value

Hello All

For the record I am completely new to both Arduino and programming of any kind so please be patient with me. I am attempting to make my own control desk for a train simulator ans so far have had some good success using and Arduino Mega 2560 along with a program called Megajoy which works as a HID game controller.

https://github.com/AlanChatham/UnoJoy/tree/master/MegaJoy

I have been able to successfuly hook up some rotary pots and get them to behave as an axis on the game controller, I have even been able to insert some code that takes some samples and returns an average so that the results are smoothed.

I have hooked up some momentary push buttons and can use them as intended no problems. My issue that I am currently facing is that I have hooked up some toggle switches and they are behaving exactly as you would expect them too. You flick the toggle and they stay in the on position, what I would like to do is flick them on but have them pulse for approx. 1/4 second and then revert to off and then to do the same when you switch them to off.

I dont have any problems with learning how to do this via googling and trial and error as such but where Im getting stuck is that it seems all the buttons / digital pins are in an array and I am not understanding how to manipulate the array so that I can intercept (in this case pin52) and manipulate the state so that I can add some lines to get it to behave how I would like it to.

#include "MegaJoy.h"

const int numReadingsA2 = 20;     //number of samples for smoothing on pin A2
const int numReadingsA3 = 20;     //number of samples for smoothing on pin A3

int readingsA2[numReadingsA2];      // the readings from the analog input A2 
int readIndexA2 = 0;              // the index of the current reading A2
int totalA2 = 0;                  // the running total A2
int averageA2 = 0;                // the average A2
int readingsA3[numReadingsA3];      // the readings from the analog input A3
int readIndexA3 = 0;              // the index of the current reading A3
int totalA3 = 0;                  // the running total A3
int averageA3 = 0;                // the average A3

void setup(){
  setupPins();
  setupMegaJoy();
  // initialize all the readings for analogue smoothing to 0:
  for (int thisReadingA3 = 0; thisReadingA3 < numReadingsA3; thisReadingA3++) {
    readingsA3[thisReadingA3] = 0;
  }
  for (int thisReadingA2 = 0; thisReadingA2 < numReadingsA2; thisReadingA2++) {
    readingsA2[thisReadingA2] = 0;
  }  
}

void loop(){
  // Always be getting fresh data
  megaJoyControllerData_t controllerData = getControllerData();
  setControllerData(controllerData);
}

void setupPins(void){
  // Set all the digital pins as inputs
  // with the pull-up enabled, except for the 
  // two serial line pins
  for (int i = 2; i <= 54; i++){
    pinMode(i, INPUT);
    digitalWrite(i, HIGH);
  }
}

megaJoyControllerData_t getControllerData(void){
  
  // Set up a place for our controller data
  //  Use the getBlankDataForController() function, since
  //  just declaring a fresh dataForController_t tends
  //  to get you one filled with junk from other, random
  //  values that were in those memory locations before
  megaJoyControllerData_t controllerData = getBlankDataForMegaController();
  // Since our buttons are all held high and
  //  pulled low when pressed, we use the "!"
  //  operator to invert the readings from the pins
  for (int i = 2; i <= 54; i++){
    controllerData.buttonArray[(i - 2) / 8] |= (!digitalRead(i)) << ((i - 2) % 8);
  }  
  
  // Set the analog sticks
  //  Since analogRead(pin) returns a 10 bit value,
  //  we need to perform a bit shift operation to
  //  lose the 2 least significant bits and get an
  //  8 bit number that we can use 
  controllerData.analogAxisArray[0] = 0;analogRead(A0);
  controllerData.analogAxisArray[1] = 0;analogRead(A1);  
  controllerData.analogAxisArray[4] = 0;//analogRead(A4); 
  controllerData.analogAxisArray[5] = 0;//analogRead(A5); 
  controllerData.analogAxisArray[6] = 0;//analogRead(A6); 
  controllerData.analogAxisArray[7] = 0;//analogRead(A7); 
  controllerData.analogAxisArray[8] = 0;//analogRead(A8); 
  controllerData.analogAxisArray[9] = 0;//analogRead(A9); 
  controllerData.analogAxisArray[10] = 0;//analogRead(A10); 
  controllerData.analogAxisArray[11] = 0;//analogRead(A11); 

   // subtract the last reading A2:
  totalA2 = totalA2 - readingsA2[readIndexA2];
  // read from the sensor A2:
  readingsA2[readIndexA2] = analogRead(A2);
  // add the reading to the total A2:
  totalA2 = totalA2 + readingsA2[readIndexA2];
  // advance to the next position in the array A2:
  readIndexA2 = readIndexA2 + 1;

  // if we're at the end of the array A2...
  if (readIndexA2 >= numReadingsA2) {
    // ...wrap around to the beginning A2:
    readIndexA2 = 0;
  }

  // calculate the average A2:
  averageA2 = totalA2 / numReadingsA2;
  controllerData.analogAxisArray[2] = averageA2;
  delay(1);
  
    // subtract the last reading A3:
  totalA3 = totalA3 - readingsA3[readIndexA3];
  // read from the sensor A3:
  readingsA3[readIndexA3] = analogRead(A3);
  // add the reading to the total A3:
  totalA3 = totalA3 + readingsA3[readIndexA3];
  // advance to the next position in the array A3:
  readIndexA3 = readIndexA3 + 1;

  // if we're at the end of the array A3...
  if (readIndexA3 >= numReadingsA3) {
    // ...wrap around to the beginning A3:
    readIndexA3 = 0;
  }

    // calculate the average A3:
  averageA3 = totalA3 / numReadingsA3;
  controllerData.analogAxisArray[3] = averageA3;
  delay(1);

// I wish to return values for the Dpads of 0 - not sure if this is working?
controllerData.dpad0LeftOn = 0;
controllerData.dpad0UpOn = 0;
controllerData.dpad0RightOn = 0;
controllerData.dpad0DownOn = 0;
    
controllerData.dpad1LeftOn = 0;
controllerData.dpad1UpOn = 0;
controllerData.dpad1RightOn = 0;
controllerData.dpad1DownOn = 0;

  // And return the data!
  return controllerData;
}

In the long run I would like to add rotary switches and encoders and I feel that I really need to understand this concept before moving forward. I could be wrong but I think there is added complexity here because the com chip has been flashed and that is where we are returning data to.

I would be appreciative of any help or guidance that would come my way

Thanks

Jareb

If you want toggle switches to act like momentary switches, you will need to a couple of things.

  1. a variable to remember the last state the switch was in
  2. a variable to know the current state the switch is in
  3. how long it has been since a state change occurred.

Take a look at "using millis() instead of delay" and "how to do multiple things at once" for examples...

blh64:
If you want toggle switches to act like momentary switches, you will need to a couple of things.

  1. a variable to remember the last state the switch was in
  2. a variable to know the current state the switch is in
  3. how long it has been since a state change occurred.

Take a look at “using millis() instead of delay” and “how to do multiple things at once” for examples…

Hi blh64

Thanks for taking the time to reply, I understand the concept of what you are saying and I think I might have over thought the process originally so I have given it another crack. I have manged to get to a point where I can change the behavior of the pin and have it output into windows via the default game controller settings.

The pin is not behaving how I would like it to but the fact that I am getting a change in behavior is encouraging. Below is the code I have now amended, it will write the ‘LOW’ value to pin52 but for some reason which is probably obvious to experienced people but not to myself it wont write the ‘HIGH’ value with or without the millis timer (which Im not even sure if works either).

Any way I will keep plugging away, any help appreciated

Thanks

#include "MegaJoy.h"

const int numReadingsA2 = 20;     //number of samples for smoothing on pin A2
const int numReadingsA3 = 20;     //number of samples for smoothing on pin A3
const long interval = 250;

int readingsA2[numReadingsA2];      // the readings from the analog input A2 
int readIndexA2 = 0;              // the index of the current reading A2
int totalA2 = 0;                  // the running total A2
int averageA2 = 0;                // the average A2
int readingsA3[numReadingsA3];      // the readings from the analog input A3
int readIndexA3 = 0;              // the index of the current reading A3
int totalA3 = 0;                  // the running total A3
int averageA3 = 0;                // the average A3
int pin52CurrentState = 0;        // the current state of digital pin 52
int pin52PreviousState = 0;       // the previous state of digital pin 52

unsigned long previousMillis = 0;  //variable to store the last time the switch was toggled

void setup(){
  setupPins();
  setupMegaJoy();
  // initialize all the readings for analogue smoothing to 0:
  for (int thisReadingA3 = 0; thisReadingA3 < numReadingsA3; thisReadingA3++) {
    readingsA3[thisReadingA3] = 0;
  }
  for (int thisReadingA2 = 0; thisReadingA2 < numReadingsA2; thisReadingA2++) {
    readingsA2[thisReadingA2] = 0;
  }  
}

void loop(){
  // Always be getting fresh data
  megaJoyControllerData_t controllerData = getControllerData();
  setControllerData(controllerData);
}

void setupPins(void){
  // Set all the digital pins as inputs
  // with the pull-up enabled, except for the 
  // two serial line pins
  for (int i = 2; i <= 54; i++){
    pinMode(i, INPUT);
    digitalWrite(i, HIGH);
  }
}

megaJoyControllerData_t getControllerData(void){
  
  // Set up a place for our controller data
  //  Use the getBlankDataForController() function, since
  //  just declaring a fresh dataForController_t tends
  //  to get you one filled with junk from other, random
  //  values that were in those memory locations before
  megaJoyControllerData_t controllerData = getBlankDataForMegaController();

 // code for pin 52 to treat toggle as momentary switch
  pin52CurrentState = digitalRead(52);  //read the current state of pin52
    if (pin52CurrentState == pin52PreviousState){ //if statement to compare if the switch has changed
    } else {  // false equals write low as pins are pulled high
      unsigned long currentMillis = millis();
      digitalWrite(52, LOW);
      previousMillis = currentMillis;  // recording time of toggle switch change
    if (currentMillis - previousMillis >= interval){ // if statement to define how long pin52 writes low
      digitalWrite(52, HIGH); // if true write pin 52 high
  pin52PreviousState = digitalRead(52); // record new previous pin state variable for original if statement
      }
    }
    
   // Since our buttons are all held high and
  //  pulled low when pressed, we use the "!"
  //  operator to invert the readings from the pins
  for (int i = 2; i <= 54; i++){
    controllerData.buttonArray[(i - 2) / 8] |= (!digitalRead(i)) << ((i - 2) % 8);
  }  
  
  // Set the analog sticks
  //  Since analogRead(pin) returns a 10 bit value,
  //  we need to perform a bit shift operation to
  //  lose the 2 least significant bits and get an
  //  8 bit number that we can use 
  controllerData.analogAxisArray[0] = 0;analogRead(A0);
  controllerData.analogAxisArray[1] = 0;analogRead(A1);  
  controllerData.analogAxisArray[4] = 0;//analogRead(A4); 
  controllerData.analogAxisArray[5] = 0;//analogRead(A5); 
  controllerData.analogAxisArray[6] = 0;//analogRead(A6); 
  controllerData.analogAxisArray[7] = 0;//analogRead(A7); 
  controllerData.analogAxisArray[8] = 0;//analogRead(A8); 
  controllerData.analogAxisArray[9] = 0;//analogRead(A9); 
  controllerData.analogAxisArray[10] = 0;//analogRead(A10); 
  controllerData.analogAxisArray[11] = 0;//analogRead(A11); 

   // subtract the last reading A2:
  totalA2 = totalA2 - readingsA2[readIndexA2];
  // read from the sensor A2:
  readingsA2[readIndexA2] = analogRead(A2);
  // add the reading to the total A2:
  totalA2 = totalA2 + readingsA2[readIndexA2];
  // advance to the next position in the array A2:
  readIndexA2 = readIndexA2 + 1;

  // if we're at the end of the array A2...
  if (readIndexA2 >= numReadingsA2) {
    // ...wrap around to the beginning A2:
    readIndexA2 = 0;
  }

  // calculate the average A2:
  averageA2 = totalA2 / numReadingsA2;
  controllerData.analogAxisArray[2] = averageA2;
  delay(1);
  
    // subtract the last reading A3:
  totalA3 = totalA3 - readingsA3[readIndexA3];
  // read from the sensor A3:
  readingsA3[readIndexA3] = analogRead(A3);
  // add the reading to the total A3:
  totalA3 = totalA3 + readingsA3[readIndexA3];
  // advance to the next position in the array A3:
  readIndexA3 = readIndexA3 + 1;

  // if we're at the end of the array A3...
  if (readIndexA3 >= numReadingsA3) {
    // ...wrap around to the beginning A3:
    readIndexA3 = 0;
  }

    // calculate the average A3:
  averageA3 = totalA3 / numReadingsA3;
  controllerData.analogAxisArray[3] = averageA3;
  delay(1);

// I wish to return values for the Dpads of 0 - not sure if this is working?
controllerData.dpad0LeftOn = 0;
controllerData.dpad0UpOn = 0;
controllerData.dpad0RightOn = 0;
controllerData.dpad0DownOn = 0;
    
controllerData.dpad1LeftOn = 0;
controllerData.dpad1UpOn = 0;
controllerData.dpad1RightOn = 0;
controllerData.dpad1DownOn = 0;

  // And return the data!
  return controllerData;
}

You define pin 52 as in input and then write to it. That doesn't do what you think. You will need to make it an output. A better approach will be to have your toggle switch on a pin (e.g. 52) and then have a "virtual" switch on some other pin. The toggle pin would be an input and your virtual pin would be the output. That way, every time you detect a state change on the input, you do your 1/4 second pulse on the output.