License

Tags
Sim racing
Recommend Projects

Dahl Design SW1

4 months ago 347
  • Description
  • Documents
  • BOM
  • Attachments
  • Members
  • Comments

Description

Schematic and PCB layout for Dahl Design SW1 sim racing steering wheel. The PCB has been build and tested, working as intended.

Essentially two ATmega32U4 connected to a single USB output with a SL2.1A USB hub IC. The SL2.1A hub has two additional USB connections available, so possibitilies for adding additional MCUs or a screen, like VoCore or Nextion. This SL2.1A chip has been tested with a VoCore screen and three other peripherals, working perfectly. In case of adding a screen, I recommend a 100µF cap close to the +5V going to screen. I also recommend having a look at my PCB layout for placing decoupling capacitors and isolated ground plane for crystal resonators.

Included in this project is also ICSP headers for both MCUs, this is necessary to burn bootloader. I used an Arduino UNO as ISP programmer, simply burning the bootloader through Arduino IDE without any issues. The PCB is then recognized as two Arduino Leonardos.

There is room for all connections on a single ATmega32U4 in this project, but I split the LEDs from the buttons to make use of SimHub (https://www.simhubdash.com/) for LED control.

  • The LEDs in my project are split up on several connectors since they are scattered around the steering wheel, not clustered together on a PCB.
  • The button matrix in the schematic would only partly be supported by SimHub, and is instead coded through Arduino IDE using the popular joystick library. - - The matrix consists of 4 x encoders, 2 x 7-way switches, 3 x latching 2-way toggles, 2 x momentary 3-way toggles and 16 x buttons, four of them being paddle shifters. The project also includes 5 analog connections, 2 for clutches, 1 for clutch bite point adjustment (potentiometer) and 2 for 12-way switches, using 12-way switches connected to an external "stepped resistor" PCB.
  • Last of all are debugging points and extra connection pads in case of adding new things to the wheel or for troubleshooting, not needed for proper function. Also LEDs to Arduino pin 12 on both MCUs to tell them appart with a simple blink sketch.

Feel free to use any element of this schematic, you'll find me in SimHub discord if you have any questions. I can also provide .stl or .step files for the build.

Finished product:

20210817_224005.jpg

Code written and flashed with Arduino IDE. Requires libraries: Joystick, Multimap and MegunoLink:

/*
  Dahl Design SW1 Firmware v1.8. By Andreas Dahl August 2021

  Version 1.7 : 
   - First official release.
  Version 1.8 :
   - Improved logic for all encoders.

*/

#include <Joystick.h>
#include <MultiMap.h>
#include <Filter.h>

#define BUTTONCOUNT 69

//Defining joystick parameters

Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID, JOYSTICK_TYPE_GAMEPAD,
                   BUTTONCOUNT,    //Button count
                   0,              //Hat switch count
                   true,           //X axis -> Clutch paddles
                   true,           //Y axis -> Clutch bite, only for dash visualization
                   false,          //Z axis
                   false,          //Rx axis
                   false,          //Ry axis
                   false,          //Rz axis
                   false,          //Rudder
                   false,          //Throttle
                   false,          //Accelerator
                   false,          //Brake
                   false);         //Steering

//Row and column pins

uint8_t row[] = {11, 3, 2, 30, 4, 12, 6};
const uint8_t rowCount = sizeof(row) / sizeof(row[0]);

uint8_t col[] = {7, A0, 13, 5, 10, 9, 8};
const uint8_t colCount = sizeof(col) / sizeof(col[0]);

//Analog pins

int rotRPin = A1;
int rotLPin = A4;
int clutchRPin = A2;
int clutchLPin = A5;
int bitePin = A3;

//Status of all buttons

uint8_t state[rowCount][colCount] = {
  {0, 0, 0, 0, 0, 0, 0}, //ROW 1,
  {0, 0, 0, 0, 0, 0, 0}, //ROW 2
  {0, 0, 0, 0, 0, 0, 0}, //ROW 3
  {0, 0, 0, 0, 0, 0, 0}, //ROW 4
  {0, 0, 0, 0, 0, 0, 0}, //ROW 5
  {0, 0, 0, 0, 0, 0, 0}, //ROW 6
  {0, 0, 0, 0, 0, 0, 0}, //ROW 7
};

/*
  Row 1, column 1 - 7
  status[0][0] --->  Right grip encoder A-channel *
  status[0][1] --->  Right grip encoder B-channel *
  status[0][2] --->  Right 3-way (ON)-OFF-(ON) push UP *
  status[0][3] --->  Right 3-way (ON)-OFF-(ON) push DOWN *
  status[0][4] --->  Right top 9N OFF-(ON) pushbutton *
  status[0][5] --->  Right middle 9N OFF-(ON) pushbutton *
  status[0][6] --->  Right lower 9N OFF-(ON) pushbutton *

  Row 2, column 1-7
  status[1][0] --->  Right 7-way down press
  status[1][1] --->  Right 7-way left press
  status[1][2] --->  Right 7-way encoder A-channel
  status[1][3] --->  Right 7-way right press
  status[1][4] --->  Right 7-way push button
  status[1][5] --->  Right 7-way encoder B-channel
  status[1][6] --->  Right 7-way up press

  Row 3, column 1-7
  status[2][0] --->  Middle top back-button *
  status[2][1] --->  Right top back-button *
  status[2][2] --->  Upshift paddle *
  status[2][3] --->  Right accessory paddle *
  status[2][4] --->  Launch control toggle *
  status[2][5] --->  Right thumb encoder A-channel *
  status[2][6] --->  Right thumb encoder B-channel *

  Row 4, column 1-7
  status[3][0] --->  Left grip encoder A-channel *
  status[3][1] --->  Left grip encoder B-channel *
  status[3][2] --->  Left 3-way (ON)-OFF-(ON) push UP *
  status[3][3] --->  Left 3-way (ON)-OFF-(ON) push DOWN *
  status[3][4] --->  Left top 9N OFF-(ON) pushbutton *
  status[3][5] --->  Left middle 9N OFF-(ON) pushbutton *
  status[3][6] --->  Left lower 9N OFF-(ON) pushbutton *

  Row 5, column 1-7
  status[4][0] --->  Left 7-way left press
  status[4][1] --->  Left 7-way encoder A-channel
  status[4][2] --->  Left 7-way encoder B-channel
  status[4][3] --->  Left 7-way up press
  status[4][4] --->  Left 7-way push button
  status[4][5] --->  Left 7-way down press
  status[4][6] --->  Left 7-way right press

  Row 6, column 1-7
  status[5][0] --->  Left thumb encoder A-channel *
  status[5][1] --->  Left thumb encoder B-channel *
  status[5][2] --->  Ignition toggle *
  status[5][3] --->  Left top back-button *
  status[5][4] --->  Left accessory paddle *
  status[5][5] --->  Downshift paddle *
  status[5][6] --->  Radio OFF-ON latching pushbutton *

  //ROW 7, column 1-7
  status[6][0] --->  Pit limiter 9N OFF-(ON) pushbutton *
  status[6][1] --->  Bite point lock toggle switch *
  status[6][2] --->  Engine start button *
  status[1][0] --->  Col 4 empty
  status[1][0] --->  Col 5 empty
  status[1][0] --->  Col 6 empty
  status[1][0] --->  Col 7 empty

*/

//List of buttons and button debounce timers

//Button 1  ---> [0][4] --->  Right top 9N OFF-(ON) pushbutton
//Button 2  ---> [0][5] --->  Right middle 9N OFF-(ON) pushbutton
//Button 3  ---> [0][6] --->  Right lower 9N OFF-(ON) pushbutton
//Button 4  ---> [3][4] --->  Left top 9N OFF-(ON) pushbutton
//Button 5  ---> [3][5] --->  Left middle 9N OFF-(ON) pushbutton
//Button 6  ---> [3][6] --->  Left lower 9N OFF-(ON) pushbutton
//Button 7  ---> [2][3] --->  Right accessory paddle
//Button 8  ---> [5][4] --->  Left accessory paddle
//Button 9  ---> [2][2] --->  Upshift paddle
//Button 10 ---> [5][5] --->  Downshift paddle
//Button 11 ---> [0][2] --->  Right 3-way (ON)-OFF-(ON) push UP
//Button 12 ---> [0][3] --->  Right 3-way (ON)-OFF-(ON) push DOWN
//Button 13 ---> [3][2] --->  Left 3-way (ON)-OFF-(ON) push UP
//Button 14 ---> [3][3] --->  Left 3-way (ON)-OFF-(ON) push DOWN

//Button 15 ---> [0][0] --->  Right grip encoder CCW
//Button 16 ---> [0][1] --->  Right grip encoder CW
//Button 17 ---> [3][0] --->  Left grip encoder CCW
//Button 18 ---> [3][1] --->  Left grip encoder CW
//Button 19 ---> [2][5] --->  Right thumb encoder CCW
//Button 20 ---> [2][6] --->  Right thumb encoder CW
//Button 21 ---> [5][0] --->  Left thumb encoder CW
//Button 22 ---> [5][1] --->  Left thumb encoder CCW

//Button 23 ---> [6][0] --->  Pit limiter 9N OFF-(ON) pushbutton
//Button 24 ---> [5][6] --->  Radio OFF-ON latching pushbutton

//Button 25 ---> [1][6] --->  Right 7-way up press
//Button 26 ---> [1][3] --->  Right 7-way right press
//Button 27 ---> [1][0] --->  Right 7-way down press
//Button 28 ---> [1][1] --->  Right 7-way left press
//Button 29 ---> [1][4] --->  Right 7-way push button
//Button 30 ---> [1][2] --->  Right 7-way encoder CCW
//Button 31 ---> [1][5] --->  Right 7-way encoder CW

//Button 32 ---> [4][3] --->  Left 7-way up press
//Button 33 ---> [4][6] --->  Left 7-way right press
//Button 34 ---> [4][5] --->  Left 7-way down press
//Button 35 ---> [4][0] --->  Left 7-way left press
//Button 36 ---> [4][4] --->  Left 7-way push button
//Button 37 ---> [4][1] --->  Left 7-way encoder CCW
//Button 38 ---> [4][2] --->  Left 7-way encoder CW

//Button 39 ---> [2][1] --->  Right top back-button
//Button 40 ---> [2][0] --->  Middle top back-button
//Button 41 ---> [5][3] --->  Left top back-button
//Button 42 ---> [2][4] --->  Launch control toggle
//Button 43 ---> [5][2] --->  Ignition toggle
//Button 44 ---> [6][2] --->  Engine start button
//Button 45 ---> [6][1] --->  Bite point lock toggle switch

// Global variables for buttons

// Button/encoder pulse duration

uint8_t encoderPulse = 20;
uint8_t funkyPulse = 20;

// Encoder variables
uint8_t enc1C = 0;
uint8_t enc1L = 0;
uint8_t enc1S = 0;
uint8_t enc1P = 0;
uint8_t enc1D = 0;

uint8_t enc2C = 0;
uint8_t enc2L = 0;
uint8_t enc2S = 0;
uint8_t enc2P = 0;
uint8_t enc2D = 0;

uint8_t enc3C = 0;
uint8_t enc3L = 0;
uint8_t enc3S = 0;
uint8_t enc3P = 0;
uint8_t enc3D = 0;

uint8_t enc4C = 0;
uint8_t enc4L = 0;
uint8_t enc4S = 0;
uint8_t enc4P = 0;
uint8_t enc4D = 0;

uint8_t funkystatus1 = 0;
uint8_t zerofetch1 = 0;
uint8_t onefetch1 = 0;
uint8_t funkycount1 = 0;
uint8_t funkycountN1 = 0;
uint8_t funkyStop1 = 0;

uint8_t funkystatus2 = 0;
uint8_t zerofetch2 = 0;
uint8_t onefetch2 = 0;
uint8_t funkycount2 = 0;
uint8_t funkycountN2 = 0;
uint8_t funkyStop2 = 0;

uint8_t b43Counter = 0;     //Button 43 counter
uint8_t b43Active = 3;      //Button 43 active state

uint8_t rotRC = 0;
uint8_t rotRL = 0;
uint8_t rotLC = 0;
uint8_t rotLL = 0;

// Clutch multiMap arrays
int inR [11] = {190, 195, 200, 210, 230, 270, 320, 370, 425, 490, 555};
int outR [11] = {0, 102, 204, 307, 409, 512, 614, 716, 819, 921, 1023};

int inL [11] = {536, 620, 680, 730, 780, 820, 840, 850, 857, 861, 864};
int outL [11] = {0, 102, 204, 307, 409, 512, 614, 716, 819, 921, 1023};

int inBite [11] = {3, 20, 40, 170, 400, 600, 900, 930, 960, 990, 1015};
int outBite [11] = {0, 102, 204, 307, 409, 512, 614, 716, 819, 921, 1023};

int bite = 600;
uint8_t mapSize = 11;

unsigned long counter;

//Filter variable

ExponentialFilter<float> filteredBite(5,0);

//-----------------------------------------------------------------------------
//-------------------------------SETUP-----------------------------------------
//-----------------------------------------------------------------------------

void setup () {

  //Serial.begin(9600);

  pinMode(rotRPin, INPUT);
  pinMode(rotLPin, INPUT);
  pinMode(clutchRPin, INPUT);
  pinMode(clutchLPin, INPUT);
  pinMode(bitePin, INPUT);

  for (int i = 0; i < colCount; i ++) {     //  All pins pulled up unless told otherwise
    pinMode(col[i], INPUT_PULLUP);
  }

  for (int i = 0; i < rowCount; i ++) {     //  All pins pulled up unless told otherwise
    pinMode(row[i], INPUT_PULLUP);
  }

  Joystick.begin(0); //Start joystick library magic

}

//-----------------------------------------------------------------------------
//-------------------------------LOOP------------------------------------------
//-----------------------------------------------------------------------------

void loop() {

  //counter++;
  //Serial.println(counter);

  matrix ();

  buttons ();

  encoder1 ();
  encoder2 ();
  encoder3 ();
  encoder4 ();

  funky1 ();
  funky2 ();

  analog ();

  Joystick.sendState();

}

//-----------------------------------------------------------------------------
//------------------------------FUNCTIONS--------------------------------------
//-----------------------------------------------------------------------------
void matrix() {
  //Beginning with matrix logics, checking status on all button connectors.

  //Based on monitoring the flow to each row pin, setting the pin to GND
  for (int i = 0; i < rowCount; i++) { //Engaging row pin after row pin

    pinMode(row[i], OUTPUT);
    digitalWrite(row[i], LOW);

    for (int u = 0; u < colCount; u++) { //Checking all column pins on this row pin
      if (digitalRead(col[u]) == 0) {
        state[i][u] = 1;
      } else {
        state[i][u] = 0;
      }
    }

    pinMode(row[i], INPUT_PULLUP); //Disengage the row pin
  }
}

void buttons() {
  //------------------------------
  //Button debounce and activation
  //------------------------------

  //Button 1
  Joystick.setButton(0, state[0][4]);

  //Button 2
  Joystick.setButton(1, state[0][5]);

  //Button 3
  Joystick.setButton(2, state[0][6]);

  //Button 4
  Joystick.setButton(3, state[3][4]);

  //Button 5
  Joystick.setButton(4, state[3][5]);

  //Button 6
  Joystick.setButton(5, state[3][6]);

  //Button 7
  Joystick.setButton(6, state[2][3]);

  //Button 8
  Joystick.setButton(7, state[5][4]);

  //Button 9
  Joystick.setButton(8, state[2][2]);

  //Button 10
  Joystick.setButton(9, state[5][5]);

  //Button 11
  Joystick.setButton(10, state[0][2]);

  //Button 12
  Joystick.setButton(11, state[0][3]);

  //Button 13
  Joystick.setButton(12, state[3][2]);

  //Button 14
  Joystick.setButton(13, state[3][3]);

  //Button 23
  Joystick.setButton(22, state[6][0]);

  //Button 24
  Joystick.setButton(23, state[5][6]);

  //Button 25
  Joystick.setButton(24, state[1][6]);

  //Button 26
  Joystick.setButton(25, state[1][3]);

  //Button 27
  Joystick.setButton(26, state[1][0]);

  //Button 28
  Joystick.setButton(27, state[1][1]);

  //Button 29 (Right 7-Way pushbutton)
  if (state[1][6] + state[1][3] + state[1][0] + state[1][1] == 0 && state[1][4] == 1) {
    Joystick.pressButton(28);
  } else {
    Joystick.releaseButton(28);
  }

  //Button 32
  Joystick.setButton(31, state[4][3]);

  //Button 33
  Joystick.setButton(32, state[4][6]);

  //Button 34
  Joystick.setButton(33, state[4][5]);

  //Button 35
  Joystick.setButton(34, state[4][0]);

  //Button 36 (Left 7-Way pushbutton)
  if (state[4][3] + state[4][6] + state[4][5] + state[4][0] == 0 && state[4][4] == 1) {
    Joystick.pressButton(35);
  } else {
    Joystick.releaseButton(35);
  }

  //Button 39
  Joystick.setButton(38, state[2][1]);

  //Button 40
  Joystick.setButton(39, state[2][0]);

  //Button 41
  Joystick.setButton(40, state[5][3]);

  //Button 42
  Joystick.setButton(41, state[2][4]);

  //Button 43 (Pulsing toggle)
  if (state[5][2] != b43Active) {
    b43Counter++;
    Joystick.setButton(42, 1);
  }

  if (b43Counter > encoderPulse) {
    Joystick.setButton(42, 0);
    b43Counter = 0;
    b43Active = state[5][2];
  }

  //Button 44
  Joystick.setButton(43, state[6][2]);

  //Button 45
  Joystick.setButton(44, state[6][1]);

}

void encoder1() {

  //Right grip encoder
  //EncS = status
  //EncP = pulse trigger on/off
  //EncL = last status
  //EncC = counter, for pulse duration
  //EncD = saving status for pulse

  if (!state[0][0] && !state[0][1]) { //Refreshing switch position
    enc1S = 1;
  }
  if (state[0][0] && !state[0][1]) {
    enc1S = 2;
  }
  if (state[0][0] && state[0][1]) {
    enc1S = 3;
  }
  if (!state[0][0] && state[0][1]) {
    enc1S = 4;
  }

  if (enc1L != enc1S && !enc1P) { //Conditions for starting pulse
    enc1P = 1;
    enc1D = enc1S;
  }

  if (enc1P) { //Counting pulse duration, initiate button press
    enc1C++;
    if ((enc1D > enc1L && !(enc1D == 4 && enc1L == 1)) || enc1D == 1 && enc1L == 4) {
      Joystick.pressButton(14);
    } else {
      Joystick.pressButton(15);
    }
  }

  if (enc1C > encoderPulse) {
    enc1C = 0;
    enc1L = enc1S;
    enc1P = 0;
    Joystick.releaseButton(14);
    Joystick.releaseButton(15);
  }
}

void encoder2() {
  //Left grip encoder

  if (!state[3][0] && !state[3][1]) { //Refreshing switch position
    enc2S = 1;
  }
  if (state[3][0] && !state[3][1]) {
    enc2S = 2;
  }
  if (state[3][0] && state[3][1]) {
    enc2S = 3;
  }
  if (!state[3][0] && state[3][1]) {
    enc2S = 4;
  }

  if (enc2L != enc2S && !enc2P) { //Conditions for starting pulse
    enc2P = 1;
    enc2D = enc2S;
  }

  if (enc2P) { //Counting pulse duration, initiate button press
    enc2C++;
    if ((enc2D > enc2L && !(enc2D == 4 && enc2L == 1)) || enc2D == 1 && enc2L == 4) {
      Joystick.pressButton(16);
    } else {
      Joystick.pressButton(17);
    }
  }

  if (enc2C > encoderPulse) {
    enc2C = 0;
    enc2L = enc2S;
    enc2P = 0;
    Joystick.releaseButton(16);
    Joystick.releaseButton(17);
  }

}

void encoder3() {
  //Right thumb encoder

  if (!state[2][5] && !state[2][6]) { //Refreshing switch position
    enc3S = 1;
  }
  if (state[2][5] && !state[2][6]) {
    enc3S = 2;
  }
  if (state[2][5] && state[2][6]) {
    enc3S = 3;
  }
  if (!state[2][5] && state[2][6]) {
    enc3S = 4;
  }

  if (enc3L != enc3S && !enc3P) { //Conditions for starting pulse
    enc3P = 1;
    enc3D = enc3S;
  }

  if (enc3P) { //Counting pulse duration, initiate button press
    enc3C++;
    if ((enc3D > enc3L && !(enc3D == 4 && enc3L == 1)) || enc3D == 1 && enc3L == 4) {
      Joystick.pressButton(18);
    } else {
      Joystick.pressButton(19);
    }
  }

  if (enc3C > encoderPulse) {
    enc3C = 0;
    enc3L = enc3S;
    enc3P = 0;
    Joystick.releaseButton(18);
    Joystick.releaseButton(19);
  }

}

void encoder4() {
  //Left thumb encoder

  if (!state[5][0] && !state[5][1]) { //Refreshing switch position
    enc4S = 1;
  }
  if (state[5][0] && !state[5][1]) {
    enc4S = 2;
  }
  if (state[5][0] && state[5][1]) {
    enc4S = 3;
  }
  if (!state[5][0] && state[5][1]) {
    enc4S = 4;
  }

  if (enc4L != enc4S && !enc4P) { //Conditions for starting pulse
    enc4P = 1;
    enc4D = enc4S;
  }

  if (enc4P) { //Counting pulse duration, initiate button press
    enc4C++;
    if ((enc4D > enc4L && !(enc4D == 4 && enc4L == 1)) || enc4D == 1 && enc4L == 4) {
      Joystick.pressButton(21);
    } else {
      Joystick.pressButton(20);
    }
  }

  if (enc4C > encoderPulse) {
    enc4C = 0;
    enc4L = enc4S;
    enc4P = 0;
    Joystick.releaseButton(20);
    Joystick.releaseButton(21);
  }
}

void funky1() {

  //Right funkyswitch

  // Built-in debounce due to the switch being "10" or "01" between detents, triggering switch only when hitting the next steady detent.

  if (!state[1][2] && !state[1][5]) {
    funkystatus1 = 1;
  }
  if (!state[1][2] && state[1][5]) {
    funkystatus1 = 2;
    onefetch1 = 1;
  }
  if (state[1][2] && state[1][5]) {
    funkystatus1 = 3;
  }
  if (state[1][2] && !state[1][5]) {
    funkystatus1 = 4;
    zerofetch1 = 1;
  }

  if ((zerofetch1 && funkystatus1 == 1) || (onefetch1 && funkystatus1 == 3)) {
    funkycount1++;
    if (funkycountN1 > 0) {funkyStop1 = 1;}
    else {
      Joystick.pressButton(29);
    }
  }

  if ((zerofetch1 && funkystatus1 == 3) || (onefetch1 && funkystatus1 == 1)) {
    funkycountN1++;
    if (funkycount1 > 0) {funkyStop1 = 1;}
    else {
      Joystick.pressButton(30);
    }
  }

  if ((funkycount1+funkycountN1) > funkyPulse || funkyStop1 ) {
    funkycount1 = 0;
    funkycountN1 = 0;
    funkyStop1 = 0;
    onefetch1 = 0;
    zerofetch1 = 0;
    Joystick.releaseButton(29);
    Joystick.releaseButton(30);
  }
}

void funky2() {

  //Left funkyswitch

  // Built-in debounce due to the switch being "10" or "01" between detents, triggering switch only when hitting the next steady detent.

  if (!state[4][1] && !state[4][2]) {
    funkystatus2 = 1;
  }
  if (!state[4][1] && state[4][2]) {
    funkystatus2 = 2;
    onefetch2 = 1;
  }
  if (state[4][1] && state[4][2]) {
    funkystatus2 = 3;
  }
  if (state[4][1] && !state[4][2]) {
    funkystatus2 = 4;
    zerofetch2 = 1;
  }

  if ((zerofetch2 && funkystatus2 == 1) || (onefetch2 && funkystatus2 == 3)) {
    funkycount2++;
    if (funkycountN2 > 0) {funkyStop2 = 1;}
    else {
      Joystick.pressButton(36);
    }
  }

  if ((zerofetch2 && funkystatus2 == 3) || (onefetch2 && funkystatus2 == 1)) {
    funkycountN2++;
    if (funkycount2 > 0) {funkyStop2 = 1;}
    else {
      Joystick.pressButton(37);
    }
  }

  if ((funkycount2+funkycountN2) > funkyPulse || funkyStop2) {
    funkycount2 = 0;
    funkycountN2 = 0;
    funkyStop2 = 0;
    onefetch2 = 0;
    zerofetch2 = 0;
    Joystick.releaseButton(36);
    Joystick.releaseButton(37);
  }
}

void analog() {

  //Analog inputs; clutches, bitepoint and 12-way switches

  int rotR = analogRead(rotRPin);        // Buttons 46 - 57 ---> 12-position switch right
  int rotL = analogRead(rotLPin);        // Buttons 58 - 69 ---> 12-position switch left
  int clutchR = analogRead(clutchRPin);
  int clutchL = analogRead(clutchLPin);
  if (state[6][1]) {
    bite = analogRead(bitePin);
  }

  //Right 12-way switch

  rotR = map (rotR, 0, 1015, 0, 11);

  if (rotR != rotRL) { //Debounce not needed on this switch, but adding 5 cycles just for the hell of it.
    rotRC++;
  }
  if (rotRC > 5) {
    rotRC = 0;
    rotRL = rotR;
  }

  if (rotRL == 0) {
    Joystick.pressButton(45);
  } else {
    Joystick.releaseButton(45);
  }
  if (rotRL == 1) {
    Joystick.pressButton(46);
  } else {
    Joystick.releaseButton(46);
  }
  if (rotRL == 2) {
    Joystick.pressButton(47);
  } else {
    Joystick.releaseButton(47);
  }
  if (rotRL == 3) {
    Joystick.pressButton(48);
  } else {
    Joystick.releaseButton(48);
  }
  if (rotRL == 4) {
    Joystick.pressButton(49);
  } else {
    Joystick.releaseButton(49);
  }
  if (rotRL == 5) {
    Joystick.pressButton(50);
  } else {
    Joystick.releaseButton(50);
  }
  if (rotRL == 6) {
    Joystick.pressButton(51);
  } else {
    Joystick.releaseButton(51);
  }
  if (rotRL == 7) {
    Joystick.pressButton(52);
  } else {
    Joystick.releaseButton(52);
  }
  if (rotRL == 8) {
    Joystick.pressButton(53);
  } else {
    Joystick.releaseButton(53);
  }
  if (rotRL == 9) {
    Joystick.pressButton(54);
  } else {
    Joystick.releaseButton(54);
  }
  if (rotRL == 10) {
    Joystick.pressButton(55);
  } else {
    Joystick.releaseButton(55);
  }
  if (rotRL == 11) {
    Joystick.pressButton(56);
  } else {
    Joystick.releaseButton(56);
  }

  //Left 12-way switch
  rotL = map (rotL, 0, 1015, 0, 11);

  if (rotL != rotLL) {  //This switch needs a proper debounce because of filter capacitor removed from the switch PCB (On first wheel build). Probably not needed on an intact switch.
    rotLC++;
  }
  if (rotLC > 30) {
    rotLC = 0;
    rotLL = rotL;
  }

  if (rotLL == 0) {
    Joystick.pressButton(57);
  } else {
    Joystick.releaseButton(57);
  }
  if (rotLL == 1) {
    Joystick.pressButton(58);
  } else {
    Joystick.releaseButton(58);
  }
  if (rotLL == 2) {
    Joystick.pressButton(59);
  } else {
    Joystick.releaseButton(59);
  }
  if (rotLL == 3) {
    Joystick.pressButton(60);
  } else {
    Joystick.releaseButton(60);
  }
  if (rotLL == 4) {
    Joystick.pressButton(61);
  } else {
    Joystick.releaseButton(61);
  }
  if (rotLL == 5) {
    Joystick.pressButton(62);
  } else {
    Joystick.releaseButton(62);
  }
  if (rotLL == 6) {
    Joystick.pressButton(63);
  } else {
    Joystick.releaseButton(63);
  }
  if (rotLL == 7) {
    Joystick.pressButton(64);
  } else {
    Joystick.releaseButton(64);
  }
  if (rotLL == 8) {
    Joystick.pressButton(65);
  } else {
    Joystick.releaseButton(65);
  }
  if (rotLL == 9) {
    Joystick.pressButton(66);
  } else {
    Joystick.releaseButton(66);
  }
  if (rotLL == 10) {
    Joystick.pressButton(67);
  } else {
    Joystick.releaseButton(67);
  }
  if (rotLL == 11) {
    Joystick.pressButton(68);
  } else {
    Joystick.releaseButton(68);
  }

  //Clutch and bite logics

  clutchR = multiMap(clutchR, inR, outR, mapSize); //No smoothening on clutch.
  clutchR = 1023 - clutchR;

  clutchL = multiMap(clutchL, inL, outL, mapSize);  //Added smoothening on bite point
  filteredBite.Filter(bite);
  int smoothBite = filteredBite.Current();
  int newBite = multiMap(smoothBite, inBite, outBite, mapSize);

  Joystick.setYAxis(newBite);

  float floatbite = newBite;

  float fraction = floatbite / 1023;

  clutchL = clutchL * fraction;

  if (clutchL > clutchR) {
    Joystick.setXAxis(clutchL);
  } else {
    Joystick.setXAxis(clutchR);
  }
}

int multiMap(int val, int* _in, int* _out, uint8_t size)
{
  // take care the value is within range
  // val = constrain(val, _in[0], _in[size-1]);
  if (val <= _in[0]) return _out[0];
  if (val >= _in[size - 1]) return _out[size - 1];

  // search right interval
  uint8_t pos = 1;  // _in[0] allready tested
  while (val > _in[pos]) pos++;

  // this will handle all exact "points" in the _in array
  if (val == _in[pos]) return _out[pos];

  // interpolate in the right segment for the rest
  return (val - _in[pos - 1]) * (_out[pos] - _out[pos - 1]) / (_in[pos] - _in[pos - 1]) + _out[pos - 1];
}

Documents

Schematic

PCB

BOM

ID Name Designator Footprint Quantity
1 ROTARY LEFT A1 JST 2.54 MM 3-PIN 1
2 CLUTCH RIGHT A2 CONN-TH_3P-P2.50_X8821WV-03K-N0SN 1
3 ROTARY RIGHT A3 CONN-TH_3P-P2.50_X8821WV-03K-N0SN 1
4 CLUTCH LEFT A4 CONN-TH_3P-P2.50_X8821WV-03K-N0SN 1
5 BITE A5 CONN-TH_3P-P2.50_X8821WV-03K-N0SN 1
6 Toggle 1+2 B1 CONN-TH_3P-P2.50_X8821WV-03K-N0SN 1
7 Push B3,B4,B5,B11,B12,B15,B18,B19,B20,B26,B27,B28,B29 CONN-TH_2P-P2.50_X8821WV-02K-N0SN 13
8 Paddle B13 CONN-TH_2P-P2.50_X8821WV-02K-N0SN 1
9 Upshift B14 CONN-TH_2P-P2.50_X8821WV-02K-N0SN 1
10 Toggle 16+17 B16 CONN-TH_3P-P2.50_X8821WV-03K-N0SN 1
11 LATCH B30 CONN-TH_2P-P2.50_X8821WV-02K-N0SN 1
12 LNC BX1 CONN-TH_2P-P2.50_X8821WV-02K-N0SN 1
13 IGN BX2 CONN-TH_2P-P2.50_X8821WV-02K-N0SN 1
14 BITE BX3 CONN-TH_2P-P2.50_X8821WV-02K-N0SN 1
15 1uF C1,C6,C14,C24 C0603 4
16 100nF C2,C7,C8,C9,C15,C17,C18,C19,C20,C21 C0603 10
17 10pF C4,C11,C16,C23 C0603 4
18 10uF C12,C13,C22 C0603 3
19 1 PIN COL1,COL2,COL3,COL4,COL5,COL6,COL7,EX_L1,EX_L2,EX_L3,EX_M,GND_PIN,ROW1,ROW2,ROW3,ROW4,ROW5,ROW6,ROW7,RX_L,RX_M,TX_L,TX_M 1 PIN 23
20 16MHz CR1,CR2 OSC-SMD_4P-L3.2-W2.5-BL 2
21 12MHz CR3 OSC-SMD_4P-L3.2-W2.5-BL 1
22 SM4007PL D1,D2,D3,D4,D5,D6,D7,D8,D9,D10,D11,D12,D13,D14,D15,D16,D17,D18,D19,D20,D21,D22,D23,D24,D25,D26,D27,D28,D29,D30,D31,D32,D33,D34,D35,D36,D37,D38,D39,D40,D41,D42,D43,D44,D45 SOD-123F_L2.8-W1.8-LS3.7-RD 45
23 RIGTH HANDLE ENC1 CONN-TH_3P-P2.50_X8821WV-03K-N0SN 1
24 RIGHT BODY ENC2 CONN-TH_3P-P2.50_X8821WV-03K-N0SN 1
25 LEFT HANDLE ENC4 CONN-TH_3P-P2.50_X8821WV-03K-N0SN 1
26 LEFT BODY ENC5 CONN-TH_3P-P2.50_X8821WV-03K-N0SN 1
27 0805-125 F1 F0805 1
28 Buttons 21-25 and E6 FUNKY_LEFT RKJXT1F42001 1
29 Buttons 6-10 and E3 FUNKY_RIGHT RKJXT1F42001 1
30 SL2.1A HUB SOP-16_L10.0-W3.9-P1.27-LS6.0-BL 1
31 Header 2x3 pin (ISP/ICSP) ICSP_LED,ICSP_MAIN HEADER_PRG_2X03 2
32 LED1 BOARD L1 CONN-TH_3P-P2.50_X8821WV-03K-N0SN 1
33 LED1 OUT L2 CONN-TH_3P-P2.50_X8821WV-03K-N0SN 1
34 LED2 IN L3 CONN-TH_3P-P2.50_X8821WV-03K-N0SN 1
35 LED2 OUT L4 CONN-TH_3P-P2.50_X8821WV-03K-N0SN 1
36 LED3 IN L5 CONN-TH_3P-P2.50_X8821WV-03K-N0SN 1
37 LED3 OUT L6 CONN-TH_3P-P2.50_X8821WV-03K-N0SN 1
38 LED4 IN L7 CONN-TH_3P-P2.50_X8821WV-03K-N0SN 1
39 Logo Recycled LA1 LOGO NO BASURA 1
40 RED LED2,LED3,PWR LED0805-RD 3
41 ATMEGA32U4-AU LED,MAIN QFP-44_L10.0-W10.0-P0.80-LS13.2-BL 2
42 1K R1,R2,R8,R9,R14 R0603 5
43 22 R3,R4,R5,R6 R0603 4
44 10K R7,R11 R0603 2
45 330 R10 R0603 1
46 SKRKAEE020 RESET1,RESET2 SW-SMD_L3.9-W3.0-P4.45 2
47 USB MAIN BUS USB_IN CONN-TH_4P-P2.50_X8821WV-04K-N0SN 1

Attachments

None
Success
The owner does not allow comments in this project now

Comments (0)

goToTop
你现在访问的是EasyEDA海外版,使用建立访问速度更快的国内版 https://lceda.cn(需要重新注册)
如果需要转移工程请在个人中心 - 工程 - 工程高级设置 - 下载工程,下载后在https://lceda.cn/editor 打开保存即可。
有问题联系QQ 3001956291 不再提醒
svg-battery svg-battery-wifi svg-books svg-more svg-paste svg-pencil svg-plant svg-ruler svg-share svg-user svg-logo-cn svg-double-arrow
We use cookies to offer you a better experience. Detailed information on the use of cookies on this website is provided in our Privacy Policy. By using this site, you consent to the use of our cookies.