Counting and Timing a shock sensor

sspbass:
I’m reading a few tutorials about interrupts but it’s clear to me that I don’t have the proper foundation to apply the knowledge.

Would an external interrupt be used initially to start the process and the timer interrupts would take over after that to do the timing and counting operations? Is the portion that does the timing and counting all in a single timer interrupt?

I wish I could just find a good example online that I could modify to fit my needs without needing to re-write the entire thing.

I’ll give it some thought but at present my thinking is thus …

Design the system so it will time for 2 separate shooters, keeping track of all their hit times separately. The system won’t correlate times with specific targets, all targets for a shooter will be lumped together, but you will know when each hit occured. This can be expanded later if desired. A set of 3 switches will be used to initiate/stop the timing functions and to scroll forward/backward through the displays. Two external interrupt pins will be used to sense when targets for the A and B shooter have been hit. That is all “A targets” will trigger one ext pin, all “B targets” will trigger the other pin.

When the start button is pushed another output pin will be used to drive a high efficiency piezo buzzer for some predetermined amount of time (say 0.5 secs) after a random time (I’m not sure how to do this on an Arduino ATM) has elapsed. Perhaps just start with a fixed time and modify the code to randomize later when every thing else is working.

When the elapsed time (above) has … well, elapsed … the present time (from the millis() function) will be stored (and the buzzer will buzz). Every time either external interrupt is triggered (from here on), the interrupt service routine (ISR) that runs for that ext pin will store the present time away in an array specific to that interrupt routine (that is for the A or B shooter). Each array will be able to save away 10 times (more if you want). Timing stops and interrupts are disabled when any of the 3 buttons is pushed.

For the moment, all times are flushed when the start button is pushed to start again or when power goes away. This can be modified later too.

The display will display which shooter, number of shots and times (total and shot-to-shot splits), scrolling as needed from shot to shot, shooter to shooter.

Other “game” modes to be added later when everything is working.

So if that sounds about right as a baseline, I’d have the Arduino power up and initialize and then sit there polling the button inputs. If there are times from a prior run, the code will run to send the proper message/info to the display in accordance with the scrolling buttons. If/when the start/stop button is pushed, you can use a series of delay() calls to get the initial “long” delay desired. This isn’t the most elegant way and will change later but let’s keep it simple to start with. After say … 3 secs of delay … the code will enable the external interrupts and force the buzzer pin to be “on”. Again a simple delay of 0.5 secs should suffice to then turn the buzzer off. There after the main() loop just polls the start/stop and scroll buttons waiting for any push to tell it to stop. The ISR’s take care of all the timing and storage of times. When the stop command had been detected, the ISRs are disabled and the code goes back to the top of the main() loop, awaiting button inputs to scroll the display or start all over again. Sounds relatively straight forward to start with … I think. :o :smiley:

For the time being I would use the same serial I/O pins to talk to the display as are used to talk to the USB port and your PC. That requires a manual switch in the Tx line to the display, otherwise the whole boot loading process has been know to futz up the display. But doing it this way will make things easier to code up front. Later if wanted, you could do some software emulation of a UART/serial port via the NewSoftSerial library … but again, let’s keep it simple to start with.

So does any of the above sound right or make sense to you ? Or am I talking all goobletygook ? :mrgreen:

You’re doing great, I’m just a noob who’s ambition is getting a little ahead of him.

I should have been studying C instead of playing Skyrim all winter! haha.

What book/resource would you recommend for learning the basics?

I went through have the book of examples but anyone who can read and follow instructions can do that.

sspbass:
You’re doing great, I’m just a noob who’s ambition is getting a little ahead of him.

I should have been studying C instead of playing Skyrim all winter! haha.

What book/resource would you recommend for learning the basics?

I went through have the book of examples but anyone who can read and follow instructions can do that.

I think for the Arduino, just learning by doing the examples will work ... at least for this project. Right now I envision a breadboard with 3 switches, a piezo buzzer and eventually your display on it. That plus one or 2 of your targets, the Arduino and a PC and in a week you'd have a working prototype. If you can read buttons and send ("print") a message to the PC, perhaps have the buzzer buzz, then amazingly that's about 50% of the project. I have some spare time tonight, I'll toss some ideas into a pseudo-Sketch you can improve upon.

Keep in mind I don’t speak Arduino so the following maybe goofy beyond my normal typos and such …

The following is a 1’st cut at doing some of the simple timer functions. Ideally it’ll time A and B circuits, with multiple targets for each shooter being shared on each circuit. Since it relies on the Arduino clock and timing functions, it’s not what I’d use for a match. This can be fixed later on though. At present it outputs to your PC instead of an LCD display. This is to keep it simple to get things working. Later on lots of changes will no doubt want to be made to improve/add functionality.

So what you need to run it is your Arduino and PC, a single normally open momentary switch and ideally one or 2 of your targets (and a hammer to ping them with). A piezo buzzer (not a speaker) that can be driven from an Arduino pin would be nice as well. I note that the [unit SF sells is a piezo speaker, not a buzzer. Driving something like that can come later.

Assuming you can copy’n’paste and get the following to compile and load (ha !), what should happen is the Arduino sits there waiting for you to push the start/stop button. When you do that the buzzer should beep for 0.5 secs after a 3 sec wait, the Arduino’s internal LED should some on and timing should then commence and run for the next 30 seconds. After 30 secs, or if you push the start/stop button again, the timer will beep, stop it’s timing (the LED goes off) and then send whatever data it has to your PC … so have a [terminal emulator / serial monitor window open and set to 8N1 and 9600 baud.

If you have targets connected and hit them while the timer is running, those times should be recorded and later presented at your PC.

The switch should be connected to Arduino ground and pin 4. Target A “E” to ground and “C” pin 2. Target B to ground and pin 3, similar to target A. The buzzer to ground and pin 5. If you don’t have a true buzzer, you could use a dropping resistor in series with an LED, similar to that in the [Blink tutorial. And that’s it … to start with.

It’ll be amusing to see how screwed up the following is. :mrgreen:

// set pin numbers
const int StartPin = 4;       // the number of the Start pushbutton pin
const int UpPin = 6;          // the number of the ScrollUp pushbutton pin
const int DownPin = 7;        // the number of the ScrollDown pushbutton pin
const int TargetAPin = 2;     // the number of the A targets input pin
const int TargetBPin = 3;     // the number of the B targets input pin
const int BuzzerPin = 5;      // the number of the buzzer output pin
const int LEDPin = 13;        // the number of the LED output pin

const unsigned long MaxTime = 30000;    // the max time the timer can run for = 30 secs
const unsigned long WaitTime = 3000;    // the wait time btw start button and timer running = 3 secs
const unsigned long DB_delay = 200;     // set a debounce wait time of 200 msecs
const unsigned long BuzzTime = 500;     // set the on time for the buzzer, 500 msecs

const int RUN = 1;            // make code easy to understand

// initialize global variables
volatile int TimerState = 0; // variable for state of timer, running or not running
int DisplayState = 0;        // variable for controlling what"s displayed
unsigned long StartTime = 0; // variable to hold the start time
volatile int A_count = 0;    // variable to hold the number of A hits
volatile int B_count = 0;    // variable to hold the number of B hits
volatile int A_Times[10];    // array to hold up to 10 hit times for target A
volatile int B_Times[10];    // array to hold up to 10 hit times for target B

void setup()
{
  // initialize output pins
  pinMode(BuzzerPin, OUTPUT);
  pinMode(LEDPin, OUTPUT);
  digitalWrite(BuzzerPin, LOW);
  digitalWrite(LEDPin, LOW);
   
  // initialize the input pins with internal pullups
  pinMode(StartPin, INPUT);
  pinMode(UpPin, INPUT);
  pinMode(DownPin, INPUT);
  pinMode(TargetAPin, INPUT);
  pinMode(TargetBPin, INPUT);
  digitalWrite(StartPin, HIGH);   
  digitalWrite(UpPin, HIGH);
  digitalWrite(DownPin, HIGH);
  digitalWrite(TargetAPin, HIGH);
  digitalWrite(TargetBPin, HIGH);

  // opens serial port, sets data rate to 9600 bps
  Serial.begin(9600);

  // setup ext pins as interrupts
  attachInterrupt(0, ISR_A, FALLING);
  attachInterrupt(1, ISR_B, FALLING);
}

void loop()
{
  if (digitalRead(StartPin) == LOW) 
  {     
    // start stop button has been pushed, is timer running
    if (TimerState == !RUN)
    {
      // timer is not running so start it

      // Do the following debug code only to get system running
      // This will send message to PC to show button was pushed
      Serial.println("Timer is running")

      // clear all the prior runs data
      ClearData()

      // delay the Wait Time from start button push
      // this delay will change to random later on    
      delay(WaitTime);

      // turn buzzer on:    
      digitalWrite(BuzzerPin, HIGH);
      // turn on the LED to show timer is running
      digitalWrite(LEDPin, HIGH);

      // enable the interrupts just in case
      interrupts();

      // save the starting time of this run
      StartTime = millis();
      // now delay buzzer on time
      delay(BuzzTime);
      // turn buzzer off:    
      digitalWrite(BuzzerPin, LOW);
      // set state of timer to running
      TimerState = RUN;
      // no need to debounce as mucho time has elapsed
    }
    else
    {
      // start stop button has been pushed again to stop timer
      StopTimer()
      Buzz()
      // no need to debounce switch, a delay is built into Buzz function
      // just for the moment send times to PC only not to display
      SendTimes()
    }
  }
  //Check for max time out if timer is running
  if (TimerState == RUN)
  { 
    if ((millis() - StartTime) > MaxTime)
    {
    // call the function that does all the things needed to stop
    StopTimer()
    Buzz()
    // just for the moment send times to PC only not to display
    SendTimes() 
    }
  }  
}

void StopTimer()
{
  //noInterrupts();
  TimerState = !RUN;
  // turn the LED off to show timer is stopped
  digitalWrite(LEDPin, LOW);
}

void Buzz()
{
  // turn buzzer on to alert user
  digitalWrite(BuzzerPin, HIGH);
  // delay the buzzer on time and then shut it off
  delay(BuzzTime);
  digitalWrite(BuzzerPin, LOW);  
}  

void ClearData()
{
  A_count = 0; 
  B_count = 0;
  A_Times = [0 0 0 0 0 0 0 0 0 0];
  B_Times = [0 0 0 0 0 0 0 0 0 0];
}

SendTimes()
{
  Serial.println("Timer is stopped");
  Serial.println("Here are the times for Shooter A");
  Serial.print("Number of hits : ");
  Serial.print("\t");
  Serial.println(A_count);
  Serial.println("A Hit times are : ");
  for (int i=0; i < A_count ; i++)
  {
    Serial.println(A_Times[i])
  }
  Serial.println("Here are the times for Shooter B");
  Serial.print("Number of hits : ");
  Serial.print("\t");
  Serial.println(B_count);
  Serial.println("B Hit times are : ");
  for (int i=0; i < B_count ; i++)
  {
    Serial.println(B_Times[i])
  }
}

void ISR_A()
{
  if(TimerState == RUN)
  {
    // store the hit time 
    A_Times[A_count] = millis() - StartTime;
    // increment the hit count and array index
    ++A_count;
  }
}

void ISR_B()
{
  if(TimerState == RUN)
  {
    // store the hit time 
    B_Times[B_count] = millis() - StartTime;
    // increment the hit count and array index
    ++B_count;
  }
}

](http://arduino.cc/en/Tutorial/Blink)](http://arduino.cc/en/Guide/Environment#serialmonitor)](Mini Speaker - PC Mount 12mm 2.048kHz - COM-07950 - SparkFun Electronics)

PrePlanned improvements would be :

  • Driving your pieze speaker w/different times and volumes and tones for differing alerts (nice to have though not required)

  • Making the wait time be a random number between X and Y (this is needed eventually to prevent “cheating”)

  • Adding a display and controlling it (I have some suggestions in this area)

  • Adding a power saving sleep mode so when battery powered it’ll last

  • Adding some “game modes”

  • Improved timing accuracy

  • ? storage of times for later download to PC ?

  • ???

Looks great man!

I read through it line by line today at lunch and I actually understand everything that is going on.

I’m at my workbench now and I’m going to try hooking everything up and try running it.

sspbass:
Looks great man!

I read through it line by line today at lunch and I actually understand everything that is going on.

I’m at my workbench now and I’m going to try hooking everything up and try running it.

Kewl. If you don’t have a target just yet, a switch just like the start/stop one can be used instead. Connect it the same way; one side to ground, the other to the input pin of the Arduino. Because switches “bounce” I’d expect you’ll get several recorded “hits” for each push … but that should be sufficient to prove that things are working.

Of course the above all assumes the code even compiles … :shifty: I won’t be holding my breath. :mrgreen:

I think I might have to change the buzzer pin to another. From the little I could gather, if you want to use the tones() function it will use a particular timer for particular output pins … and the timer for pin 5 is already in use in that code. Pin 9 may be a good choice to do PWM (to make a tone) on the piezo speaker that you have to make a “buzzer”. I figure different tones and durations for the start and stop alerts would be nice ??

I got it all put together and loaded your sketch. It didn’t compile the first time but I had it going within 5 minutes so no big deal!

I tried running it and when I pushed the button it did absolutely nothing! I hooked up an led into my circuit to tell if it was sensing the hit and it is working like it should so I wouldn’t think that its in the hardware. I found the serial monitor on the arduino program and it was set to 9600 baud but I don’t know what the 8n1 is. It doesn’t do anything though so I’m not sure what to do. I am using a tiny piezo buzzer and I can see it move ever so slightly when I push the button for it to start but it doesn’t make a sound.

The piezo I was using wasn’t working but I confirmed that another one that I had still doesn’t work.

And so the “fun” begins … :mrgreen:

I wouldn’t expect the “buzzer” that you have to do much at this point. Perhaps you’ll get a click out of it when the buzzer is supposed to turn on and then another click when it supposed to turn off. The Arduino supposedly has an LED onboard that’s connected to pin13. Is this LED off to start and then comes on when the start button is pushed ? If so then that parts working and it’s the serial “print” that needs attention.

The 8N1 stands for 8 bits, no parity bit and 1 stop bit. These are settings used in a common UART (which is a hardware device that handles the serial interface) and those numbers are the most common values. I don’t know if your Arduino environment sets them up or if you have to do that via Windows, Perhaps the thing to do, assuming the LED works as described, is load the code from …

http://arduino.cc/en/Tutorial/ASCIITable

… and see if you can get a serial output to the PC from that.

BTW if you have an LED + resistor lying about, you can connect them as in the Blink tutorial but to the buzzer pin (5) and see the “buzzer” come on when the start button is pushed. If the code is running well enough to read the button that is.

Try the simple tutorial code here first …

http://arduino.cc/en/Tutorial/DigitalReadSerial

Also I looked at the schematic and I don’t see any LED connected on the board to pin13 so if you have an LED+resistor, connect them between pon13 and ground see what happens with the timer code.

No beans with the on board led. It’s off and stays off but why would it light up at all when pin 13 isn’t used anywhere in the code at all?

sspbass:
No beans with the on board led. It’s off and stays off but why would it light up at all when pin 13 isn’t used anywhere in the code at all?

There’s a write to pin13 (HIGH) when the timer starts timing. I read there was an LED on the board connected to it but now that I look … there isn’t one. See my edit on the post above. Do you have either the LED+resistor or a voltmeter (DMM) to measure the pin 13 or pin 5 outputs ?

Hooked an LED and 330 ohm resistor to pin 13 nothing, There is also nothing reading from pin 5 on my volt meter when i push the push button.

I also skipped the switch with a jumper to make sure the switch wasn’t bad and still nothing.

ETA- I just don’t get it. Turning on that LED is almost the first thing it does.

I can’t see whats wrong with the code but I don’t know what the hell I’m doing so that doesn’t say much haha!

sspbass:
Hooked an LED and 330 ohm resistor to pin 13 nothing, There is also nothing reading from pin 5 on my volt meter when i push the push button.

I also skipped the switch with a jumper to make sure the switch wasn’t bad and still nothing.

OK so there’s something fundamentally goofy with my code attempt. Let’s start real simple and take 10 mins to establish a baseline.

First load and run the tutorial from here

http://arduino.cc/en/Tutorial/DigitalReadSerial

This is that code.

void setup() {
  Serial.begin(9600);
  pinMode(2, INPUT);
}

void loop() {
  int sensorValue = digitalRead(2);
  Serial.println(sensorValue);
}

So your serial monitor should show a lot of 0s or 1s. The switch you have won’t do anything … yet.

Then you can modify that code to read the switch you have on the pin you have and see if you can control the 0s and 1s you just saw. That modified code should be this …

void setup() {
  Serial.begin(9600);
  pinMode(4, INPUT);  // change input pin to read switch on pin 4
  digitalWrite(4, HIGH); // enable the internal pull-up
}

void loop() {
  int sensorValue = digitalRead(4);
  Serial.println(sensorValue);
}

If that works then this should as well …

const int StartPin = 4;           // the number of the Start pushbutton pin

void setup() {
  Serial.begin(9600);
  pinMode(StartPin, INPUT);        // read switch on pin 4
  digitalWrite(StartPin, HIGH);    // enable the internal pull-up
}

void loop() {
  int sensorValue = digitalRead(StartPin);
  Serial.println(sensorValue);
  digitalWrite(13, sensorValue);    // set pin 13 to the read value
}

Ideally you’ll see 0s and 1s under your switch control and pin 13 should follow (low, high) those readings.

Hold up, stop racking your brain! I think I’ve got it and I think you’re going to hate me when I tell you :slight_smile:

sspbass:
Hold up, stop racking your brain! I think I’ve got it and I think you’re going to hate me when I tell you :slight_smile:

naaah … simple wiring error ? :mrgreen:

Tadaaaaa, you are awesome man!

You’re code works great!

It’s been months since I worked with the Arduino and even then I only did a few circuits.

What I forgot to do was upload the damn program!

I was compiling it and I thought that was sending it until I compiled it accidentally without it plugged in.

I was expecting a communication error but when it didn’t I realized something was up.

So as embarrassing as this is at least I figured out what was wrong.

Now I’m excited to get a functional setup on my target and then take it even further!