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

Committer:
JonFreeman
Date:
Mon Mar 04 17:47:27 2019 +0000
Revision:
14:6bcec5ac21ca
Parent:
12:a25bdf135348
'Brute' Locomotive Touch Screen Controller - Driver's Controls; Always a 'Work In Progress', snapshot March 2019

Who changed what in which revision?

UserRevisionLine numberNew contents of line
JonFreeman 12:a25bdf135348 1 #include "mbed.h"
JonFreeman 12:a25bdf135348 2 #include "Electric_Loco.h"
JonFreeman 12:a25bdf135348 3 #include "TS_DISCO_F746NG.h"
JonFreeman 12:a25bdf135348 4 #include "LCD_DISCO_F746NG.h"
JonFreeman 12:a25bdf135348 5
JonFreeman 12:a25bdf135348 6 /**
JonFreeman 12:a25bdf135348 7 void read_keypresses (struct ky_bd & a)
JonFreeman 12:a25bdf135348 8 Sets values in struct ky_bd, containing :
JonFreeman 12:a25bdf135348 9 struct ky_bd { int count, slider_y; keystr key[MAX_TOUCHES + 1]; bool sli; } ;
JonFreeman 12:a25bdf135348 10 struct keystr { int keynum; int x; int y; } ;
JonFreeman 12:a25bdf135348 11 sets a.count to number of fingers found pressing buttons
JonFreeman 12:a25bdf135348 12 fills a.key[].keynum with list of 'a.count' button return codes
JonFreeman 12:a25bdf135348 13 fills corresponding a.key[].x and a.key[].y with finger coordinates
JonFreeman 12:a25bdf135348 14 if button is SLIDER_BUTTON
JonFreeman 12:a25bdf135348 15 sets a.sli true else sets false
JonFreeman 12:a25bdf135348 16 sets a.slider_y with new slider y coordinate - 0 at top
JonFreeman 12:a25bdf135348 17 */
JonFreeman 12:a25bdf135348 18 extern STM3_ESC_Interface My_STM3_ESC_boards ;
JonFreeman 12:a25bdf135348 19 extern void throttle (double p) ; // New Apr 2018 ; servo adjusts throttle lever on Honda GX120
JonFreeman 12:a25bdf135348 20 extern void read_keypresses (struct ky_bd & a) ;
JonFreeman 12:a25bdf135348 21 extern void draw_button_hilight (int but, int colour) ;
JonFreeman 12:a25bdf135348 22 extern void draw_button (struct button_specs & bu, int body_colour) ;
JonFreeman 12:a25bdf135348 23 extern void horn (int which, int onoff) ;
JonFreeman 12:a25bdf135348 24
JonFreeman 12:a25bdf135348 25 extern Serial pc;
JonFreeman 12:a25bdf135348 26 /**
JonFreeman 12:a25bdf135348 27 int screen_touch_handler::viscous_drag (int up_viscosity, int dn_viscosity) ;
JonFreeman 12:a25bdf135348 28 Usage
JonFreeman 12:a25bdf135348 29 position = viscous_drag (a, b);
JonFreeman 12:a25bdf135348 30 Uses latest slider_y and present 'position'
JonFreeman 12:a25bdf135348 31 Returns a value for new position moved in direction by amount determined by difference but reduced more for high viscosity
JonFreeman 12:a25bdf135348 32 This allows for different rates of control movement for rise and fall
JonFreeman 12:a25bdf135348 33 */
JonFreeman 12:a25bdf135348 34 int screen_touch_handler::viscous_drag (int ip, double up_drag, double dn_drag) {
JonFreeman 12:a25bdf135348 35 int s = (ip - position); // ip is final destination position of slider on scale
JonFreeman 12:a25bdf135348 36 if (!s) // If no movement
JonFreeman 12:a25bdf135348 37 return position;
JonFreeman 12:a25bdf135348 38 int rv;
JonFreeman 12:a25bdf135348 39 double d = (double) s;
JonFreeman 12:a25bdf135348 40 if (up_drag < 0.1) up_drag = 0.1;
JonFreeman 12:a25bdf135348 41 if (dn_drag < 0.1) dn_drag = 0.1; // avoiding DIV0 errors
JonFreeman 12:a25bdf135348 42 if (s < 0) { // Finger has moved up the slider
JonFreeman 12:a25bdf135348 43 rv = position - 1 + (int)(d / up_drag);
JonFreeman 12:a25bdf135348 44 }
JonFreeman 12:a25bdf135348 45 if (s > 0) { // Finger has moved down the slider
JonFreeman 12:a25bdf135348 46 rv = position + 1 + (int)(d / dn_drag);
JonFreeman 12:a25bdf135348 47 }
JonFreeman 12:a25bdf135348 48 return rv;
JonFreeman 12:a25bdf135348 49 }
JonFreeman 12:a25bdf135348 50
JonFreeman 12:a25bdf135348 51 void screen_touch_handler::flush () { // clear keyboard buffers
JonFreeman 12:a25bdf135348 52 kybd_a.count = kybd_b.count = 0;
JonFreeman 12:a25bdf135348 53 for (int i = 0; i <= MAX_TOUCHES; i++) {
JonFreeman 12:a25bdf135348 54 kybd_a.key[i].keynum = kybd_b.key[i].keynum = 0;
JonFreeman 12:a25bdf135348 55 }
JonFreeman 12:a25bdf135348 56 }
JonFreeman 12:a25bdf135348 57 /*
JonFreeman 12:a25bdf135348 58 Dealing with Keys Pressed
JonFreeman 12:a25bdf135348 59 This time and Last time AUTOREPEAT
JonFreeman 12:a25bdf135348 60 This time and !Last time NEW_PRESS
JonFreeman 12:a25bdf135348 61 !This time and Last time NEW_RELEASE
JonFreeman 12:a25bdf135348 62 !This time and !Last time not detectable as key not in either list
JonFreeman 12:a25bdf135348 63 */
JonFreeman 12:a25bdf135348 64
JonFreeman 12:a25bdf135348 65 /**
JonFreeman 12:a25bdf135348 66 bool in_list (struct ky_bd & a, int key)
JonFreeman 12:a25bdf135348 67 Scans current keyboard buffer searching for 'key'.
JonFreeman 12:a25bdf135348 68 Returns true if found, false otherwise
JonFreeman 12:a25bdf135348 69 */
JonFreeman 12:a25bdf135348 70 bool screen_touch_handler::in_list (struct ky_bd & a, int key)
JonFreeman 12:a25bdf135348 71 {
JonFreeman 12:a25bdf135348 72 int i = 0;
JonFreeman 12:a25bdf135348 73 while (i < a.count)
JonFreeman 12:a25bdf135348 74 if (key == a.key[i++].keynum)
JonFreeman 12:a25bdf135348 75 return true;
JonFreeman 12:a25bdf135348 76 return false;
JonFreeman 12:a25bdf135348 77 }
JonFreeman 12:a25bdf135348 78
JonFreeman 12:a25bdf135348 79 void screen_touch_handler::motor_power () { // uses position to set motor volts and amps and Honda throttle
JonFreeman 12:a25bdf135348 80 int b = NEUTRAL_VAL - position; // now got integer going positive for increasing power demand
JonFreeman 12:a25bdf135348 81 double torque_req = ((double) b) / (double)(NEUTRAL_VAL - MIN_POS); // in range 0.0 to 1.0
JonFreeman 12:a25bdf135348 82 if (torque_req < 0.0) torque_req = 0.0;
JonFreeman 12:a25bdf135348 83 if (torque_req > 1.0) torque_req = 1.0;
JonFreeman 12:a25bdf135348 84 // pc.printf ("torque_rec = %.3f, last_V = %.3f\r\n", torque_req, last_V);
JonFreeman 12:a25bdf135348 85 My_STM3_ESC_boards.set_I_limit (torque_req);
JonFreeman 12:a25bdf135348 86 if (torque_req < 0.05) {
JonFreeman 12:a25bdf135348 87 My_STM3_ESC_boards.set_V_limit (My_STM3_ESC_boards.last_V / 2.0);
JonFreeman 12:a25bdf135348 88 throttle (torque_req * 6.0);
JonFreeman 12:a25bdf135348 89 }
JonFreeman 12:a25bdf135348 90 else { // torque_rec >= 0.05
JonFreeman 12:a25bdf135348 91 throttle (0.3 + (torque_req / 2.0));
JonFreeman 12:a25bdf135348 92 if (My_STM3_ESC_boards.last_V < 0.99)
JonFreeman 12:a25bdf135348 93 My_STM3_ESC_boards.set_V_limit (My_STM3_ESC_boards.last_V + 0.05); // ramp voltage up rather than slam to max
JonFreeman 12:a25bdf135348 94 } // endof if/else (torque_req < 0.05) {
JonFreeman 12:a25bdf135348 95 }
JonFreeman 12:a25bdf135348 96
JonFreeman 12:a25bdf135348 97
JonFreeman 12:a25bdf135348 98 void screen_touch_handler::HandleFingerInput () {
JonFreeman 12:a25bdf135348 99 int key;
JonFreeman 12:a25bdf135348 100 if (present_kybd == &kybd_b) { // swap keyboard buffers
JonFreeman 12:a25bdf135348 101 present_kybd = &kybd_a;
JonFreeman 12:a25bdf135348 102 previous_kybd = &kybd_b;
JonFreeman 12:a25bdf135348 103 } else {
JonFreeman 12:a25bdf135348 104 present_kybd = &kybd_b;
JonFreeman 12:a25bdf135348 105 previous_kybd = &kybd_a;
JonFreeman 12:a25bdf135348 106 }
JonFreeman 12:a25bdf135348 107 read_keypresses (*present_kybd);
JonFreeman 12:a25bdf135348 108
JonFreeman 12:a25bdf135348 109 // slider_state_machine (); // Takes care of all actions required of slider
JonFreeman 12:a25bdf135348 110
JonFreeman 12:a25bdf135348 111 //void screen_touch_handler::slider_state_machine () {
JonFreeman 12:a25bdf135348 112 int old_position = position; // Used at end to decide if screen update required
JonFreeman 12:a25bdf135348 113 switch (next_state) {
JonFreeman 12:a25bdf135348 114
JonFreeman 12:a25bdf135348 115 case NEUTRAL_DRIFT: // slider is at 'N', loco not being driven or braked but may well be rolling
JonFreeman 12:a25bdf135348 116 if (present_kybd->sli && previous_kybd->sli) { // finger is definitely on slider, found this time and last time
JonFreeman 12:a25bdf135348 117 if (present_kybd->slider_y < NEUTRAL_VAL)
JonFreeman 12:a25bdf135348 118 next_state = INTO_RUN;
JonFreeman 12:a25bdf135348 119 if (present_kybd->slider_y > NEUTRAL_VAL)
JonFreeman 12:a25bdf135348 120 next_state = INTO_REGEN_BRAKE;
JonFreeman 12:a25bdf135348 121 }
JonFreeman 12:a25bdf135348 122 break; // endof case NEUTRAL_DRIFT
JonFreeman 12:a25bdf135348 123
JonFreeman 12:a25bdf135348 124 case INTO_NEUTRAL_DRIFT:
JonFreeman 12:a25bdf135348 125 My_STM3_ESC_boards.set_I_limit (0.0);
JonFreeman 12:a25bdf135348 126 My_STM3_ESC_boards.set_V_limit (0.0);
JonFreeman 12:a25bdf135348 127 throttle (0.0); // Honda revs to tickover
JonFreeman 12:a25bdf135348 128 position = NEUTRAL_VAL; // 'position' is copy of slider_y after application of any viscous damping
JonFreeman 12:a25bdf135348 129 next_state = NEUTRAL_DRIFT;
JonFreeman 12:a25bdf135348 130 break;
JonFreeman 12:a25bdf135348 131
JonFreeman 12:a25bdf135348 132 case INTO_RUN: // cut motor power and set direction of travel
JonFreeman 12:a25bdf135348 133 if (present_kybd->sli) { // finger is on slider
JonFreeman 12:a25bdf135348 134 throttle (0.33);
JonFreeman 12:a25bdf135348 135 if (direction) My_STM3_ESC_boards.message ("fw\r"); // Forward run command
JonFreeman 12:a25bdf135348 136 else My_STM3_ESC_boards.message ("re\r"); // Reverse run command
JonFreeman 12:a25bdf135348 137 next_state = RUN;
JonFreeman 12:a25bdf135348 138 }
JonFreeman 12:a25bdf135348 139 break; // endof case INTO_RUN
JonFreeman 12:a25bdf135348 140
JonFreeman 12:a25bdf135348 141 case INTO_REGEN_BRAKE: // cut motor power and set 'rb'
JonFreeman 12:a25bdf135348 142 My_STM3_ESC_boards.message ("rb\r"); // Regen Brake command
JonFreeman 12:a25bdf135348 143 throttle (0.0); // Wind Honda engine revs down to tickover
JonFreeman 12:a25bdf135348 144 next_state = REGEN_BRAKE;
JonFreeman 12:a25bdf135348 145 break; // endof case INTO_REGEN_BRAKE
JonFreeman 12:a25bdf135348 146
JonFreeman 12:a25bdf135348 147 case REGEN_BRAKE: // established in regenerative braking mode, loco may or may not be rolling
JonFreeman 12:a25bdf135348 148 if (present_kybd->sli) { // finger is on slider. No action without finger
JonFreeman 12:a25bdf135348 149 if (position != present_kybd->slider_y) { // update braking effort according to finger movement
JonFreeman 12:a25bdf135348 150 position = viscous_drag (present_kybd->slider_y, 5.0, 5.0);
JonFreeman 12:a25bdf135348 151 if (position <= NEUTRAL_VAL) // if position risen out of REGEN_BRAKE region
JonFreeman 12:a25bdf135348 152 next_state = INTO_NEUTRAL_DRIFT;
JonFreeman 12:a25bdf135348 153 else { // position is within REGEN_BRAKE area
JonFreeman 12:a25bdf135348 154 double brake_effort = ((double)(position - NEUTRAL_VAL) / (double)(MAX_POS - NEUTRAL_VAL));
JonFreeman 12:a25bdf135348 155 // brake_effort normalised to range 0.0 to 1.0
JonFreeman 12:a25bdf135348 156 brake_effort *= 0.98; // upper limit to braking effort, observed effect before was quite fierce
JonFreeman 12:a25bdf135348 157 My_STM3_ESC_boards.set_V_limit (sqrt(brake_effort)); // sqrt gives more linear feel to control
JonFreeman 12:a25bdf135348 158 My_STM3_ESC_boards.set_I_limit (1.0);
JonFreeman 12:a25bdf135348 159 } // endof else position is within REGEN_BRAKE area
JonFreeman 12:a25bdf135348 160 } // endof if finger moved
JonFreeman 12:a25bdf135348 161 } // endof finger is on slider
JonFreeman 12:a25bdf135348 162 break; // endof case REGEN_BRAKE
JonFreeman 12:a25bdf135348 163
JonFreeman 12:a25bdf135348 164 case RUN: // remains in this state while finger remains on slider in run range. Drive effort determined by finger position
JonFreeman 12:a25bdf135348 165 if (My_STM3_ESC_boards.last_V < 0.99)
JonFreeman 12:a25bdf135348 166 My_STM3_ESC_boards.set_V_limit (My_STM3_ESC_boards.last_V + 0.05); // ramp voltage up rather than slam to max
JonFreeman 12:a25bdf135348 167 if (present_kybd->sli) { // finger is on slider
JonFreeman 12:a25bdf135348 168 if (position != present_kybd->slider_y) { // update driving power according to finger movement
JonFreeman 12:a25bdf135348 169 position = viscous_drag (present_kybd->slider_y, 45.0, 20.0);
JonFreeman 12:a25bdf135348 170 if (position >= NEUTRAL_VAL) // if position falen below RUN region
JonFreeman 12:a25bdf135348 171 next_state = INTO_NEUTRAL_DRIFT;
JonFreeman 12:a25bdf135348 172 else // Finger is still in RUN range
JonFreeman 12:a25bdf135348 173 motor_power (); // class member already has position, sets volts, amps and throttle
JonFreeman 12:a25bdf135348 174 } // endof update driving power according to finger movement
JonFreeman 12:a25bdf135348 175 } // endof finger is on slider
JonFreeman 12:a25bdf135348 176 else { // finger not on slider
JonFreeman 12:a25bdf135348 177 throttle (0.0); // Honda revs down to tickover
JonFreeman 12:a25bdf135348 178 next_state = RUN_DOWN;
JonFreeman 12:a25bdf135348 179 }
JonFreeman 12:a25bdf135348 180 break; // endof case RUN
JonFreeman 12:a25bdf135348 181
JonFreeman 12:a25bdf135348 182 case RUN_DOWN: // if finger removed during RUN, slider is to auto-glide back down to 'N'
JonFreeman 12:a25bdf135348 183 if (present_kybd->sli) // finger is on slider
JonFreeman 12:a25bdf135348 184 next_state = RUN;
JonFreeman 12:a25bdf135348 185 else { // finger is not on slider
JonFreeman 12:a25bdf135348 186 position = viscous_drag (NEUTRAL_VAL, 45.0, 20.0);
JonFreeman 12:a25bdf135348 187 if (position >= NEUTRAL_VAL)
JonFreeman 12:a25bdf135348 188 next_state = INTO_NEUTRAL_DRIFT;
JonFreeman 12:a25bdf135348 189 else
JonFreeman 12:a25bdf135348 190 motor_power ();
JonFreeman 12:a25bdf135348 191 }
JonFreeman 12:a25bdf135348 192 break; // endof RUN_DOWN
JonFreeman 12:a25bdf135348 193
JonFreeman 12:a25bdf135348 194 } // endof switch (next_state) {
JonFreeman 12:a25bdf135348 195
JonFreeman 12:a25bdf135348 196 if (position != old_position) { // partial screen rewrite is required
JonFreeman 12:a25bdf135348 197 DrawSlider ();
JonFreeman 12:a25bdf135348 198 }
JonFreeman 12:a25bdf135348 199 //} // endof void slider_state_machine () {
JonFreeman 12:a25bdf135348 200
JonFreeman 12:a25bdf135348 201
JonFreeman 12:a25bdf135348 202 if (present_kybd->count || previous_kybd->count) { // at least one key pressed this time or last time
JonFreeman 12:a25bdf135348 203
JonFreeman 12:a25bdf135348 204 for (int i = 0; i < present_kybd->count; i++) { // PRESENT Do for all keys pressed on this pass
JonFreeman 12:a25bdf135348 205 key = present_kybd->key[i].keynum;
JonFreeman 12:a25bdf135348 206 if (in_list(*previous_kybd, key)) { // AUTOREPEAT This key is being pressed now and last time also
JonFreeman 12:a25bdf135348 207 // pc.printf ("Autorep key %d\r\n", key);
JonFreeman 12:a25bdf135348 208 } // endof AUTOREPEAT This key is being pressed now and last time also
JonFreeman 12:a25bdf135348 209 else { // NEW_PRESS key is a new keypress
JonFreeman 12:a25bdf135348 210 // pc.printf ("New Press %d\r\n", key);
JonFreeman 12:a25bdf135348 211 draw_button_hilight (key, LCD_COLOR_YELLOW) ;
JonFreeman 12:a25bdf135348 212 switch (key) { // Handle new touch screen button presses here - single action per press, not autorepeat
JonFreeman 12:a25bdf135348 213 case SLIDER_BUTTON: // All slider action handled in state machine above
JonFreeman 12:a25bdf135348 214 break;
JonFreeman 12:a25bdf135348 215 case SPEEDO_BUTTON: // No action currently assigned to speedo button
JonFreeman 12:a25bdf135348 216 break;
JonFreeman 12:a25bdf135348 217 case VMETER_BUTTON: // Turn on high tone horn
JonFreeman 12:a25bdf135348 218 horn (HI_HORN, 1);
JonFreeman 12:a25bdf135348 219 break;
JonFreeman 12:a25bdf135348 220 case AMETER_BUTTON: // Turn on low tone horn
JonFreeman 12:a25bdf135348 221 horn (LO_HORN, 1);
JonFreeman 12:a25bdf135348 222 break;
JonFreeman 12:a25bdf135348 223 default:
JonFreeman 12:a25bdf135348 224 pc.printf ("Unhandled keypress %d\r\n", key);
JonFreeman 12:a25bdf135348 225 break;
JonFreeman 12:a25bdf135348 226 } // endof switch (key) endof Handle new touch screen button presses here - single action per press, not autorepeat
JonFreeman 12:a25bdf135348 227 } // endof NEW_PRESS key is a new keypress
JonFreeman 12:a25bdf135348 228 } // endof PRESENT Do for all keys pressed on this pass
JonFreeman 12:a25bdf135348 229
JonFreeman 12:a25bdf135348 230 for (int i = 0; i < previous_kybd->count; i++) { // Do for all keys pressed on previous pass
JonFreeman 12:a25bdf135348 231 key = previous_kybd->key[i].keynum;
JonFreeman 12:a25bdf135348 232 if (!in_list(*present_kybd, key)) { // NEW_RELEASE
JonFreeman 12:a25bdf135348 233 // pc.printf ("New Release %d\r\n", key);
JonFreeman 12:a25bdf135348 234 draw_button_hilight (key, LCD_COLOR_DARKBLUE) ;
JonFreeman 12:a25bdf135348 235 switch (key) { // Handle new touch screen button RELEASEs here - single action per press, not autorepeat
JonFreeman 12:a25bdf135348 236 case SLIDER_BUTTON: //
JonFreeman 12:a25bdf135348 237 break;
JonFreeman 12:a25bdf135348 238 case SPEEDO_BUTTON: //
JonFreeman 12:a25bdf135348 239 break;
JonFreeman 12:a25bdf135348 240 case VMETER_BUTTON: //
JonFreeman 12:a25bdf135348 241 horn (HI_HORN, 0); // Turn hi-tone horn off (voltmeter key)
JonFreeman 12:a25bdf135348 242 break;
JonFreeman 12:a25bdf135348 243 case AMETER_BUTTON: //
JonFreeman 12:a25bdf135348 244 horn (LO_HORN, 0); // Turn lo-tone horn off (powermeter key)
JonFreeman 12:a25bdf135348 245 break;
JonFreeman 12:a25bdf135348 246 default:
JonFreeman 12:a25bdf135348 247 pc.printf ("Unhandled key release %d\r\n", key);
JonFreeman 12:a25bdf135348 248 break;
JonFreeman 12:a25bdf135348 249 } // endof switch (button)
JonFreeman 12:a25bdf135348 250 } // endof NEW_RELEASE
JonFreeman 12:a25bdf135348 251 /* else { // DO NOT NEED SECOND FIND OF AUTOREPEAT
JonFreeman 12:a25bdf135348 252 pc.printf ("Autorep2\r\n");
JonFreeman 12:a25bdf135348 253 }*/
JonFreeman 12:a25bdf135348 254 } // endof Do for all keys pressed on previous pass
JonFreeman 12:a25bdf135348 255 } // endof at least one key pressed this time or last time
JonFreeman 12:a25bdf135348 256 else { // no keys being pressed on this pass or previous pass
JonFreeman 12:a25bdf135348 257 // pc.printf ("no key being pressed\r\n");
JonFreeman 12:a25bdf135348 258 } // endof no keys being pressed on this pass or previous pass
JonFreeman 12:a25bdf135348 259 } // endof void screen_touch_handler::HandleFingerInput () {
JonFreeman 12:a25bdf135348 260
JonFreeman 12:a25bdf135348 261 screen_touch_handler::screen_touch_handler () { // default constructor
JonFreeman 12:a25bdf135348 262 present_kybd = & kybd_a;
JonFreeman 12:a25bdf135348 263 previous_kybd = & kybd_b;
JonFreeman 12:a25bdf135348 264 oldpos = 0;
JonFreeman 12:a25bdf135348 265 position = MAX_POS - 2;
JonFreeman 12:a25bdf135348 266 next_state = INTO_REGEN_BRAKE;
JonFreeman 12:a25bdf135348 267 flush ();
JonFreeman 12:a25bdf135348 268 }
JonFreeman 12:a25bdf135348 269