Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Gamepad.cpp
00001 #include "Gamepad.h" 00002 00003 #include "mbed.h" 00004 00005 //////////// constructor/destructor //////////// 00006 Gamepad::Gamepad() 00007 : 00008 _led1(new PwmOut(PTA2)), 00009 _led2(new PwmOut(PTC2)), 00010 _led3(new PwmOut(PTC3)), 00011 _led4(new PwmOut(PTA1)), 00012 _led5(new PwmOut(PTC10)), 00013 _led6(new PwmOut(PTC11)), 00014 00015 _button_A(new InterruptIn(PTC7)), 00016 _button_B(new InterruptIn(PTC9)), 00017 _button_X(new InterruptIn(PTC5)), 00018 _button_Y(new InterruptIn(PTC0)), 00019 _button_start(new InterruptIn(PTC8)), 00020 00021 00022 _vert(new AnalogIn(PTB11)), 00023 _horiz(new AnalogIn(PTB10)), 00024 00025 00026 _pot1(new AnalogIn(PTB2)), 00027 _pot2(new AnalogIn(PTB3)), 00028 00029 _speaker(new AnalogOut(DAC0_OUT)), 00030 _ticker(new Ticker()), 00031 _timeout(new Timeout()), 00032 00033 00034 00035 _x0(0), 00036 _y0(0) 00037 {} 00038 00039 00040 ///////////////// public methods ///////////////// 00041 00042 void Gamepad::init() 00043 { 00044 leds_off(); 00045 00046 // read centred values of joystick 00047 _x0 = _horiz->read(); 00048 _y0 = _vert->read(); 00049 00050 // Set all buttons to PullUp 00051 _button_A->mode(PullUp); 00052 _button_B->mode(PullUp); 00053 _button_X->mode(PullUp); 00054 _button_Y->mode(PullUp); 00055 _button_start->mode(PullUp); 00056 00057 // Set up interrupts for the fall of buttons 00058 _button_A->fall(callback(this,&Gamepad::A_fall_interrupt)); 00059 _button_B->fall(callback(this,&Gamepad::B_fall_interrupt)); 00060 _button_X->fall(callback(this,&Gamepad::X_fall_interrupt)); 00061 _button_Y->fall(callback(this,&Gamepad::Y_fall_interrupt)); 00062 _button_start->fall(callback(this,&Gamepad::start_fall_interrupt)); 00063 00064 // initalise button flags 00065 reset_buttons(); 00066 00067 // Initalise speaker as low 00068 _speaker->write(0); 00069 } 00070 00071 void Gamepad::leds_off() 00072 { 00073 leds(0.0); 00074 } 00075 00076 void Gamepad::leds_on() 00077 { 00078 leds(1.0); 00079 } 00080 00081 void Gamepad::leds(float val) const 00082 { 00083 if (val < 0.0f) { 00084 val = 0.0f; 00085 } 00086 if (val > 1.0f) { 00087 val = 1.0f; 00088 } 00089 00090 // leds are active-low, so subtract from 1.0 00091 // 0.0 corresponds to fully-off, 1.0 to fully-on 00092 val = 1.0f - val; 00093 00094 _led1->write(val); 00095 _led2->write(val); 00096 _led3->write(val); 00097 _led4->write(val); 00098 _led5->write(val); 00099 _led6->write(val); 00100 } 00101 00102 void Gamepad::led(int n,float val) const 00103 { 00104 // ensure they are within valid range 00105 if (val < 0.0f) { 00106 val = 0.0f; 00107 } 00108 if (val > 1.0f) { 00109 val = 1.0f; 00110 } 00111 00112 switch (n) { 00113 00114 // check for valid LED number and set value 00115 00116 case 1: 00117 _led1->write(1.0f-val); // active-low so subtract from 1 00118 break; 00119 case 2: 00120 _led2->write(1.0f-val); // active-low so subtract from 1 00121 break; 00122 case 3: 00123 _led3->write(1.0f-val); // active-low so subtract from 1 00124 break; 00125 case 4: 00126 _led4->write(1.0f-val); // active-low so subtract from 1 00127 break; 00128 case 5: 00129 _led5->write(1.0f-val); // active-low so subtract from 1 00130 break; 00131 case 6: 00132 _led6->write(1.0f-val); // active-low so subtract from 1 00133 break; 00134 00135 } 00136 } 00137 00138 float Gamepad::read_pot1() const 00139 { 00140 return _pot1->read(); 00141 } 00142 00143 float Gamepad::read_pot2() const 00144 { 00145 return _pot2->read(); 00146 } 00147 00148 void Gamepad::tone(float frequency, float duration) 00149 { 00150 // Too low frequencys can damage the speaker 00151 if (frequency < 1000) { 00152 return; 00153 } 00154 // Generates a square wave by flipping the dac from 1 to 0 00155 // and vice versa at half the time period 00156 _ticker->attach(callback(this,&Gamepad::flip_DAC),(1.0f/frequency)*0.5f); 00157 00158 // After the duration the ticker is detached. 00159 _timeout->attach(callback(this, &Gamepad::tone_off), duration ); 00160 } 00161 00162 00163 00164 // this method gets the magnitude of the joystick movement 00165 float Gamepad::get_mag() 00166 { 00167 Polar p = get_polar(); 00168 return p.mag; 00169 } 00170 00171 // this method gets the angle of joystick movement (0 to 360, 0 North) 00172 float Gamepad::get_angle() 00173 { 00174 Polar p = get_polar(); 00175 return p.angle; 00176 } 00177 00178 Direction Gamepad::get_direction() 00179 { 00180 float angle = get_angle(); // 0 to 360, -1 for centred 00181 00182 Direction d; 00183 // partition 360 into segments and check which segment the angle is in 00184 if (angle < 0.0f) { 00185 d = CENTRE; // check for -1.0 angle 00186 } else if (angle < 22.5f) { // then keep going in 45 degree increments 00187 d = N; 00188 } else if (angle < 67.5f) { 00189 d = NE; 00190 } else if (angle < 112.5f) { 00191 d = E; 00192 } else if (angle < 157.5f) { 00193 d = SE; 00194 } else if (angle < 202.5f) { 00195 d = S; 00196 } else if (angle < 247.5f) { 00197 d = SW; 00198 } else if (angle < 292.5f) { 00199 d = W; 00200 } else if (angle < 337.5f) { 00201 d = NW; 00202 } else { 00203 d = N; 00204 } 00205 00206 return d; 00207 } 00208 00209 void Gamepad::reset_buttons() { 00210 A_fall = B_fall = X_fall = Y_fall = start_fall = false; 00211 } 00212 00213 bool Gamepad::A_pressed() { 00214 if (A_fall) { 00215 A_fall = false; 00216 return true; 00217 } else { 00218 return false; 00219 } 00220 } 00221 00222 bool Gamepad::B_pressed() { 00223 if (B_fall) { 00224 B_fall = false; 00225 return true; 00226 } else { 00227 return false; 00228 } 00229 } 00230 00231 bool Gamepad::X_pressed() { 00232 if (X_fall) { 00233 X_fall = false; 00234 return true; 00235 } else { 00236 return false; 00237 } 00238 } 00239 00240 bool Gamepad::Y_pressed() { 00241 if (Y_fall) { 00242 Y_fall = false; 00243 return true; 00244 } else { 00245 return false; 00246 } 00247 } 00248 00249 bool Gamepad::start_pressed() { 00250 if (start_fall) { 00251 start_fall = false; 00252 return true; 00253 } else { 00254 return false; 00255 } 00256 } 00257 00258 bool Gamepad::A_held() { 00259 // Buttons are configured as PullUp hence the not 00260 return !_button_A->read(); 00261 } 00262 00263 bool Gamepad::B_held() { 00264 return !_button_B->read(); 00265 } 00266 00267 bool Gamepad::X_held() { 00268 return !_button_X->read(); 00269 } 00270 00271 bool Gamepad::Y_held() { 00272 return !_button_Y->read(); 00273 } 00274 00275 bool Gamepad::start_held() { 00276 return !_button_start->read(); 00277 } 00278 00279 ///////////////////// private methods //////////////////////// 00280 00281 void Gamepad::tone_off() 00282 { 00283 _ticker->detach(); 00284 } 00285 00286 void Gamepad::flip_DAC() 00287 { 00288 if (_speaker->read() == 1) { 00289 _speaker->write(0); 00290 } else { 00291 _speaker->write(1); 00292 } 00293 } 00294 00295 00296 00297 // get raw joystick coordinate in range -1 to 1 00298 // Direction (x,y) 00299 // North (0,1) 00300 // East (1,0) 00301 // South (0,-1) 00302 // West (-1,0) 00303 Vector2D Gamepad::get_coord() 00304 { 00305 // read() returns value in range 0.0 to 1.0 so is scaled and centre value 00306 // substracted to get values in the range -1.0 to 1.0 00307 float x = 2.0f*( _horiz->read() - _x0 ); 00308 float y = 2.0f*( _vert->read() - _y0 ); 00309 00310 // Note: the x value here is inverted to ensure the positive x is to the 00311 // right. This is simply due to how the potentiometer on the joystick 00312 // I was using was connected up. It could have been corrected in hardware 00313 // by swapping the power supply pins. Instead it is done in software so may 00314 // need to be changed depending on your wiring setup 00315 00316 Vector2D coord = {-x,y}; 00317 return coord; 00318 } 00319 00320 // This maps the raw x,y coord onto a circular grid. 00321 // See: http://mathproofs.blogspot.co.uk/2005/07/mapping-square-to-circle.html 00322 Vector2D Gamepad::get_mapped_coord() 00323 { 00324 Vector2D coord = get_coord(); 00325 00326 // do the transformation 00327 float x = coord.x*sqrt(1.0f-pow(coord.y,2.0f)/2.0f); 00328 float y = coord.y*sqrt(1.0f-pow(coord.x,2.0f)/2.0f); 00329 00330 Vector2D mapped_coord = {-x,-y}; 00331 return mapped_coord; 00332 } 00333 00334 // this function converts the mapped coordinates into polar form 00335 Polar Gamepad::get_polar() 00336 { 00337 // get the mapped coordinate 00338 Vector2D coord = get_mapped_coord(); 00339 00340 // at this point, 0 degrees (i.e. x-axis) will be defined to the East. 00341 // We want 0 degrees to correspond to North and increase clockwise to 359 00342 // like a compass heading, so we need to swap the axis and invert y 00343 float x = coord.y; 00344 float y = coord.x; 00345 00346 float mag = sqrt(x*x+y*y); // pythagoras 00347 float angle = RAD2DEG*atan2(y,x); 00348 // angle will be in range -180 to 180, so add 360 to negative angles to 00349 // move to 0 to 360 range 00350 if (angle < 0.0f) { 00351 angle+=360.0f; 00352 } 00353 00354 // the noise on the ADC causes the values of x and y to fluctuate slightly 00355 // around the centred values. This causes the random angle values to get 00356 // calculated when the joystick is centred and untouched. This is also when 00357 // the magnitude is very small, so we can check for a small magnitude and then 00358 // set the angle to -1. This will inform us when the angle is invalid and the 00359 // joystick is centred 00360 00361 if (mag < TOL) { 00362 mag = 0.0f; 00363 angle = -1.0f; 00364 } 00365 00366 Polar p = {mag,angle}; 00367 return p; 00368 } 00369 00370 // ISRs for buttons 00371 void Gamepad::A_fall_interrupt() { 00372 A_fall = true; 00373 } 00374 void Gamepad::B_fall_interrupt() { 00375 B_fall = true; 00376 } 00377 void Gamepad::X_fall_interrupt() { 00378 X_fall = true; 00379 } 00380 void Gamepad::Y_fall_interrupt() { 00381 Y_fall = true; 00382 } 00383 void Gamepad::start_fall_interrupt() { 00384 start_fall = true; 00385 }
Generated on Sat Jul 16 2022 16:00:56 by
1.7.2