problem with micros()

I am building a balistic chronograph. I have most of it working but getting strange results from the Micros() function. At the beginning of the program and after a few runs, I get 4us resolution. For some reason after it runs for a while I get 64us resolution. I tried setting the prescaler for timer1 but it didn't seem to help. I get 4us resolution for a while and then it jumps to 64us. I've stripped the program down to the essentials, just waits for a high going pulse on two pins, reads the micros() function after each and calculates the FPS between the two pulses. I then send the results up the serial line.

Any pointers?

Any pointers?

Just the usual one. Post your code. That was why you posted in Programming, wasn't it?

I have now typed this message 5 times and keep hitting the backspace function.

The code below returns 64us resolution (35 x 64 = 2,240us; 34 x 64 = 2,176us, 36 x 64 = 2,304us) after about 5 minutes of running. Prior to that, I get the correct 4us resolution that I would expect. I tried setting the prescaler as in the commented-out code but it didn’t help so I guess I didn’t know what I am doing. It gives me 4us resolution prior to that for some odd reason. The test gun should be shooting around 450fps or 2,222us so I should be getting 2,224us or 449.64fps.

So I guess the first thing I need is the correct way to set the prescaler consistently and the next, if it will keep going to 64us resolution because of either the lcd routine or serial printing, then a way to reset the timer (timer1, I think) as well as the prescaler.

The strange thing is that it reports 4us resolution for the first few minutes.

thanks,

Jerry

 /* */
 #include <LiquidCrystal.h> 
 
float start_time;
float stop_time;
float delta_time;
float fps;

int ScreenPin1 = 2;
int ScreenPin2 = 3;
int ScreenPin3 = 4;
LiquidCrystal lcd(A0, A1, A2,A3,A4,A5);


void setup() {
 // initialize timer1 
    
 
  pinMode(ScreenPin1, INPUT);   
  pinMode(ScreenPin2, INPUT);
  pinMode(ScreenPin3, INPUT);
  
  lcd.begin(16, 4);
  lcd.print("     Resetting...");
  
  Serial.begin(115200);    
  Serial.print("Reset");
//  TCCR1B = 0<<CS22 | (0<<CS21) | (1<<CS20); 
}

void loop() {
  
     Serial.print("waiting...");
     Serial.println();

     lcd.setCursor(0,0);
     lcd.print("                  ");
     lcd.setCursor(0,0);
     lcd.print("waiting...");
     
     
   while (digitalRead(ScreenPin1)==0) { }
          start_time=micros();
          
   while (digitalRead(ScreenPin2)==0) { }
          stop_time=micros();   
          
          Serial.print("start: ");
          Serial.print(start_time);
          Serial.print(" stop: ");
          Serial.print(stop_time);
          Serial.print(" delta:");
          delta_time=stop_time-start_time;
          Serial.print(delta_time);  
          Serial.print(" fps: ");
           
          fps = delta_time/1000000;
          fps = 1/fps;
          
          lcd.setCursor(0,0);
          lcd.print("           ");
          lcd.setCursor(0,1);
          lcd.print("                ");
          lcd.setCursor(0,1);
          lcd.print(fps);
          Serial.print (fps);       
          Serial.println();  
          delay(2000); 
      
      }

          
[code end]

Let me throw another thing in there... Is there a more efficient/faster / accurate way to grab the microseconds after a high going pulse? I initially used an interrupt on rising and set a flag but I removed it as overkill. Maybe if I do the interrupt on rising in two attached interrupt routines that are written in assembly grabbing the microseconds would be more accurate? I am going to move to three screens so they will be 1 foot apart and using the average as well as the time from screen 1 to 2 followed by 2 to 3 might give me the ballistic coefficient as well. The time from screen 2 to 3 should be slightly slower.

Thanks again.

Jerry

You seem to be using float variables to hold time values. That means that as the absolute value increases the precision reduces.

Since the return value from micros() is an unsigned long, any attempt to store those values in any different type is liable to cause overflow/precision errors.

The basic approach of calling micros() twice and subtracting the two values to get an elapsed time is correct and should work fine if you just change those floats to unsigned longs.

cncjerry:
Let me throw another thing in there... Is there a more efficient/faster / accurate way to grab the microseconds after a high going pulse?

Yes. "Input Capture" is made to do exactly what you want. I believe this library... FreqMeasure Library, for Measuring Frequencies in the 0.1 to 1000 Hz range, or RPM Tachometer Applications ...will give you most or all of what you need.

However, using micros the way you are using it (with @PeterH's suggestion) is very likely a good choice. What is the fastest bullet you expect to measure?

Since delta is a small number I will convert the stop and start time to unsigned long and leave deltas as float. I guess I am still looking for a way to ensure the is set to 4us and reset the timer.

As far as bullets go, I shoot air guns up to about 1400 fps but I need the resolution as low as possible since the speed variance is very critical. We also shoot high power and fast rifles like 7mm mag and I am looking at a 17 remington that goes to 4050fps plus. So in order to get the resolution at that speed we will use the first and third gate which are two feet apart.

Would an interrupt on rising be faster than waiting on high?

Jerry

cncjerry:
Would an interrupt on rising be faster than waiting on high?

No. A busy-loop is the better choice.

4000 f/s over 1 foot is 250 us. A resolution of 4 us is 1.6% of that. Is 1.6% good enough?

and leave deltas as float.

Why? Are you expecting the difference between two integer values to be a fractional amount?

No. A busy-loop is the better choice.

Not often that this statement is true, but in this case it very much is.

..for such high-speed events measurements I would take for example an XC9572XL CPLD breakout board from ebay ($14), add a 100MHz canned oscillator ($1), connect to arduino, and you can measure the events with 10ns resolution and 32bit range (or bigger).. 12.5micrometers bullet's position resolution @ 4500ft/sec.. $15 investment incl postage, and some effort.. just an idea.. :slight_smile:
p.

cncjerry:
Since delta is a small number I will convert the stop and start time to unsigned long and leave deltas as float.

That makes no sense at all. You don't seem to have taken on board that it is necessary to choose the appropriate data types for your data. This is fundamentally important, and if you leave this to trial and error or guesswork you will run into exactly the sort of precision/overflow problem that has bit you here. These are integer values and need to be stored in an integer big enough to hold the full range of values that this variable could have.

Yah instead of dividing by 1 million, just print the decimal point 6 places to the left.

Since long ago the method used to tell time of flight was to measure bullet drop. They fall at the same speed as any thrown or dropped object when fired horizontal.

When you have that working you might try for a ballistic pendulum. Then you can know bullet speed at range. Check out how old those are!

To make everyone happy, I will change delta_time to unsigned long int though I tested it as float and somewhere float needs to come into play without a lot of gymnastics. I want the numbers on the serial and LCD to be xxx.x though the .x means nothing, it looks good and at low speeds < 550 for instance, it will be accurate.

I don’t see how you would be able to divide delta_time by 1,000,000 leaving it all as unsigned integer and since delta will always be under 5000us for valid data, overflow is not applicable.

As far as accuracy goes, for a gun at 4,500 fps, the returned delta time will be one of 2: 4545ps / 220us or 4464fps / 216us which are 1% and .8% respectively of target. This is acceptable at those speeds and represent the high end problem. Most of my concerns are down around 500fps.

As far as the cpld, I was thinking that if I used a 100mhz crystal and a simple counter circuit I could get higher accuracy. I have more than enough pins on the mega I am using and was kicking that around but I need this working already. Also, I don’t know if the opto detectors can slew much faster than 4us anyway.

So I never got the prescaler code I wanted. Anyone?

  1. how do I set the prescaler?

  2. how do I reset the timer?

Thanks.

Jerry

I want the numbers on the serial and LCD to be xxx.x though the .x means nothing, it looks good and at low speeds < 550 for instance, it will be accurate.

What, exactly, does xxx.x represent? If the value is time, the .x will be meaningless at any speed. If it represents a speed, then the distance part of the calculation needs to be a float, but the time part (speed = distance/time) does not. Speed, of course needs to be a float.

You should consider changing the format as the speed increases. You might be able to measure the speed accurately to +/- a tenth of an inch (or foot or meter or mile) at low speeds, but not at higher speeds. At some point, the xxx.x format should change to just xxx.

  1. how do I reset the timer?

This comes up about twice a month on the forum. The general answer is “you don’t”. How often do you reset your watch? Practically never, right? That’s how often you should be trying to reset the Arduino’s timers.

cncjerry:
I don't see how you would be able to divide delta_time by 1,000,000 leaving it all as unsigned integer and since delta will always be under 5000us for valid data, overflow is not applicable.

You don't need to divide. Keep your units as microseconds. Just print the decimal point 6 places to the left, as you would with pencil and paper. You might have to fill in a few zeros but so what? Keep your units as microseconds.

This comes up about twice a month on the forum. The general answer is "you don't". How often do you reset your watch? Practically never, right? That's how often you should be trying to reset the Arduino's timers.

Truth about Arduino:
Anyone who ask:

How can I reset mills or timers?

Does not need the true answer.

By the way wife highjacked the TV so I got this code working:

const int ScreenPin1 = 11;
const int ScreenPin2 = 12;
const float dist = 1.0;     // Distance between 1 and 2 [ft] 

unsigned long time1, time2, deltaTime;
float flySpeed;
boolean running = 0;

void setup(){
  pinMode(ScreenPin1, INPUT);
  digitalWrite(ScreenPin1, HIGH);
  pinMode(ScreenPin2, INPUT);
  digitalWrite(ScreenPin2, HIGH);
  Serial.begin(115200);
  Serial.println("Starting");
}

void loop(){
  if (!running && (digitalRead(ScreenPin1)) == LOW) {
    time1 = micros();
    running = 1;
  }
  if ((running && (digitalRead(ScreenPin2)) == LOW)) {
    time2 = micros();
    deltaTime = time2-time1;
    Serial.print("Time: ");
    Serial.print(deltaTime);
    Serial.println(" us");
    
    flySpeed = dist*1000000UL/deltaTime;
    Serial.print("Speed: ");
    Serial.print(flySpeed);
    Serial.println(" fps");
    Serial.println();
    running = 0;
    delay(1000);
  }
}

-Fletcher

if (!running && (digitalRead(ScreenPin1)) == LOW) {
time1 = micros();

wouldn't adding the extra comparison above along with the digital read add a few microseconds to the test?

After I put my code back together above, admittedly it had been scrambled by all the testing, I am getting great results as below:

Resetwaiting 
start: 1571500 stop: 1590536 delta:19036 fps: 52.53
waiting 
start: 7126232 stop: 7129456 delta:3224 fps: 310.17
waiting 
start: 9639132 stop: 9642336 delta:3204 fps: 312.11
waiting 
start: 13143116 stop: 13146320 delta:3204 fps: 312.11
waiting 
start: 15361540 stop: 15364684 delta:3144 fps: 318.07
waiting 
start: 20252128 stop: 20255324 delta:3196 fps: 312.89
waiting 
start: 23142756 stop: 23145920 delta:3164 fps: 316.06
waiting 
start: 25452168 stop: 25455384 delta:3216 fps: 310.95
waiting 
start: 27555424 stop: 27558544 delta:3120 fps: 320.51
waiting 
start: 29655736 stop: 29658928 delta:3192 fps: 313.28
waiting 
start: 31798376 stop: 31801544 delta:3168 fps: 315.66
waiting 
start: 34366376 stop: 34369572 delta:3196 fps: 312.89
waiting 
start: 36558520 stop: 36561652 delta:3132 fps: 319.28
waiting 
start: 38875120 stop: 38878400 delta:3280 fps: 304.88
waiting 
start: 41867332 stop: 41871548 delta:4216 fps: 237.19
waiting 
start: 59274036 stop: 59277188 delta:3152 fps: 317.26
waiting 
start: 62496612 stop: 62499812 delta:3200 fps: 312.50
waiting 
start: 64731744 stop: 64734908 delta:3164 fps: 316.06
waiting 
start: 68112352 stop: 68115512 delta:3160 fps: 316.46
waiting 
start: 75685216 stop: 75688428 delta:3212 fps: 311.33
waiting 
start: 78567324 stop: 78570464 delta:3140 fps: 318.47
waiting 
start: 81081000 stop: 81084128 delta:3128 fps: 319.69
waiting 
start: 83781792 stop: 83784964 delta:3172 fps: 315.26
waiting 
start: 86281528 stop: 86284732 delta:3204 fps: 312.11
waiting 
start: 88920876 stop: 88924080 delta:3204 fps: 312.11
waiting 
start: 91739304 stop: 91742460 delta:3156 fps: 316.86
waiting 
start: 94520088 stop: 94523188 delta:3100 fps: 322.58
waiting 
start: 96960184 stop: 96963400 delta:3216 fps: 310.95
waiting 
start: 100195504 stop: 100198676 delta:3172 fps: 315.26
waiting 
start: 102875604 stop: 102878736 delta:3132 fps: 319.28
waiting 
start: 105423140 stop: 105426352 delta:3212 fps: 311.33
waiting 
start: 108066612 stop: 108069756 delta:3144 fps: 318.07
waiting 
start: 110471824 stop: 110475000 delta:3176 fps: 314.86
waiting 
start: 113031392 stop: 113034532 delta:3140 fps: 318.47
waiting 
start: 115346620 stop: 115349716 delta:3096 fps: 323.00
waiting 
start: 117823612 stop: 117826724 delta:3112 fps: 321.34
waiting 
start: 120745928 stop: 120749020 delta:3092 fps: 323.42
waiting 
start: 123798104 stop: 123801284 delta:3180 fps: 314.47
waiting 
start: 126775456 stop: 126778584 delta:3128 fps: 319.69
waiting 
start: 129056296 stop: 129059456 delta:3160 fps: 316.46
waiting 
start: 131807004 stop: 131810152 delta:3148 fps: 317.66
waiting 
start: 134434988 stop: 134438044 delta:3056 fps: 327.23
waiting 
start: 137054868 stop: 137058064 delta:3196 fps: 312.89
waiting 
start: 139526780 stop: 139529944 delta:3164 fps: 316.06
waiting 
start: 182862824 stop: 186076668 delta:3213844 fps: 0.31
waiting 
start: 189112232 stop: 189115436 delta:3204 fps: 312.11
waiting 
start: 191749796 stop: 191753008 delta:3212 fps: 311.33
waiting 
start: 194438388 stop: 194441536 delta:3148 fps: 317.66
waiting 
start: 196996860 stop: 197000000 delta:3140 fps: 318.47
waiting 
start: 199483564 stop: 199486720 delta:3156 fps: 316.86
waiting 
start: 201896860 stop: 201899980 delta:3120 fps: 320.51
waiting 
start: 204334060 stop: 204337216 delta:3156 fps: 316.86
waiting 
start: 206805724 stop: 206808896 delta:3172 fps: 315.26
waiting 
start: 209207500 stop: 209210696 delta:3196 fps: 312.89
waiting 
start: 211584012 stop: 211587216 delta:3204 fps: 312.11
waiting 
start: 214062448 stop: 214065608 delta:3160 fps: 316.46
waiting 
start: 217071216 stop: 217074372 delta:3156 fps: 316.86
waiting 
start: 219795556 stop: 219798764 delta:3208 fps: 311.72
waiting 
start: 222722200 stop: 222725404 delta:3204 fps: 312.11
waiting 
start: 225834208 stop: 225837376 delta:3168 fps: 315.66
waiting 
start: 228429400 stop: 228432616 delta:3216 fps: 310.95
waiting 
start: 232172244 stop: 232175404 delta:3160 fps: 316.46
waiting 
start: 236323860 stop: 236327032 delta:3172 fps: 315.26
waiting 
start: 238810232 stop: 238813416 delta:3184 fps: 314.07
waiting 
start: 241663588 stop: 241666760 delta:3172 fps: 315.26
waiting 
start: 244544448 stop: 244547608 delta:3160 fps: 316.46
waiting 
start: 247357816 stop: 247360928 delta:3112 fps: 321.34
waiting 
start: 250075792 stop: 250078936 delta:3144 fps: 318.07
waiting 
start: 252722972 stop: 252726112 delta:3140 fps: 318.47
waiting 
start: 255601524 stop: 255604708 delta:3184 fps: 314.07
waiting 
start: 258301528 stop: 258304720 delta:3192 fps: 313.28
waiting 
start: 261156612 stop: 261159732 delta:3120 fps: 320.51
waiting 
start: 263804040 stop: 263807248 delta:3208 fps: 311.72
waiting 
start: 266529140 stop: 266532352 delta:3212 fps: 311.33
waiting 
start: 269656956 stop: 269660108 delta:3152 fps: 317.26
waiting 
start: 272716860 stop: 272720020 delta:3160 fps: 316.46
waiting 
start: 275410120 stop: 275413252 delta:3132 fps: 319.28
waiting 
start: 277846792 stop: 277849972 delta:3180 fps: 314.47
waiting 
start: 280535604 stop: 280538808 delta:3204 fps: 312.11
waiting 
[end code]

This was with an airsoft sub machine gun.  It is supposed to shoot around 315fps.