· 6 years ago · Sep 15, 2019, 03:02 PM
1/* Arcade Spinner v0.7
2* Copyright 2018 Joe W (jmtw000 a/t gmail.com)
3* Craig B - Updated code for mouse movement modes(DROP, ACCM) and case statement for Button port bit validation
4*
5* This program is free software: you can redistribute it and/or modify
6* it under the terms of the GNU General Public License as published by
7* the Free Software Foundation, either version 3 of the License, or
8* (at your option) any later version.
9*
10* This program is distributed in the hope that it will be useful,
11* but WITHOUT ANY WARRANTY; without even the implied warranty of
12* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13* GNU General Public License for more details.
14*
15* You should have received a copy of the GNU General Public License
16* along with this program. If not, see <https://www.gnu.org/licenses/>.
17*/
18
19#include "Mouse.h"
20#include <Joystick.h>
21
22
23#define pinA 2 //The pins that the rotary encoder's A and B terminals are connected to.
24#define pinB 3
25#define maxBut 10 //The number of buttons you are using up to 10.
26
27
28//Create a Joystick object.
29Joystick_ Joystick(JOYSTICK_DEFAULT_REPORT_ID,JOYSTICK_TYPE_GAMEPAD,
30 maxBut, 0, // Button Count, Hat Switch Count
31 true, true, false, // X, Y, but no Z Axis. We need at least two axes even though they're not used.
32 false, false, false, // No Rx, Ry, or Rz
33 false, false, // No rudder or throttle
34 false, false, false); // No accelerator, brake, or steering;
35
36
37//The previous state of the AB pins
38volatile int previousReading = 0;
39
40//Keeps track of how much the encoder has been moved
41volatile int rotPosition = 0;
42
43volatile int rotMulti = 0;
44
45
46//Sets the initial last joypad states
47int lastJoyState[4] = {1,1,1,1};
48
49//Set the initial last state of the buttons depending on the max number of buttons defined in maxBut
50
51#if maxBut==1
52int lastButtonState[maxBut] = {1};
53#endif
54
55#if maxBut==2
56int lastButtonState[maxBut] = {1,1};
57#endif
58
59#if maxBut==3
60int lastButtonState[maxBut] = {1,1,1};
61#endif
62
63#if maxBut==4
64int lastButtonState[maxBut] = {1,1,1,1};
65#endif
66
67#if maxBut==5
68int lastButtonState[maxBut] = {1,1,1,1,1};
69#endif
70
71#if maxBut==6
72int lastButtonState[maxBut] = {1,1,1,1,1,1};
73#endif
74
75#if maxBut==7
76int lastButtonState[maxBut] = {1,1,1,1,1,1,1};
77#endif
78
79#if maxBut==8
80int lastButtonState[maxBut] = {1,1,1,1,1,1,1,1};
81#endif
82
83#if maxBut==9
84int lastButtonState[maxBut] = {1,1,1,1,1,1,1,1,1};
85#endif
86
87#if maxBut==10
88int lastButtonState[maxBut] = {1,1,1,1,1,1,1,1,1,1};
89#endif
90
91void setup() {
92 //No need to set the pin modes with DDRx = DDRx | 0b00000000 as we're using all input and that's the initial state of the pins
93 //Use internal input resistors for all the pins we're using
94 PORTD = 0b11010011; //Digital pins D2, D3, D4, D6, and D12.
95 PORTB = 0b11110000; //Digital pins D8, D9, D10, D11
96 //PORTB = 0b01110010; //Digital pins D8, D9, D10, and D15 Pro Micro Craig B
97 PORTC = 0b11000000; //Digital pin D5 and D13
98 PORTE = 0b01000000; //Digital pin D7
99 PORTF = 0b11111100; //Digital pin A0, A1, A2, A3, A4, A5
100
101
102
103 //Start the joystick
104 Joystick.begin();
105
106 // Set Range for digital joystick / joypad ie on/off.
107 Joystick.setXAxisRange(-1, 1);
108 Joystick.setYAxisRange(-1, 1);
109
110 //Center the X and Y axes on the joystick
111 Joystick.setXAxis(0);
112 Joystick.setYAxis(0);
113
114 //Set up the interrupt handler for the encoder's A and B terminals on digital pins 2 and 3 respectively. Both interrupts use the same handler.
115 attachInterrupt(digitalPinToInterrupt(pinA), pinChange, CHANGE);
116 attachInterrupt(digitalPinToInterrupt(pinB), pinChange, CHANGE);
117
118 //Start the mouse
119 Mouse.begin();
120 }
121
122//Interrupt handler
123void pinChange() {
124
125 //Set the currentReading variable to the current state of encoder terminals A and B which are conveniently located in bits 0 and 1 (digital pins 2 and 3) of PIND
126 //This will give us a nice binary number, eg. 0b00000011, representing the current state of the two terminals.
127 //You could do int currentReading = (digitalRead(pinA) << 1) | digitalRead(pinB); to get the same thing, but it would be much slower.
128 int currentReading = PIND & 0b00000011;
129
130 //Take the nice binary number we got last time there was an interrupt and shift it to the left by 2 then OR it with the current reading.
131 //This will give us a nice binary number, eg. 0b00001100, representing the former and current state of the two encoder terminals.
132
133 int combinedReading = (previousReading << 2) | currentReading;
134
135 //Now that we know the previous and current state of the two terminals we can determine which direction the rotary encoder is turning.
136
137 //Going to the right
138 if(combinedReading == 0b0010 ||
139 combinedReading == 0b1011 ||
140 combinedReading == 0b1101 ||
141 combinedReading == 0b0100) {
142
143 rotPosition++; //update the position of the encoder
144
145 }
146
147 //Going to the left
148 if(combinedReading == 0b0001 ||
149 combinedReading == 0b0111 ||
150 combinedReading == 0b1110 ||
151 combinedReading == 0b1000) {
152
153 rotPosition--; //update the position of the encoder
154
155 }
156
157
158 //Save the previous state of the A and B terminals for next time
159 previousReading = currentReading;
160}
161
162
163void loop(){
164
165 int currentButtonState;
166 int currentJoyState;
167
168 //If the encoder has moved 1 or more transitions move the mouse in the appropriate direction
169 //and update the rotPosition variable to reflect that we have moved the mouse. The mouse will move 1/2
170 //the number of pixels of the value currently in the rotPosition variable. We are using 1/2 (rotPosition>>1) because the total number
171 //of transitions(positions) on our encoder is 2400 which is way too high. 1200 positions is more than enough.
172
173 if(rotPosition >= 1 || rotPosition <= -1) {
174 rotMulti = rotPosition>> 1; //copy rotPosition/2 to a temporary variable in case there's an interrupt while we're moving the mouse
175 Mouse.move(rotMulti,0,0);
176 rotPosition -= (rotMulti<< 1); //adjust rotPosition to account for mouse movement
177 }
178
179 //Iterate through the 4 axis button presses (0-4) assigning the current state of the pin for each button, HIGH(0b00000001) or LOW(0b00000000), to the currentState variable
180 int jb = 0;
181 do {
182 switch ( jb ) {
183 case 0: //on digital pin A0, PF1 - Joystick Up
184 currentJoyState = (PINF & 0b10000000) >> 7; //logical AND the 8-bit pin reading with a mask to isolate the specific bit we're interested in and then shift it to the end of the byte
185 break;
186 case 1: //on digital pin A1, PF2 - Joystick Right
187 currentJoyState = (PINF & 0b01000000) >> 6;
188 break;
189 case 2: //on digital pin A2, PF2 - Joystick Down
190 currentJoyState = (PINF & 0b00100000) >> 5;
191 break;
192 case 3: //on digital pin A3, PE6 - Joystick Left
193 currentJoyState = (PINF & 0b00010000) >> 4;
194 break;
195 default: //should never happen
196 currentJoyState = 0b00000000;
197 break;
198 }
199 if(currentJoyState != lastJoyState[jb])
200 //add code here for what you want to happen when the axis state has changed
201
202 switch ( jb ) {
203 case 0: // Joystick Up
204 {
205 Joystick.setYAxis(!jb);
206 }
207 case 2: // Joystick Down
208 {
209 Joystick.setYAxis(!jb*-1);
210 }
211 case 1: // Joystick Right
212 {
213 Joystick.setXAxis(!jb);
214 }
215 case 3: // Joystick Left
216 {
217 Joystick.setXAxis(!jb*-1);
218 }
219 }
220
221 //Save the last state for each axis for next time
222 lastJoyState[jb] = currentJoyState;
223
224 ++jb;
225 } while (jb < 4);
226
227 //Iterate through the 10 buttons (0-9) assigning the current state of the pin for each button, HIGH(0b00000001) or LOW(0b00000000), to the currentState variable
228 int button = 0;
229 do {
230 switch ( button ) {
231 case 0: //on digital pin 4, PD4 - Arcade Button 0
232 currentButtonState = (PIND & 0b00010000) >> 4; //logical AND the 8-bit pin reading with a mask to isolate the specific bit we're interested in and then shift it to the end of the byte
233 break;
234 case 1: //on digital pin 5, PC6 - Arcade Button 1
235 currentButtonState = (PINC & 0b01000000) >> 6;
236 break;
237 case 2: //on digital pin 6, PD7 - Arcade Button 2
238 currentButtonState = (PIND & 0b10000000) >> 7;
239 break;
240 case 3: //on digital pin 7, PE6 - Arcade Button 3
241 currentButtonState = (PINE & 0b01000000) >> 6;
242 break;
243 case 4: //on digital pin 8, PB4 - Arcade Button 4
244 currentButtonState = (PINB & 0b00010000) >> 4;
245 break;
246 case 5: //on digital pin 9, PB5 - Arcade Button 5
247 currentButtonState = (PINB & 0b00100000) >> 5;
248 break;
249 case 6: //on digital pin 10, PB6 - Arcade Button 6
250 currentButtonState = (PINB & 0b01000000) >> 6;
251 break;
252 case 7: //on digital pin 11, PB7 - Arcade Button 7
253 currentButtonState = (PINB & 0b10000000) >> 7;
254 break;
255 case 8: //on digital pin 12, PD6 - Arcade Button 8
256 currentButtonState = (PIND & 0b01000000) >> 6;
257 break;
258 case 9: //on digital pin 13, PC7 - Arcade Button 9
259 currentButtonState = (PINC & 0b10000000) >> 6;
260 break;
261 default: //should never happen
262 currentButtonState = 0b00000000;
263 break;
264
265 /*Pro Micro 10 buttons (2 unused) Craig B
266 * switch ( button ) {
267 case 0: //on digital pin 4, PD4 - Arcade Button 1
268 currentButtonState = (PIND & 0b00010000) >> 4;
269 break;
270 case 1: //on digital pin 5, PC6 - Arcade Button 2
271 currentButtonState = (PINC & 0b01000000) >> 6;
272 break;
273 case 2: //on digital pin 6, PD7 - Arcade Button 3
274 currentButtonState = (PIND & 0b10000000) >> 7;
275 break;
276 case 3: //on digital pin 7, PE6 - Arcade Button 4
277 currentButtonState = (PINE & 0b01000000) >> 6;
278 break;
279 case 4: //on digital pin 8, PB4 - Arcade Button 5
280 currentButtonState = (PINB & 0b00010000) >> 4;
281 break;
282 case 5: //on digital pin 9, PB5 - Arcade Button 6
283 currentButtonState = (PINB & 0b00100000) >> 5;
284 break;
285 case 8: //on digital pin 10, PB6 - COIN/Select Button 9
286 currentButtonState = (PINB & 0b01000000) >> 6;
287 break;
288 case 9: //on digital pin 15, PB1 - PLAYER/Start Button 10
289 currentButtonState = (PINB & 0b00000010) >> 1;
290 break;
291 default: //Extra digital pins 16, PB2 and 14, PB3
292 currentButtonState = 0b00000000;
293 break;
294 */
295 }
296 //If the current state of the pin for each button is different than last time, update the joystick button state
297 if(currentButtonState != lastButtonState[button])
298 Joystick.setButton(button, !currentButtonState);
299
300 //Save the last button state for each button for next time
301 lastButtonState[button] = currentButtonState;
302
303 ++button;
304 } while (button < maxBut);
305
306}