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
- Committer:
- JonFreeman
- Date:
- 2019-03-04
- Revision:
- 14:6bcec5ac21ca
- Parent:
- 12:a25bdf135348
File content as of revision 14:6bcec5ac21ca:
#include "mbed.h" #include "Electric_Loco.h" #include "TS_DISCO_F746NG.h" #include "LCD_DISCO_F746NG.h" /** void read_keypresses (struct ky_bd & a) Sets values in struct ky_bd, containing : struct ky_bd { int count, slider_y; keystr key[MAX_TOUCHES + 1]; bool sli; } ; struct keystr { int keynum; int x; int y; } ; sets a.count to number of fingers found pressing buttons fills a.key[].keynum with list of 'a.count' button return codes fills corresponding a.key[].x and a.key[].y with finger coordinates if button is SLIDER_BUTTON sets a.sli true else sets false sets a.slider_y with new slider y coordinate - 0 at top */ extern STM3_ESC_Interface My_STM3_ESC_boards ; extern void throttle (double p) ; // New Apr 2018 ; servo adjusts throttle lever on Honda GX120 extern void read_keypresses (struct ky_bd & a) ; extern void draw_button_hilight (int but, int colour) ; extern void draw_button (struct button_specs & bu, int body_colour) ; extern void horn (int which, int onoff) ; extern Serial pc; /** int screen_touch_handler::viscous_drag (int up_viscosity, int dn_viscosity) ; Usage position = viscous_drag (a, b); Uses latest slider_y and present 'position' Returns a value for new position moved in direction by amount determined by difference but reduced more for high viscosity This allows for different rates of control movement for rise and fall */ int screen_touch_handler::viscous_drag (int ip, double up_drag, double dn_drag) { int s = (ip - position); // ip is final destination position of slider on scale if (!s) // If no movement return position; int rv; double d = (double) s; if (up_drag < 0.1) up_drag = 0.1; if (dn_drag < 0.1) dn_drag = 0.1; // avoiding DIV0 errors if (s < 0) { // Finger has moved up the slider rv = position - 1 + (int)(d / up_drag); } if (s > 0) { // Finger has moved down the slider rv = position + 1 + (int)(d / dn_drag); } return rv; } void screen_touch_handler::flush () { // clear keyboard buffers kybd_a.count = kybd_b.count = 0; for (int i = 0; i <= MAX_TOUCHES; i++) { kybd_a.key[i].keynum = kybd_b.key[i].keynum = 0; } } /* Dealing with Keys Pressed This time and Last time AUTOREPEAT This time and !Last time NEW_PRESS !This time and Last time NEW_RELEASE !This time and !Last time not detectable as key not in either list */ /** bool in_list (struct ky_bd & a, int key) Scans current keyboard buffer searching for 'key'. Returns true if found, false otherwise */ bool screen_touch_handler::in_list (struct ky_bd & a, int key) { int i = 0; while (i < a.count) if (key == a.key[i++].keynum) return true; return false; } void screen_touch_handler::motor_power () { // uses position to set motor volts and amps and Honda throttle int b = NEUTRAL_VAL - position; // now got integer going positive for increasing power demand double torque_req = ((double) b) / (double)(NEUTRAL_VAL - MIN_POS); // in range 0.0 to 1.0 if (torque_req < 0.0) torque_req = 0.0; if (torque_req > 1.0) torque_req = 1.0; // pc.printf ("torque_rec = %.3f, last_V = %.3f\r\n", torque_req, last_V); My_STM3_ESC_boards.set_I_limit (torque_req); if (torque_req < 0.05) { My_STM3_ESC_boards.set_V_limit (My_STM3_ESC_boards.last_V / 2.0); throttle (torque_req * 6.0); } else { // torque_rec >= 0.05 throttle (0.3 + (torque_req / 2.0)); if (My_STM3_ESC_boards.last_V < 0.99) My_STM3_ESC_boards.set_V_limit (My_STM3_ESC_boards.last_V + 0.05); // ramp voltage up rather than slam to max } // endof if/else (torque_req < 0.05) { } void screen_touch_handler::HandleFingerInput () { int key; if (present_kybd == &kybd_b) { // swap keyboard buffers present_kybd = &kybd_a; previous_kybd = &kybd_b; } else { present_kybd = &kybd_b; previous_kybd = &kybd_a; } read_keypresses (*present_kybd); // slider_state_machine (); // Takes care of all actions required of slider //void screen_touch_handler::slider_state_machine () { int old_position = position; // Used at end to decide if screen update required switch (next_state) { case NEUTRAL_DRIFT: // slider is at 'N', loco not being driven or braked but may well be rolling if (present_kybd->sli && previous_kybd->sli) { // finger is definitely on slider, found this time and last time if (present_kybd->slider_y < NEUTRAL_VAL) next_state = INTO_RUN; if (present_kybd->slider_y > NEUTRAL_VAL) next_state = INTO_REGEN_BRAKE; } break; // endof case NEUTRAL_DRIFT case INTO_NEUTRAL_DRIFT: My_STM3_ESC_boards.set_I_limit (0.0); My_STM3_ESC_boards.set_V_limit (0.0); throttle (0.0); // Honda revs to tickover position = NEUTRAL_VAL; // 'position' is copy of slider_y after application of any viscous damping next_state = NEUTRAL_DRIFT; break; case INTO_RUN: // cut motor power and set direction of travel if (present_kybd->sli) { // finger is on slider throttle (0.33); if (direction) My_STM3_ESC_boards.message ("fw\r"); // Forward run command else My_STM3_ESC_boards.message ("re\r"); // Reverse run command next_state = RUN; } break; // endof case INTO_RUN case INTO_REGEN_BRAKE: // cut motor power and set 'rb' My_STM3_ESC_boards.message ("rb\r"); // Regen Brake command throttle (0.0); // Wind Honda engine revs down to tickover next_state = REGEN_BRAKE; break; // endof case INTO_REGEN_BRAKE case REGEN_BRAKE: // established in regenerative braking mode, loco may or may not be rolling if (present_kybd->sli) { // finger is on slider. No action without finger if (position != present_kybd->slider_y) { // update braking effort according to finger movement position = viscous_drag (present_kybd->slider_y, 5.0, 5.0); if (position <= NEUTRAL_VAL) // if position risen out of REGEN_BRAKE region next_state = INTO_NEUTRAL_DRIFT; else { // position is within REGEN_BRAKE area double brake_effort = ((double)(position - NEUTRAL_VAL) / (double)(MAX_POS - NEUTRAL_VAL)); // brake_effort normalised to range 0.0 to 1.0 brake_effort *= 0.98; // upper limit to braking effort, observed effect before was quite fierce My_STM3_ESC_boards.set_V_limit (sqrt(brake_effort)); // sqrt gives more linear feel to control My_STM3_ESC_boards.set_I_limit (1.0); } // endof else position is within REGEN_BRAKE area } // endof if finger moved } // endof finger is on slider break; // endof case REGEN_BRAKE case RUN: // remains in this state while finger remains on slider in run range. Drive effort determined by finger position if (My_STM3_ESC_boards.last_V < 0.99) My_STM3_ESC_boards.set_V_limit (My_STM3_ESC_boards.last_V + 0.05); // ramp voltage up rather than slam to max if (present_kybd->sli) { // finger is on slider if (position != present_kybd->slider_y) { // update driving power according to finger movement position = viscous_drag (present_kybd->slider_y, 45.0, 20.0); if (position >= NEUTRAL_VAL) // if position falen below RUN region next_state = INTO_NEUTRAL_DRIFT; else // Finger is still in RUN range motor_power (); // class member already has position, sets volts, amps and throttle } // endof update driving power according to finger movement } // endof finger is on slider else { // finger not on slider throttle (0.0); // Honda revs down to tickover next_state = RUN_DOWN; } break; // endof case RUN case RUN_DOWN: // if finger removed during RUN, slider is to auto-glide back down to 'N' if (present_kybd->sli) // finger is on slider next_state = RUN; else { // finger is not on slider position = viscous_drag (NEUTRAL_VAL, 45.0, 20.0); if (position >= NEUTRAL_VAL) next_state = INTO_NEUTRAL_DRIFT; else motor_power (); } break; // endof RUN_DOWN } // endof switch (next_state) { if (position != old_position) { // partial screen rewrite is required DrawSlider (); } //} // endof void slider_state_machine () { if (present_kybd->count || previous_kybd->count) { // at least one key pressed this time or last time for (int i = 0; i < present_kybd->count; i++) { // PRESENT Do for all keys pressed on this pass key = present_kybd->key[i].keynum; if (in_list(*previous_kybd, key)) { // AUTOREPEAT This key is being pressed now and last time also // pc.printf ("Autorep key %d\r\n", key); } // endof AUTOREPEAT This key is being pressed now and last time also else { // NEW_PRESS key is a new keypress // pc.printf ("New Press %d\r\n", key); draw_button_hilight (key, LCD_COLOR_YELLOW) ; switch (key) { // Handle new touch screen button presses here - single action per press, not autorepeat case SLIDER_BUTTON: // All slider action handled in state machine above break; case SPEEDO_BUTTON: // No action currently assigned to speedo button break; case VMETER_BUTTON: // Turn on high tone horn horn (HI_HORN, 1); break; case AMETER_BUTTON: // Turn on low tone horn horn (LO_HORN, 1); break; default: pc.printf ("Unhandled keypress %d\r\n", key); break; } // endof switch (key) endof Handle new touch screen button presses here - single action per press, not autorepeat } // endof NEW_PRESS key is a new keypress } // endof PRESENT Do for all keys pressed on this pass for (int i = 0; i < previous_kybd->count; i++) { // Do for all keys pressed on previous pass key = previous_kybd->key[i].keynum; if (!in_list(*present_kybd, key)) { // NEW_RELEASE // pc.printf ("New Release %d\r\n", key); draw_button_hilight (key, LCD_COLOR_DARKBLUE) ; switch (key) { // Handle new touch screen button RELEASEs here - single action per press, not autorepeat case SLIDER_BUTTON: // break; case SPEEDO_BUTTON: // break; case VMETER_BUTTON: // horn (HI_HORN, 0); // Turn hi-tone horn off (voltmeter key) break; case AMETER_BUTTON: // horn (LO_HORN, 0); // Turn lo-tone horn off (powermeter key) break; default: pc.printf ("Unhandled key release %d\r\n", key); break; } // endof switch (button) } // endof NEW_RELEASE /* else { // DO NOT NEED SECOND FIND OF AUTOREPEAT pc.printf ("Autorep2\r\n"); }*/ } // endof Do for all keys pressed on previous pass } // endof at least one key pressed this time or last time else { // no keys being pressed on this pass or previous pass // pc.printf ("no key being pressed\r\n"); } // endof no keys being pressed on this pass or previous pass } // endof void screen_touch_handler::HandleFingerInput () { screen_touch_handler::screen_touch_handler () { // default constructor present_kybd = & kybd_a; previous_kybd = & kybd_b; oldpos = 0; position = MAX_POS - 2; next_state = INTO_REGEN_BRAKE; flush (); }