Li Ruofan 201199450
Dependencies: mbed Gamepad Joystick
Joystick/Joystick.cpp@3:cf9fead9c3f4, 2020-05-14 (annotated)
- Committer:
- DannyLee
- Date:
- Thu May 14 13:12:28 2020 +0000
- Revision:
- 3:cf9fead9c3f4
aaa
Who changed what in which revision?
User | Revision | Line number | New 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 | } |