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.
Fork of Gamepad by
Gamepad.cpp
00001 #include "Gamepad.h" 00002 00003 #include "mbed.h" 00004 00005 //////////// constructor/destructor //////////// 00006 Gamepad::Gamepad() 00007 : 00008 _led1(new PwmOut(PTA1)), 00009 _led2(new PwmOut(PTA2)), 00010 _led3(new PwmOut(PTC2)), 00011 _led4(new PwmOut(PTC3)), 00012 _led5(new PwmOut(PTC4)), 00013 _led6(new PwmOut(PTD3)), 00014 00015 _button_A(new InterruptIn(PTB9)), 00016 _button_B(new InterruptIn(PTD0)), 00017 _button_X(new InterruptIn(PTC17)), 00018 _button_Y(new InterruptIn(PTC12)), 00019 _button_L(new InterruptIn(PTB18)), 00020 _button_R(new InterruptIn(PTB3)), 00021 _button_back(new InterruptIn(PTB19)), 00022 _button_start(new InterruptIn(PTC5)), 00023 _button_joystick(new InterruptIn(PTC16)), 00024 00025 _vert(new AnalogIn(PTB10)), 00026 _horiz(new AnalogIn(PTB11)), 00027 00028 _buzzer(new PwmOut(PTC10)), 00029 _pot(new AnalogIn(PTB2)), 00030 00031 _timeout(new Timeout()), 00032 00033 _event_state(0), 00034 00035 _x0(0), 00036 _y0(0) 00037 {} 00038 00039 Gamepad::~Gamepad() 00040 { 00041 delete _led1,_led2,_led3,_led4,_led5,_led6; 00042 delete _button_A,_button_B,_button_joystick,_vert,_horiz; 00043 delete _button_X,_button_Y,_button_back,_button_start; 00044 delete _button_L,_button_R, _buzzer, _pot, _timeout; 00045 } 00046 00047 ///////////////// public methods ///////////////// 00048 00049 void Gamepad::init() 00050 { 00051 leds_off(); 00052 init_buttons(); 00053 00054 // read centred values of joystick 00055 _x0 = _horiz->read(); 00056 _y0 = _vert->read(); 00057 00058 // clear all flags 00059 _event_state = 0; 00060 } 00061 00062 void Gamepad::leds_off() 00063 { 00064 leds(0.0); 00065 } 00066 00067 void Gamepad::leds_on() 00068 { 00069 leds(1.0); 00070 } 00071 00072 void Gamepad::leds(float val) const 00073 { 00074 if (val < 0.0f) { 00075 val = 0.0f; 00076 } 00077 if (val > 1.0f) { 00078 val = 1.0f; 00079 } 00080 00081 // leds are active-low, so subtract from 1.0 00082 // 0.0 corresponds to fully-off, 1.0 to fully-on 00083 val = 1.0f - val; 00084 00085 _led1->write(val); 00086 _led2->write(val); 00087 _led3->write(val); 00088 _led4->write(val); 00089 _led5->write(val); 00090 _led6->write(val); 00091 } 00092 00093 void Gamepad::led(int n,float val) const 00094 { 00095 // ensure they are within vlaid range 00096 if (val < 0.0f) { 00097 val = 0.0f; 00098 } 00099 if (val > 1.0f) { 00100 val = 1.0f; 00101 } 00102 00103 switch (n) { 00104 00105 // check for valid LED number and set value 00106 00107 case 1: 00108 _led1->write(1.0f-val); // active-low so subtract from 1 00109 break; 00110 case 2: 00111 _led2->write(1.0f-val); // active-low so subtract from 1 00112 break; 00113 case 3: 00114 _led3->write(1.0f-val); // active-low so subtract from 1 00115 break; 00116 case 4: 00117 _led4->write(1.0f-val); // active-low so subtract from 1 00118 break; 00119 case 5: 00120 _led5->write(1.0f-val); // active-low so subtract from 1 00121 break; 00122 case 6: 00123 _led6->write(1.0f-val); // active-low so subtract from 1 00124 break; 00125 00126 } 00127 } 00128 00129 float Gamepad::read_pot() const 00130 { 00131 return _pot->read(); 00132 } 00133 00134 void Gamepad::tone(float frequency, float duration) 00135 { 00136 _buzzer->period(1.0f/frequency); 00137 _buzzer->write(0.5); // 50% duty cycle - square wave 00138 _timeout->attach(callback(this, &Gamepad::tone_off), duration ); 00139 } 00140 00141 bool Gamepad::check_event(GamepadEvent const id) 00142 { 00143 // Check whether event flag is set 00144 if (_event_state[id]) { 00145 _event_state.reset(id); // clear flag 00146 return true; 00147 } else { 00148 return false; 00149 } 00150 } 00151 00152 // this method gets the magnitude of the joystick movement 00153 float Gamepad::get_mag() 00154 { 00155 Polar p = get_polar(); 00156 return p.mag; 00157 } 00158 00159 // this method gets the angle of joystick movement (0 to 360, 0 North) 00160 float Gamepad::get_angle() 00161 { 00162 Polar p = get_polar(); 00163 return p.angle; 00164 } 00165 00166 Direction Gamepad::get_direction() 00167 { 00168 float angle = get_angle(); // 0 to 360, -1 for centred 00169 00170 Direction d; 00171 // partition 360 into segments and check which segment the angle is in 00172 if (angle < 0.0f) { 00173 d = CENTRE; // check for -1.0 angle 00174 } else if (angle < 22.5f) { // then keep going in 45 degree increments 00175 d = N; 00176 } else if (angle < 67.5f) { 00177 d = NE; 00178 } else if (angle < 112.5f) { 00179 d = E; 00180 } else if (angle < 157.5f) { 00181 d = SE; 00182 } else if (angle < 202.5f) { 00183 d = S; 00184 } else if (angle < 247.5f) { 00185 d = SW; 00186 } else if (angle < 292.5f) { 00187 d = W; 00188 } else if (angle < 337.5f) { 00189 d = NW; 00190 } else { 00191 d = N; 00192 } 00193 00194 return d; 00195 } 00196 00197 ///////////////////// private methods //////////////////////// 00198 00199 void Gamepad::tone_off() 00200 { 00201 // called after timeout 00202 _buzzer->write(0.0); 00203 } 00204 00205 void Gamepad::init_buttons() 00206 { 00207 // turn on pull-downs as other side of button is connected to 3V3 00208 // button is 0 when not pressed and 1 when pressed 00209 _button_A->mode(PullDown); 00210 _button_B->mode(PullDown); 00211 _button_X->mode(PullDown); 00212 _button_Y->mode(PullDown); 00213 _button_back->mode(PullDown); 00214 _button_start->mode(PullDown); 00215 _button_L->mode(PullDown); 00216 _button_R->mode(PullDown); 00217 _button_joystick->mode(PullDown); 00218 // therefore setup rising edge interrupts 00219 _button_A->rise(callback(this,&Gamepad::a_isr)); 00220 _button_B->rise(callback(this,&Gamepad::b_isr)); 00221 _button_X->rise(callback(this,&Gamepad::x_isr)); 00222 _button_Y->rise(callback(this,&Gamepad::y_isr)); 00223 _button_L->rise(callback(this,&Gamepad::l_isr)); 00224 _button_R->rise(callback(this,&Gamepad::r_isr)); 00225 _button_start->rise(callback(this,&Gamepad::start_isr)); 00226 _button_back->rise(callback(this,&Gamepad::back_isr)); 00227 _button_joystick->rise(callback(this,&Gamepad::joy_isr)); 00228 } 00229 00230 // button interrupts ISRs 00231 // Each of these simply sets the appropriate event bit in the _event_state 00232 // variable 00233 void Gamepad::a_isr() 00234 { 00235 _event_state.set(A_PRESSED); 00236 } 00237 void Gamepad::b_isr() 00238 { 00239 _event_state.set(B_PRESSED); 00240 } 00241 void Gamepad::x_isr() 00242 { 00243 _event_state.set(X_PRESSED); 00244 } 00245 void Gamepad::y_isr() 00246 { 00247 _event_state.set(Y_PRESSED); 00248 } 00249 void Gamepad::l_isr() 00250 { 00251 _event_state.set(L_PRESSED); 00252 } 00253 void Gamepad::r_isr() 00254 { 00255 _event_state.set(R_PRESSED); 00256 } 00257 void Gamepad::back_isr() 00258 { 00259 _event_state.set(BACK_PRESSED); 00260 } 00261 void Gamepad::start_isr() 00262 { 00263 _event_state.set(START_PRESSED); 00264 } 00265 void Gamepad::joy_isr() 00266 { 00267 _event_state.set(JOY_PRESSED); 00268 } 00269 00270 // get raw joystick coordinate in range -1 to 1 00271 // Direction (x,y) 00272 // North (0,1) 00273 // East (1,0) 00274 // South (0,-1) 00275 // West (-1,0) 00276 Vector2D Gamepad::get_coord() 00277 { 00278 // read() returns value in range 0.0 to 1.0 so is scaled and centre value 00279 // substracted to get values in the range -1.0 to 1.0 00280 float x = 2.0f*( _horiz->read() - _x0 ); 00281 float y = 2.0f*( _vert->read() - _y0 ); 00282 00283 // Note: the x value here is inverted to ensure the positive x is to the 00284 // right. This is simply due to how the potentiometer on the joystick 00285 // I was using was connected up. It could have been corrected in hardware 00286 // by swapping the power supply pins. Instead it is done in software so may 00287 // need to be changed depending on your wiring setup 00288 00289 Vector2D coord = {-x,y}; 00290 return coord; 00291 } 00292 00293 // This maps the raw x,y coord onto a circular grid. 00294 // See: http://mathproofs.blogspot.co.uk/2005/07/mapping-square-to-circle.html 00295 Vector2D Gamepad::get_mapped_coord() 00296 { 00297 Vector2D coord = get_coord(); 00298 00299 // do the transformation 00300 float x = coord.x*sqrt(1.0f-pow(coord.y,2.0f)/2.0f); 00301 float y = coord.y*sqrt(1.0f-pow(coord.x,2.0f)/2.0f); 00302 00303 Vector2D mapped_coord = {x,y}; 00304 return mapped_coord; 00305 } 00306 00307 // this function converts the mapped coordinates into polar form 00308 Polar Gamepad::get_polar() 00309 { 00310 // get the mapped coordinate 00311 Vector2D coord = get_mapped_coord(); 00312 00313 // at this point, 0 degrees (i.e. x-axis) will be defined to the East. 00314 // We want 0 degrees to correspond to North and increase clockwise to 359 00315 // like a compass heading, so we need to swap the axis and invert y 00316 float x = coord.y; 00317 float y = coord.x; 00318 00319 float mag = sqrt(x*x+y*y); // pythagoras 00320 float angle = RAD2DEG*atan2(y,x); 00321 // angle will be in range -180 to 180, so add 360 to negative angles to 00322 // move to 0 to 360 range 00323 if (angle < 0.0f) { 00324 angle+=360.0f; 00325 } 00326 00327 // the noise on the ADC causes the values of x and y to fluctuate slightly 00328 // around the centred values. This causes the random angle values to get 00329 // calculated when the joystick is centred and untouched. This is also when 00330 // the magnitude is very small, so we can check for a small magnitude and then 00331 // set the angle to -1. This will inform us when the angle is invalid and the 00332 // joystick is centred 00333 00334 if (mag < TOL) { 00335 mag = 0.0f; 00336 angle = -1.0f; 00337 } 00338 00339 Polar p = {mag,angle}; 00340 return p; 00341 }
Generated on Mon Aug 1 2022 10:22:06 by
