Touch screen drivers control dashboard for miniature locomotive. Features meters for speed, volts, power. Switches for lights, horns. Drives multiple STM3_ESC brushless motor controllers for complete brushless loco system as used in "The Brute" - www.jons-workshop.com
Dependencies: TS_DISCO_F746NG mbed Servo LCD_DISCO_F746NG BSP_DISCO_F746NG QSPI_DISCO_F746NG AsyncSerial FastPWM
touch_handler.cpp
00001 #include "mbed.h" 00002 #include "Electric_Loco.h" 00003 #include "TS_DISCO_F746NG.h" 00004 #include "LCD_DISCO_F746NG.h" 00005 00006 /** 00007 void read_keypresses (struct ky_bd & a) 00008 Sets values in struct ky_bd, containing : 00009 struct ky_bd { int count, slider_y; keystr key[MAX_TOUCHES + 1]; bool sli; } ; 00010 struct keystr { int keynum; int x; int y; } ; 00011 sets a.count to number of fingers found pressing buttons 00012 fills a.key[].keynum with list of 'a.count' button return codes 00013 fills corresponding a.key[].x and a.key[].y with finger coordinates 00014 if button is SLIDER_BUTTON 00015 sets a.sli true else sets false 00016 sets a.slider_y with new slider y coordinate - 0 at top 00017 */ 00018 extern STM3_ESC_Interface My_STM3_ESC_boards ; 00019 extern void throttle (double p) ; // New Apr 2018 ; servo adjusts throttle lever on Honda GX120 00020 extern void read_keypresses (struct ky_bd & a) ; 00021 extern void draw_button_hilight (int but, int colour) ; 00022 extern void draw_button (struct button_specs & bu, int body_colour) ; 00023 extern void horn (int which, int onoff) ; 00024 00025 extern Serial pc; 00026 /** 00027 int screen_touch_handler::viscous_drag (int up_viscosity, int dn_viscosity) ; 00028 Usage 00029 position = viscous_drag (a, b); 00030 Uses latest slider_y and present 'position' 00031 Returns a value for new position moved in direction by amount determined by difference but reduced more for high viscosity 00032 This allows for different rates of control movement for rise and fall 00033 */ 00034 int screen_touch_handler::viscous_drag (int ip, double up_drag, double dn_drag) { 00035 int s = (ip - position); // ip is final destination position of slider on scale 00036 if (!s) // If no movement 00037 return position; 00038 int rv; 00039 double d = (double) s; 00040 if (up_drag < 0.1) up_drag = 0.1; 00041 if (dn_drag < 0.1) dn_drag = 0.1; // avoiding DIV0 errors 00042 if (s < 0) { // Finger has moved up the slider 00043 rv = position - 1 + (int)(d / up_drag); 00044 } 00045 if (s > 0) { // Finger has moved down the slider 00046 rv = position + 1 + (int)(d / dn_drag); 00047 } 00048 return rv; 00049 } 00050 00051 void screen_touch_handler::flush () { // clear keyboard buffers 00052 kybd_a.count = kybd_b.count = 0; 00053 for (int i = 0; i <= MAX_TOUCHES; i++) { 00054 kybd_a.key[i].keynum = kybd_b.key[i].keynum = 0; 00055 } 00056 } 00057 /* 00058 Dealing with Keys Pressed 00059 This time and Last time AUTOREPEAT 00060 This time and !Last time NEW_PRESS 00061 !This time and Last time NEW_RELEASE 00062 !This time and !Last time not detectable as key not in either list 00063 */ 00064 00065 /** 00066 bool in_list (struct ky_bd & a, int key) 00067 Scans current keyboard buffer searching for 'key'. 00068 Returns true if found, false otherwise 00069 */ 00070 bool screen_touch_handler::in_list (struct ky_bd & a, int key) 00071 { 00072 int i = 0; 00073 while (i < a.count) 00074 if (key == a.key[i++].keynum) 00075 return true; 00076 return false; 00077 } 00078 00079 void screen_touch_handler::motor_power () { // uses position to set motor volts and amps and Honda throttle 00080 int b = NEUTRAL_VAL - position; // now got integer going positive for increasing power demand 00081 double torque_req = ((double) b) / (double)(NEUTRAL_VAL - MIN_POS); // in range 0.0 to 1.0 00082 if (torque_req < 0.0) torque_req = 0.0; 00083 if (torque_req > 1.0) torque_req = 1.0; 00084 // pc.printf ("torque_rec = %.3f, last_V = %.3f\r\n", torque_req, last_V); 00085 My_STM3_ESC_boards.set_I_limit (torque_req); 00086 if (torque_req < 0.05) { 00087 My_STM3_ESC_boards.set_V_limit (My_STM3_ESC_boards.last_V / 2.0); 00088 throttle (torque_req * 6.0); 00089 } 00090 else { // torque_rec >= 0.05 00091 throttle (0.3 + (torque_req / 2.0)); 00092 if (My_STM3_ESC_boards.last_V < 0.99) 00093 My_STM3_ESC_boards.set_V_limit (My_STM3_ESC_boards.last_V + 0.05); // ramp voltage up rather than slam to max 00094 } // endof if/else (torque_req < 0.05) { 00095 } 00096 00097 00098 void screen_touch_handler::HandleFingerInput () { 00099 int key; 00100 if (present_kybd == &kybd_b) { // swap keyboard buffers 00101 present_kybd = &kybd_a; 00102 previous_kybd = &kybd_b; 00103 } else { 00104 present_kybd = &kybd_b; 00105 previous_kybd = &kybd_a; 00106 } 00107 read_keypresses (*present_kybd); 00108 00109 // slider_state_machine (); // Takes care of all actions required of slider 00110 00111 //void screen_touch_handler::slider_state_machine () { 00112 int old_position = position; // Used at end to decide if screen update required 00113 switch (next_state) { 00114 00115 case NEUTRAL_DRIFT: // slider is at 'N', loco not being driven or braked but may well be rolling 00116 if (present_kybd->sli && previous_kybd->sli) { // finger is definitely on slider, found this time and last time 00117 if (present_kybd->slider_y < NEUTRAL_VAL) 00118 next_state = INTO_RUN; 00119 if (present_kybd->slider_y > NEUTRAL_VAL) 00120 next_state = INTO_REGEN_BRAKE; 00121 } 00122 break; // endof case NEUTRAL_DRIFT 00123 00124 case INTO_NEUTRAL_DRIFT: 00125 My_STM3_ESC_boards.set_I_limit (0.0); 00126 My_STM3_ESC_boards.set_V_limit (0.0); 00127 throttle (0.0); // Honda revs to tickover 00128 position = NEUTRAL_VAL; // 'position' is copy of slider_y after application of any viscous damping 00129 next_state = NEUTRAL_DRIFT; 00130 break; 00131 00132 case INTO_RUN: // cut motor power and set direction of travel 00133 if (present_kybd->sli) { // finger is on slider 00134 throttle (0.33); 00135 if (direction) My_STM3_ESC_boards.message ("fw\r"); // Forward run command 00136 else My_STM3_ESC_boards.message ("re\r"); // Reverse run command 00137 next_state = RUN; 00138 } 00139 break; // endof case INTO_RUN 00140 00141 case INTO_REGEN_BRAKE: // cut motor power and set 'rb' 00142 My_STM3_ESC_boards.message ("rb\r"); // Regen Brake command 00143 throttle (0.0); // Wind Honda engine revs down to tickover 00144 next_state = REGEN_BRAKE; 00145 break; // endof case INTO_REGEN_BRAKE 00146 00147 case REGEN_BRAKE: // established in regenerative braking mode, loco may or may not be rolling 00148 if (present_kybd->sli) { // finger is on slider. No action without finger 00149 if (position != present_kybd->slider_y) { // update braking effort according to finger movement 00150 position = viscous_drag (present_kybd->slider_y, 5.0, 5.0); 00151 if (position <= NEUTRAL_VAL) // if position risen out of REGEN_BRAKE region 00152 next_state = INTO_NEUTRAL_DRIFT; 00153 else { // position is within REGEN_BRAKE area 00154 double brake_effort = ((double)(position - NEUTRAL_VAL) / (double)(MAX_POS - NEUTRAL_VAL)); 00155 // brake_effort normalised to range 0.0 to 1.0 00156 brake_effort *= 0.98; // upper limit to braking effort, observed effect before was quite fierce 00157 My_STM3_ESC_boards.set_V_limit (sqrt(brake_effort)); // sqrt gives more linear feel to control 00158 My_STM3_ESC_boards.set_I_limit (1.0); 00159 } // endof else position is within REGEN_BRAKE area 00160 } // endof if finger moved 00161 } // endof finger is on slider 00162 break; // endof case REGEN_BRAKE 00163 00164 case RUN: // remains in this state while finger remains on slider in run range. Drive effort determined by finger position 00165 if (My_STM3_ESC_boards.last_V < 0.99) 00166 My_STM3_ESC_boards.set_V_limit (My_STM3_ESC_boards.last_V + 0.05); // ramp voltage up rather than slam to max 00167 if (present_kybd->sli) { // finger is on slider 00168 if (position != present_kybd->slider_y) { // update driving power according to finger movement 00169 position = viscous_drag (present_kybd->slider_y, 45.0, 20.0); 00170 if (position >= NEUTRAL_VAL) // if position falen below RUN region 00171 next_state = INTO_NEUTRAL_DRIFT; 00172 else // Finger is still in RUN range 00173 motor_power (); // class member already has position, sets volts, amps and throttle 00174 } // endof update driving power according to finger movement 00175 } // endof finger is on slider 00176 else { // finger not on slider 00177 throttle (0.0); // Honda revs down to tickover 00178 next_state = RUN_DOWN; 00179 } 00180 break; // endof case RUN 00181 00182 case RUN_DOWN: // if finger removed during RUN, slider is to auto-glide back down to 'N' 00183 if (present_kybd->sli) // finger is on slider 00184 next_state = RUN; 00185 else { // finger is not on slider 00186 position = viscous_drag (NEUTRAL_VAL, 45.0, 20.0); 00187 if (position >= NEUTRAL_VAL) 00188 next_state = INTO_NEUTRAL_DRIFT; 00189 else 00190 motor_power (); 00191 } 00192 break; // endof RUN_DOWN 00193 00194 } // endof switch (next_state) { 00195 00196 if (position != old_position) { // partial screen rewrite is required 00197 DrawSlider (); 00198 } 00199 //} // endof void slider_state_machine () { 00200 00201 00202 if (present_kybd->count || previous_kybd->count) { // at least one key pressed this time or last time 00203 00204 for (int i = 0; i < present_kybd->count; i++) { // PRESENT Do for all keys pressed on this pass 00205 key = present_kybd->key[i].keynum; 00206 if (in_list(*previous_kybd, key)) { // AUTOREPEAT This key is being pressed now and last time also 00207 // pc.printf ("Autorep key %d\r\n", key); 00208 } // endof AUTOREPEAT This key is being pressed now and last time also 00209 else { // NEW_PRESS key is a new keypress 00210 // pc.printf ("New Press %d\r\n", key); 00211 draw_button_hilight (key, LCD_COLOR_YELLOW) ; 00212 switch (key) { // Handle new touch screen button presses here - single action per press, not autorepeat 00213 case SLIDER_BUTTON: // All slider action handled in state machine above 00214 break; 00215 case SPEEDO_BUTTON: // No action currently assigned to speedo button 00216 break; 00217 case VMETER_BUTTON: // Turn on high tone horn 00218 horn (HI_HORN, 1); 00219 break; 00220 case AMETER_BUTTON: // Turn on low tone horn 00221 horn (LO_HORN, 1); 00222 break; 00223 default: 00224 pc.printf ("Unhandled keypress %d\r\n", key); 00225 break; 00226 } // endof switch (key) endof Handle new touch screen button presses here - single action per press, not autorepeat 00227 } // endof NEW_PRESS key is a new keypress 00228 } // endof PRESENT Do for all keys pressed on this pass 00229 00230 for (int i = 0; i < previous_kybd->count; i++) { // Do for all keys pressed on previous pass 00231 key = previous_kybd->key[i].keynum; 00232 if (!in_list(*present_kybd, key)) { // NEW_RELEASE 00233 // pc.printf ("New Release %d\r\n", key); 00234 draw_button_hilight (key, LCD_COLOR_DARKBLUE) ; 00235 switch (key) { // Handle new touch screen button RELEASEs here - single action per press, not autorepeat 00236 case SLIDER_BUTTON: // 00237 break; 00238 case SPEEDO_BUTTON: // 00239 break; 00240 case VMETER_BUTTON: // 00241 horn (HI_HORN, 0); // Turn hi-tone horn off (voltmeter key) 00242 break; 00243 case AMETER_BUTTON: // 00244 horn (LO_HORN, 0); // Turn lo-tone horn off (powermeter key) 00245 break; 00246 default: 00247 pc.printf ("Unhandled key release %d\r\n", key); 00248 break; 00249 } // endof switch (button) 00250 } // endof NEW_RELEASE 00251 /* else { // DO NOT NEED SECOND FIND OF AUTOREPEAT 00252 pc.printf ("Autorep2\r\n"); 00253 }*/ 00254 } // endof Do for all keys pressed on previous pass 00255 } // endof at least one key pressed this time or last time 00256 else { // no keys being pressed on this pass or previous pass 00257 // pc.printf ("no key being pressed\r\n"); 00258 } // endof no keys being pressed on this pass or previous pass 00259 } // endof void screen_touch_handler::HandleFingerInput () { 00260 00261 screen_touch_handler::screen_touch_handler () { // default constructor 00262 present_kybd = & kybd_a; 00263 previous_kybd = & kybd_b; 00264 oldpos = 0; 00265 position = MAX_POS - 2; 00266 next_state = INTO_REGEN_BRAKE; 00267 flush (); 00268 } 00269
Generated on Thu Jul 14 2022 06:50:34 by 1.7.2