VR FabLab - RoboVal / Mbed 2 deprecated Chronometer_V2

Dependencies:   mbed keypadLib TextLCD

Committer:
peps
Date:
Wed Apr 10 22:03:07 2019 +0000
Revision:
6:369dafe4ed5e
Parent:
5:47a452a6f248
Child:
7:f687eda36aec
v.2.1.1:; - improvement on keyboard handling; - added version display; - added keyboard test

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Ghiri 0:1a92e4a37697 1 //##############################################################
Ghiri 0:1a92e4a37697 2 //##
Ghiri 0:1a92e4a37697 3 //## Event: RoboVal - Robot Race
Ghiri 0:1a92e4a37697 4 //##
Ghiri 0:1a92e4a37697 5 //## Chronometer double use
Ghiri 0:1a92e4a37697 6 //##
peps 6:369dafe4ed5e 7 //## Version 2.1.1
Ghiri 0:1a92e4a37697 8 //##
Ghiri 0:1a92e4a37697 9 //## Hardware platform used: ST NUCLEO-F401RE
Ghiri 0:1a92e4a37697 10 //##
Ghiri 0:1a92e4a37697 11 //## Software IDE used: mbed online version
Ghiri 0:1a92e4a37697 12 //##
Ghiri 0:1a92e4a37697 13 //## Organizzation: Verona FabLab
Ghiri 0:1a92e4a37697 14 //##
Ghiri 0:1a92e4a37697 15 //## Date creation: 2018.01.01
Ghiri 0:1a92e4a37697 16 //##
peps 6:369dafe4ed5e 17 //## Software developpers: FdF,GV,AG
Ghiri 0:1a92e4a37697 18 //##
Ghiri 0:1a92e4a37697 19 //## Base on original version of by FdF
Ghiri 0:1a92e4a37697 20 //##
Ghiri 0:1a92e4a37697 21 //##############################################################
Ghiri 0:1a92e4a37697 22
Ghiri 0:1a92e4a37697 23 #include <stdlib.h>
Ghiri 0:1a92e4a37697 24 #include "mbed.h"
Ghiri 0:1a92e4a37697 25 #include "TextLCD.h"
peps 2:bd0c735e81d6 26
Ghiri 0:1a92e4a37697 27 // Default Number Lap
Ghiri 0:1a92e4a37697 28 #define NUM_LAP 3
Ghiri 0:1a92e4a37697 29
Ghiri 0:1a92e4a37697 30 // Reference for Low/Min Voltage battery
Ghiri 0:1a92e4a37697 31 #define VBAT_MIN 7.2
peps 2:bd0c735e81d6 32
peps 3:fd1353986910 33 // Different function modes
peps 2:bd0c735e81d6 34 enum modes {
peps 2:bd0c735e81d6 35 LABYRINTH,
peps 2:bd0c735e81d6 36 SPEED
peps 2:bd0c735e81d6 37 } mode = SPEED;
peps 2:bd0c735e81d6 38
peps 3:fd1353986910 39 // Human-readable time helper
peps 2:bd0c735e81d6 40 typedef struct time_screen {
peps 2:bd0c735e81d6 41 int cents;
peps 2:bd0c735e81d6 42 int seconds;
peps 2:bd0c735e81d6 43 int minutes;
peps 2:bd0c735e81d6 44 } measured_time;
Ghiri 1:26bcd89c18e5 45
peps 3:fd1353986910 46 // Heartbeat LED
Ghiri 0:1a92e4a37697 47 DigitalOut heartbeat(LED1);
Ghiri 0:1a92e4a37697 48
Ghiri 0:1a92e4a37697 49 // read Voltage battery, analog pin used PC_3 (Pin 37 of Morpho layout)
Ghiri 1:26bcd89c18e5 50 //AnalogIn vbat(PC_3);
Ghiri 0:1a92e4a37697 51
Ghiri 0:1a92e4a37697 52 // User button pressure
Ghiri 0:1a92e4a37697 53 InterruptIn user_button(USER_BUTTON);
Ghiri 0:1a92e4a37697 54
peps 3:fd1353986910 55 // Gates connected to digital input PA_15 and PB_7
peps 3:fd1353986910 56 InterruptIn gateStart(PA_15), gateEnd(PB_7);
Ghiri 0:1a92e4a37697 57
Ghiri 0:1a92e4a37697 58 // LCD Display (RS, E, D4, D5, D6, D7);
Ghiri 0:1a92e4a37697 59 TextLCD lcd(D2,D3,D4,D5,D6,D7);
peps 2:bd0c735e81d6 60
peps 3:fd1353986910 61 // Timer for the chrono function
peps 2:bd0c735e81d6 62 Timer t;
Ghiri 0:1a92e4a37697 63
peps 3:fd1353986910 64 // Number of laps
peps 3:fd1353986910 65 int lap = -1;
peps 6:369dafe4ed5e 66
peps 3:fd1353986910 67 // Best lap
peps 3:fd1353986910 68 int best_lap = 0;
peps 6:369dafe4ed5e 69
peps 3:fd1353986910 70 // Last time read
peps 2:bd0c735e81d6 71 int last_read = 0;
peps 6:369dafe4ed5e 72
peps 3:fd1353986910 73 // Last lap time
peps 2:bd0c735e81d6 74 int lap_time = 0;
peps 6:369dafe4ed5e 75
peps 3:fd1353986910 76 // Best lap time
peps 3:fd1353986910 77 int best_time = -1;
peps 6:369dafe4ed5e 78
peps 3:fd1353986910 79 // Pointer to the loop function (depending on the selected mode)
peps 2:bd0c735e81d6 80 void (*loopMethod)(void);
peps 6:369dafe4ed5e 81
peps 5:47a452a6f248 82 // Flag to avoid unwanted mode switch when running
peps 5:47a452a6f248 83 bool isRunning = false;
peps 2:bd0c735e81d6 84
peps 6:369dafe4ed5e 85 // Version string (max 16 chars)
peps 6:369dafe4ed5e 86 const char * VERSION_STRING = "Firmware v.2.1.1";
peps 6:369dafe4ed5e 87 const char * VERSION_DATE = "Date: 2019.04.10";
peps 5:47a452a6f248 88 /*** Keypad handling ****/
peps 4:23472c2b246b 89 PinName rowPins[4] = { PA_13, PA_14, PC_2, PC_3 };
peps 4:23472c2b246b 90 PinName colPins[4] = { PA_0, PA_1, PA_4, PB_0 };
peps 4:23472c2b246b 91
peps 4:23472c2b246b 92 DigitalOut* _rows[4];
peps 4:23472c2b246b 93 DigitalIn* _cols[4];
peps 4:23472c2b246b 94
peps 4:23472c2b246b 95 // Define your own keypad values
peps 4:23472c2b246b 96 char Keytable[] = {
peps 4:23472c2b246b 97 '1', '2', '3', 'A', // r0
peps 4:23472c2b246b 98 '4', '5', '6', 'B', // r1
peps 4:23472c2b246b 99 '7', '8', '9', 'C', // r2
peps 4:23472c2b246b 100 '*', '0', '#', 'D' // r3
peps 4:23472c2b246b 101 // c0 c1 c2 c3
peps 4:23472c2b246b 102 };
peps 4:23472c2b246b 103
peps 4:23472c2b246b 104 int getKeyIndex() {
peps 4:23472c2b246b 105 int result = -1;
peps 6:369dafe4ed5e 106 for (int r = 0; r < 4 && result == -1; r++) {
peps 4:23472c2b246b 107 _rows[r]->write(1);
peps 6:369dafe4ed5e 108 for(int c = 0;c < 4 && result == -1;c++){
peps 4:23472c2b246b 109 DigitalIn *col = _cols[c];
peps 4:23472c2b246b 110 if(col->read() == 1) {
peps 4:23472c2b246b 111 result = r*4+c;
peps 4:23472c2b246b 112 }
peps 4:23472c2b246b 113 }
peps 4:23472c2b246b 114 _rows[r]->write(0);
peps 4:23472c2b246b 115 }
peps 6:369dafe4ed5e 116 wait_ms(100);
peps 4:23472c2b246b 117 return result;
peps 4:23472c2b246b 118 }
peps 4:23472c2b246b 119
peps 4:23472c2b246b 120 char getKey() {
peps 4:23472c2b246b 121 int idx = getKeyIndex();
peps 4:23472c2b246b 122 return idx != -1 ? Keytable[idx] : '\0';
peps 4:23472c2b246b 123 }
peps 4:23472c2b246b 124
peps 4:23472c2b246b 125 void keypadInit() {
peps 4:23472c2b246b 126 for(int i = 0;i < 4; i++){
peps 4:23472c2b246b 127 _rows[i] = new DigitalOut(rowPins[i]);
peps 4:23472c2b246b 128 _rows[i]->write(0);
peps 4:23472c2b246b 129 }
peps 4:23472c2b246b 130 for(int i = 0;i < 4; i++){
peps 4:23472c2b246b 131 _cols[i] = new DigitalIn(colPins[i],PullDown);
peps 4:23472c2b246b 132 }
peps 4:23472c2b246b 133 }
peps 5:47a452a6f248 134 /**** End keypad handling ****/
peps 4:23472c2b246b 135
peps 5:47a452a6f248 136 //Convert milliseconds in human-readabe (mm:ss:cc) format
peps 2:bd0c735e81d6 137 measured_time human_read(int ms){
peps 2:bd0c735e81d6 138 measured_time read;
peps 2:bd0c735e81d6 139 div_t qr = div(ms,1000);
peps 2:bd0c735e81d6 140
peps 2:bd0c735e81d6 141 read.cents = qr.rem % 100;
peps 2:bd0c735e81d6 142
peps 2:bd0c735e81d6 143 qr = div(qr.quot,60);
peps 2:bd0c735e81d6 144 read.seconds = qr.rem;
peps 2:bd0c735e81d6 145
peps 2:bd0c735e81d6 146 qr = div(qr.quot,60);
peps 2:bd0c735e81d6 147 read.minutes = qr.rem;
peps 2:bd0c735e81d6 148
peps 2:bd0c735e81d6 149 return read;
peps 2:bd0c735e81d6 150 }
peps 2:bd0c735e81d6 151
peps 5:47a452a6f248 152 // Invoked when startGate triggered in SPEED mode.
peps 3:fd1353986910 153 // Start the timer or read the timer and store lap and best time
peps 3:fd1353986910 154 void measure_time() {
peps 5:47a452a6f248 155 isRunning = true;
peps 2:bd0c735e81d6 156 int read = t.read_ms();
peps 3:fd1353986910 157
peps 6:369dafe4ed5e 158 if(lap == -1) {
peps 2:bd0c735e81d6 159 t.start();
peps 2:bd0c735e81d6 160 lap++;
peps 6:369dafe4ed5e 161 } else {
peps 6:369dafe4ed5e 162 //Debouncing per evitare problemi
peps 6:369dafe4ed5e 163 if(read - last_read > 1000) {
peps 3:fd1353986910 164 lap++;
peps 2:bd0c735e81d6 165 lap_time = read - last_read;
peps 3:fd1353986910 166 if (best_time < 0 || lap_time < best_time) {
peps 3:fd1353986910 167 best_time = lap_time;
peps 3:fd1353986910 168 best_lap = lap;
peps 3:fd1353986910 169 }
peps 2:bd0c735e81d6 170
peps 3:fd1353986910 171 if(lap >= NUM_LAP) {
peps 2:bd0c735e81d6 172 t.stop();
peps 2:bd0c735e81d6 173 }
peps 2:bd0c735e81d6 174
peps 6:369dafe4ed5e 175 last_read = read;
peps 2:bd0c735e81d6 176 }
peps 3:fd1353986910 177 }
peps 2:bd0c735e81d6 178 }
peps 2:bd0c735e81d6 179
peps 4:23472c2b246b 180 // Handler for loop when in SPEED mode
peps 2:bd0c735e81d6 181 void speedLoop() {
peps 2:bd0c735e81d6 182 int read = t.read_ms();
peps 2:bd0c735e81d6 183
peps 2:bd0c735e81d6 184 measured_time time = human_read(read);
peps 2:bd0c735e81d6 185
peps 2:bd0c735e81d6 186 lcd.locate(0,0);
peps 2:bd0c735e81d6 187 lcd.printf("Totale %02d:%02d:%02d",time.minutes,time.seconds,time.cents);
peps 4:23472c2b246b 188
peps 4:23472c2b246b 189 // Handle lap time display
peps 4:23472c2b246b 190 switch(lap) {
peps 4:23472c2b246b 191 // only display time if at least 1 lap completed
peps 4:23472c2b246b 192 case -1:
peps 4:23472c2b246b 193 case 0:
peps 4:23472c2b246b 194 break;
peps 4:23472c2b246b 195 // all laps completed - display best lap time
peps 4:23472c2b246b 196 case NUM_LAP + 1:
peps 4:23472c2b246b 197 time = human_read(best_time);
peps 4:23472c2b246b 198 lcd.locate(0,1);
peps 4:23472c2b246b 199 lcd.printf("Best %d %02d:%02d:%02d",best_lap,time.minutes,time.seconds,time.cents);
peps 5:47a452a6f248 200 isRunning = false;
peps 4:23472c2b246b 201 break;
peps 4:23472c2b246b 202 // Default - display last completed lap time
peps 4:23472c2b246b 203 // In case of last lap, wait 1 sec -- next time, best lap will be displayed
peps 4:23472c2b246b 204 default:
peps 4:23472c2b246b 205 time = human_read(lap_time);
peps 4:23472c2b246b 206 lcd.locate(0,1);
peps 4:23472c2b246b 207 lcd.printf("Giro %d %02d:%02d:%02d",lap,time.minutes,time.seconds,time.cents);
peps 4:23472c2b246b 208 if (lap == NUM_LAP) {
peps 4:23472c2b246b 209 wait(1);
peps 4:23472c2b246b 210 lap++;
peps 4:23472c2b246b 211 }
peps 4:23472c2b246b 212 break;
peps 2:bd0c735e81d6 213 }
peps 2:bd0c735e81d6 214 }
peps 2:bd0c735e81d6 215
peps 5:47a452a6f248 216 // Invoked when startGate triggered in LABIRYNTH mode.
peps 2:bd0c735e81d6 217 void start_time() {
peps 5:47a452a6f248 218 isRunning = true;
peps 2:bd0c735e81d6 219 lap = 0;
peps 2:bd0c735e81d6 220 t.start();
peps 2:bd0c735e81d6 221 }
peps 2:bd0c735e81d6 222
peps 5:47a452a6f248 223 // Invoked when endGate triggered in LABIRYNTH mode.
peps 2:bd0c735e81d6 224 void stop_time() {
peps 5:47a452a6f248 225 isRunning = false;
peps 2:bd0c735e81d6 226 lap = 1;
peps 2:bd0c735e81d6 227 t.stop();
peps 2:bd0c735e81d6 228 int read = t.read_ms();
peps 2:bd0c735e81d6 229
peps 2:bd0c735e81d6 230 measured_time time = human_read(read);
peps 2:bd0c735e81d6 231
peps 3:fd1353986910 232 lcd.cls();
peps 3:fd1353986910 233 lcd.locate(0,0);
peps 4:23472c2b246b 234 lcd.printf("Finish!");
peps 2:bd0c735e81d6 235 lcd.locate(0,1);
peps 2:bd0c735e81d6 236 lcd.printf("Totale %02d:%02d:%02d",time.minutes,time.seconds,time.cents);
peps 4:23472c2b246b 237 gateStart.disable_irq();
peps 4:23472c2b246b 238 gateEnd.disable_irq();
peps 2:bd0c735e81d6 239 }
peps 2:bd0c735e81d6 240
peps 2:bd0c735e81d6 241 void labyrinthLoop() {
peps 4:23472c2b246b 242 int read = t.read_ms();
peps 4:23472c2b246b 243 measured_time time = human_read(read);
peps 4:23472c2b246b 244 lcd.locate(0,1);
peps 4:23472c2b246b 245 lcd.printf("Elapsed %02d:%02d:%02d",time.minutes,time.seconds,time.cents);
peps 2:bd0c735e81d6 246 }
peps 2:bd0c735e81d6 247
peps 2:bd0c735e81d6 248 void configMode() {
peps 2:bd0c735e81d6 249 switch(mode) {
peps 2:bd0c735e81d6 250 case LABYRINTH:
peps 4:23472c2b246b 251 gateStart.enable_irq();
peps 2:bd0c735e81d6 252 gateStart.rise(&start_time);
peps 3:fd1353986910 253 gateEnd.enable_irq();
peps 2:bd0c735e81d6 254 gateEnd.rise(&stop_time);
peps 2:bd0c735e81d6 255 loopMethod = &labyrinthLoop;
peps 3:fd1353986910 256 lcd.cls();
peps 3:fd1353986910 257 lcd.locate(0,0);
peps 3:fd1353986910 258 lcd.printf("Mode: LABYRINTH ");
peps 3:fd1353986910 259 wait(1);
peps 2:bd0c735e81d6 260 break;
peps 2:bd0c735e81d6 261
peps 2:bd0c735e81d6 262 case SPEED:
peps 2:bd0c735e81d6 263 default:
peps 4:23472c2b246b 264 gateStart.enable_irq();
peps 2:bd0c735e81d6 265 gateStart.rise(&measure_time);
peps 3:fd1353986910 266 gateEnd.disable_irq();
peps 2:bd0c735e81d6 267 loopMethod = &speedLoop;
peps 3:fd1353986910 268 lcd.cls();
peps 3:fd1353986910 269 lcd.locate(0,0);
peps 3:fd1353986910 270 lcd.printf("Mode: SPEED ");
peps 3:fd1353986910 271 wait(1);
peps 3:fd1353986910 272 lcd.cls();
peps 2:bd0c735e81d6 273 break;
peps 2:bd0c735e81d6 274 }
peps 2:bd0c735e81d6 275 }
peps 2:bd0c735e81d6 276
peps 5:47a452a6f248 277 // Reset state and configure current mode
peps 5:47a452a6f248 278 // Invoked when RESET (#) key pressed on the keypad
peps 3:fd1353986910 279 void reset_measure(){
peps 5:47a452a6f248 280 isRunning = false;
peps 3:fd1353986910 281 t.stop();
peps 3:fd1353986910 282 t.reset();
peps 3:fd1353986910 283 lap = -1;
peps 3:fd1353986910 284 last_read = 0;
peps 3:fd1353986910 285 best_lap = 0;
peps 3:fd1353986910 286 best_time = -1;
peps 4:23472c2b246b 287 configMode();
peps 3:fd1353986910 288 }
peps 3:fd1353986910 289
peps 3:fd1353986910 290 void switchMode() {
peps 3:fd1353986910 291 mode = mode == SPEED ? LABYRINTH : SPEED;
peps 3:fd1353986910 292 reset_measure();
peps 3:fd1353986910 293 }
peps 3:fd1353986910 294
peps 6:369dafe4ed5e 295 void test_keyboard() {
peps 6:369dafe4ed5e 296 lcd.cls();
peps 6:369dafe4ed5e 297 lcd.locate(0,0);
peps 6:369dafe4ed5e 298 lcd.printf("Test Keyboard");
peps 6:369dafe4ed5e 299 wait_ms(500);
peps 6:369dafe4ed5e 300 char key;
peps 6:369dafe4ed5e 301 while(1) {
peps 6:369dafe4ed5e 302 key = getKey();
peps 6:369dafe4ed5e 303 if (key == 'D') {
peps 6:369dafe4ed5e 304 lcd.cls();
peps 6:369dafe4ed5e 305 return;
peps 6:369dafe4ed5e 306 }
peps 6:369dafe4ed5e 307 if (key != '\0') {
peps 6:369dafe4ed5e 308 lcd.locate(0,1);
peps 6:369dafe4ed5e 309 lcd.printf("Key pressed: %c", key);
peps 6:369dafe4ed5e 310 }
peps 6:369dafe4ed5e 311 }
peps 6:369dafe4ed5e 312 }
peps 6:369dafe4ed5e 313
Ghiri 0:1a92e4a37697 314 //------------------------------------------------------------
Ghiri 0:1a92e4a37697 315 //
Ghiri 0:1a92e4a37697 316 // Main body
Ghiri 0:1a92e4a37697 317 //
Ghiri 0:1a92e4a37697 318 //------------------------------------------------------------
Ghiri 0:1a92e4a37697 319 int main() {
peps 2:bd0c735e81d6 320 char key;
peps 4:23472c2b246b 321 keypadInit();
peps 4:23472c2b246b 322
peps 3:fd1353986910 323 user_button.fall(&switchMode);
peps 2:bd0c735e81d6 324
peps 2:bd0c735e81d6 325 gateStart.mode(PullDown);
peps 2:bd0c735e81d6 326 gateEnd.mode(PullDown);
peps 2:bd0c735e81d6 327
peps 4:23472c2b246b 328 reset_measure();
peps 2:bd0c735e81d6 329
peps 2:bd0c735e81d6 330 while(true) {
Ghiri 0:1a92e4a37697 331 heartbeat = !heartbeat;
peps 2:bd0c735e81d6 332 loopMethod();
peps 6:369dafe4ed5e 333 wait_ms(100);
peps 5:47a452a6f248 334 key = getKey();
peps 4:23472c2b246b 335 if (key != '\0') {
peps 6:369dafe4ed5e 336 if(key == '#') {
peps 6:369dafe4ed5e 337 reset_measure();
peps 6:369dafe4ed5e 338 }
peps 5:47a452a6f248 339 if (!isRunning) {
peps 5:47a452a6f248 340 if(key == 'A') {
peps 5:47a452a6f248 341 mode = LABYRINTH;
peps 5:47a452a6f248 342 reset_measure();
peps 5:47a452a6f248 343 } else if(key == 'B') {
peps 5:47a452a6f248 344 mode = SPEED;
peps 5:47a452a6f248 345 reset_measure();
peps 6:369dafe4ed5e 346 } else if (key == '*') {
peps 6:369dafe4ed5e 347 lcd.cls();
peps 6:369dafe4ed5e 348 lcd.locate(0,0);
peps 6:369dafe4ed5e 349 lcd.printf(VERSION_STRING);
peps 6:369dafe4ed5e 350 lcd.locate(0,1);
peps 6:369dafe4ed5e 351 lcd.printf(VERSION_DATE);
peps 6:369dafe4ed5e 352 wait(3);
peps 6:369dafe4ed5e 353 lcd.cls();
peps 6:369dafe4ed5e 354 } else if (key == 'D') {
peps 6:369dafe4ed5e 355 test_keyboard();
peps 5:47a452a6f248 356 }
peps 5:47a452a6f248 357 }
Ghiri 0:1a92e4a37697 358 }
Ghiri 0:1a92e4a37697 359 }
Ghiri 0:1a92e4a37697 360 }