Got a problem with millis().
I have created a little set up for my classroom. A ball (I use a golf ball) is held by a clamp and holds a switch HIGH. When the switch goes LOW, the program takes millis then waits for a peizo sensor below to detect a knock. When a knock occurs, take another millis, do some math and display to an LCD. We take this time and use it to solve for the acceleration due to gravity. The times are in the range from 0.350 (drop off a desk) seconds up to 2.5 seconds (drop off a balcony).
Physically, everything seems to work perfect, but the time keeps coming up short by 6-10%, so either millis is not keeping good time, or the acceleration due to gravity happens to be significantly greater wherever my Arduino and laptop seem to go. If it was coming in long, I would assume hardware or circuitry, but the time is less than it should be.
In anticipation of questions:
I have had it display the raw "long" xt2 variable on the lcd with the calculated millis and they are identical, so i don't think it is a change in variable type causing any issues.
I have monitored it thoroughly through the serial monitor with other people around and nothing in it looks unusual.
I have reworked and reworked and reworked the code to find anywhere I could be losing time and nothing changes.
I have reloaded the code to multiple Arduinos and get identical results each time.
In the long run, my goal is to create a simple and inexpensive open source lab sensors for use in science classrooms, especially in the developing world. I am happy to provide schematics, pictures, etc., but I believe this to be a software problem at this point.
So here is the code. I have tried to annotate it well, and near the end, there is some code that translates the numbers into a readable format for students and sets the system up for the next trial.
/*
CAPOSC: December 2013
Uses a clip with a switch to hold a golfball. While switch is closed, program waits.
Once switch is opened, the program takes millis and starts to look at knock sensor.
Once knock is detected, take a second millis, do some math, and spit out a time to an LCD.
*/
#include <LiquidCrystal.h>
//timing vars
unsigned long xt;
unsigned long xt2;
//LED pins
int led = 3;
int com = 2;
int nc = A3; //Switch pin, when switch is closed, an object is ready to drop
int knock = A2; //knock sensor, when struck it ends the timer
int threshold = 10; //threshold of the knock sensor to prevent background noise from setting it off
int sensor = 0;
int tran = 0;
LiquidCrystal lcd(8, 9, 4, 5, 6, 7); //using a SainSmart LCD button board
void setup() {
pinMode(com, OUTPUT); //Sets LED pins
pinMode(led, OUTPUT);
pinMode(nc, INPUT); //sets analog pin as input from switch
pinMode(knock, INPUT); //sets analog to knock sensor
// set up the LCD's number of columns and rows:
lcd.begin(16, 2);
// Print a message to the LCD.
lcd.print("Place a ball in ");
lcd.setCursor(0,1);
lcd.println("the clip. ");
//Serial.begin(9600);
}
void loop() {
digitalWrite(led,HIGH); //external power indicator
//this while loop waits for an object, golf ball, to be placed in the clamp.
while (tran < threshold){
tran = analogRead(nc);
delay(1);}
digitalWrite(led,LOW);
//some idiot proofing code so my students think before they do something
lcd.setCursor(0,0);
lcd.print("WAIT ");
lcd.setCursor(0,1);
lcd.print(" ");
delay(500);
lcd.setCursor(0,0);
//Ready for the drop to occur
lcd.print("READY TO GO!!!!>");
digitalWrite(led,HIGH);
digitalWrite(com,HIGH);
//waits for the switch to open
while (tran > threshold){
tran = analogRead(nc);
delay(0);
}
xt = millis(); //takes time just after switch opens
digitalWrite(led,LOW);
digitalWrite(com,LOW);
//now we are waiting for the knock sensor to be triggered
while (sensor < threshold){
sensor = analogRead(knock);
Serial.println(sensor);
}
// The knock has been triggered, we take another millis and subtract
// the initial millis for elapsed time
xt2 = millis()-xt;
//the code here simply makes the millis easy to read on the screen
//again, idiot proofing
int one = xt2/1000;
int two = (xt2 - (one*1000));
lcd.setCursor(0, 1); //line=2, x=0
lcd.print("Time: ");
lcd.print(one);
lcd.print(".");
if (two < 10){
lcd.print("00");
}
else{
if(two < 100){
lcd.print("0");
}
}
lcd.print(two);
lcd.println(" ");
//Gets ready for the next trial
digitalWrite(com,HIGH);
sensor = 0;
tran = 0;
delay(5000);
digitalWrite(led,HIGH);
digitalWrite(com,LOW);
lcd.setCursor(0,0);
lcd.print("Replace ball....");
}