teensySNES_test2.ino
1 // SPDX-FileCopyrightText: 2019 Anne Barela for Adafruit Industries 2 // 3 // SPDX-License-Identifier: MIT 4 5 const int pinAnalogXInput = 3; 6 const int pinAnalogYInput = 1; 7 const int pinAnalogZInput = 2; 8 const int pinAnalogDummyInput = 0; 9 10 #define KEYREPEAT 100 // milliseconds 11 #define KEYDELAY 200 // delay from first to second character 12 13 const int pinBtnUp = 0; 14 const int pinBtnRight = 1; 15 const int pinBtnDown = 2; 16 const int pinBtnLeft = 3; 17 18 const int pinBtnSelect = 4; 19 const int pinBtnStart = 5; 20 21 const int pinBtnB = 7; 22 const int pinBtnA = 8; 23 const int pinBtnY = 10; 24 const int pinBtnX = 9; 25 26 const int pinBtnTrigLeft = 6; 27 const int pinBtnTrigRight = 23; 28 29 const int pinLEDOutput = 11; 30 31 //Variables for the states of the SNES buttons 32 byte buttons[] = { pinBtnUp, pinBtnRight, pinBtnDown, pinBtnLeft, pinBtnSelect, pinBtnStart, 33 pinBtnB, pinBtnA, pinBtnY, pinBtnX, pinBtnTrigLeft, pinBtnTrigRight 34 }; 35 short keys[] = {KEY_U, KEY_R, KEY_D, KEY_L, KEY_ENTER, KEY_TAB, KEY_B, KEY_A, KEY_Y, KEY_X, KEY_P, KEY_Q}; 36 37 #define NUMBUTTONS sizeof(buttons) 38 39 typedef void KeyFunction_t(uint8_t c); 40 41 KeyFunction_t* buttonActive[NUMBUTTONS]; 42 KeyFunction_t* keyList[] = {myset_key6, myset_key5, myset_key4, myset_key3, myset_key2, myset_key1}; 43 int keySlot = sizeof(keyList) / sizeof(KeyFunction_t*); 44 45 //Change these values if accelerometer reading are different: 46 //How far the accerometer is tilted before 47 //the Teensy starts moving the mouse: 48 const int cintMovementThreshold = 18; 49 50 //The average zero acceleration values read 51 //from the accelerometer for each axis: 52 const int cintZeroXValue = 328; 53 const int cintZeroYValue = 328; 54 const int cintZeroZValue = 328; 55 56 //The maximum (positive) acceleration values read 57 //from the accelerometer for each axis: 58 const int cintMaxXValue = 396; 59 const int cintMaxYValue = 396; 60 const int cintMaxZValue = 396; 61 62 //The minimum (negative) acceleration values read 63 //from the accelerometer for each axis: 64 const int cintMinXValue = 256; 65 const int cintMinYValue = 256; 66 const int cintMinZValue = 256; 67 68 //The sign of the mouse movement relative to the acceleration. 69 //If your cursor is going in the opposite direction you think it 70 //should go, change the sign for the appropriate axis. 71 const int cintXSign = 1; 72 const int cintYSign = -1; 73 const int cintZSign = 1; 74 75 //const float cfloatMovementMultiplier = 1; 76 77 //The maximum speed in each axis (x and y) 78 //that the cursor should move. Set this to a higher or lower 79 //number if the cursor does not move fast enough or is too fast. 80 const int cintMaxMouseMovement = 10; 81 82 //This reduces the 'twitchiness' of the cursor by calling 83 //a delay function at the end of the main loop. 84 //There is a better way to do this without delaying the whole 85 //microcontroller, but that is left for another time or person. 86 const int cintMouseDelay = 8; 87 88 89 void setup() 90 { 91 //This is not needed and set to default but can be useful if you 92 //want to get the full range out of the analog channels when 93 //reading from the 3.3V ADXL335. 94 //If the analog reference is used, the thresholds, zeroes, 95 //maxima and minima will need to be re-evaluated. 96 analogReference( DEFAULT ); 97 98 //Setup the pin modes. 99 pinMode( pinLEDOutput, OUTPUT ); 100 101 //Special for the Teensy is the INPUT_PULLUP 102 //It enables a pullup resitor on the pin. 103 for (byte i=0; i< NUMBUTTONS; i++) { 104 pinMode(buttons[i], INPUT_PULLUP); 105 } 106 107 //Uncomment this line to debug the acceleromter values: 108 // Serial.begin(); 109 110 } 111 112 113 void loop() 114 { 115 // //debugging the start button... 116 digitalWrite ( pinLEDOutput, digitalRead(pinBtnStart)); 117 118 119 //Process the accelerometer to make the cursor move. 120 //Comment this line to debug the accelerometer values: 121 fcnProcessAccelerometer(); 122 123 //Progess the SNES controller buttons to send keystrokes. 124 fcnProcessButtons(); 125 126 127 //Delay to avoid 'twitchiness' and bouncing inputs 128 //due to too fast of sampling. 129 //As said above, there is a better way to do this 130 //than delay the whole MCU. 131 delay(cintMouseDelay); 132 } 133 134 135 //Function to process the acclerometer data 136 //and send mouse movement information to the host computer. 137 void fcnProcessAccelerometer() 138 { 139 //Initialize values for the mouse cursor movement. 140 int intMouseXMovement = 0; 141 int intMouseYMovement = 0; 142 143 //Read the dummy analog channel 144 //This must be done first because the X analog channel was first 145 //and was unstable, it dropped or pegged periodically regardless 146 //of pin or source. 147 analogRead( pinAnalogDummyInput ); 148 149 //Read accelerometer readings 150 int intAnalogXReading = analogRead(pinAnalogXInput); 151 int intAnalogYReading = analogRead(pinAnalogYInput); 152 int intAnalogZReading = analogRead(pinAnalogZInput); 153 154 //Calculate mouse movement 155 //If the analog X reading is ouside of the zero threshold... 156 if( cintMovementThreshold < abs( intAnalogXReading - cintZeroXValue ) ) 157 { 158 //...calculate X mouse movement based on how far the X acceleration is from its zero value. 159 intMouseXMovement = cintXSign * ( ( ( (float)( 2 * cintMaxMouseMovement ) / ( cintMaxXValue - cintMinXValue ) ) * ( intAnalogXReading - cintMinXValue ) ) - cintMaxMouseMovement ); 160 //it could use some improvement, like making it trigonometric. 161 } 162 else 163 { 164 //Within the zero threshold, the cursor does not move in the X. 165 intMouseXMovement = 0; 166 } 167 168 //If the analog Y reading is ouside of the zero threshold... 169 if( cintMovementThreshold < abs( intAnalogYReading - cintZeroYValue ) ) 170 { 171 //...calculate Y mouse movement based on how far the Y acceleration is from its zero value. 172 intMouseYMovement = cintYSign * ( ( ( (float)( 2 * cintMaxMouseMovement ) / ( cintMaxYValue - cintMinYValue ) ) * ( intAnalogYReading - cintMinYValue ) ) - cintMaxMouseMovement ); 173 //it could use some improvement, like making it trigonometric. 174 } 175 else 176 { 177 //Within the zero threshold, the cursor does not move in the Y. 178 intMouseYMovement = 0; 179 } 180 181 Mouse.move(intMouseXMovement, intMouseYMovement); 182 183 } 184 185 //Function to process the buttons from the SNES controller 186 void fcnProcessButtons() 187 { 188 bool keysPressed = false; 189 bool keysReleased = false; 190 191 // run through all the buttons 192 for (byte i = 0; i < NUMBUTTONS; i++) { 193 194 // are any of them pressed? 195 if (! digitalRead(buttons[i])) 196 { //this button is pressed 197 keysPressed = true; 198 if (!buttonActive[i]) //was it pressed before? 199 activateButton(i); //no - activate the keypress 200 } 201 else 202 { //this button is not pressed 203 if (buttonActive[i]) { //was it pressed before? 204 releaseButton(i); //yes - release the keypress 205 keysReleased = true; 206 } 207 } 208 } 209 210 if (keysPressed || keysReleased) 211 Keyboard.send_now(); //update all the keypresses 212 213 } 214 215 void activateButton(byte index) 216 { 217 if (keySlot) //any key slots left? 218 { 219 keySlot--; //Push the keySlot stack 220 buttonActive[index] = keyList[keySlot]; //Associate the keySlot function pointer with the button 221 (*keyList[keySlot])(keys[index]); //Call the key slot function to set the key value 222 } 223 } 224 225 void releaseButton(byte index) 226 { 227 keyList[keySlot] = buttonActive[index]; //retrieve the keySlot function pointer 228 buttonActive[index] = 0; //mark the button as no longer pressed 229 (*keyList[keySlot])(0); //release the key slot 230 keySlot++; //pop the keySlot stack 231 } 232 233 void myset_key1(uint8_t c) 234 { 235 Keyboard.set_key1(c); 236 } 237 238 void myset_key2(uint8_t c) 239 { 240 Keyboard.set_key2(c); 241 } 242 243 void myset_key3(uint8_t c) 244 { 245 Keyboard.set_key3(c); 246 } 247 248 void myset_key4(uint8_t c) 249 { 250 Keyboard.set_key4(c); 251 } 252 253 void myset_key5(uint8_t c) 254 { 255 Keyboard.set_key5(c); 256 } 257 258 void myset_key6(uint8_t c) 259 { 260 Keyboard.set_key6(c); 261 }