SHARE
TWEET

Pinewood Derby Race Timer

sweenig Mar 26th, 2014 224 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. // Interrupt Driven Pinewood Derby Timer
  2. // BDub @ Technobly.com 3/19/2014
  3. //
  4. // All inputs are pulled high with internal pullups.
  5. // GND D2 to reset and run the timer for all lanes.
  6. // GND A6, A7, D3 and D4 to stop the timer for each
  7. // lane and display the results.
  8. //
  9. // D0-D3 were initially chosen, but because
  10. // individual control of dis/en'abling their
  11. // interrupt handlers was not available, A6, A7
  12. // D3 and D4 were chosen instead.  D0, D1, D2
  13. // A0, A1, A3, A4 are all tied to one interrupt
  14. // handler, so for the one remaining input any
  15. // of these will do.  D2 was chosen to allow
  16. // for the most flexibility of the remaining inputs.
  17. //
  18. // EXTI_ClearITPendingBit() is necessary to clear
  19. // the interrupt Pending register, or interrupts
  20. // will fire immediately after enabling the
  21. // interrupt handlers again.
  22. //
  23. // DWT->CYCCNT was used for the timer instead of
  24. // micros() which wraps this hardware counter and
  25. // returns the number of microseconds associated
  26. // with it; because it's not clean to handle the
  27. // case where micros() wraps at 59.652323 seconds.
  28. // This give us 72x more resolution on the timing
  29. // anyway and it's super easy to deal with wrapping.
  30. // It just works out through subtraction of unsigned
  31. // 32-bit variables; as long as you don't time
  32. // something longer than 59.652323 seconds.
  33. //
  34. //==================================================
  35.  
  36. #include "application.h"
  37.  
  38. void startRace(void);
  39. void lane1(void);
  40. void lane2(void);
  41. void lane3(void);
  42. void lane4(void);
  43. bool showStartMsg = false;
  44. bool raceEnded = true; // start off assuming the race has not started.
  45. volatile uint32_t timeStart1;
  46. volatile uint32_t timeStart2;
  47. volatile uint32_t timeStart3;
  48. volatile uint32_t timeStart4;
  49. volatile uint32_t timeEnd1;
  50. volatile uint32_t timeEnd2;
  51. volatile uint32_t timeEnd3;
  52. volatile uint32_t timeEnd4;
  53. volatile uint32_t mph1;
  54. volatile uint32_t mph2;
  55. volatile uint32_t mph3;
  56. volatile uint32_t mph4;
  57.  
  58.  
  59.  
  60.  
  61. uint32_t startTime;
  62. const uint32_t DISQUALIFIED_TIME = 20 * 1000;  // in milliseconds (20 seconds)
  63.  
  64. void setup()
  65. {
  66.   Serial.begin(115200);
  67.   while(!Serial.available()) SPARK_WLAN_Loop(); // Waiting for user to open terminal and press ENTER
  68.   // Enter waiting state, waiting for D2 to go low.
  69.   Serial.println("================================");
  70.   Serial.println("Waiting for race to start.");
  71.  
  72.   //setup pins
  73.   pinMode(D2, INPUT); // startRace trigger
  74.   pinMode(A6, INPUT); // lane1
  75.   pinMode(A7, INPUT); // lane2
  76.   pinMode(D3, INPUT); // lane3
  77.   pinMode(D4, INPUT); // lane4
  78.  
  79.   //setup actions to perform on interrupts
  80.   attachInterrupt(D2, startRace, FALLING); // startRace
  81.   attachInterrupt(A6, lane1, FALLING); // lane1
  82.   attachInterrupt(A7, lane2, FALLING); // lane2
  83.   attachInterrupt(D3, lane3, FALLING); // lane3
  84.   attachInterrupt(D4, lane4, FALLING); // lane4
  85.  
  86.   //Stop listening to interrupts on all lanes
  87.   NVIC_DisableIRQ(EXTI0_IRQn); // A6 "Lane 1"
  88.   NVIC_DisableIRQ(EXTI1_IRQn); // A7 "Lane 2"
  89.   NVIC_DisableIRQ(EXTI4_IRQn); // D3 "Lane 3"
  90.   NVIC_DisableIRQ(EXTI3_IRQn); // D4 "Lane 4"
  91. }
  92.  
  93. void loop()
  94. {
  95.   //wait for race to end
  96.   if(!raceEnded) {
  97.     //wait for all lanes to have times (this includes any empty lanes, which will timeout at 20 seconds)
  98.     if((timeEnd1 != timeStart1 && timeEnd2 != timeStart2 && timeEnd3 != timeStart3 && timeEnd4 != timeStart4) || (millis() - startTime) > DISQUALIFIED_TIME) {
  99.  
  100.       double tempTime;
  101.  
  102.       Serial.println("Race Finished!");
  103.       Serial.println("= Lane Times in seconds =");
  104.      
  105.       //output lane times
  106.       Serial.print("Lane 1: ");
  107.       tempTime = (double)(timeEnd1 - timeStart1)/72000000.0;
  108.       if(tempTime != 0.0) {
  109.           Serial.print(tempTime,8);
  110.           Serial.print(" (");
  111.           mph1 = (double)(31 * 60 * 60 * 24 / 5280 / tempTime);
  112.           Serial.print(mph1,6);
  113.           Serial.println(" mph)");
  114.       } else Serial.println("DNF");
  115.       delay(50);
  116.       Serial.print("Lane 2: ");
  117.       tempTime = (double)(timeEnd2 - timeStart2)/72000000.0;
  118.       if(tempTime != 0.0) {
  119.           Serial.print(tempTime,8);
  120.           Serial.print(" (");
  121.           mph2 = (double)(31 * 60 * 60 * 24 / 5280 / tempTime);
  122.           Serial.print(mph2,6);
  123.           Serial.println(" mph)");
  124.       } else Serial.println("DNF");
  125.       delay(50);
  126.       Serial.print("Lane 3: ");
  127.       tempTime = (double)(timeEnd3 - timeStart3)/72000000.0;
  128.       if(tempTime != 0.0) {
  129.           Serial.print(tempTime,8);
  130.           Serial.print(" (");
  131.           mph3 = (double)(31 * 60 * 60 * 24 / 5280 / tempTime);
  132.           Serial.print(mph3,6);
  133.           Serial.println(" mph)");
  134.       } else Serial.println("DNF");
  135.       delay(50);
  136.       Serial.print("Lane 4: ");
  137.       tempTime = (double)(timeEnd4 - timeStart4)/72000000.0;
  138.       if(tempTime != 0.0) {
  139.           Serial.print(tempTime,8);
  140.           Serial.print(" (");
  141.           mph4 = (double)(31 * 60 * 60 * 24 / 5280 / tempTime);
  142.           Serial.print(mph4,6);
  143.           Serial.println(" mph)");
  144.       } else Serial.println("DNF");
  145.       delay(50);
  146.      
  147.       //cleanup
  148.       raceEnded = true; // prevents results from being displayed over and over  
  149.       EXTI_ClearITPendingBit(EXTI_Line5); // D2 "startRace"
  150.       NVIC_EnableIRQ(EXTI9_5_IRQn); // D2
  151.      
  152.       // Enter waiting state, waiting for D2 to go low.
  153.       Serial.println("================================");
  154.       Serial.println("Waiting for race to start.");
  155.     }
  156.   }
  157.  
  158.   if(showStartMsg) {
  159.     Serial.println("================================");
  160.     Serial.println("================================");
  161.     Serial.println("================================");
  162.     Serial.println("================================");
  163.     Serial.println("================================");
  164.     Serial.println("================================");
  165.     Serial.println("================================");
  166.     Serial.println("================================");
  167.     Serial.println("================================");
  168.     Serial.println("================================");
  169.     Serial.println("================================");
  170.     Serial.println("================================");
  171.     Serial.println("================================");
  172.     Serial.println("================================");
  173.     Serial.println("================================");
  174.     Serial.println("Race started!");
  175.     showStartMsg = false;
  176.     raceEnded = false;
  177.     startTime = millis(); // Capture the rough start time, for disqualification timer
  178.   }
  179. }
  180.  
  181. void lane1()
  182. {
  183.   NVIC_DisableIRQ(EXTI0_IRQn); // stop listening for an interrupt on A6
  184.   timeEnd1 = DWT->CYCCNT; //get the lane time (instead of using micros();)
  185. }
  186.  
  187. void lane2()
  188. {
  189.   NVIC_DisableIRQ(EXTI1_IRQn); // stop listening for an interrupt on A7
  190.   timeEnd2 = DWT->CYCCNT; //get the lane time (instead of using micros();)
  191. }
  192.  
  193. void lane3()
  194. {
  195.   NVIC_DisableIRQ(EXTI4_IRQn); // stop listening for an interrupt on D3
  196.   timeEnd3 = DWT->CYCCNT; //get the lane time (instead of using micros();)
  197. }
  198.  
  199. void lane4()
  200. {
  201.   NVIC_DisableIRQ(EXTI3_IRQn); // stop listening for an interrupt on D4
  202.   timeEnd4 = DWT->CYCCNT; //get the lane time (instead of using micros();)
  203. }
  204.  
  205. void startRace()
  206. {
  207.   NVIC_DisableIRQ(EXTI9_5_IRQn); // stop listening for an interrupt on D2
  208.   timeStart1 = DWT->CYCCNT; // get the start time for each lane
  209.   timeStart2 = timeStart1; // set the start time for each line the same
  210.   timeStart3 = timeStart1; // set the start time for each line the same
  211.   timeStart4 = timeStart1; // set the start time for each line the same
  212.   timeEnd1 = timeStart1; // set the end time to the start time temporarily
  213.   timeEnd2 = timeStart1; // set the end time to the start time temporarily
  214.   timeEnd3 = timeStart1; // set the end time to the start time temporarily
  215.   timeEnd4 = timeStart1; // set the end time to the start time temporarily
  216.   EXTI_ClearITPendingBit(EXTI_Line0); // Reset the interrupt for A6 "Lane 1"
  217.   EXTI_ClearITPendingBit(EXTI_Line1); // Reset the interrupt for A7 "Lane 2"
  218.   EXTI_ClearITPendingBit(EXTI_Line4); // Reset the interrupt for D3 "Lane 3"
  219.   EXTI_ClearITPendingBit(EXTI_Line3); // Reset the interrupt for D4 "Lane 4"
  220.   NVIC_EnableIRQ(EXTI0_IRQn); // Start listening for an interrupt on A6 "Lane 1"
  221.   NVIC_EnableIRQ(EXTI1_IRQn); // Start listening for an interrupt on A7 "Lane 2"
  222.   NVIC_EnableIRQ(EXTI4_IRQn); // Start listening for an interrupt on D3 "Lane 3"
  223.   NVIC_EnableIRQ(EXTI3_IRQn); // Start listening for an interrupt on D4 "Lane 4"
  224.   showStartMsg = true; //indicate that the race has started
  225. }
RAW Paste Data
Top