Li Ruofan 201199450

Dependencies:   mbed Gamepad Joystick

Committer:
DannyLee
Date:
Thu May 14 13:12:28 2020 +0000
Revision:
3:cf9fead9c3f4
aaa

Who changed what in which revision?

UserRevisionLine numberNew contents of line
DannyLee 3:cf9fead9c3f4 1 #include "Joystick.h"
DannyLee 3:cf9fead9c3f4 2
DannyLee 3:cf9fead9c3f4 3 Joystick::Joystick(PinName vertPin,PinName horizPin,PinName clickPin)
DannyLee 3:cf9fead9c3f4 4 {
DannyLee 3:cf9fead9c3f4 5 vert = new AnalogIn(vertPin);
DannyLee 3:cf9fead9c3f4 6 horiz = new AnalogIn(horizPin);
DannyLee 3:cf9fead9c3f4 7 click = new InterruptIn(clickPin);
DannyLee 3:cf9fead9c3f4 8 }
DannyLee 3:cf9fead9c3f4 9
DannyLee 3:cf9fead9c3f4 10 void Joystick::init()
DannyLee 3:cf9fead9c3f4 11 {
DannyLee 3:cf9fead9c3f4 12 // read centred values of joystick
DannyLee 3:cf9fead9c3f4 13 _x0 = horiz->read();
DannyLee 3:cf9fead9c3f4 14 _y0 = vert->read();
DannyLee 3:cf9fead9c3f4 15
DannyLee 3:cf9fead9c3f4 16 // this assumes that the joystick is centred when the init function is called
DannyLee 3:cf9fead9c3f4 17 // if perfectly centred, the pots should read 0.5, but this may
DannyLee 3:cf9fead9c3f4 18 // not be the case and x0 and y0 will be used to calibrate readings
DannyLee 3:cf9fead9c3f4 19
DannyLee 3:cf9fead9c3f4 20 // turn on pull-down for button -> this assumes the other side of the button
DannyLee 3:cf9fead9c3f4 21 // is connected to +3V3 so we read 1 when pressed and 0 when not pressed
DannyLee 3:cf9fead9c3f4 22 click->mode(PullDown);
DannyLee 3:cf9fead9c3f4 23 // we therefore need to fire the interrupt on a rising edge
DannyLee 3:cf9fead9c3f4 24 click->rise(callback(this,&Joystick::click_isr));
DannyLee 3:cf9fead9c3f4 25 // need to use a callback since mbed-os5 - basically tells it to look in this class for the ISR
DannyLee 3:cf9fead9c3f4 26 _click_flag = 0;
DannyLee 3:cf9fead9c3f4 27
DannyLee 3:cf9fead9c3f4 28 }
DannyLee 3:cf9fead9c3f4 29
DannyLee 3:cf9fead9c3f4 30 Direction Joystick::get_direction()
DannyLee 3:cf9fead9c3f4 31 {
DannyLee 3:cf9fead9c3f4 32 float angle = get_angle(); // 0 to 360, -1 for centred
DannyLee 3:cf9fead9c3f4 33
DannyLee 3:cf9fead9c3f4 34 Direction d;
DannyLee 3:cf9fead9c3f4 35 // partition 360 into segments and check which segment the angle is in
DannyLee 3:cf9fead9c3f4 36 if (angle < 0.0f) {
DannyLee 3:cf9fead9c3f4 37 d = CENTRE; // check for -1.0 angle
DannyLee 3:cf9fead9c3f4 38 } else if (angle < 22.5f) { // then keep going in 45 degree increments
DannyLee 3:cf9fead9c3f4 39 d = N;
DannyLee 3:cf9fead9c3f4 40 } else if (angle < 67.5f) {
DannyLee 3:cf9fead9c3f4 41 d = NE;
DannyLee 3:cf9fead9c3f4 42 } else if (angle < 112.5f) {
DannyLee 3:cf9fead9c3f4 43 d = E;
DannyLee 3:cf9fead9c3f4 44 } else if (angle < 157.5f) {
DannyLee 3:cf9fead9c3f4 45 d = SE;
DannyLee 3:cf9fead9c3f4 46 } else if (angle < 202.5f) {
DannyLee 3:cf9fead9c3f4 47 d = S;
DannyLee 3:cf9fead9c3f4 48 } else if (angle < 247.5f) {
DannyLee 3:cf9fead9c3f4 49 d = SW;
DannyLee 3:cf9fead9c3f4 50 } else if (angle < 292.5f) {
DannyLee 3:cf9fead9c3f4 51 d = W;
DannyLee 3:cf9fead9c3f4 52 } else if (angle < 337.5f) {
DannyLee 3:cf9fead9c3f4 53 d = NW;
DannyLee 3:cf9fead9c3f4 54 } else {
DannyLee 3:cf9fead9c3f4 55 d = N;
DannyLee 3:cf9fead9c3f4 56 }
DannyLee 3:cf9fead9c3f4 57
DannyLee 3:cf9fead9c3f4 58 return d;
DannyLee 3:cf9fead9c3f4 59 }
DannyLee 3:cf9fead9c3f4 60
DannyLee 3:cf9fead9c3f4 61 // this method gets the magnitude of the joystick movement
DannyLee 3:cf9fead9c3f4 62 float Joystick::get_mag()
DannyLee 3:cf9fead9c3f4 63 {
DannyLee 3:cf9fead9c3f4 64 Polar p = get_polar();
DannyLee 3:cf9fead9c3f4 65 return p.mag;
DannyLee 3:cf9fead9c3f4 66 }
DannyLee 3:cf9fead9c3f4 67
DannyLee 3:cf9fead9c3f4 68 // this method gets the angle of joystick movement (0 to 360, 0 North)
DannyLee 3:cf9fead9c3f4 69 float Joystick::get_angle()
DannyLee 3:cf9fead9c3f4 70 {
DannyLee 3:cf9fead9c3f4 71 Polar p = get_polar();
DannyLee 3:cf9fead9c3f4 72 return p.angle;
DannyLee 3:cf9fead9c3f4 73 }
DannyLee 3:cf9fead9c3f4 74
DannyLee 3:cf9fead9c3f4 75 // get raw joystick coordinate in range -1 to 1
DannyLee 3:cf9fead9c3f4 76 // Direction (x,y)
DannyLee 3:cf9fead9c3f4 77 // North (0,1)
DannyLee 3:cf9fead9c3f4 78 // East (1,0)
DannyLee 3:cf9fead9c3f4 79 // South (0,-1)
DannyLee 3:cf9fead9c3f4 80 // West (-1,0)
DannyLee 3:cf9fead9c3f4 81 Vector2D Joystick::get_coord()
DannyLee 3:cf9fead9c3f4 82 {
DannyLee 3:cf9fead9c3f4 83 // read() returns value in range 0.0 to 1.0 so is scaled and centre value
DannyLee 3:cf9fead9c3f4 84 // substracted to get values in the range -1.0 to 1.0
DannyLee 3:cf9fead9c3f4 85 float x = 2.0f*( horiz->read() - _x0 );
DannyLee 3:cf9fead9c3f4 86 float y = 2.0f*( vert->read() - _y0 );
DannyLee 3:cf9fead9c3f4 87
DannyLee 3:cf9fead9c3f4 88 // Note: the x value here is inverted to ensure the positive x is to the
DannyLee 3:cf9fead9c3f4 89 // right. This is simply due to how the potentiometer on the joystick
DannyLee 3:cf9fead9c3f4 90 // I was using was connected up. It could have been corrected in hardware
DannyLee 3:cf9fead9c3f4 91 // by swapping the power supply pins. Instead it is done in software so may
DannyLee 3:cf9fead9c3f4 92 // need to be changed depending on your wiring setup
DannyLee 3:cf9fead9c3f4 93
DannyLee 3:cf9fead9c3f4 94 Vector2D coord = {-x,y};
DannyLee 3:cf9fead9c3f4 95 return coord;
DannyLee 3:cf9fead9c3f4 96 }
DannyLee 3:cf9fead9c3f4 97
DannyLee 3:cf9fead9c3f4 98 // This maps the raw x,y coord onto a circular grid.
DannyLee 3:cf9fead9c3f4 99 // See: http://mathproofs.blogspot.co.uk/2005/07/mapping-square-to-circle.html
DannyLee 3:cf9fead9c3f4 100 Vector2D Joystick::get_mapped_coord()
DannyLee 3:cf9fead9c3f4 101 {
DannyLee 3:cf9fead9c3f4 102 Vector2D coord = get_coord();
DannyLee 3:cf9fead9c3f4 103
DannyLee 3:cf9fead9c3f4 104 // do the transformation
DannyLee 3:cf9fead9c3f4 105 float x = coord.x*sqrt(1.0f-pow(coord.y,2.0f)/2.0f);
DannyLee 3:cf9fead9c3f4 106 float y = coord.y*sqrt(1.0f-pow(coord.x,2.0f)/2.0f);
DannyLee 3:cf9fead9c3f4 107
DannyLee 3:cf9fead9c3f4 108 Vector2D mapped_coord = {x,y};
DannyLee 3:cf9fead9c3f4 109 return mapped_coord;
DannyLee 3:cf9fead9c3f4 110 }
DannyLee 3:cf9fead9c3f4 111
DannyLee 3:cf9fead9c3f4 112 // this function converts the mapped coordinates into polar form
DannyLee 3:cf9fead9c3f4 113 Polar Joystick::get_polar()
DannyLee 3:cf9fead9c3f4 114 {
DannyLee 3:cf9fead9c3f4 115 // get the mapped coordinate
DannyLee 3:cf9fead9c3f4 116 Vector2D coord = get_mapped_coord();
DannyLee 3:cf9fead9c3f4 117
DannyLee 3:cf9fead9c3f4 118 // at this point, 0 degrees (i.e. x-axis) will be defined to the East.
DannyLee 3:cf9fead9c3f4 119 // We want 0 degrees to correspond to North and increase clockwise to 359
DannyLee 3:cf9fead9c3f4 120 // like a compass heading, so we need to swap the axis and invert y
DannyLee 3:cf9fead9c3f4 121 float x = coord.y;
DannyLee 3:cf9fead9c3f4 122 float y = coord.x;
DannyLee 3:cf9fead9c3f4 123
DannyLee 3:cf9fead9c3f4 124 float mag = sqrt(x*x+y*y); // pythagoras
DannyLee 3:cf9fead9c3f4 125 float angle = RAD2DEG*atan2(y,x);
DannyLee 3:cf9fead9c3f4 126 // angle will be in range -180 to 180, so add 360 to negative angles to
DannyLee 3:cf9fead9c3f4 127 // move to 0 to 360 range
DannyLee 3:cf9fead9c3f4 128 if (angle < 0.0f) {
DannyLee 3:cf9fead9c3f4 129 angle+=360.0f;
DannyLee 3:cf9fead9c3f4 130 }
DannyLee 3:cf9fead9c3f4 131
DannyLee 3:cf9fead9c3f4 132 // the noise on the ADC causes the values of x and y to fluctuate slightly
DannyLee 3:cf9fead9c3f4 133 // around the centred values. This causes the random angle values to get
DannyLee 3:cf9fead9c3f4 134 // calculated when the joystick is centred and untouched. This is also when
DannyLee 3:cf9fead9c3f4 135 // the magnitude is very small, so we can check for a small magnitude and then
DannyLee 3:cf9fead9c3f4 136 // set the angle to -1. This will inform us when the angle is invalid and the
DannyLee 3:cf9fead9c3f4 137 // joystick is centred
DannyLee 3:cf9fead9c3f4 138
DannyLee 3:cf9fead9c3f4 139 if (mag < TOL) {
DannyLee 3:cf9fead9c3f4 140 mag = 0.0f;
DannyLee 3:cf9fead9c3f4 141 angle = -1.0f;
DannyLee 3:cf9fead9c3f4 142 }
DannyLee 3:cf9fead9c3f4 143
DannyLee 3:cf9fead9c3f4 144 Polar p = {mag,angle};
DannyLee 3:cf9fead9c3f4 145 return p;
DannyLee 3:cf9fead9c3f4 146 }
DannyLee 3:cf9fead9c3f4 147
DannyLee 3:cf9fead9c3f4 148 bool Joystick::button_pressed()
DannyLee 3:cf9fead9c3f4 149 {
DannyLee 3:cf9fead9c3f4 150 // ISR must have been triggered
DannyLee 3:cf9fead9c3f4 151 if (_click_flag) {
DannyLee 3:cf9fead9c3f4 152 _click_flag = 0; // clear flag
DannyLee 3:cf9fead9c3f4 153 return true;
DannyLee 3:cf9fead9c3f4 154 } else {
DannyLee 3:cf9fead9c3f4 155 return false;
DannyLee 3:cf9fead9c3f4 156 }
DannyLee 3:cf9fead9c3f4 157 }
DannyLee 3:cf9fead9c3f4 158
DannyLee 3:cf9fead9c3f4 159 void Joystick::click_isr()
DannyLee 3:cf9fead9c3f4 160 {
DannyLee 3:cf9fead9c3f4 161 _click_flag = 1;
DannyLee 3:cf9fead9c3f4 162 }#include "Gamepad.h"
DannyLee 3:cf9fead9c3f4 163
DannyLee 3:cf9fead9c3f4 164 #include "mbed.h"
DannyLee 3:cf9fead9c3f4 165
DannyLee 3:cf9fead9c3f4 166 //////////// constructor/destructor ////////////
DannyLee 3:cf9fead9c3f4 167 Gamepad::Gamepad()
DannyLee 3:cf9fead9c3f4 168 :
DannyLee 3:cf9fead9c3f4 169 _led1(new PwmOut(PTA1)),
DannyLee 3:cf9fead9c3f4 170 _led2(new PwmOut(PTA2)),
DannyLee 3:cf9fead9c3f4 171 _led3(new PwmOut(PTC2)),
DannyLee 3:cf9fead9c3f4 172 _led4(new PwmOut(PTC3)),
DannyLee 3:cf9fead9c3f4 173 _led5(new PwmOut(PTC4)),
DannyLee 3:cf9fead9c3f4 174 _led6(new PwmOut(PTD3)),
DannyLee 3:cf9fead9c3f4 175
DannyLee 3:cf9fead9c3f4 176 _button_A(new InterruptIn(PTB9)),
DannyLee 3:cf9fead9c3f4 177 _button_B(new InterruptIn(PTD0)),
DannyLee 3:cf9fead9c3f4 178 _button_X(new InterruptIn(PTC17)),
DannyLee 3:cf9fead9c3f4 179 _button_Y(new InterruptIn(PTC12)),
DannyLee 3:cf9fead9c3f4 180 _button_L(new InterruptIn(PTB18)),
DannyLee 3:cf9fead9c3f4 181 _button_R(new InterruptIn(PTB3)),
DannyLee 3:cf9fead9c3f4 182 _button_back(new InterruptIn(PTB19)),
DannyLee 3:cf9fead9c3f4 183 _button_start(new InterruptIn(PTC5)),
DannyLee 3:cf9fead9c3f4 184 _button_joystick(new InterruptIn(PTC16)),
DannyLee 3:cf9fead9c3f4 185
DannyLee 3:cf9fead9c3f4 186 _vert(new AnalogIn(PTB10)),
DannyLee 3:cf9fead9c3f4 187 _horiz(new AnalogIn(PTB11)),
DannyLee 3:cf9fead9c3f4 188
DannyLee 3:cf9fead9c3f4 189 _buzzer(new PwmOut(PTC10)),
DannyLee 3:cf9fead9c3f4 190 _pot(new AnalogIn(PTB2)),
DannyLee 3:cf9fead9c3f4 191
DannyLee 3:cf9fead9c3f4 192 _timeout(new Timeout()),
DannyLee 3:cf9fead9c3f4 193
DannyLee 3:cf9fead9c3f4 194 _event_state(0),
DannyLee 3:cf9fead9c3f4 195
DannyLee 3:cf9fead9c3f4 196 _x0(0),
DannyLee 3:cf9fead9c3f4 197 _y0(0)
DannyLee 3:cf9fead9c3f4 198 {}
DannyLee 3:cf9fead9c3f4 199
DannyLee 3:cf9fead9c3f4 200 Gamepad::~Gamepad()
DannyLee 3:cf9fead9c3f4 201 {
DannyLee 3:cf9fead9c3f4 202 delete _led1,_led2,_led3,_led4,_led5,_led6;
DannyLee 3:cf9fead9c3f4 203 delete _button_A,_button_B,_button_joystick,_vert,_horiz;
DannyLee 3:cf9fead9c3f4 204 delete _button_X,_button_Y,_button_back,_button_start;
DannyLee 3:cf9fead9c3f4 205 delete _button_L,_button_R, _buzzer, _pot, _timeout;
DannyLee 3:cf9fead9c3f4 206 }
DannyLee 3:cf9fead9c3f4 207
DannyLee 3:cf9fead9c3f4 208 ///////////////// public methods /////////////////
DannyLee 3:cf9fead9c3f4 209
DannyLee 3:cf9fead9c3f4 210 void Gamepad::init()
DannyLee 3:cf9fead9c3f4 211 {
DannyLee 3:cf9fead9c3f4 212 leds_off();
DannyLee 3:cf9fead9c3f4 213 init_buttons();
DannyLee 3:cf9fead9c3f4 214
DannyLee 3:cf9fead9c3f4 215 // read centred values of joystick
DannyLee 3:cf9fead9c3f4 216 _x0 = _horiz->read();
DannyLee 3:cf9fead9c3f4 217 _y0 = _vert->read();
DannyLee 3:cf9fead9c3f4 218
DannyLee 3:cf9fead9c3f4 219 // clear all flags
DannyLee 3:cf9fead9c3f4 220 _event_state = 0;
DannyLee 3:cf9fead9c3f4 221 }
DannyLee 3:cf9fead9c3f4 222
DannyLee 3:cf9fead9c3f4 223 void Gamepad::leds_off()
DannyLee 3:cf9fead9c3f4 224 {
DannyLee 3:cf9fead9c3f4 225 leds(0.0);
DannyLee 3:cf9fead9c3f4 226 }
DannyLee 3:cf9fead9c3f4 227
DannyLee 3:cf9fead9c3f4 228 void Gamepad::leds_on()
DannyLee 3:cf9fead9c3f4 229 {
DannyLee 3:cf9fead9c3f4 230 leds(1.0);
DannyLee 3:cf9fead9c3f4 231 }
DannyLee 3:cf9fead9c3f4 232
DannyLee 3:cf9fead9c3f4 233 void Gamepad::leds(float val) const
DannyLee 3:cf9fead9c3f4 234 {
DannyLee 3:cf9fead9c3f4 235 if (val < 0.0f) {
DannyLee 3:cf9fead9c3f4 236 val = 0.0f;
DannyLee 3:cf9fead9c3f4 237 }
DannyLee 3:cf9fead9c3f4 238 if (val > 1.0f) {
DannyLee 3:cf9fead9c3f4 239 val = 1.0f;
DannyLee 3:cf9fead9c3f4 240 }
DannyLee 3:cf9fead9c3f4 241
DannyLee 3:cf9fead9c3f4 242 // leds are active-low, so subtract from 1.0
DannyLee 3:cf9fead9c3f4 243 // 0.0 corresponds to fully-off, 1.0 to fully-on
DannyLee 3:cf9fead9c3f4 244 val = 1.0f - val;
DannyLee 3:cf9fead9c3f4 245
DannyLee 3:cf9fead9c3f4 246 _led1->write(val);
DannyLee 3:cf9fead9c3f4 247 _led2->write(val);
DannyLee 3:cf9fead9c3f4 248 _led3->write(val);
DannyLee 3:cf9fead9c3f4 249 _led4->write(val);
DannyLee 3:cf9fead9c3f4 250 _led5->write(val);
DannyLee 3:cf9fead9c3f4 251 _led6->write(val);
DannyLee 3:cf9fead9c3f4 252 }
DannyLee 3:cf9fead9c3f4 253
DannyLee 3:cf9fead9c3f4 254 void Gamepad::led(int n,float val) const
DannyLee 3:cf9fead9c3f4 255 {
DannyLee 3:cf9fead9c3f4 256 // ensure they are within vlaid range
DannyLee 3:cf9fead9c3f4 257 if (val < 0.0f) {
DannyLee 3:cf9fead9c3f4 258 val = 0.0f;
DannyLee 3:cf9fead9c3f4 259 }
DannyLee 3:cf9fead9c3f4 260 if (val > 1.0f) {
DannyLee 3:cf9fead9c3f4 261 val = 1.0f;
DannyLee 3:cf9fead9c3f4 262 }
DannyLee 3:cf9fead9c3f4 263
DannyLee 3:cf9fead9c3f4 264 switch (n) {
DannyLee 3:cf9fead9c3f4 265
DannyLee 3:cf9fead9c3f4 266 // check for valid LED number and set value
DannyLee 3:cf9fead9c3f4 267
DannyLee 3:cf9fead9c3f4 268 case 1:
DannyLee 3:cf9fead9c3f4 269 _led1->write(1.0f-val); // active-low so subtract from 1
DannyLee 3:cf9fead9c3f4 270 break;
DannyLee 3:cf9fead9c3f4 271 case 2:
DannyLee 3:cf9fead9c3f4 272 _led2->write(1.0f-val); // active-low so subtract from 1
DannyLee 3:cf9fead9c3f4 273 break;
DannyLee 3:cf9fead9c3f4 274 case 3:
DannyLee 3:cf9fead9c3f4 275 _led3->write(1.0f-val); // active-low so subtract from 1
DannyLee 3:cf9fead9c3f4 276 break;
DannyLee 3:cf9fead9c3f4 277 case 4:
DannyLee 3:cf9fead9c3f4 278 _led4->write(1.0f-val); // active-low so subtract from 1
DannyLee 3:cf9fead9c3f4 279 break;
DannyLee 3:cf9fead9c3f4 280 case 5:
DannyLee 3:cf9fead9c3f4 281 _led5->write(1.0f-val); // active-low so subtract from 1
DannyLee 3:cf9fead9c3f4 282 break;
DannyLee 3:cf9fead9c3f4 283 case 6:
DannyLee 3:cf9fead9c3f4 284 _led6->write(1.0f-val); // active-low so subtract from 1
DannyLee 3:cf9fead9c3f4 285 break;
DannyLee 3:cf9fead9c3f4 286
DannyLee 3:cf9fead9c3f4 287 }
DannyLee 3:cf9fead9c3f4 288 }
DannyLee 3:cf9fead9c3f4 289
DannyLee 3:cf9fead9c3f4 290 float Gamepad::read_pot() const
DannyLee 3:cf9fead9c3f4 291 {
DannyLee 3:cf9fead9c3f4 292 return _pot->read();
DannyLee 3:cf9fead9c3f4 293 }
DannyLee 3:cf9fead9c3f4 294
DannyLee 3:cf9fead9c3f4 295 void Gamepad::tone(float frequency, float duration)
DannyLee 3:cf9fead9c3f4 296 {
DannyLee 3:cf9fead9c3f4 297 _buzzer->period(1.0f/frequency);
DannyLee 3:cf9fead9c3f4 298 _buzzer->write(0.5); // 50% duty cycle - square wave
DannyLee 3:cf9fead9c3f4 299 _timeout->attach(callback(this, &Gamepad::tone_off), duration );
DannyLee 3:cf9fead9c3f4 300 }
DannyLee 3:cf9fead9c3f4 301
DannyLee 3:cf9fead9c3f4 302 bool Gamepad::check_event(GamepadEvent const id)
DannyLee 3:cf9fead9c3f4 303 {
DannyLee 3:cf9fead9c3f4 304 // Check whether event flag is set
DannyLee 3:cf9fead9c3f4 305 if (_event_state[id]) {
DannyLee 3:cf9fead9c3f4 306 _event_state.reset(id); // clear flag
DannyLee 3:cf9fead9c3f4 307 return true;
DannyLee 3:cf9fead9c3f4 308 } else {
DannyLee 3:cf9fead9c3f4 309 return false;
DannyLee 3:cf9fead9c3f4 310 }
DannyLee 3:cf9fead9c3f4 311 }
DannyLee 3:cf9fead9c3f4 312
DannyLee 3:cf9fead9c3f4 313 // this method gets the magnitude of the joystick movement
DannyLee 3:cf9fead9c3f4 314 float Gamepad::get_mag()
DannyLee 3:cf9fead9c3f4 315 {
DannyLee 3:cf9fead9c3f4 316 Polar p = get_polar();
DannyLee 3:cf9fead9c3f4 317 return p.mag;
DannyLee 3:cf9fead9c3f4 318 }
DannyLee 3:cf9fead9c3f4 319
DannyLee 3:cf9fead9c3f4 320 // this method gets the angle of joystick movement (0 to 360, 0 North)
DannyLee 3:cf9fead9c3f4 321 float Gamepad::get_angle()
DannyLee 3:cf9fead9c3f4 322 {
DannyLee 3:cf9fead9c3f4 323 Polar p = get_polar();
DannyLee 3:cf9fead9c3f4 324 return p.angle;
DannyLee 3:cf9fead9c3f4 325 }
DannyLee 3:cf9fead9c3f4 326
DannyLee 3:cf9fead9c3f4 327 Direction Gamepad::get_direction()
DannyLee 3:cf9fead9c3f4 328 {
DannyLee 3:cf9fead9c3f4 329 float angle = get_angle(); // 0 to 360, -1 for centred
DannyLee 3:cf9fead9c3f4 330
DannyLee 3:cf9fead9c3f4 331 Direction d;
DannyLee 3:cf9fead9c3f4 332 // partition 360 into segments and check which segment the angle is in
DannyLee 3:cf9fead9c3f4 333 if (angle < 0.0f) {
DannyLee 3:cf9fead9c3f4 334 d = CENTRE; // check for -1.0 angle
DannyLee 3:cf9fead9c3f4 335 } else if (angle < 22.5f) { // then keep going in 45 degree increments
DannyLee 3:cf9fead9c3f4 336 d = N;
DannyLee 3:cf9fead9c3f4 337 } else if (angle < 67.5f) {
DannyLee 3:cf9fead9c3f4 338 d = NE;
DannyLee 3:cf9fead9c3f4 339 } else if (angle < 112.5f) {
DannyLee 3:cf9fead9c3f4 340 d = E;
DannyLee 3:cf9fead9c3f4 341 } else if (angle < 157.5f) {
DannyLee 3:cf9fead9c3f4 342 d = SE;
DannyLee 3:cf9fead9c3f4 343 } else if (angle < 202.5f) {
DannyLee 3:cf9fead9c3f4 344 d = S;
DannyLee 3:cf9fead9c3f4 345 } else if (angle < 247.5f) {
DannyLee 3:cf9fead9c3f4 346 d = SW;
DannyLee 3:cf9fead9c3f4 347 } else if (angle < 292.5f) {
DannyLee 3:cf9fead9c3f4 348 d = W;
DannyLee 3:cf9fead9c3f4 349 } else if (angle < 337.5f) {
DannyLee 3:cf9fead9c3f4 350 d = NW;
DannyLee 3:cf9fead9c3f4 351 } else {
DannyLee 3:cf9fead9c3f4 352 d = N;
DannyLee 3:cf9fead9c3f4 353 }
DannyLee 3:cf9fead9c3f4 354
DannyLee 3:cf9fead9c3f4 355 return d;
DannyLee 3:cf9fead9c3f4 356 }
DannyLee 3:cf9fead9c3f4 357
DannyLee 3:cf9fead9c3f4 358 ///////////////////// private methods ////////////////////////
DannyLee 3:cf9fead9c3f4 359
DannyLee 3:cf9fead9c3f4 360 void Gamepad::tone_off()
DannyLee 3:cf9fead9c3f4 361 {
DannyLee 3:cf9fead9c3f4 362 // called after timeout
DannyLee 3:cf9fead9c3f4 363 _buzzer->write(0.0);
DannyLee 3:cf9fead9c3f4 364 }
DannyLee 3:cf9fead9c3f4 365
DannyLee 3:cf9fead9c3f4 366 void Gamepad::init_buttons()
DannyLee 3:cf9fead9c3f4 367 {
DannyLee 3:cf9fead9c3f4 368 // turn on pull-downs as other side of button is connected to 3V3
DannyLee 3:cf9fead9c3f4 369 // button is 0 when not pressed and 1 when pressed
DannyLee 3:cf9fead9c3f4 370 _button_A->mode(PullDown);
DannyLee 3:cf9fead9c3f4 371 _button_B->mode(PullDown);
DannyLee 3:cf9fead9c3f4 372 _button_X->mode(PullDown);
DannyLee 3:cf9fead9c3f4 373 _button_Y->mode(PullDown);
DannyLee 3:cf9fead9c3f4 374 _button_back->mode(PullDown);
DannyLee 3:cf9fead9c3f4 375 _button_start->mode(PullDown);
DannyLee 3:cf9fead9c3f4 376 _button_L->mode(PullDown);
DannyLee 3:cf9fead9c3f4 377 _button_R->mode(PullDown);
DannyLee 3:cf9fead9c3f4 378 _button_joystick->mode(PullDown);
DannyLee 3:cf9fead9c3f4 379 // therefore setup rising edge interrupts
DannyLee 3:cf9fead9c3f4 380 _button_A->rise(callback(this,&Gamepad::a_isr));
DannyLee 3:cf9fead9c3f4 381 _button_B->rise(callback(this,&Gamepad::b_isr));
DannyLee 3:cf9fead9c3f4 382 _button_X->rise(callback(this,&Gamepad::x_isr));
DannyLee 3:cf9fead9c3f4 383 _button_Y->rise(callback(this,&Gamepad::y_isr));
DannyLee 3:cf9fead9c3f4 384 _button_L->rise(callback(this,&Gamepad::l_isr));
DannyLee 3:cf9fead9c3f4 385 _button_R->rise(callback(this,&Gamepad::r_isr));
DannyLee 3:cf9fead9c3f4 386 _button_start->rise(callback(this,&Gamepad::start_isr));
DannyLee 3:cf9fead9c3f4 387 _button_back->rise(callback(this,&Gamepad::back_isr));
DannyLee 3:cf9fead9c3f4 388 _button_joystick->rise(callback(this,&Gamepad::joy_isr));
DannyLee 3:cf9fead9c3f4 389 }
DannyLee 3:cf9fead9c3f4 390
DannyLee 3:cf9fead9c3f4 391 // button interrupts ISRs
DannyLee 3:cf9fead9c3f4 392 // Each of these simply sets the appropriate event bit in the _event_state
DannyLee 3:cf9fead9c3f4 393 // variable
DannyLee 3:cf9fead9c3f4 394 void Gamepad::a_isr()
DannyLee 3:cf9fead9c3f4 395 {
DannyLee 3:cf9fead9c3f4 396 _event_state.set(A_PRESSED);
DannyLee 3:cf9fead9c3f4 397 }
DannyLee 3:cf9fead9c3f4 398 void Gamepad::b_isr()
DannyLee 3:cf9fead9c3f4 399 {
DannyLee 3:cf9fead9c3f4 400 _event_state.set(B_PRESSED);
DannyLee 3:cf9fead9c3f4 401 }
DannyLee 3:cf9fead9c3f4 402 void Gamepad::x_isr()
DannyLee 3:cf9fead9c3f4 403 {
DannyLee 3:cf9fead9c3f4 404 _event_state.set(X_PRESSED);
DannyLee 3:cf9fead9c3f4 405 }
DannyLee 3:cf9fead9c3f4 406 void Gamepad::y_isr()
DannyLee 3:cf9fead9c3f4 407 {
DannyLee 3:cf9fead9c3f4 408 _event_state.set(Y_PRESSED);
DannyLee 3:cf9fead9c3f4 409 }
DannyLee 3:cf9fead9c3f4 410 void Gamepad::l_isr()
DannyLee 3:cf9fead9c3f4 411 {
DannyLee 3:cf9fead9c3f4 412 _event_state.set(L_PRESSED);
DannyLee 3:cf9fead9c3f4 413 }
DannyLee 3:cf9fead9c3f4 414 void Gamepad::r_isr()
DannyLee 3:cf9fead9c3f4 415 {
DannyLee 3:cf9fead9c3f4 416 _event_state.set(R_PRESSED);
DannyLee 3:cf9fead9c3f4 417 }
DannyLee 3:cf9fead9c3f4 418 void Gamepad::back_isr()
DannyLee 3:cf9fead9c3f4 419 {
DannyLee 3:cf9fead9c3f4 420 _event_state.set(BACK_PRESSED);
DannyLee 3:cf9fead9c3f4 421 }
DannyLee 3:cf9fead9c3f4 422 void Gamepad::start_isr()
DannyLee 3:cf9fead9c3f4 423 {
DannyLee 3:cf9fead9c3f4 424 _event_state.set(START_PRESSED);
DannyLee 3:cf9fead9c3f4 425 }
DannyLee 3:cf9fead9c3f4 426 void Gamepad::joy_isr()
DannyLee 3:cf9fead9c3f4 427 {
DannyLee 3:cf9fead9c3f4 428 _event_state.set(JOY_PRESSED);
DannyLee 3:cf9fead9c3f4 429 }
DannyLee 3:cf9fead9c3f4 430
DannyLee 3:cf9fead9c3f4 431 // get raw joystick coordinate in range -1 to 1
DannyLee 3:cf9fead9c3f4 432 // Direction (x,y)
DannyLee 3:cf9fead9c3f4 433 // North (0,1)
DannyLee 3:cf9fead9c3f4 434 // East (1,0)
DannyLee 3:cf9fead9c3f4 435 // South (0,-1)
DannyLee 3:cf9fead9c3f4 436 // West (-1,0)
DannyLee 3:cf9fead9c3f4 437 Vector2D Gamepad::get_coord()
DannyLee 3:cf9fead9c3f4 438 {
DannyLee 3:cf9fead9c3f4 439 // read() returns value in range 0.0 to 1.0 so is scaled and centre value
DannyLee 3:cf9fead9c3f4 440 // substracted to get values in the range -1.0 to 1.0
DannyLee 3:cf9fead9c3f4 441 float x = 2.0f*( _horiz->read() - _x0 );
DannyLee 3:cf9fead9c3f4 442 float y = 2.0f*( _vert->read() - _y0 );
DannyLee 3:cf9fead9c3f4 443
DannyLee 3:cf9fead9c3f4 444 // Note: the x value here is inverted to ensure the positive x is to the
DannyLee 3:cf9fead9c3f4 445 // right. This is simply due to how the potentiometer on the joystick
DannyLee 3:cf9fead9c3f4 446 // I was using was connected up. It could have been corrected in hardware
DannyLee 3:cf9fead9c3f4 447 // by swapping the power supply pins. Instead it is done in software so may
DannyLee 3:cf9fead9c3f4 448 // need to be changed depending on your wiring setup
DannyLee 3:cf9fead9c3f4 449
DannyLee 3:cf9fead9c3f4 450 Vector2D coord = {-x,y};
DannyLee 3:cf9fead9c3f4 451 return coord;
DannyLee 3:cf9fead9c3f4 452 }
DannyLee 3:cf9fead9c3f4 453
DannyLee 3:cf9fead9c3f4 454 // This maps the raw x,y coord onto a circular grid.
DannyLee 3:cf9fead9c3f4 455 // See: http://mathproofs.blogspot.co.uk/2005/07/mapping-square-to-circle.html
DannyLee 3:cf9fead9c3f4 456 Vector2D Gamepad::get_mapped_coord()
DannyLee 3:cf9fead9c3f4 457 {
DannyLee 3:cf9fead9c3f4 458 Vector2D coord = get_coord();
DannyLee 3:cf9fead9c3f4 459
DannyLee 3:cf9fead9c3f4 460 // do the transformation
DannyLee 3:cf9fead9c3f4 461 float x = coord.x*sqrt(1.0f-pow(coord.y,2.0f)/2.0f);
DannyLee 3:cf9fead9c3f4 462 float y = coord.y*sqrt(1.0f-pow(coord.x,2.0f)/2.0f);
DannyLee 3:cf9fead9c3f4 463
DannyLee 3:cf9fead9c3f4 464 Vector2D mapped_coord = {x,y};
DannyLee 3:cf9fead9c3f4 465 return mapped_coord;
DannyLee 3:cf9fead9c3f4 466 }
DannyLee 3:cf9fead9c3f4 467
DannyLee 3:cf9fead9c3f4 468 // this function converts the mapped coordinates into polar form
DannyLee 3:cf9fead9c3f4 469 Polar Gamepad::get_polar()
DannyLee 3:cf9fead9c3f4 470 {
DannyLee 3:cf9fead9c3f4 471 // get the mapped coordinate
DannyLee 3:cf9fead9c3f4 472 Vector2D coord = get_mapped_coord();
DannyLee 3:cf9fead9c3f4 473
DannyLee 3:cf9fead9c3f4 474 // at this point, 0 degrees (i.e. x-axis) will be defined to the East.
DannyLee 3:cf9fead9c3f4 475 // We want 0 degrees to correspond to North and increase clockwise to 359
DannyLee 3:cf9fead9c3f4 476 // like a compass heading, so we need to swap the axis and invert y
DannyLee 3:cf9fead9c3f4 477 float x = coord.y;
DannyLee 3:cf9fead9c3f4 478 float y = coord.x;
DannyLee 3:cf9fead9c3f4 479
DannyLee 3:cf9fead9c3f4 480 float mag = sqrt(x*x+y*y); // pythagoras
DannyLee 3:cf9fead9c3f4 481 float angle = RAD2DEG*atan2(y,x);
DannyLee 3:cf9fead9c3f4 482 // angle will be in range -180 to 180, so add 360 to negative angles to
DannyLee 3:cf9fead9c3f4 483 // move to 0 to 360 range
DannyLee 3:cf9fead9c3f4 484 if (angle < 0.0f) {
DannyLee 3:cf9fead9c3f4 485 angle+=360.0f;
DannyLee 3:cf9fead9c3f4 486 }
DannyLee 3:cf9fead9c3f4 487
DannyLee 3:cf9fead9c3f4 488 // the noise on the ADC causes the values of x and y to fluctuate slightly
DannyLee 3:cf9fead9c3f4 489 // around the centred values. This causes the random angle values to get
DannyLee 3:cf9fead9c3f4 490 // calculated when the joystick is centred and untouched. This is also when
DannyLee 3:cf9fead9c3f4 491 // the magnitude is very small, so we can check for a small magnitude and then
DannyLee 3:cf9fead9c3f4 492 // set the angle to -1. This will inform us when the angle is invalid and the
DannyLee 3:cf9fead9c3f4 493 // joystick is centred
DannyLee 3:cf9fead9c3f4 494
DannyLee 3:cf9fead9c3f4 495 if (mag < TOL) {
DannyLee 3:cf9fead9c3f4 496 mag = 0.0f;
DannyLee 3:cf9fead9c3f4 497 angle = -1.0f;
DannyLee 3:cf9fead9c3f4 498 }
DannyLee 3:cf9fead9c3f4 499
DannyLee 3:cf9fead9c3f4 500 Polar p = {mag,angle};
DannyLee 3:cf9fead9c3f4 501 return p;
DannyLee 3:cf9fead9c3f4 502 }